From 6d6d0300084ea76b8489cd1fe397f578ccaa6e44 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sat, 2 Nov 2024 22:55:53 -0700 Subject: [PATCH] add __rvalue(expression) builtin --- compiler/src/dmd/astbase.d | 1 + compiler/src/dmd/clone.d | 3 +- compiler/src/dmd/dscope.d | 2 + compiler/src/dmd/e2ir.d | 2 + compiler/src/dmd/expression.d | 39 ++++++----- compiler/src/dmd/expression.h | 1 + compiler/src/dmd/expressionsem.d | 2 + compiler/src/dmd/frontend.h | 76 ++++++++++++---------- compiler/src/dmd/hdrgen.d | 6 ++ compiler/src/dmd/parse.d | 10 +++ compiler/src/dmd/scope.h | 1 + compiler/src/dmd/tokens.d | 7 ++ compiler/src/dmd/tokens.h | 1 + compiler/src/dmd/typesem.d | 18 +++-- compiler/test/fail_compilation/fail19871.d | 20 ------ compiler/test/fail_compilation/fail19931.d | 15 ----- compiler/test/fail_compilation/fail23036.d | 22 ------- compiler/test/runnable/rvalue1.d | 42 ++++++++++++ compiler/test/runnable/test23036.d | 13 ++++ compiler/test/unit/lexer/location_offset.d | 1 + 20 files changed, 170 insertions(+), 112 deletions(-) delete mode 100644 compiler/test/fail_compilation/fail19871.d delete mode 100644 compiler/test/fail_compilation/fail19931.d delete mode 100644 compiler/test/fail_compilation/fail23036.d create mode 100644 compiler/test/runnable/rvalue1.d create mode 100644 compiler/test/runnable/test23036.d diff --git a/compiler/src/dmd/astbase.d b/compiler/src/dmd/astbase.d index bdc489871c36..379a22ccc7a7 100644 --- a/compiler/src/dmd/astbase.d +++ b/compiler/src/dmd/astbase.d @@ -4548,6 +4548,7 @@ struct ASTBase EXP op; ubyte size; ubyte parens; + ubyte rvalue; // consider this an rvalue, even if it is an lvalue Type type; Loc loc; diff --git a/compiler/src/dmd/clone.d b/compiler/src/dmd/clone.d index bbfb1ee9f87d..6e104be10281 100644 --- a/compiler/src/dmd/clone.d +++ b/compiler/src/dmd/clone.d @@ -1617,6 +1617,7 @@ private Statement generateCopyCtorBody(StructDeclaration sd) */ bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) { + //printf("needCopyCtor() %s\n", sd.toChars()); if (global.errors) return false; @@ -1655,7 +1656,7 @@ bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) if (cpCtor) { - if (rvalueCtor) + if (0 && rvalueCtor) { .error(sd.loc, "`struct %s` may not define both a rvalue constructor and a copy constructor", sd.toChars()); errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here"); diff --git a/compiler/src/dmd/dscope.d b/compiler/src/dmd/dscope.d index 05cc8f156e11..030a0240116b 100644 --- a/compiler/src/dmd/dscope.d +++ b/compiler/src/dmd/dscope.d @@ -24,6 +24,7 @@ import dmd.dclass; import dmd.declaration; import dmd.dmodule; import dmd.doc; +import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; @@ -156,6 +157,7 @@ extern (C++) struct Scope AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value, /// do not set wasRead for it + StructDeclaration argStruct; /// elimiate recursion when looking for rvalue construction extern (D) __gshared Scope* freelist; diff --git a/compiler/src/dmd/e2ir.d b/compiler/src/dmd/e2ir.d index 1aff7df4e7e1..fe2844a20c65 100644 --- a/compiler/src/dmd/e2ir.d +++ b/compiler/src/dmd/e2ir.d @@ -5532,6 +5532,8 @@ elem *callfunc(const ref Loc loc, v = ve.var.isVarDeclaration(); bool copy = !(v && (v.isArgDtorVar || v.storage_class & STC.rvalue)); // copy unless the destructor is going to be run on it // then assume the frontend took care of the copying and pass it by ref + if (arg.rvalue) // marked with __rvalue + copy = false; elems[i] = addressElem(ea, arg.type, copy); continue; diff --git a/compiler/src/dmd/expression.d b/compiler/src/dmd/expression.d index dc72b3a8df1b..3d0ae2528460 100644 --- a/compiler/src/dmd/expression.d +++ b/compiler/src/dmd/expression.d @@ -297,6 +297,7 @@ extern (C++) abstract class Expression : ASTNode Loc loc; // file location const EXP op; // to minimize use of dynamic_cast bool parens; // if this is a parenthesized expression + bool rvalue; // true if this is considered to be an rvalue, even if it is an lvalue extern (D) this(const ref Loc loc, EXP op) scope @safe { @@ -1307,7 +1308,7 @@ extern (C++) class IdentifierExp : Expression override final bool isLvalue() { - return true; + return !this.rvalue; } override void accept(Visitor v) @@ -1351,7 +1352,7 @@ extern (C++) final class DsymbolExp : Expression override bool isLvalue() { - return true; + return !rvalue; } override void accept(Visitor v) @@ -1397,7 +1398,7 @@ extern (C++) class ThisExp : Expression override final bool isLvalue() { // Class `this` should be an rvalue; struct `this` should be an lvalue. - return type.toBasetype().ty != Tclass; + return !rvalue && type.toBasetype().ty != Tclass; } override void accept(Visitor v) @@ -1782,7 +1783,7 @@ extern (C++) final class StringExp : Expression /* string literal is rvalue in default, but * conversion to reference of static array is only allowed. */ - return (type && type.toBasetype().ty == Tsarray); + return !rvalue && (type && type.toBasetype().ty == Tsarray); } /******************************** @@ -2719,7 +2720,7 @@ extern (C++) final class VarExp : SymbolExp override bool isLvalue() { - if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest)) + if (rvalue || var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest)) return false; return true; } @@ -3098,7 +3099,7 @@ extern (C++) class BinAssignExp : BinExp override final bool isLvalue() { - return true; + return !rvalue; } override void accept(Visitor v) @@ -3303,6 +3304,8 @@ extern (C++) final class DotVarExp : UnaExp override bool isLvalue() { + if (rvalue) + return false; if (e1.op != EXP.structLiteral) return true; auto vd = var.isVarDeclaration(); @@ -3530,6 +3533,8 @@ extern (C++) final class CallExp : UnaExp override bool isLvalue() { + if (rvalue) + return false; Type tb = e1.type.toBasetype(); if (tb.ty == Tdelegate || tb.ty == Tpointer) tb = tb.nextOf(); @@ -3648,7 +3653,7 @@ extern (C++) final class PtrExp : UnaExp override bool isLvalue() { - return true; + return !rvalue; } override void accept(Visitor v) @@ -3777,7 +3782,7 @@ extern (C++) final class CastExp : UnaExp override bool isLvalue() { //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars()); - if (!e1.isLvalue()) + if (rvalue || !e1.isLvalue()) return false; return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) || e1.type.mutableOf.unSharedOf().equals(to.mutableOf().unSharedOf()); @@ -3834,7 +3839,7 @@ extern (C++) final class VectorArrayExp : UnaExp override bool isLvalue() { - return e1.isLvalue(); + return !rvalue && e1.isLvalue(); } override void accept(Visitor v) @@ -3891,7 +3896,7 @@ extern (C++) final class SliceExp : UnaExp /* slice expression is rvalue in default, but * conversion to reference of static array is only allowed. */ - return (type && type.toBasetype().ty == Tsarray); + return !rvalue && (type && type.toBasetype().ty == Tsarray); } override Optional!bool toBool() @@ -3956,6 +3961,8 @@ extern (C++) final class ArrayExp : UnaExp override bool isLvalue() { + if (rvalue) + return false; if (type && type.toBasetype().ty == Tvoid) return false; return true; @@ -4005,7 +4012,7 @@ extern (C++) final class CommaExp : BinExp override bool isLvalue() { - return e2.isLvalue(); + return !rvalue && e2.isLvalue(); } override Optional!bool toBool() @@ -4080,7 +4087,7 @@ extern (C++) final class DelegatePtrExp : UnaExp override bool isLvalue() { - return e1.isLvalue(); + return !rvalue && e1.isLvalue(); } override void accept(Visitor v) @@ -4103,7 +4110,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp override bool isLvalue() { - return e1.isLvalue(); + return !rvalue && e1.isLvalue(); } override void accept(Visitor v) @@ -4143,6 +4150,8 @@ extern (C++) final class IndexExp : BinExp override bool isLvalue() { + if (rvalue) + return false; auto t1b = e1.type.toBasetype(); if (t1b.isTypeAArray() || t1b.isTypeSArray() || (e1.isIndexExp() && t1b != t1b.isTypeDArray())) @@ -4251,7 +4260,7 @@ extern (C++) class AssignExp : BinExp { return false; } - return true; + return !rvalue; } override void accept(Visitor v) @@ -4982,7 +4991,7 @@ extern (C++) final class CondExp : BinExp override bool isLvalue() { - return e1.isLvalue() && e2.isLvalue(); + return !rvalue && e1.isLvalue() && e2.isLvalue(); } override void accept(Visitor v) diff --git a/compiler/src/dmd/expression.h b/compiler/src/dmd/expression.h index c353a191a662..73bb950d32ff 100644 --- a/compiler/src/dmd/expression.h +++ b/compiler/src/dmd/expression.h @@ -78,6 +78,7 @@ class Expression : public ASTNode Loc loc; // file location EXP op; // to minimize use of dynamic_cast d_bool parens; // if this is a parenthesized expression + d_bool rvalue; // consider this an rvalue, even if it is an lvalue size_t size() const; static void _init(); diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index d5a8c81020d2..d6cb20f0c636 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -3892,6 +3892,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + scope (success) result.rvalue = exp.rvalue; + Dsymbol scopesym; Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); if (s) diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index a77f064576d8..518260465773 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -2068,6 +2068,7 @@ enum class EXP : uint8_t _Generic_ = 125u, interval = 126u, loweredAssignExp = 127u, + rvalue = 128u, }; typedef uint64_t dinteger_t; @@ -2105,6 +2106,7 @@ class Expression : public ASTNode Loc loc; const EXP op; bool parens; + bool rvalue; size_t size() const; static void _init(); static void deinitialize(); @@ -2888,33 +2890,34 @@ enum class TOK : uint8_t wchar_tLiteral = 196u, endOfLine = 197u, whitespace = 198u, - inline_ = 199u, - register_ = 200u, - restrict_ = 201u, - signed_ = 202u, - sizeof_ = 203u, - typedef_ = 204u, - unsigned_ = 205u, - volatile_ = 206u, - _Alignas_ = 207u, - _Alignof_ = 208u, - _Atomic_ = 209u, - _Bool_ = 210u, - _Complex_ = 211u, - _Generic_ = 212u, - _Imaginary_ = 213u, - _Noreturn_ = 214u, - _Static_assert_ = 215u, - _Thread_local_ = 216u, - _assert_ = 217u, - _import_ = 218u, - __cdecl_ = 219u, - __declspec_ = 220u, - __stdcall_ = 221u, - __thread_ = 222u, - __pragma_ = 223u, - __int128_ = 224u, - __attribute___ = 225u, + rvalue = 199u, + inline_ = 200u, + register_ = 201u, + restrict_ = 202u, + signed_ = 203u, + sizeof_ = 204u, + typedef_ = 205u, + unsigned_ = 206u, + volatile_ = 207u, + _Alignas_ = 208u, + _Alignof_ = 209u, + _Atomic_ = 210u, + _Bool_ = 211u, + _Complex_ = 212u, + _Generic_ = 213u, + _Imaginary_ = 214u, + _Noreturn_ = 215u, + _Static_assert_ = 216u, + _Thread_local_ = 217u, + _assert_ = 218u, + _import_ = 219u, + __cdecl_ = 220u, + __declspec_ = 221u, + __stdcall_ = 222u, + __thread_ = 223u, + __pragma_ = 224u, + __int128_ = 225u, + __attribute___ = 226u, }; class FuncExp final : public Expression @@ -5259,18 +5262,18 @@ struct UnionExp final private: union _AnonStruct_u { - char exp[30LLU]; + char exp[31LLU]; char integerexp[40LLU]; - char errorexp[30LLU]; + char errorexp[31LLU]; char realexp[48LLU]; char complexexp[64LLU]; char symoffexp[64LLU]; - char stringexp[51LLU]; - char arrayliteralexp[48LLU]; + char stringexp[59LLU]; + char arrayliteralexp[56LLU]; char assocarrayliteralexp[56LLU]; char structliteralexp[76LLU]; char compoundliteralexp[40LLU]; - char nullexp[30LLU]; + char nullexp[31LLU]; char dotvarexp[49LLU]; char addrexp[40LLU]; char indexexp[74LLU]; @@ -7137,6 +7140,7 @@ struct Scope final void* anchorCounts; Identifier* prevAnchor; AliasDeclaration* aliasAsg; + StructDeclaration* argStruct; Dsymbol* search(const Loc& loc, Identifier* ident, Dsymbol*& pscopesym, uint32_t flags = 0u); Scope() : enclosing(), @@ -7177,10 +7181,11 @@ struct Scope final userAttribDecl(), lastdc(), prevAnchor(), - aliasAsg() + aliasAsg(), + argStruct() { } - Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* sw = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tf = nullptr, ScopeGuardStatement* os = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, bool nofree = false, bool inLoop = false, bool inDefaultArg = false, int32_t intypeof = 0, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), int32_t explicitVisibility = 0, uint64_t stc = 0LLU, DeprecatedDeclaration* depdecl = nullptr, uint32_t bitFields = 0u, UserAttributeDeclaration* userAttribDecl = nullptr, DocComment* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr) : + Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* sw = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tf = nullptr, ScopeGuardStatement* os = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, bool nofree = false, bool inLoop = false, bool inDefaultArg = false, int32_t intypeof = 0, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), int32_t explicitVisibility = 0, uint64_t stc = 0LLU, DeprecatedDeclaration* depdecl = nullptr, uint32_t bitFields = 0u, UserAttributeDeclaration* userAttribDecl = nullptr, DocComment* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr, StructDeclaration* argStruct = nullptr) : enclosing(enclosing), _module(_module), scopesym(scopesym), @@ -7220,7 +7225,8 @@ struct Scope final lastdc(lastdc), anchorCounts(anchorCounts), prevAnchor(prevAnchor), - aliasAsg(aliasAsg) + aliasAsg(aliasAsg), + argStruct(argStruct) {} }; diff --git a/compiler/src/dmd/hdrgen.d b/compiler/src/dmd/hdrgen.d index 86131f2f11c9..26ded423663f 100644 --- a/compiler/src/dmd/hdrgen.d +++ b/compiler/src/dmd/hdrgen.d @@ -2888,6 +2888,12 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt buf.writestring(e.value.toChars()); } + if (e.rvalue) + buf.writestring("__rvalue("); + scope (success) + if (e.rvalue) + buf.writeByte(')'); + switch (e.op) { default: diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 3e145be5499f..ef62558ae74d 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -5877,6 +5877,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.moduleString: case TOK.functionString: case TOK.prettyFunction: + case TOK.rvalue: Lexp: { AST.Expression exp = parseExpression(); @@ -8423,6 +8424,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer e = new AST.TypeidExp(loc, o); break; } + case TOK.rvalue: + { + nextToken(); + check(TOK.leftParenthesis, "`__rvalue`"); + e = parseAssignExp(); + e.rvalue = true; + check(TOK.rightParenthesis); + break; + } case TOK.traits: { /* __traits(identifier, args...) diff --git a/compiler/src/dmd/scope.h b/compiler/src/dmd/scope.h index f36a14ba0518..556100ac2350 100644 --- a/compiler/src/dmd/scope.h +++ b/compiler/src/dmd/scope.h @@ -130,6 +130,7 @@ struct Scope AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value, // do not set wasRead for it + StructDeclaration *argStruct; // elimiate recursion when looking for rvalue construction Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol *&pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); }; diff --git a/compiler/src/dmd/tokens.d b/compiler/src/dmd/tokens.d index da4a3ee209ef..b499c008eab3 100644 --- a/compiler/src/dmd/tokens.d +++ b/compiler/src/dmd/tokens.d @@ -27,6 +27,9 @@ enum TOK : ubyte { reserved, + // if this list changes, update + // tokens.h, ../tests/cxxfrontend.cc and ../../test/unit/lexer/location_offset.d to match + // Other leftParenthesis, rightParenthesis, @@ -249,6 +252,7 @@ enum TOK : ubyte wchar_tLiteral, endOfLine, // \n, \r, \u2028, \u2029 whitespace, + rvalue, // C only keywords inline, @@ -425,6 +429,7 @@ enum EXP : ubyte interval, loweredAssignExp, + rvalue, } enum FirstCKeyword = TOK.inline; @@ -556,6 +561,7 @@ private immutable TOK[] keywords = TOK.prettyFunction, TOK.shared_, TOK.immutable_, + TOK.rvalue, // C only keywords TOK.inline, @@ -680,6 +686,7 @@ extern (C++) struct Token TOK.pragma_: "pragma", TOK.typeof_: "typeof", TOK.typeid_: "typeid", + TOK.rvalue: "__rvalue", TOK.template_: "template", TOK.void_: "void", TOK.int8: "byte", diff --git a/compiler/src/dmd/tokens.h b/compiler/src/dmd/tokens.h index 929897a3fa6f..2a984b4b7b62 100644 --- a/compiler/src/dmd/tokens.h +++ b/compiler/src/dmd/tokens.h @@ -258,6 +258,7 @@ enum class TOK : unsigned char wchar_tLiteral, endOfLine, // \n, \r, \u2028, \u2029 whitespace, + rvalue, // C only keywords inline_, diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index aea969a2e08d..67aefc332823 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -894,6 +894,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, Expression arg, Type tprm, Scope* sc, const(char)** pMessage) { + //printf("isCopyConstructorCallable() argStruct: %s arg: %s tprm: %s\n", argStruct.toChars(), toChars(arg), toChars(tprm)); auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; tmp.dsymbolSemantic(sc); @@ -998,7 +999,9 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) { - //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); + static if (0) + printf("argumentMatchParameter() tf: %s, p: %s, arg: %s, arg.type: %s\n", + tf.toChars(), parameterToChars(p, tf, false), arg.toChars(), arg.type.toChars()); MATCH m; Type targ = arg.type; Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; @@ -1026,9 +1029,16 @@ private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, // check if the copy constructor may be called to copy the argument if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) { - if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) - return MATCH.nomatch; - m = MATCH.exact; + if (sc.argStruct == argStruct) + { + // do not recursively construct rvalue parameter + return MATCH.exact; + } + Scope* sc2 = sc.push(); + sc2.argStruct = argStruct; + bool b = isCopyConstructorCallable(argStruct, arg, tprm, sc2, pMessage); + sc2.pop(); + return b ? MATCH.exact : MATCH.nomatch; } else { diff --git a/compiler/test/fail_compilation/fail19871.d b/compiler/test/fail_compilation/fail19871.d deleted file mode 100644 index ad458df20019..000000000000 --- a/compiler/test/fail_compilation/fail19871.d +++ /dev/null @@ -1,20 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail19871.d(10): Error: `struct Struct` may not define both a rvalue constructor and a copy constructor -fail_compilation/fail19871.d(19): rvalue constructor defined here -fail_compilation/fail19871.d(13): copy constructor defined here ---- -*/ - -struct Struct -{ - @disable this(); - this(ref Struct other) - { - const Struct s = void; - this(s); - } - - this(Struct) {} -} diff --git a/compiler/test/fail_compilation/fail19931.d b/compiler/test/fail_compilation/fail19931.d deleted file mode 100644 index 940a1faee028..000000000000 --- a/compiler/test/fail_compilation/fail19931.d +++ /dev/null @@ -1,15 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail19931.d(10): Error: `struct S` may not define both a rvalue constructor and a copy constructor -fail_compilation/fail19931.d(12): rvalue constructor defined here -fail_compilation/fail19931.d(13): copy constructor defined here ---- -*/ - -struct S -{ - this(S s) {} - this(ref S s) {} - this(this) {} -} diff --git a/compiler/test/fail_compilation/fail23036.d b/compiler/test/fail_compilation/fail23036.d deleted file mode 100644 index 8920586c67a8..000000000000 --- a/compiler/test/fail_compilation/fail23036.d +++ /dev/null @@ -1,22 +0,0 @@ -// https://issues.dlang.org/show_bug.cgi?id=23036 - -/* -TEST_OUTPUT: ---- -fail_compilation/fail23036.d(12): Error: `struct S` may not define both a rvalue constructor and a copy constructor -fail_compilation/fail23036.d(15): rvalue constructor defined here -fail_compilation/fail23036.d(14): copy constructor defined here ---- -*/ - -struct S -{ - this(ref S) {} - this(S, int a = 2) {} -} - -void main() -{ - S a; - S b = a; -} diff --git a/compiler/test/runnable/rvalue1.d b/compiler/test/runnable/rvalue1.d new file mode 100644 index 000000000000..2d5214f425b1 --- /dev/null +++ b/compiler/test/runnable/rvalue1.d @@ -0,0 +1,42 @@ +/* testing __rvalue */ + +import core.stdc.stdio; + +/********************************/ + +int foo(int) { printf("foo(int)\n"); return 1; } +int foo(ref int) { printf("foo(ref int)\n"); return 2; } + +void test1() +{ + int s; + assert(foo(s) == 2); + assert(foo(__rvalue(s)) == 1); +} + +/********************************/ + +struct S +{ + nothrow: + ~this() { printf("~this() %p\n", &this); } + this(ref S) { printf("this(ref S)\n"); } + void opAssign(S) { printf("opAssign(S)\n"); } +} + +void test2() +{ + S s; + S t; + + t = __rvalue(s); +} + +/********************************/ + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/compiler/test/runnable/test23036.d b/compiler/test/runnable/test23036.d new file mode 100644 index 000000000000..efb6fef3953b --- /dev/null +++ b/compiler/test/runnable/test23036.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=23036 + +struct S +{ + this(ref S) {} + this(S, int a = 2) {} +} + +void main() +{ + S a; + S b = a; +} diff --git a/compiler/test/unit/lexer/location_offset.d b/compiler/test/unit/lexer/location_offset.d index 21266276d2c3..fb7edfd5eb21 100644 --- a/compiler/test/unit/lexer/location_offset.d +++ b/compiler/test/unit/lexer/location_offset.d @@ -399,6 +399,7 @@ enum Test[string] tests = [ "auto_" : Test("auto"), "package_" : Test("package"), "immutable_" : Test("immutable"), + "rvalue" : Test("__rvalue"), "if_" : Test("if"), "else_" : Test("else"),