www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 10995] New: [REG]CTFE failures for structs with void initialized members

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995

           Summary: [REG]CTFE failures for structs with void initialized
                    members
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: regression
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: monarchdodra gmail.com



Regression 2.063.2 => 2.064-devel

Possibly related (or even the root cause) of 10994:
http://d.puremagic.com/issues/show_bug.cgi?id=10994

Let T be a struct with a void initialized member:

REG 1:
//----
struct T
{
    short a = void;
}
enum i = T.init.a;
//----
main.d(5): Error: cannot read uninitialized variable T().a in ctfe
main.d(3): Error: variable main.T.a was uninitialized and used before set

REG2:
This one is more problematic, as there would seem to be some type system
corruption:

//----
struct T
{
    short a = void;
}

T foo()
{
    auto t = T.init;
    return t;
}

enum i = foo().a;
//----
main.d(12): Error: couldn't find field a in short
//----

Apparently, doing the call ".a" "transforms" the type of "foo()" to "a's" type,
giving the cryptic error message. Or something.


Both these cases passed in 2.063.2.
Both these cases pass if a is not declared void-initialized.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 08 2013
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995


Don <clugdbug yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |diagnostic, ice
            Summary|[REG]CTFE failures for      |CTFE failures for structs
                   |structs with void           |with void initialized
                   |initialized members         |members
           Severity|regression                  |normal



This is not a regression. The change in behaviour is an accepts-invalid bug
that was fixed. In both cases, an uninitialized variable is indeed being read.
To get the intended behaviour, use 

-enum i = T.init.a; 
+enum i = T.a.init;

In the first test case, the second error message is a bit useless and should be
removed.
And the second case, the error message is so bad it's practically a internal
compiler error.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 12 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995





 This is not a regression. The change in behaviour is an accepts-invalid bug
 that was fixed. In both cases, an uninitialized variable is indeed being read.
I somehow expected that answer, but I'm not sure I entirely agree. Marking a field to void means the compiler is allowed to optimize out giving the field a deterministic value on initializing the field, for run-time performance reasons. But that don't mean it's not actually initialized. I think that for CTFE, it should *just work* Not being able to count on "T t = T.init" meaning "t is in an initialized state", goes against what ".init" represents. No-one said it had a deterministic value though. In any case, I think it is not that problematic. "10994" is a real blocker for me though... -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 12 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995




 Marking a field to void means the compiler is allowed to optimize out giving
the field a deterministic value on initializing the field, for run-time performance reasons. But that don't mean it's not actually initialized. No, it's illegal. You're telling the compiler that you will initialize it. The compiler attempts to detect cases where you failed to do so, but it isn't always successful. For DMD, you need to compile with -O. struct S { int x; } void main() { S s = void; s.x++; } $ dmd -O bug bug.d(7): Error: variable s used before set The reason it seemed to be legal in structs, is that the compiler historically ignored the = void, and initialized it anyway! Now marking a field as void actually has an effect... (at least in some cases).
 "10994" is a real blocker for me though...
Yup. I've marked that with ctfe so that it appears on my list. The fix for the diagnostics in this one is here: https://github.com/D-Programming-Language/dmd/pull/2551 -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 13 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995


Maxim Fomin <maxim maxim-fomin.ru> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |maxim maxim-fomin.ru



---


 This is not a regression. The change in behaviour is an accepts-invalid bug
 that was fixed. In both cases, an uninitialized variable is indeed being read.
I somehow expected that answer, but I'm not sure I entirely agree. Marking a field to void means the compiler is allowed to optimize out giving the field a deterministic value on initializing the field, for run-time performance reasons. But that don't mean it's not actually initialized. I think that for CTFE, it should *just work*
Marking a field of aggregate to void does different thing comparing to void initialization of variable - it makes dmd to blit memory with zeroes regardless of type (for many types default value is zero, but for some types - likes doubles and chars dmd still produces zeroes). I think CTFE should follow runtime in this regard, so in your example value of 'a' should be zero. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 13 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995




---

 No, it's illegal. You're telling the compiler that you will initialize it. The
 compiler attempts to detect cases where you failed to do so, but it isn't
 always successful. For DMD, you need to compile with -O.
 
 struct S {
    int x;
 }
 
 void main() {
    S s = void;
    s.x++;
 }
This is irrelevant to the issue because it is a different case.
 $ dmd -O bug
 bug.d(7): Error: variable s used before set
 
 The reason it seemed to be legal in structs, is that the compiler historically
 ignored the = void, and initialized it anyway! Now marking a field as void
 actually has an effect... (at least in some cases).
 
