Skip to content

Commit

Permalink
add __rvalue(expression) builtin
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Dec 8, 2024
1 parent 347c883 commit 0dc145b
Show file tree
Hide file tree
Showing 26 changed files with 254 additions and 163 deletions.
1 change: 1 addition & 0 deletions compiler/src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
5 changes: 3 additions & 2 deletions compiler/src/dmd/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -1648,14 +1649,14 @@ bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
return 0;
}

if (isRvalueConstructor(sd, ctorDecl))
if (ctorDecl.isMoveCtor)
rvalueCtor = ctorDecl;
return 0;
});

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");
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ class CtorDeclaration final : public FuncDeclaration
{
public:
d_bool isCpCtor;
d_bool isMoveCtor;
CtorDeclaration *syntaxCopy(Dsymbol *) override;
const char *kind() const override;
const char *toChars() const override;
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/dscope.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
34 changes: 6 additions & 28 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ Return:
*/
bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, TemplateInstance ti)
{
if (sd && sd.hasCopyCtor && isRvalueConstructor(sd, ctor))
if (sd && sd.hasCopyCtor && ctor.isMoveCtor)
{
.error(ctor.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars());
.errorSupplemental(ti.loc, "Template instance `%s` creates an rvalue constructor for `struct %s`",
Expand All @@ -268,31 +268,6 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem
return false;
}

/************************************************
* Check if ctor is an rvalue constructor.
* A constructor that receives a single parameter of the same type as
* `Unqual!typeof(this)` is an rvalue constructor.
* Params:
* sd = struct that ctor is a member of
* ctor = constructor to test
* Returns:
* true if it is an rvalue constructor
*/
bool isRvalueConstructor(StructDeclaration sd, CtorDeclaration ctor)
{
auto tf = ctor.type.isTypeFunction();
const dim = tf.parameterList.length;
if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
{
auto param = tf.parameterList[0];
if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
{
return true;
}
}
return false;
}

/*************************************
* Find the `alias this` symbol of e's type.
* Params:
Expand Down Expand Up @@ -2484,10 +2459,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
//printf("tf: %s\n", tf.toChars());
auto param = tf.parameterList[0];
if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
{
//printf("copy constructor\n");
ctd.isCpCtor = true;
if (param.storageClass & STC.ref_)
ctd.isCpCtor = true; // copy constructor
else
ctd.isMoveCtor = true; // move constructor
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/e2ir.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
39 changes: 24 additions & 15 deletions compiler/src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -1307,7 +1308,7 @@ extern (C++) class IdentifierExp : Expression

override final bool isLvalue()
{
return true;
return !this.rvalue;
}

override void accept(Visitor v)
Expand Down Expand Up @@ -1351,7 +1352,7 @@ extern (C++) final class DsymbolExp : Expression

override bool isLvalue()
{
return true;
return !rvalue;
}

override void accept(Visitor v)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}

/********************************
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -3098,7 +3099,7 @@ extern (C++) class BinAssignExp : BinExp

override final bool isLvalue()
{
return true;
return !rvalue;
}

override void accept(Visitor v)
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -3648,7 +3653,7 @@ extern (C++) final class PtrExp : UnaExp

override bool isLvalue()
{
return true;
return !rvalue;
}

override void accept(Visitor v)
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -4005,7 +4012,7 @@ extern (C++) final class CommaExp : BinExp

override bool isLvalue()
{
return e2.isLvalue();
return !rvalue && e2.isLvalue();
}

override Optional!bool toBool()
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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()))
Expand Down Expand Up @@ -4251,7 +4260,7 @@ extern (C++) class AssignExp : BinExp
{
return false;
}
return true;
return !rvalue;
}

override void accept(Visitor v)
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
16 changes: 13 additions & 3 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,7 @@ extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
*/
private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
{
//printf("callCpCtor(e: %s et: %s destinationType: %s\n", toChars(e), toChars(e.type), toChars(destinationType));
auto ts = e.type.baseElemOf().isTypeStruct();

if (!ts)
Expand All @@ -860,6 +861,13 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
* This is not the most efficient, ideally tmp would be constructed
* directly onto the stack.
*/
static if (0) printf("copyToTemp\n");
{
import core.stdc.stdlib;
__gshared int x;
if (++x == 3)
exit(1);
}
auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
if (sd.hasCopyCtor && destinationType)
{
Expand Down Expand Up @@ -2952,7 +2960,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
Type* prettype, Expression* peprefix)
{
Expressions* arguments = argumentList.arguments;
//printf("functionParameters() %s\n", fd ? fd.toChars() : "");
//printf("functionParameters() fd: %s tf: %s\n", fd ? fd.ident.toChars() : "", toChars(tf));
assert(arguments);
assert(fd || tf.next);
const size_t nparams = tf.parameterList.length;
Expand Down Expand Up @@ -3892,6 +3900,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)
Expand Down Expand Up @@ -6725,7 +6735,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
errorSupplemental(exp.loc, "%s", failMessage);
}

if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
return setError();

// Purity and safety check should run after testing arguments matching
Expand Down Expand Up @@ -6808,7 +6818,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.f = null;
}

if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
exp.f = null;
}
if (!exp.f || exp.f.errors)
Expand Down
Loading

0 comments on commit 0dc145b

Please sign in to comment.