2702 – Struct initialisation silently inserts deadly casts

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 2702 - Struct initialisation silently inserts deadly casts
Summary: Struct initialisation silently inserts deadly casts
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D1 (retired)
Hardware: x86 Windows
: P2 critical
Assignee: No Owner
URL:
Keywords: accepts-invalid, patch, wrong-code
: 3259 (view as issue list)
Depends on:
Blocks:
Reported: 2009年03月01日 19:37 UTC by David Simcha
Modified: 2014年03月01日 00:36 UTC (History)
3 users (show)

See Also:


Attachments
Add an attachment (proposed patch, testcase, etc.)

Note You need to log in before you can comment on or make changes to this issue.
Description David Simcha 2009年03月01日 19:37:49 UTC
import std.stdio;
struct Bar {
 uint num;
 Bar opAssign(uint otherNum) {
 num = otherNum;
 return this;
 }
}
void main() {
 Bar bar = 1;
 writeln(bar.num); // Prints 0.
}
Comment 1 Don 2009年08月04日 02:22:05 UTC
I think this is invalid.
Bar bar=1; is a construction, not an assignment.
Comment 2 Don 2009年08月07日 01:16:33 UTC
Actually there is a bug:
Bar bar = 1;
should not be accepted.
Here's a really frightening case:
struct A { char [] a; }
struct B { long x; }
void main() {
 B s; 
 A q = s;
}
--------------
The cause is in VarDeclaration::semantic in declaration.c, line 1083 (DMD 2.031), in the section dealing with initialisation of a struct. The code is:
		 if (!ei->exp->implicitConvTo(type))
		 {	Type *ti = ei->exp->type->toBasetype();
			// Don't cast away invariant or mutability in initializer
 if (!(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) {
			 ei->exp = new CastExp(loc, ei->exp, type);
 }
		 }
and in D1, it's just (line 1074):
 if (!ei->exp->implicitConvTo(type))
	ei->exp = new CastExp(loc, ei->exp, type);
If it can't be implicitly converted to a struct, why the heck should an explicit cast be inserted??? 
PATCH(D1): Delete those 2 lines.
On D2, we need the same logic as for assignment.
Comment 3 Don 2009年08月08日 22:19:09 UTC
I have confirmed that after completely removing that section of code, the DMD test suite still passes all tests. I tried to construct a valid case which required that code, but was unable to find one -- it looks as though that code is ONLY creating bugs.
Comment 4 Don 2009年09月07日 01:16:45 UTC
*** Issue 3259 has been marked as a duplicate of this issue. ***
Comment 5 Don 2009年09月24日 06:40:24 UTC
There must have been something wrong with the way I tested this. It fails one of the test suite tests. Not yet patched.
Comment 6 Don 2009年09月24日 07:02:06 UTC
Hmm. It seems that code I commented out is used to invoke static opCall(). That seems very wrong to me, as it's allowing all sorts of other garbage to compile.
Comment 7 Don 2009年09月25日 01:06:47 UTC
Here's a revised patch, same place (VarDeclaration::semantic in declaration.c, around line 1083). Replace the existing code with this version, which explicitly allows opCall and NOTHING ELSE:
---
		 // Dynamic initialization uses static opCall.
		 if (!ei->exp->implicitConvTo(type))
		 {	// Look for opCall
			if (search_function(sd, Id::call))
		 	{ // Rewrite as e1.call(arguments)
			 Expression * eCall = new DotIdExp(loc, e1, Id::call);
			 ei->exp = new CallExp(loc, eCall, ei->exp);
			}
		 }
---
This passes everything in the DMD test suite, except for one line in one test (xtest46.d, test30) which I believe to be broken. I don't think that all of the opDot() and 'alias this' possibilities are tested in the test suite, however.
Here's a tiny test which concisely tests the main features:
struct A { char [] a; }
struct B { long x; }
struct C { int a;
 static C opCall(int b) { C q; q.a=b; return q; }
}
static assert(!is(typeof( (){ A s; B q = s; })));
static assert(!is(typeof( (){ B x =1L; })));
static assert(is(typeof( (){ C g = 7; })));
static assert(is(typeof( (){ C g = 7; C h = g;})));
Comment 8 Walter Bright 2009年10月06日 02:15:10 UTC
Fixed dmd 1.048 and 2.033


AltStyle によって変換されたページ (->オリジナル) /