I think this point (issuing not initialized error) is wrong. Regardless of what dmd does produce in runtime (technically speaking dmd didn't ignored void initializer for fields - its presence actually affected behavior), there should be statically known default value of any type - that's why during CTFE dmd should produce some default value even for structs having void initialized fields. So, if dmd accepts this feature, it should produce some value. Not initialized type does not make much sense. It looks like initializaing some filed with void is a wired idea which doesn't fit into design, so it should be probably removed from language. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 13 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995






 No, it's illegal. You're telling the compiler that you will initialize it. The
 compiler attempts to detect cases where you failed to do so, but it isn't
 always successful. For DMD, you need to compile with -O.
 
 struct S {
    int x;
 }
 
 void main() {
    S s = void;
    s.x++;
 }
This is irrelevant to the issue because it is a different case.
It illustrates that it is illegal to read a value initialized to void. It is the same case, unless .init is magical. (And maybe it should be magical, see below).
 $ dmd -O bug
 bug.d(7): Error: variable s used before set
 
 The reason it seemed to be legal in structs, is that the compiler historically
 ignored the = void, and initialized it anyway! Now marking a field as void
 actually has an effect... (at least in some cases).
 
I think this point (issuing not initialized error) is wrong. Regardless of what dmd does produce in runtime (technically speaking dmd didn't ignored void initializer for fields - its presence actually affected behavior),
That's only because it's been generating extremely bad code. Intuitively, initializing a struct should be the same as initializing each member individually. struct S { int a = 2; int b = void; } S s; should mean: S s = void; S.a = S.a.init; S.b = S.b.init; and only the S.a case should generate any code. In fact, if it doesn't behave in that way, it's a completely pointless feature. (It's not an optimization).
 there should
 be statically known default value of any type - that's why during CTFE dmd
 should produce some default value even for structs having void initialized
 fields. So, if dmd accepts this feature, it should produce some value. Not
 initialized type does not make much sense.
 
 It looks like initializing some field with void is a weird idea which doesn't
 fit into design, so it should be probably removed from language.
Quite possibly. It's a fight: .init gives what it was initialized with. 'void' says it's not initialized! They can't both be true! Certainly the current runtime behaviour (blitting zeros onto the struct) is useless. Another possible resolution would be to define .init to mean "the value the object would be initialized to, with = void treated as the default initializer. This would however mean that: S s; and S s = S.init; would not be the same, in the case where a void initializer is present. Of course they are different anyway, if a constructor is present. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 13 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995






 I think this point (issuing not initialized error) is wrong. Regardless of what
 dmd does produce in runtime (technically speaking dmd didn't ignored void
 initializer for fields - its presence actually affected behavior),
That's only because it's been generating extremely bad code. Intuitively, initializing a struct should be the same as initializing each member individually. struct S { int a = 2; int b = void; } S s; should mean: S s = void; S.a = S.a.init; S.b = S.b.init; and only the S.a case should generate any code.
Just for the record, you should never initialize a struct instance like this. If you do this, then the padding bytes will not be initialized. This is important, as if S has no elaborate opEquals, comparison becomes a straight up memcompare, which will unconditonally scan the totality of S, padding and all. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 13 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995




---


 This is irrelevant to the issue because it is a different case.
It illustrates that it is illegal to read a value initialized to void. It is the same case, unless .init is magical. (And maybe it should be magical, see below).
In case of particular variable void initialization there is no questions regarding default value of type per se, its semantic is clear and there is consensus regarding it. However in case of field initialization, usecase affects not some variable but type of variable (which is essential point here) and as consequence, all instances of that type. And there is no consensus on what does this feature mean. That's why I ask to concentrate on field void initialization.
 That's only because it's been generating extremely bad code.
 Intuitively, initializing a struct should be the same as initializing each
 member individually.
 
 struct S { 
    int a = 2;
    int b = void;
 }
 
 S s;
 
 should mean:
 S s = void;
 S.a = S.a.init;
 S.b = S.b.init;
 and only the S.a case should generate any code.
 
 In fact, if it doesn't behave in that way, it's a completely pointless feature.
 (It's not an optimization).
Yes, this behavior makes sense. There is one question left - what is default value of type S in CT, in particular what static assert(S.init.a == ??) should be.
 It looks like initializing some field with void is a weird idea which doesn't
 fit into design, so it should be probably removed from language.
Quite possibly. It's a fight: .init gives what it was initialized with. 'void' says it's not initialized! They can't both be true!
Yes.
 Certainly the current runtime behaviour (blitting zeros onto the struct) is
 useless.
Yes.
 Another possible resolution would be to define .init to mean "the value the
 object would be initialized to, with = void treated as the default initializer.
 This would however mean that:
 S s;
 and
 S s = S.init;
 would not be the same, in the case where a void initializer is present.
 Of course they are different anyway, if a constructor is present.
I think this is better option than current situation. Init value of aggregate with void field should give default value of respective type. If it does provide in CT zeroes irrespective of type, it is useless, if it doesn't yield anything at all, than it badly integrates into language design and should not be supported at all. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 13 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995




Commit pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/a65d3247bf1e2443f2ed4c1632cf5b032edf78d3
Fix bug 10995 CTFE failure for void initialized members

Fix the duplicate error message, and don't scrub twice -- only scrub
when CTFE is actually finished.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 13 2013
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=10995


Walter Bright <bugzilla digitalmars.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |bugzilla digitalmars.com
         Resolution|                            |FIXED



10:54:14 PDT ---
https://github.com/D-Programming-Language/dmd/pull/2551

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Sep 13 2013