D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 5889 - Struct literal/construction should be rvalue (it binds to ref parameters)
Summary: Struct literal/construction should be rvalue (it binds to ref parameters)
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 normal
Assignee: No Owner
URL:
Keywords: accepts-invalid, patch
: 4843 5178 5769 7100 (view as issue list)
Depends on: 3659
Blocks: 4843
  Show dependency treegraph
 
Reported: 2011-04-26 00:31 UTC by Kenji Hara
Modified: 2012-04-23 11:18 UTC (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Kenji Hara 2011-04-26 00:31:19 UTC
This issue is combined issue 5178 and 5769, etc.

Following code should be passed.
----
struct S1{  }
struct S2{ int n; }
struct S3{ this(int n){} }

struct X1(T){  }
struct X2(T){ int n; }
struct X3(T){ this(int n){} }

bool isRvalue(T)(auto ref T t){ return !__traits(isRef, t); }
template Fn(string code){ mixin(code); }

void main()
{
    // 1.
    assert(isRvalue(S1(  )));       // now false, expect true
    assert(isRvalue(S2(12)));       // now false, expect true
    assert(isRvalue(S3(13)));       // now false, expect true

    // 2.
    static assert(!__traits(compiles, Fn!`ref S1 get1(){return S1(  );}`));             // now OK, expect NG
    static assert(!__traits(compiles, Fn!`ref S2 get2(){return S2(22);}`));             // now OK, expect NG
    static assert(!__traits(compiles, Fn!`ref S3 get3(){return S3(23);}`));             // now OK, expect NG

    static assert(!__traits(compiles, Fn!`ref X1!int get(){ return X1!int(  ); }`));    // now OK, expect NG
    static assert(!__traits(compiles, Fn!`ref X2!int get(){ return X2!int(32); }`));    // now OK, expect NG
    static assert(!__traits(compiles, Fn!`ref X3!int get(){ return X3!int(33); }`));    // now OK, expect NG

    // 3.
    void getref(T)(ref T t){}
    static assert(!__traits(compiles, getref(S1(  ))));         // now OK, expect NG
    static assert(!__traits(compiles, getref(S2(42))));         // now OK, expect NG
    static assert(!__traits(compiles, getref(S3(43))));         // now OK, expect NG

    static assert(!__traits(compiles, getref(X1!int(  ))));     // now OK, expect NG
    static assert(!__traits(compiles, getref(X2!int(10))));     // now OK, expect NG
    static assert(!__traits(compiles, getref(X3!int(10))));     // now OK, expect NG

    void getrefS1(ref S1 t){}
    void getrefS2(ref S2 t){}
    void getrefS3(ref S3 t){}
    static assert(!__traits(compiles, getrefS1(S1(  ))));       // now OK, expect NG
    static assert(!__traits(compiles, getrefS2(S2(10))));       // now OK, expect NG
    static assert(!__traits(compiles, getrefS3(S3(10))));       // now OK, expect NG

    void getrefX1(ref X1!int t){}
    void getrefX2(ref X2!int t){}
    void getrefX3(ref X3!int t){}
    static assert(!__traits(compiles, getrefX1(X1!int(  ))));   // now OK, expect NG
    static assert(!__traits(compiles, getrefX2(X2!int(10))));   // now OK, expect NG
    static assert(!__traits(compiles, getrefX3(X3!int(10))));   // now OK, expect NG
}
----

1. struct literal/construction should make rvalue.
2. returning struct literal/construction ref is invalid.
3. implicit conversion struct literal/construction to lvalue is invalid.
   (At least on ref parameter.)

My patch is here:
https://github.com/9rnsr/dmd/tree/rvalue-struct-literal
Comment 1 Kenji Hara 2011-04-29 21:27:14 UTC
Send pull request:
https://github.com/D-Programming-Language/dmd/pull/41

After pull requested, I thought this request may be too early to fix. This fix may break some existing codes.

Example:
----
struct S {
  int val;
  bool opEquals(ref const(S) rhs) const {
    return val == rhs.val;
  }
}
void main() {
  S s = S(10);
  assert(s == S(10));  // if S(10) changes from lvalue to rvalue,
                       // this line makes error.
}
----

Should fix struct opEquals signature problem before fixing this issue.
Comment 2 kennytm 2011-04-30 03:44:08 UTC
(In reply to comment #1)
> Send pull request:
> https://github.com/D-Programming-Language/dmd/pull/41
> 
> After pull requested, I thought this request may be too early to fix. This fix
> may break some existing codes.
> 
> Example:
> ----
> struct S {
>   int val;
>   bool opEquals(ref const(S) rhs) const {
>     return val == rhs.val;
>   }
> }
> void main() {
>   S s = S(10);
>   assert(s == S(10));  // if S(10) changes from lvalue to rvalue,
>                        // this line makes error.
> }
> ----
> 
> Should fix struct opEquals signature problem before fixing this issue.

So, it depends on bug 3659?
Comment 3 Kenji Hara 2011-04-30 03:53:31 UTC
(In reply to comment #2)
> So, it depends on bug 3659?

Yes. I change 'Depends on' status.
Comment 4 Kenji Hara 2011-06-24 04:52:32 UTC
bug4843 (and its duplication bug6201) is part of this issue.

FuncDeclaration::overloadResolve use TypeStruct::defaultInit, but it makes lvalue.
So ref and non-ref overloads make ambiguous.
Comment 5 Don 2011-06-29 17:47:15 UTC
I'm not convinced about this bug. Why do you think that struct literals should become rvalues (rather than non-modifiable lvalues)? It's a breaking change.

You've mentioned opEquals, but it's much broader than that. Fairly obviously it also affects opCmp, but in fact, any function which takes a struct by const ref will currently accept a struct literal.

Also, what about member functions? 'this' is passed by reference, yet you can use CTFE on member functions of struct literals.

It's clearly a bug to allow a struct literal to be passed by non-const reference, but as to making them rvalues, I'm not sure. This needs confirmation from Walter.
Comment 6 Kenji Hara 2011-06-29 18:11:03 UTC
(In reply to comment #5)
'Literal is rvalue' is very important semantics for strict typed languages.
A literal is not referenced from any other places, so it is _unique_ and _thread_local_. This is necessary for good resource management.
(e.g. Unique!T, Scoped!T, etc.)

But now, In D we cannot create rvalue struct object 'in place'.
(Note: Returned rvalue from function might be moved, so it is not 'in place'.)
It looks to me like a serious flaw.
Comment 7 Don 2011-06-29 23:28:22 UTC
(In reply to comment #6)
> (In reply to comment #5)
> 'Literal is rvalue' is very important semantics for strict typed languages.
> A literal is not referenced from any other places, so it is _unique_ and
> _thread_local_. This is necessary for good resource management.
> (e.g. Unique!T, Scoped!T, etc.)

But that's true of immutable as well. In reality, any struct literal which exists at run time is stored in the executable as if it were immutable (just as for a string literal).

> But now, In D we cannot create rvalue struct object 'in place'.
> (Note: Returned rvalue from function might be moved, so it is not 'in place'.)
> It looks to me like a serious flaw.
Comment 8 Kenji Hara 2011-06-30 00:14:51 UTC
(In reply to comment #7)
> But that's true of immutable as well. In reality, any struct literal which
> exists at run time is stored in the executable as if it were immutable (just as
> for a string literal).

??? I'm not speaking about object const-ness.
Yes, immutable struct literal will be stored in data-segment, but that is binary level issue, and definitely different from language semantics level.

Give you an example.
https://github.com/9rnsr/scrap/blob/master/typecons/unique.d
This is my prototype code to improve std.typecons.Unique.
In it, by receiving only rvalues for its initializing and assignment, Unique type can keep the uniqueness of stored object.

Similar improvements will be able on Scoped!T. By receiving only rvalue for initializing, we can separate the struct object that allocated on stack and others not.
Comment 9 Walter Bright 2011-06-30 00:43:08 UTC
I appreciate what you're trying to do, but I tend to agree with Don. I'm not sure this is a correct thing to do.
Comment 10 Kenji Hara 2011-06-30 04:37:33 UTC
OK. Here's another advantage of that.

----
struct S1{ int n; }
struct S2{ this(int n){} }
struct S3{ int n; void opAssign(S3 rhs){} }

void main()
{
    S1(0) = S1(0);  // Line 7
    S2(0) = S2(0);  // Line 8
    S3(0) = S3(0);  // Line 9 
}
----

Line 7 and 8 are no effect codes. We can reject them by making struct literal as rvalue.
Line 9 is an exception. S3.opAssign can have effect, so it is legal.
Comment 11 Kenji Hara 2011-06-30 04:47:55 UTC
Another example.
In C++0x (gcc-4.5.1), following code prints "1".
It seems to me that the S() makes rvalue instead of lvalue.
----
#include <stdio.h>

struct S {};

int f(S&&){ return 1; }
int f(const S&){ return 2; }

int main()
{
  printf("%d\n", f(S()));
  return 0;
}
----
Comment 12 Kenji Hara 2011-12-12 19:55:11 UTC
*** Issue 7100 has been marked as a duplicate of this issue. ***
Comment 13 yebblies 2012-01-30 19:36:09 UTC
*** Issue 5178 has been marked as a duplicate of this issue. ***
Comment 14 github-bugzilla 2012-02-20 19:22:11 UTC
Commit pushed to master at https://github.com/D-Programming-Language/dmd

https://github.com/D-Programming-Language/dmd/commit/907c94de34b9d99438e7e244c556903224a0c094
Merge pull request #41 from 9rnsr/rvalue-struct-literal

Issue 5889 - Struct literal/construction should be rvalue
Comment 15 Kenji Hara 2012-04-22 16:38:58 UTC
*** Issue 4843 has been marked as a duplicate of this issue. ***
Comment 16 Kenji Hara 2012-04-23 11:18:45 UTC
*** Issue 5769 has been marked as a duplicate of this issue. ***