Bug 3984 – Segfault(interpret.c): CTFE using struct constructor on a local static variable
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
All
Creation time
2010-03-18T23:44:00Z
Last change time
2014-02-15T02:43:43Z
Keywords
ice-on-valid-code, patch, wrong-code
Assigned to
nobody
Creator
sludwig
Comments
Comment #0 by sludwig — 2010-03-18T23:44:20Z
In the following code snipped, for global variables or enums, this.s is not correctly written in the constructor. The direct way to assign a value without the 'dst' temporary does not work due to http://d.puremagic.com/issues/show_bug.cgi?id=3801.
---
struct S {
float[1] s;
this(float x){
float[] dst = this.s;
dst[0] = x;
}
}
S S_zero = S(0); // initialization fails
enum S S_zero2 = S(0); // initialization fails
void main()
{
//enum S z = S(0); // ICE
//static S z = S(0); // ICE
//S z = S(0); // works, initialized with 0
//S z = S_zero; // contains NaN
S z = S_zero2; // contains NaN
assert(z.s[0] == 0);
}
---
Comment #1 by clugdbug — 2010-03-24T12:02:25Z
Most of the issues described here are duplicates of bug 1330, or bug 3801.
The segfault is the only new bug here. Here's a reduced test case:
struct Segfault3984 {
int a;
this(int x){
a = x;
}
}
void bug3984(){
static assert(Segfault3984(3).a == 3);
}
Root cause:
Struct constructors can result in a situation where a CTFE variable is created
outside of a CTFE function. They need a context to put the variable into.
Effectively, the comma expression acts a very simple function.
PATCH:
Interpret.c line 2641
Expression *CommaExp::interpret(InterState *istate)
{
#if LOG
printf("CommaExp::interpret() %s\n", toChars());
#endif
// If the comma returns a temporary variable, it needs to be an lvalue
// (this is particularly important for struct constructors)
if (e1->op == TOKdeclaration && e2->op == TOKvar
&& ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var)
{
+ // If there's no context for the variable to be created in,
+ // we need to create one now.
+ InterState istateComma;
+ if (!istate)
+ istate = &istateComma;
VarExp* ve = (VarExp *)e2;
VarDeclaration *v = ve->var->isVarDeclaration();
if (!v->init && !v->value)
v->value = v->type->defaultInitLiteral();