www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 7021] New: Structs with disabled default constructors can be constructed without calling a constructor.

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

           Summary: Structs with disabled default constructors can be
                    constructed without calling a constructor.
           Product: D
           Version: D2
          Platform: Other
        OS/Version: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: simen.kjaras gmail.com



PST ---
struct Foo {
     disable this();
}

void main() {
    auto foo = Foo();
}

The above code compiles and runs just fine on dmd 2.056.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Nov 27 2011
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021


Jonathan M Davis <jmdavisProg gmx.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jmdavisProg gmx.com
           Severity|normal                      |major



PDT ---
This works just fine too (with dmd 2.060HEAD)

struct Foo
{
     disable this();
}

void main()
{
    auto foo = Foo.init;
}

It looks to me like  disable this() isn't working at all.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 09 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




PDT ---
*** Issue 8457 has been marked as a duplicate of this issue. ***

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 27 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021


Simen Kjaeraas <simen.kjaras gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |k.hara.pg gmail.com



PDT ---
*** Issue 8703 has been marked as a duplicate of this issue. ***

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





 This works just fine too (with dmd 2.060HEAD)
 
 struct Foo
 {
      disable this();
 }
 
 void main()
 {
     auto foo = Foo.init;
 }
 
 It looks to me like  disable this() isn't working at all.
I think that built-in init property should be valid even if default ctor is disabled. T.init shows runtime object initial bit-wise representation. So, in this case, Foo.init would be 1 byte zero filled memory, and should be accessible even if Foo is not default constructible. But T.init sometimes does not *valid* object. See following example. struct Bar { int value; disable this(); this(int v) { assert(v > 0); value = v; } } Bar's constructor appeals that Bar.value is initialized with natural number. But Bar.init.value == 0, because it doesn't call valid ctor. Then T.init is *invalid* object. This is not a defect of D language, but also it is a point you should be careful. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 21 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021


Kenji Hara <k.hara.pg gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull
           Platform|Other                       |All



https://github.com/D-Programming-Language/dmd/pull/1132

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




PDT ---

 I think that built-in init property should be valid even if default ctor is
 disabled.
 T.init shows runtime object initial bit-wise representation. So, in this case,
 Foo.init would be 1 byte zero filled memory, and should be accessible even if
 Foo is not default constructible.
I agree, seeing as T.init can be disabled. If someone really, *really* needs a T without calling its constructor, there are still ways. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 21 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




PDT ---
Wait.

 disable this();

_is_ the way to disable init. If

 diasble this();

was used, then there should be no init property. That's the entire point of

 disable this;

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


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

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



---

 Wait.
 
  disable this();
 
 _is_ the way to disable init. If
 
  diasble this();
 
 was used, then there should be no init property. That's the entire point of
 
  disable this;
Why? .init is a property which currently (2.060) can be hijacked. Dmd seems not to generate an implicit constructor function, it just initialize raw memory with default values when it faces S(). This is why disabling any function (ctors too) doesn't prevent it from creating S object. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 21 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021





 Wait.
 
  disable this();
 
 _is_ the way to disable init. If
 
  diasble this();
 
 was used, then there should be no init property. That's the entire point of
 
  disable this;
