3809 – Struct initializers apparently always CTFE'd

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3809 - Struct initializers apparently always CTFE'd
Summary: Struct initializers apparently always CTFE'd
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 major
Assignee: No Owner
URL:
Keywords: diagnostic, rejects-valid
Depends on:
Blocks:
Reported: 2010年02月16日 14:25 UTC by Matti Niemenmaa
Modified: 2015年06月09日 05:12 UTC (History)
2 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 Matti Niemenmaa 2010年02月16日 14:25:34 UTC
This worked at least as late as 1.051, but now fails in 1.056:
struct S { int xx; int x() { return xx; } }
void foo(S s) {
	S a = {100 / s.x()};
	S b = {100 / s.x()};
}
$ dmd arst.d
Error: divide by 0
arst.d(4): Error: cannot evaluate s.x() at compile time
It seems like it's CTFEing the s.x() calls, which would explain the (bonus: location-lacking) division by zero error as well: xx is zero by default, after all.
Confirmed by changing "int xx" to "int xx = 1" and returning b from foo: the code compiles, and the disassembly shows that no divisions are being performed, it was erroneously done at compile time. Similarly, changing the code to perform e.g. a multiplication instead of a division makes it compile (as the division by zero is the cause for the lack of compilation), but again the s.x() has been improperly CTFE'd.
An additional point of interest: the "cannot evaluate" error is only reported for the S's after the first: with only one, the code compiles (to wrong code, again).
Comment 1 Don 2010年02月26日 07:49:20 UTC
I think this is the same as bug 3792.
Comment 2 Don 2010年04月23日 12:51:54 UTC
Starting with the simple thing: the missing line number in the division by 0 error message.
PATCH: interpret.c, near the start of BinExp::interpretAssignCommon().
 else if (e1->op != TOKslice)
 { /* Look for special case of struct being initialized with 0.
 */
 if (type->toBasetype()->ty == Tstruct && newval->op == TOKint64)
 {
- newval = type->defaultInitLiteral();
+ newval = type->defaultInitLiteral(loc);
 }
 newval = Cast(type, type, newval);
 e = newval;
 }
Comment 3 Don 2010年04月23日 12:58:21 UTC
(In reply to comment #2)
> Starting with the simple thing: the missing line number in the division by 0
> error message.
> PATCH: interpret.c, near the start of BinExp::interpretAssignCommon().
[snip]
Oops, that patch fixed a related test case:
struct S { int xx; }
int badline() { S s; return 100/s.xx; }
static assert(badline());
To fix this one as well, the same patch needs to applied to interpret.c, getVarExp(), around line 1250.
 if (v->init)
 {
 if (v->init->isVoidInitializer())
 {
 error(loc, "variable %s is used before initialization", v->toChars());
 return EXP_CANT_INTERPRET;
 }
 e = v->init->toExpression();
 e = e->interpret(istate);
 }
 else // This should never happen
 {
- e = v->type->defaultInitLiteral();
+ e = v->type->defaultInitLiteral(loc);
 }
Comment 4 Don 2010年05月31日 11:46:37 UTC
This isn't really a regression. Struct static initializers
have always been CTFEd, for example the code below generates a compile-time
div-by-zero error even in DMD 1.023. The only reason this code ever worked
was that CTFE didn't work for member functions. Starting with svn 337 
(DMD1.056), member functions can be called at compile time.
However, the spec says:
"The static initializer syntax can also be used to initialize non-static variables, provided that the member names are not given. 
The initializer need not be evaluatable at compile time."
The compiler has never complied with this part of the spec.
// Should compile, but fails
int bug3809() { asm { nop; } return 0; }
struct BUG3809 { int xx; }
void bug3809b() {
 BUG3809 b = { bug3809() };
}
Comment 5 Walter Bright 2010年06月02日 15:37:10 UTC
http://www.dsource.org/projects/dmd/changeset/517 turns it into rejects-valid
Comment 6 Don 2010年08月06日 03:34:42 UTC
Although CTFE is still performed, it's no longer performed incorrectly.
Since CTFE has always been performed on struct initializers, I'm removing the 'regression' tag.


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