Bug 3863 – Various errors and ICE(todt.c) for struct constructors with ellipses

Status
RESOLVED
Resolution
DUPLICATE
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Windows
Creation time
2010-02-28T02:41:00Z
Last change time
2014-02-15T02:45:56Z
Keywords
ice, patch, wrong-code
Assigned to
nobody
Creator
sludwig

Comments

Comment #0 by sludwig — 2010-02-28T02:41:00Z
The following code snipped lists a number of ways to define a struct constant which fail compilation in one way or another. This happens only --- struct Vec(int N){ //static immutable constant = Vec(1, 2); // error more initializers than fields //static immutable Vec constant = Vec(1, 2); // compiles //enum constant = Vec(1, 2); // error more initializers than fields enum Vec constant = Vec(1, 2); // compiles this(const float[N] args...) {} //this(float a, float b) {} // all cases compile } struct Test { alias Vec!2 Vec2; Vec2 member; //static immutable constant = Test(Vec!2(1, 2)); // compiler crash //static immutable Test constant = Test(Vec!2(1, 2)); // assertion failure on todt.c:688 //static immutable constant = Test(Vec!(2).constant); // assertion failure on todt.c:688 //enum constant = Test(Vec!(2).constant); // compiles enum Test constant = Test(Vec2.constant); // compiles //enum Test constant = Test(Vec2(1, 2)); // error void initializer has no value this(Vec2 x){ member = x; } } --- When the first sturct is not templated, the situation changes: --- struct Vec { static immutable Vec constant = Vec(1, 2); this(const float[2] args...) {} } struct Test { alias Vec Vec2; Vec2 member; static immutable constant = Test(Vec2(1, 2)); // compiler crash //static immutable Test constant = Test(Vec2(1, 2)); // compiles //static immutable constant = Test(Vec2.constant); // compiles //enum constant = Test(Vec2.constant); // compiles //enum Test constant = Test(Vec2.constant); // compiles //enum Test constant = Test(Vec2(1, 2)); // error void initializer has no value this(Vec2 x){ member = x; } } --- Using an enum in the first struct makes things worse: --- struct Vec { enum Vec constant = Vec(1, 2); this(const float[2] args...) {} } struct Test { alias Vec Vec2; Vec2 member; static immutable constant = Test(Vec2(1, 2)); // compiler crash //static immutable Test constant = Test(Vec2(1, 2)); // compiles //static immutable constant = Test(Vec2.constant); // compiler crash //enum constant = Test(Vec2.constant); // compiler crash //enum Test constant = Test(Vec2.constant); // error void initializer has no value //enum Test constant = Test(Vec2(1, 2)); // error void initializer has no value this(Vec2 x){ member = x; } } ---
Comment #1 by sludwig — 2010-02-28T03:29:17Z
(In reply to comment #0) > The following code snipped lists a number of ways to define a struct constant > which fail compilation in one way or another. This happens only ... if ellipses are used for the constructor arguments. However, the "more fields than initializers" case remains even without them: --- struct Vec{ //static immutable constant = Vec(1, 2); // error more initializers than fields //static immutable Vec constant = Vec(1, 2); // compiles //enum constant = Vec(1, 2); // error more initializers than fields //enum Vec constant = Vec(1, 2); // compiles this(float a, float b) {} } ---
Comment #2 by clugdbug — 2010-04-10T13:55:43Z
The first step is to turn the segfaults into an ICE: todt.c, line 59. dt_t *VoidInitializer::toDt() { /* Void initializers are set to 0, just because we need something * to set them to in the static data segment. */ dt_t *dt = NULL; + assert(type); dtnzeros(&dt, type->size()); return dt; } I haven't been able to reproduce the other ICE (todt.c 688) on either 2.043, 2.040, or 2.041.
Comment #3 by sludwig — 2010-04-11T07:53:32Z
I looked again at the assertion failure and it seems as it has had nothing to do with the ellipses. Also does not occur on 2.043 anymore (but does on 2.041). Reduced repro case: --- struct Vec{ float member[2]; enum Vec constant = Vec(1, 2); this(float a, float b){} } struct Test { Vec member; static immutable Test constant1 = Test(Vec(1, 2)); } --- I could not find an existing bug report for the error messages "more initializers than fields" or "void initializer has no value". It seems that when using type inference for the enum constant, the order of declarations of the member variable, the enum constant and the constructor determines what "Vec(1, 2)" means (struct literal or constructor call) or "sees". But maybe it would be better to make a seperate bug report and consider only the compiler crash here?
Comment #4 by clugdbug — 2010-04-11T11:32:54Z
(In reply to comment #3) > I looked again at the assertion failure and it seems as it has had nothing to > do with the ellipses. Also does not occur on 2.043 anymore (but does on 2.041). Great! I can reproduce that, too. > I could not find an existing bug report for the error messages "more > initializers than fields" or "void initializer has no value". It seems that > when using type inference for the enum constant, the order of declarations of > the member variable, the enum constant and the constructor determines what > "Vec(1, 2)" means (struct literal or constructor call) or "sees". But maybe it > would be better to make a seperate bug report and consider only the compiler > crash here? Yes, please make a separate bug. I'm pretty sure that the crash has a cause which is different from the rest.
Comment #5 by clugdbug — 2010-04-11T14:51:25Z
Actually this is a rare case where the ICE bug is the same as the others. I don't think it has anything to do with constructor varargs, actually. It involves using a struct constructor to perform type inference of a member of that struct. Here's an example of a situation where the current behaviour leads to wrong code: struct Vec { int w; this(int x) { w = 2; } enum KK = Vec(100); enum Vec KK2 = Vec(100); } static assert(Vec.KK == Vec.KK2); // Error: static assert ((Vec(100)) == (Vec(2))) is false ========= PATCH. Issue an error message in these potentially recursive situations. Although in this specific case, it could be made to compile by running semantic on the constructors first, that won't work in general (the constructor may make use of the enum, for example). I've tested this on the DMD test suite, and it passes. expression.c CallExp::semantic(), line 6790. ========== #if !STRUCTTHISREF /* Constructors return a pointer to the instance */ e = new PtrExp(loc, e); #endif e = e->semantic(sc); return e; } + // Check for a forward reference to a struct constructor. + else if (arguments && arguments->dim && !ad->ctor && ad->sizeok != 1) + { + // The semantic pass of the struct isn't yet complete. + // Check for attempt to use a constructor. + Dsymbol *ctor = ad->search(0, Id::ctor, 0); + if (ctor) + { + error("Forward reference to struct constructor"); + return new ErrorExp(); + } + }
Comment #6 by sludwig — 2010-04-27T14:13:23Z
Just wanted to note that this bug actually provides the only way to work around issue 3801. So please, do not fix or change this into an error message before implementing "struct.member[] = x;" or "struct.member[i] = x;" for CTFE.
Comment #7 by clugdbug — 2013-01-16T03:07:00Z
Fixed when bug 8741 was fixed. the wrong-code and ICE test cases now generate error messages. *** This issue has been marked as a duplicate of issue 8741 ***