I think that using T.init does not call any constructors. Therefore any constructor declarations cannot stop its using. ---- I think a struct that has disable this(); is similar to nested struct that used outside of the valid scope. void main() { struct S { // nested struct int n; void foo(){} } static assert(is(typeof(S.init.tupleof[$-1]) == void*)); // hidden frame ptr check!S(); } void check!T() { T t1; // today this is rejected by fixing issue 8339 T t2 = T.init; // this is still valid assert(t2.tupleof[$-1] is null); // but hidden frame ptr is null // then, t2 is *invalid* object. } On the other hand, even if disable this(); is declared, init property exists. struct S { disable this(); // disable default construction this(int n) { // valid construction with a parameter // in here, the memory of 'this' is filled with *S.init*. ...logical initialization of 'this' object with ctor parameters... } } T.init property does not guarantee that the returned object is logically correctly initialized, but it always provides the initial bit representation of T. I think this rule is reasonable also for disable this(); struct. Of course, you can select a following design: "If struct has disable this(); *and* no other ctors, init property is also disabled." But, it seems to me that is a special case which reduces the orthogonality and increase the complexity. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 21 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




PDT ---
It was my understanding that

 disable this();

was specifically the syntax to disable the init property. Certainly, trying to
disable init directly doesn't work as far as I can tell. And since structs
don't _have_ default constructors, I don't know what else

 disable this();

would be disabling (other than perhaps S(), which uses the init property
anyway, since there's no default consturctor).

The whole point is to be able disable init so that you can _never_ use it for
_anything_. You must _always_ directly initialize such a type (unless you
directly initialize it with void).

Yes, normally, T.init is the value that the type has before any constructor is
called, but if it's disabled, then it effectively does not exist, and it should
be impossible to use T.init _anywhere_. Construction should work the same with
any constructors that do exist (so the object state prior to construction is
the same as what T.init would have been had it existed), but it should be
impossible to default initialize such a type or to use it in any context which
would require default initialization, and it should be impossible to reference
that type's init in code anywhere. That's the whole point of disabling init,
and

 disable this();

is specifically for disabling init. It doesn't affect declared constructors
work, but it affects every other aspect of init.

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




---

 It was my understanding that
 
  disable this();
 
 was specifically the syntax to disable the init property. Certainly, trying to
 disable init directly doesn't work as far as I can tell. And since structs
 don't _have_ default constructors, I don't know what else
 
  disable this();
 
 would be disabling (other than perhaps S(), which uses the init property
 anyway, since there's no default consturctor).
I think disable this(); _does_ disables just a default constructor, and doesn't disable init property. As long as I repeated, init property represents a initial state of the object. (In the language reference, it is called 'default initializer'; http://dlang.org/property.html#init ). My first point is: init property does not construct anything. Next, if any constructor is declared in struct S, S(...) is always calls the constructors, and _should not_ become struct literal expression. This is my second point. S() would call this(), but it is disabled, then the compiler show an error so disable function is used. The third point is: the first and second are orthogonal. So I can agree that disable this(); would forbid a usage of S(), but I don't think that S.init would also be forbidden.
 The whole point is to be able disable init so that you can _never_ use it for
 _anything_. You must _always_ directly initialize such a type (unless you
 directly initialize it with void).
 
 Yes, normally, T.init is the value that the type has before any constructor is
 called, but if it's disabled, then it effectively does not exist, and it should
 be impossible to use T.init _anywhere_. Construction should work the same with
 any constructors that do exist (so the object state prior to construction is
 the same as what T.init would have been had it existed), but it should be
 impossible to default initialize such a type or to use it in any context which
 would require default initialization, and it should be impossible to reference
 that type's init in code anywhere. That's the whole point of disabling init,
 and
 
  disable this();
 
 is specifically for disabling init. It doesn't affect declared constructors
 work, but it affects every other aspect of init.
There is a way to disable explicit init property usage. struct S { disable this(); // disable default construction disable enum int init; // dummy disabled init property, this is allowed ... } I think that the usage of S.init is at your own risk. S.init may generate invalid object, but it is sometimes useful. I hesitate that stopping such usage by the compiler. At least, S() would be disabled by disable this(); declaration. It is the point of this issue, and my pull request will fix it. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 21 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




PDT ---
For structs, as long as there is no static opCall declared, S() and S.init
should be identical, and I'd strongly argue that if one is disabled, the other
should be disabled. They do exactly the same thing. It makes _no_ sense IMHO to
allow S.init but allow S() or vice versa (as long as no static opCall is
declared).

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




---

 For structs, as long as there is no static opCall declared, S() and S.init
 should be identical, 
This is not already true for nested structs. void main() { int g = 10; struct S { int n; auto foo(){ return g; } } auto s1 = S(); // StructLiteralExp assert(s1.tupleof[$-1] !is null); // hidden ptr is filled assert(s1.foo() == 10); // OK auto s2 = S.init; assert(s2.tupleof[$-1] is null); // hidden ptr isn't filled assert(s2.foo() == 10); // Access Violation! } -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 21 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




PDT ---
 This is not already true for nested structs.
Well, that's disgusting. There are way too many special cases here. I'd vote to just make S() identical to S.init even with nested structs. It's more consistent that way, especially since you can't have a default constructor making it so that S() can't possible refer to a default constructor. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 21 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021


Don <clugdbug yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |clugdbug yahoo.com.au





 For structs, as long as there is no static opCall declared, S() and S.init
 should be identical, 
This is not already true for nested structs. void main() { int g = 10; struct S { int n; auto foo(){ return g; } } auto s1 = S(); // StructLiteralExp assert(s1.tupleof[$-1] !is null); // hidden ptr is filled assert(s1.foo() == 10); // OK auto s2 = S.init; assert(s2.tupleof[$-1] is null); // hidden ptr isn't filled assert(s2.foo() == 10); // Access Violation! }
That's a bug: .init for nested structs is garbage. It's the cause of bug 6419, for example. defaultInitLiteral() is wrong. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 24 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




PDT ---
 That's a bug: .init for nested structs is garbage. It's the cause of bug 6419,
for example. defaultInitLiteral() is wrong. Then I _definitely_ think that S() and S.init should always be the same for structs as long as static opCall has not been declared, and disable this(); should disable S.init such that it's impossible to ever default-initialize S or to use S.init or to use S() (though S() should still work if static opCall is declared). -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 24 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




---

 That's a bug: .init for nested structs is garbage. It's the cause of bug 6419,
 for example. defaultInitLiteral() is wrong.
Hmmm? Now all cases in bug 6419 run correctly. In current, by fixing bug 7965, TypeStruct::defaultInitLiteral always returns StructLiteralExp. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 24 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021




---

 Then I _definitely_ think that S() and S.init should always be the same for
 structs as long as static opCall has not been declared
I cannot agree with your this opinion. If S() is identical with S.init, default construction of nested struct will cause Access Violation in anywhere. It means that s1 would be broken at the -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Sep 24 2012
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021


monarchdodra gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |monarchdodra gmail.com



Erm, it was my understanding that  disable this() meant that it becomes illegal
to initialize a struct to *just* .init (or call the .init property directly),
and that a constructor must be called. The .init property still exists though,
because construction can't actually happen without .init anyways...

------
import std.stdio;
struct S
{
    int i;
    S(int v)
    {
        i+=v;
    }
}

void main()
{

    // S s1; //Error: variable main.main.s1 initializer required for type S
    S s3 = S(3);
    writeln(s3.i);
}
------
3
------
The fact that this program outputs three is proof that s3 is first .init
initialized, before the constructor is called proper. That's the only logical
behavior (IMO) when you think of how D's initialization scheme works. If .init
was truly disabled, the ONLY legal initialization would become:
----
S s = void;
----


THIS works though :/ ???
--------
void main()
{
    S s2 = S(); //WHAT...?
    S s3 = S(3);
    writeln(s3.i);
}
--------
I side with Jonathan that S() and .init should be the same thing. There are no
"default constructors" (or "no-arg", to my great dismay), in D, so having "S s
= S();" do some things behind the scenes that "S s;" doesn't is just not
conceivable from a language standpoint.

The fact that the stack pointer is not known at compile time in .init (I think,
anyways) should not prevent "S s;" from properly initialized, be it by a
stwo-step scheme if needed. That is a compiler implementation details, and
users should (NEED) to remain blissfully unaware of it.

Either that, or we allow a true constructor that takes no argument:
S s; // .init
S s = S(); // this(){...}

But as of right now, it would seem there is a bastard of an hybrid that is half
of both.

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




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

https://github.com/D-Programming-Language/dmd/commit/572b28e157c534bcbe918e11f9a52c7c6aa1379e
fix Issue 7021 - Structs with disabled default constructors can be constructed
without calling a constructor.

https://github.com/D-Programming-Language/dmd/commit/3038cf1a60e07dfae3976aa7f0f2e0d17aef47d1


Issue 7021 - Structs with disabled default constructors can be constructed
without calling a constructor.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 11 2012
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=7021


yebblies <yebblies gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |yebblies gmail.com
         Resolution|                            |FIXED


-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Oct 28 2012