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/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 e7cdf7e9e065..80c675753bd2 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]; 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/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/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/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"),