d: Merge upstream dmd ad8412530, druntime fd9a4544, phobos 495e835c2.

D front-end changes:

    - Import dmd v2.098.1
    - Remove calling of _d_delstruct from code generator.

Druntime changes:

    - Import druntime v2.098.1

Phobos changes:

    - Import phobos v2.098.1

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd ad8412530.
	* expr.cc (ExprVisitor::visit (DeleteExp *)): Remove code generation
	of _d_delstruct.
	* runtime.def (DELSTRUCT): Remove.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime fd9a4544.
	* src/MERGE: Merge upstream phobos 495e835c2.
This commit is contained in:
Iain Buclaw 2021-12-20 19:25:32 +01:00
parent 7d5d5032c7
commit b3f58f87d7
28 changed files with 468 additions and 272 deletions

View file

@ -1,4 +1,4 @@
93108bb9ea6216d67fa97bb4842fb59f26f6bfc7
ad8412530e607ffebec36f2dbdff1a6f2798faf7
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -82,6 +82,22 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
if (global.errors && !ce.e1.type)
return; // error recovery
import dmd.id : Id;
if (ce.f && ce.f.ident == Id._d_delstruct)
{
// Only check if the dtor throws.
Type tb = (*ce.arguments)[0].type.toBasetype();
auto ts = tb.nextOf().baseElemOf().isTypeStruct();
if (ts)
{
auto sd = ts.sym;
if (sd.dtor)
checkFuncThrows(ce, sd.dtor);
}
}
/* If calling a function or delegate that is typed as nothrow,
* then this expression cannot throw.
* Note that pure functions can throw.

View file

@ -1565,9 +1565,9 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
result = e;
return;
}
if (e.op == EXP.variable)
if (auto ve = e.isVarExp())
{
VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
VarDeclaration v = ve.var.isVarDeclaration();
if (v && v.storage_class & STC.manifest)
{
result = e.ctfeInterpret();
@ -1852,8 +1852,8 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
override void visit(StructLiteralExp e)
{
visit(cast(Expression)e);
if (result.op == EXP.structLiteral)
(cast(StructLiteralExp)result).stype = t; // commit type
if (auto sle = result.isStructLiteralExp())
sle.stype = t; // commit type
}
override void visit(StringExp e)
@ -1866,7 +1866,8 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
//printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid)
if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid &&
(!sc || !(sc.flags & SCOPE.Cfile)))
{
e.error("cannot convert string literal to `void*`");
result = ErrorExp.get();
@ -1883,7 +1884,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
if (!e.committed)
{
se = cast(StringExp)e.copy();
se = e.copy().isStringExp();
se.committed = 1;
copied = 1;
}
@ -1908,7 +1909,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (!copied)
{
se = cast(StringExp)e.copy();
se = e.copy().isStringExp();
copied = 1;
}
se.type = t;
@ -1924,7 +1925,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
*/
if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray)
{
se = cast(StringExp)e.copy();
se = e.copy().isStringExp();
d_uns64 szx = tb.nextOf().size();
assert(szx <= 255);
se.sz = cast(ubyte)szx;
@ -1952,7 +1953,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (!copied)
{
se = cast(StringExp)e.copy();
se = e.copy().isStringExp();
copied = 1;
}
return lcast();
@ -1961,7 +1962,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (!copied)
{
se = cast(StringExp)e.copy();
se = e.copy().isStringExp();
copied = 1;
}
return lcast();
@ -1977,7 +1978,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (!copied)
{
se = cast(StringExp)e.copy();
se = e.copy().isStringExp();
copied = 1;
}
if (tb.ty == Tsarray)
@ -2088,7 +2089,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
L1:
if (!copied)
{
se = cast(StringExp)e.copy();
se = e.copy().isStringExp();
copied = 1;
}
@ -2154,10 +2155,10 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
}
// Look for pointers to functions where the functions are overloaded.
if (e.e1.op == EXP.overloadSet &&
if (e.e1.isOverExp() &&
(tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
{
OverExp eo = cast(OverExp)e.e1;
OverExp eo = e.e1.isOverExp();
FuncDeclaration f = null;
for (size_t i = 0; i < eo.vars.a.dim; i++)
{
@ -2188,11 +2189,11 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
}
}
if (e.e1.op == EXP.variable &&
if (e.e1.isVarExp() &&
typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
{
auto ve = cast(VarExp)e.e1;
auto ve = e.e1.isVarExp();
auto f = ve.var.isFuncDeclaration();
if (f)
{
@ -2303,7 +2304,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
goto L1;
}
ae = cast(ArrayLiteralExp)e.copy();
ae = e.copy().isArrayLiteralExp();
if (e.basis)
ae.basis = e.basis.castTo(sc, tb.nextOf());
ae.elements = e.elements.copy();
@ -2325,7 +2326,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
Type tp = typeb.nextOf().pointerTo();
if (!tp.equals(ae.type))
{
ae = cast(ArrayLiteralExp)e.copy();
ae = e.copy().isArrayLiteralExp();
ae.type = tp;
}
}
@ -2382,7 +2383,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
if (tb.ty == Taarray && typeb.ty == Taarray &&
tb.nextOf().toBasetype().ty != Tvoid)
{
AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e.copy();
AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp();
ae.keys = e.keys.copy();
ae.values = e.values.copy();
assert(e.keys.dim == e.values.dim);
@ -2422,7 +2423,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
result = e.copy();
result.type = t;
(cast(SymOffExp)result).hasOverloads = false;
result.isSymOffExp().hasOverloads = false;
return;
}
@ -2641,7 +2642,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
Expression e1x = e.e1.implicitCastTo(sc, t1b);
assert(e1x.op != EXP.error);
e = cast(SliceExp)e.copy();
e = e.copy().isSliceExp();
e.e1 = e1x;
e.type = t;
result = e;
@ -2751,10 +2752,10 @@ Expression inferType(Expression e, Type t, int flag = 0)
if (t) switch (e.op)
{
case EXP.arrayLiteral: return visitAle(cast(ArrayLiteralExp) e);
case EXP.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e);
case EXP.function_: return visitFun(cast(FuncExp) e);
case EXP.question: return visitTer(cast(CondExp) e);
case EXP.arrayLiteral: return visitAle(e.isArrayLiteralExp());
case EXP.assocArrayLiteral: return visitAar(e.isAssocArrayLiteralExp());
case EXP.function_: return visitFun(e.isFuncExp());
case EXP.question: return visitTer(e.isCondExp());
default:
}
return e;
@ -2830,9 +2831,9 @@ Expression scaleFactor(BinExp be, Scope* sc)
*/
private bool isVoidArrayLiteral(Expression e, Type other)
{
while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1))
while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && (e.isArrayLiteralExp().elements.dim == 1))
{
auto ale = cast(ArrayLiteralExp)e;
auto ale = e.isArrayLiteralExp();
e = ale[0];
if (other.ty == Tsarray || other.ty == Tarray)
other = other.nextOf();
@ -2842,7 +2843,7 @@ private bool isVoidArrayLiteral(Expression e, Type other)
if (other.ty != Tsarray && other.ty != Tarray)
return false;
Type t = e.type;
return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0);
return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && e.isArrayLiteralExp().elements.dim == 0);
}
/**
@ -3463,20 +3464,20 @@ LmodCompare:
Expression rhs = e2;
// T[x .. y] op ?
if (e1.isSliceExp())
lhs = new IndexExp(Loc.initial, (cast(UnaExp)e1).e1, IntegerExp.literal!0);
if (auto se1 = e1.isSliceExp())
lhs = new IndexExp(Loc.initial, se1.e1, IntegerExp.literal!0);
// [t1, t2, .. t3] op ?
if (e1.isArrayLiteralExp())
lhs = (cast(ArrayLiteralExp)e1).opIndex(0);
if (auto ale1 = e1.isArrayLiteralExp())
lhs = ale1.opIndex(0);
// ? op U[z .. t]
if (e2.isSliceExp())
rhs = new IndexExp(Loc.initial, (cast(UnaExp)e2).e1, IntegerExp.literal!0);
if (auto se2 = e2.isSliceExp())
rhs = new IndexExp(Loc.initial, se2.e1, IntegerExp.literal!0);
// ? op [u1, u2, .. u3]
if (e2.isArrayLiteralExp())
rhs = (cast(ArrayLiteralExp)e2).opIndex(0);
if (auto ale2 = e2.isArrayLiteralExp())
rhs = ale2.opIndex(0);
// create a new binary expression with the new lhs and rhs (at this stage, at least
// one of lhs/rhs has been replaced with the 0'th element of the array it was before)

View file

@ -4837,6 +4837,47 @@ public:
result = interpret(ce, istate);
return;
}
else if (fd.ident == Id._d_delstruct)
{
// Only interpret the dtor and the argument.
assert(e.arguments.dim == 1);
Type tb = (*e.arguments)[0].type.toBasetype();
auto ts = tb.nextOf().baseElemOf().isTypeStruct();
if (ts)
{
result = interpretRegion((*e.arguments)[0], istate);
if (exceptionOrCant(result))
return;
if (result.op == EXP.null_)
{
result = CTFEExp.voidexp;
return;
}
if (result.op != EXP.address ||
(cast(AddrExp)result).e1.op != EXP.structLiteral)
{
e.error("`delete` on invalid struct pointer `%s`", result.toChars());
result = CTFEExp.cantexp;
return;
}
auto sd = ts.sym;
if (sd.dtor)
{
auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
result = interpretFunction(pue, sd.dtor, istate, null, sle);
if (exceptionOrCant(result))
return;
result = CTFEExp.voidexp;
}
}
return;
}
}
else if (auto soe = ecall.isSymOffExp())
{

View file

@ -2453,10 +2453,10 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
if (i1 && i2)
return collision(); // can't both have initializers
if (i1)
if (i1) // vd is the definition
{
vd2._init = vd._init;
vd._init = null;
sds.symtab.update(vd); // replace vd2 with the definition
return vd;
}
/* BUG: the types should match, which needs semantic() to be run on it
@ -2497,14 +2497,10 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
if (fd.fbody && fd2.fbody)
return collision(); // can't both have bodies
if (fd.fbody)
if (fd.fbody) // fd is the definition
{
fd2.fbody = fd.fbody; // transfer body to existing declaration
fd.fbody = null;
auto tf = fd.type.toTypeFunction();
auto tf2 = fd2.type.toTypeFunction();
tf2.parameterList = tf.parameterList; // transfer parameter list.
sds.symtab.update(fd); // replace fd2 in symbol table with fd
return fd;
}
/* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.

View file

@ -3981,15 +3981,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
return;
TypeFunction tf = ctd.type.toTypeFunction();
immutable dim = tf.parameterList.length;
auto sd = ad.isStructDeclaration();
/* See if it's the default constructor
* But, template constructor should not become a default constructor.
*/
if (ad && (!ctd.parent.isTemplateInstance() || ctd.parent.isTemplateMixin()))
{
immutable dim = tf.parameterList.length;
if (auto sd = ad.isStructDeclaration())
if (sd)
{
if (dim == 0 && tf.parameterList.varargs == VarArg.none) // empty default ctor w/o any varargs
{
@ -4034,6 +4034,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ad.defaultCtor = ctd;
}
}
// https://issues.dlang.org/show_bug.cgi?id=22593
else if (auto ti = ctd.parent.isTemplateInstance())
{
if (sd && sd.hasCopyCtor && (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)))
{
auto param = tf.parameterList[0];
// if the template instance introduces an rvalue constructor
// between the members of a struct declaration, we should check if a
// copy constructor exists and issue an error in that case.
if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
{
.error(ctd.loc, "Cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars);
.errorSupplemental(ti.loc, "Template instance `%s` creates a rvalue constructor for `struct %s`",
ti.toChars(), sd.toChars());
}
}
}
}
override void visit(PostBlitDeclaration pbd)

View file

@ -7316,6 +7316,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
}
Expression e = exp;
if (Expression ex = unaSemantic(exp, sc))
{
result = ex;
@ -7352,7 +7354,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (tb.ty == Tstruct)
{
ad = (cast(TypeStruct)tb).sym;
semanticTypeInfo(sc, tb);
Identifier hook = global.params.tracegc ? Id._d_delstructTrace : Id._d_delstruct;
if (!verifyHookExist(exp.loc, *sc, Id._d_delstructImpl, "deleting struct with dtor", Id.object))
return setError();
// Lower to .object._d_delstruct{,Trace}(exp.e1)
Expression id = new IdentifierExp(exp.loc, Id.empty);
id = new DotIdExp(exp.loc, id, Id.object);
auto tiargs = new Objects();
tiargs.push(exp.e1.type);
id = new DotTemplateInstanceExp(exp.loc, id, Id._d_delstructImpl, tiargs);
id = new DotIdExp(exp.loc, id, hook);
e = new CallExp(exp.loc, id, exp.e1);
/* Gag errors generated by calls to `_d_delstruct`, because they display
* internal compiler information, which is unnecessary to the user.
*/
uint errors = global.startGagging();
e = e.expressionSemantic(sc);
global.endGagging(errors);
}
break;
@ -7397,7 +7419,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (err)
return setError();
result = exp;
result = e;
}
override void visit(CastExp exp)

View file

@ -311,6 +311,9 @@ immutable Msgtable[] msgtable =
{ "__ArrayPostblit" },
{ "__ArrayDtor" },
{ "_d_delThrowable" },
{ "_d_delstructImpl" },
{ "_d_delstruct" },
{ "_d_delstructTrace" },
{ "_d_assert_fail" },
{ "dup" },
{ "_aaApply" },

View file

@ -284,7 +284,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
case Tarray:
break;
case Tvector:
t = (cast(TypeVector)t).basetype;
t = t.isTypeVector().basetype;
break;
case Taarray:
case Tstruct: // consider implicit constructor call
@ -346,7 +346,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
// found a tuple, expand it
if (ei && ei.exp.op == EXP.tuple)
{
TupleExp te = cast(TupleExp)ei.exp;
TupleExp te = ei.exp.isTupleExp();
i.index.remove(j);
i.value.remove(j);
for (size_t k = 0; k < te.exps.dim; ++k)
@ -462,7 +462,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
return i; // Failed, suppress duplicate error messages
}
if (i.exp.type.ty == Ttuple && (cast(TypeTuple)i.exp.type).arguments.dim == 0)
if (i.exp.type.isTypeTuple() && i.exp.type.isTypeTuple().arguments.dim == 0)
{
Type et = i.exp.type;
i.exp = new TupleExp(i.exp.loc, new Expressions());
@ -492,12 +492,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
*/
if (i.exp.op == EXP.string_ && tb.ty == Tsarray)
{
StringExp se = cast(StringExp)i.exp;
StringExp se = i.exp.isStringExp();
Type typeb = se.type.toBasetype();
TY tynto = tb.nextOf().ty;
if (!se.committed &&
(typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
se.numberOfCodeUnits(tynto) < tb.isTypeSArray().dim.toInteger())
{
i.exp = se.castTo(sc, t);
goto L1;
@ -520,7 +520,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
// Look for implicit constructor call
if (tb.ty == Tstruct && !(ti.ty == Tstruct && tb.toDsymbol(sc) == ti.toDsymbol(sc)) && !i.exp.implicitConvTo(t))
{
StructDeclaration sd = (cast(TypeStruct)tb).sym;
StructDeclaration sd = tb.isTypeStruct().sym;
if (sd.ctor)
{
// Rewrite as S().ctor(exp)
@ -573,18 +573,16 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
// better diagnostic message, as same as AssignExp::semantic.
if (tb.ty == Tsarray && i.exp.implicitConvTo(tb.nextOf().arrayOf()) > MATCH.nomatch)
{
uinteger_t dim1 = (cast(TypeSArray)tb).dim.toInteger();
uinteger_t dim1 = tb.isTypeSArray().dim.toInteger();
uinteger_t dim2 = dim1;
if (i.exp.op == EXP.arrayLiteral)
if (auto ale = i.exp.isArrayLiteralExp())
{
ArrayLiteralExp ale = cast(ArrayLiteralExp)i.exp;
dim2 = ale.elements ? ale.elements.dim : 0;
}
else if (i.exp.op == EXP.slice)
else if (auto se = i.exp.isSliceExp())
{
Type tx = toStaticArrayType(cast(SliceExp)i.exp);
if (tx)
dim2 = (cast(TypeSArray)tx).dim.toInteger();
if (Type tx = toStaticArrayType(se))
dim2 = tx.isTypeSArray().dim.toInteger();
}
if (dim1 != dim2)
{
@ -746,10 +744,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
* Params:
* t = element type
* dim = max number of elements
* simple = true if array of simple elements
* Returns:
* # of elements in array
*/
size_t array(Type t, size_t dim)
size_t array(Type t, size_t dim, ref bool simple)
{
//printf(" type %s i %d dim %d dil.length = %d\n", t.toChars(), cast(int)i, cast(int)dim, cast(int)dil.length);
auto tn = t.nextOf().toBasetype();
@ -791,14 +790,30 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (tnsa && di.initializer.isExpInitializer())
{
// no braces enclosing array initializer, so recurse
array(tnsa, nelems);
array(tnsa, nelems, simple);
}
else if (auto tns = tn.isTypeStruct())
{
if (di.initializer.isExpInitializer())
if (auto ei = di.initializer.isExpInitializer())
{
// no braces enclosing struct initializer
dil[n].initializer = structs(tns);
/* Disambiguate between an exp representing the entire
* struct, and an exp representing the first field of the struct
*/
if (needInterpret)
sc = sc.startCTFE();
ei.exp = ei.exp.expressionSemantic(sc);
ei.exp = resolveProperties(sc, ei.exp);
if (needInterpret)
sc = sc.endCTFE();
if (ei.exp.implicitConvTo(tn))
di.initializer = elem(di.initializer); // the whole struct
else
{
simple = false;
dil[n].initializer = structs(tns); // the first field
}
}
else
dil[n].initializer = elem(di.initializer);
@ -816,7 +831,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
}
size_t dim = tsa.isIncomplete() ? dil.length : cast(size_t)tsa.dim.toInteger();
auto newdim = array(t, dim);
bool simple = true;
auto newdim = array(t, dim, simple);
if (errors)
return err();
@ -849,7 +865,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
/* If an array of simple elements, replace with an ArrayInitializer
*/
auto tnb = tn.toBasetype();
if (!(tnb.isTypeSArray() || tnb.isTypeStruct()))
if (!tnb.isTypeSArray() && (!tnb.isTypeStruct() || simple))
{
auto ai = new ArrayInitializer(ci.loc);
ai.dim = cast(uint) dil.length;
@ -884,12 +900,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
final switch (init.kind)
{
case InitKind.void_: return visitVoid (cast( VoidInitializer)init);
case InitKind.error: return visitError (cast( ErrorInitializer)init);
case InitKind.struct_: return visitStruct(cast(StructInitializer)init);
case InitKind.array: return visitArray (cast( ArrayInitializer)init);
case InitKind.exp: return visitExp (cast( ExpInitializer)init);
case InitKind.C_: return visitC (cast( CInitializer)init);
case InitKind.void_: return visitVoid (init.isVoidInitializer());
case InitKind.error: return visitError (init.isErrorInitializer());
case InitKind.struct_: return visitStruct(init.isStructInitializer());
case InitKind.array: return visitArray (init.isArrayInitializer());
case InitKind.exp: return visitExp (init.isExpInitializer());
case InitKind.C_: return visitC (init.isCInitializer());
}
}
@ -943,8 +959,7 @@ Initializer inferType(Initializer init, Scope* sc)
{
return iz;
}
assert(iz.isExpInitializer());
(*values)[i] = (cast(ExpInitializer)iz).exp;
(*values)[i] = iz.isExpInitializer().exp;
assert(!(*values)[i].isErrorExp());
}
Expression e = new AssocArrayLiteralExp(init.loc, keys, values);
@ -966,8 +981,7 @@ Initializer inferType(Initializer init, Scope* sc)
{
return iz;
}
assert(iz.isExpInitializer());
(*elements)[i] = (cast(ExpInitializer)iz).exp;
(*elements)[i] = iz.isExpInitializer().exp;
assert(!(*elements)[i].isErrorExp());
}
Expression e = new ArrayLiteralExp(init.loc, null, elements);
@ -996,9 +1010,8 @@ Initializer inferType(Initializer init, Scope* sc)
init.exp = resolveAliasThis(sc, init.exp);
init.exp = resolveProperties(sc, init.exp);
if (init.exp.op == EXP.scope_)
if (auto se = init.exp.isScopeExp())
{
ScopeExp se = cast(ScopeExp)init.exp;
TemplateInstance ti = se.sds.isTemplateInstance();
if (ti && ti.semanticRun == PASS.semantic && !ti.aliasdecl)
se.error("cannot infer type from %s `%s`, possible circular dependency", se.sds.kind(), se.toChars());
@ -1021,16 +1034,15 @@ Initializer inferType(Initializer init, Scope* sc)
return new ErrorInitializer();
}
}
if (init.exp.op == EXP.address)
if (auto ae = init.exp.isAddrExp())
{
AddrExp ae = cast(AddrExp)init.exp;
if (ae.e1.op == EXP.overloadSet)
{
init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars());
return new ErrorInitializer();
}
}
if (init.exp.op == EXP.error)
if (init.exp.isErrorExp())
{
return new ErrorInitializer();
}
@ -1050,12 +1062,12 @@ Initializer inferType(Initializer init, Scope* sc)
final switch (init.kind)
{
case InitKind.void_: return visitVoid (cast( VoidInitializer)init);
case InitKind.error: return visitError (cast( ErrorInitializer)init);
case InitKind.struct_: return visitStruct(cast(StructInitializer)init);
case InitKind.array: return visitArray (cast( ArrayInitializer)init);
case InitKind.exp: return visitExp (cast( ExpInitializer)init);
case InitKind.C_: return visitC (cast( CInitializer)init);
case InitKind.void_: return visitVoid (init.isVoidInitializer());
case InitKind.error: return visitError (init.isErrorInitializer());
case InitKind.struct_: return visitStruct(init.isStructInitializer());
case InitKind.array: return visitArray (init.isArrayInitializer());
case InitKind.exp: return visitExp (init.isExpInitializer());
case InitKind.C_: return visitC (init.isCInitializer());
}
}
@ -1260,12 +1272,12 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
final switch (init.kind)
{
case InitKind.void_: return visitVoid (cast( VoidInitializer)init);
case InitKind.error: return visitError (cast( ErrorInitializer)init);
case InitKind.struct_: return visitStruct(cast(StructInitializer)init);
case InitKind.array: return visitArray (cast( ArrayInitializer)init);
case InitKind.exp: return visitExp (cast( ExpInitializer)init);
case InitKind.C_: return visitC (cast( CInitializer)init);
case InitKind.void_: return visitVoid (init.isVoidInitializer());
case InitKind.error: return visitError (init.isErrorInitializer());
case InitKind.struct_: return visitStruct(init.isStructInitializer());
case InitKind.array: return visitArray (init.isArrayInitializer());
case InitKind.exp: return visitExp (init.isExpInitializer());
case InitKind.C_: return visitC (init.isCInitializer());
}
}
@ -1308,7 +1320,7 @@ private bool hasNonConstPointers(Expression e)
{
if (ae.type.nextOf().hasPointers() && checkArray(ae.values))
return true;
if ((cast(TypeAArray)ae.type).index.hasPointers())
if (ae.type.isTypeAArray().index.hasPointers())
return checkArray(ae.keys);
return false;
}

View file

@ -83,6 +83,20 @@ public:
}
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
}
else if (fd.ident == Id._d_delstruct)
{
// In expressionsem.d, `delete s` was lowererd to `_d_delstruct(s)`.
// The following code handles the call like the original expression,
// so the error is menaningful to the user.
if (f.setGC())
{
e.error("cannot use `delete` in `@nogc` %s `%s`", f.kind(),
f.toPrettyChars());
err = true;
return;
}
f.printGCUsage(e.loc, "`delete` requires the GC");
}
}
override void visit(ArrayLiteralExp e)

View file

@ -419,8 +419,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc2.insert(_arguments);
_arguments.parent = funcdecl;
}
if ((f.linkage == LINK.d || f.parameterList.length) &&
!(sc.flags & SCOPE.Cfile)) // don't want to require importing stdarg for C files
if (f.linkage == LINK.d || f.parameterList.length)
{
// Declare _argptr
Type t = target.va_listType(funcdecl.loc, sc);

View file

@ -23,7 +23,7 @@ import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.utf;
enum TOK : ushort
enum TOK : ubyte
{
reserved,
@ -84,10 +84,7 @@ enum TOK : ushort
rightShiftAssign,
unsignedRightShift,
unsignedRightShiftAssign,
concatenate,
concatenateAssign, // ~=
concatenateElemAssign,
concatenateDcharAssign,
add,
min,
addAssign,
@ -109,15 +106,11 @@ enum TOK : ushort
tilde,
plusPlus,
minusMinus,
construct,
blit,
dot,
comma,
question,
andAnd,
orOr,
prePlusPlus,
preMinusMinus,
// Numeric literals
int32Literal,
@ -144,7 +137,6 @@ enum TOK : ushort
hexadecimalString,
this_,
super_,
tuple,
error,
// Basic types
@ -244,7 +236,6 @@ enum TOK : ushort
parameters,
traits,
overloadSet,
pure_,
nothrow_,
gshared,
@ -564,7 +555,6 @@ private immutable TOK[] keywords =
TOK.gshared,
TOK.traits,
TOK.vector,
TOK.overloadSet,
TOK.file,
TOK.fileFullPath,
TOK.line,
@ -769,7 +759,6 @@ extern (C++) struct Token
TOK.gshared: "__gshared",
TOK.traits: "__traits",
TOK.vector: "__vector",
TOK.overloadSet: "__overloadset",
TOK.file: "__FILE__",
TOK.fileFullPath: "__FILE_FULL_PATH__",
TOK.line: "__LINE__",
@ -793,8 +782,6 @@ extern (C++) struct Token
TOK.xor: "^",
TOK.xorAssign: "^=",
TOK.assign: "=",
TOK.construct: "=",
TOK.blit: "=",
TOK.lessThan: "<",
TOK.greaterThan: ">",
TOK.lessOrEqual: "<=",
@ -824,8 +811,6 @@ extern (C++) struct Token
TOK.dollar: "$",
TOK.plusPlus: "++",
TOK.minusMinus: "--",
TOK.prePlusPlus: "++",
TOK.preMinusMinus: "--",
TOK.type: "type",
TOK.question: "?",
TOK.negate: "-",
@ -842,9 +827,6 @@ extern (C++) struct Token
TOK.andAssign: "&=",
TOK.orAssign: "|=",
TOK.concatenateAssign: "~=",
TOK.concatenateElemAssign: "~=",
TOK.concatenateDcharAssign: "~=",
TOK.concatenate: "~",
TOK.call: "call",
TOK.identity: "is",
TOK.notIdentity: "!is",
@ -860,7 +842,6 @@ extern (C++) struct Token
// For debugging
TOK.error: "error",
TOK.string_: "string",
TOK.tuple: "tuple",
TOK.declaration: "declaration",
TOK.onScopeExit: "scope(exit)",
TOK.onScopeSuccess: "scope(success)",
@ -1113,11 +1094,6 @@ nothrow:
return toString(value).ptr;
}
static const(char)* toChars(ushort value)
{
return toString(cast(TOK)value).ptr;
}
extern (D) static string toString(TOK value) pure nothrow @nogc @safe
{
return tochars[value];

View file

@ -32,7 +32,7 @@ class Identifier;
? && ||
*/
enum class TOK : unsigned short
enum class TOK : unsigned char
{
reserved,
@ -93,10 +93,7 @@ enum class TOK : unsigned short
rightShiftAssign,
unsignedRightShift,
unsignedRightShiftAssign,
concatenate,
concatenateAssign, // ~=
concatenateElemAssign,
concatenateDcharAssign,
add,
min,
addAssign,
@ -118,15 +115,11 @@ enum class TOK : unsigned short
tilde,
plusPlus,
minusMinus,
construct,
blit,
dot,
comma,
question,
andAnd,
orOr,
prePlusPlus,
preMinusMinus,
// Numeric literals
int32Literal, // 104,
@ -153,7 +146,6 @@ enum class TOK : unsigned short
hexadecimalString,
this_,
super_,
tuple,
error,
// Basic types
@ -253,7 +245,6 @@ enum class TOK : unsigned short
parameters, // 210
traits,
overloadSet,
pure_,
nothrow_,
gshared,

View file

@ -271,7 +271,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
sm = null;
}
// Same check as in Expression.semanticY(DotIdExp)
else if (sm.isPackage() && checkAccess(sc, cast(Package)sm))
else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
{
// @@@DEPRECATED_2.096@@@
// Should be an error in 2.106. Just remove the deprecation call
@ -509,7 +509,7 @@ private Type stripDefaultArgs(Type t)
Parameters* params = stripParams(tf.parameterList.parameters);
if (tret == tf.next && params == tf.parameterList.parameters)
return t;
TypeFunction tr = cast(TypeFunction)tf.copy();
TypeFunction tr = tf.copy().isTypeFunction();
tr.parameterList.parameters = params;
tr.next = tret;
//printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
@ -520,7 +520,7 @@ private Type stripDefaultArgs(Type t)
Parameters* args = stripParams(tt.arguments);
if (args == tt.arguments)
return t;
TypeTuple tr = cast(TypeTuple)t.copy();
TypeTuple tr = t.copy().isTypeTuple();
tr.arguments = args;
return tr;
}
@ -588,11 +588,11 @@ Expression typeToExpression(Type t)
return null;
switch (t.ty)
{
case Tsarray: return visitSArray(cast(TypeSArray) t);
case Taarray: return visitAArray(cast(TypeAArray) t);
case Tident: return visitIdentifier(cast(TypeIdentifier) t);
case Tinstance: return visitInstance(cast(TypeInstance) t);
case Tmixin: return visitMixin(cast(TypeMixin) t);
case Tsarray: return visitSArray(t.isTypeSArray());
case Taarray: return visitAArray(t.isTypeAArray());
case Tident: return visitIdentifier(t.isTypeIdentifier());
case Tinstance: return visitInstance(t.isTypeInstance());
case Tmixin: return visitMixin(t.isTypeMixin());
default: return null;
}
}
@ -684,7 +684,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
.error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
return error();
}
TypeSArray t = cast(TypeSArray)mtype.basetype;
TypeSArray t = mtype.basetype.isTypeSArray();
const sz = cast(int)t.size(loc);
final switch (target.isVectorTypeSupported(sz, t.nextOf()))
{
@ -790,8 +790,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
return overflowError();
Type tbx = tbn.baseElemOf();
if (tbx.ty == Tstruct && !(cast(TypeStruct)tbx).sym.members ||
tbx.ty == Tenum && !(cast(TypeEnum)tbx).sym.members)
if (tbx.ty == Tstruct && !tbx.isTypeStruct().sym.members ||
tbx.ty == Tenum && !tbx.isTypeEnum().sym.members)
{
/* To avoid meaningless error message, skip the total size limit check
* when the bottom of element type is opaque.
@ -802,7 +802,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
tbn.ty == Tarray ||
tbn.ty == Tsarray ||
tbn.ty == Taarray ||
(tbn.ty == Tstruct && ((cast(TypeStruct)tbn).sym.sizeok == Sizeok.done)) ||
(tbn.ty == Tstruct && tbn.isTypeStruct().sym.sizeok == Sizeok.done) ||
tbn.ty == Tclass)
{
/* Only do this for types that don't need to have semantic()
@ -819,7 +819,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
{
// Index the tuple to get the type
assert(mtype.dim);
TypeTuple tt = cast(TypeTuple)tbn;
TypeTuple tt = tbn.isTypeTuple();
uinteger_t d = mtype.dim.toUInteger();
if (d >= tt.arguments.dim)
{
@ -1026,9 +1026,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
*/
}
}
else if (tbase.ty == Tclass && !(cast(TypeClass)tbase).sym.isInterfaceDeclaration())
else if (tbase.ty == Tclass && !tbase.isTypeClass().sym.isInterfaceDeclaration())
{
ClassDeclaration cd = (cast(TypeClass)tbase).sym;
ClassDeclaration cd = tbase.isTypeClass().sym;
if (cd.semanticRun < PASS.semanticdone)
cd.dsymbolSemantic(null);
@ -1275,7 +1275,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
{
FuncExp fe = cast(FuncExp)e;
FuncExp fe = e.isFuncExp();
// Replace function literal with a function symbol,
// since default arg expression must be copied when used
// and copying the literal itself is wrong.
@ -1402,8 +1402,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
(t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
{
Type tb2 = t.baseElemOf();
if (tb2.ty == Tstruct && !(cast(TypeStruct)tb2).sym.members ||
tb2.ty == Tenum && !(cast(TypeEnum)tb2).sym.memtype)
if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members ||
tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype)
{
if (global.params.previewIn && (fparam.storageClass & STC.in_))
{
@ -1467,7 +1467,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
else
{
Type tv = t.baseElemOf();
if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.noDefaultCtor)
if (tv.ty == Tstruct && tv.isTypeStruct().sym.noDefaultCtor)
{
.error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
errors = true;
@ -1824,26 +1824,26 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
switch (e.op)
{
case EXP.dotVariable:
mtype.sym = (cast(DotVarExp)e).var;
mtype.sym = e.isDotVarExp().var;
break;
case EXP.variable:
mtype.sym = (cast(VarExp)e).var;
mtype.sym = e.isVarExp().var;
break;
case EXP.function_:
auto fe = cast(FuncExp)e;
auto fe = e.isFuncExp();
mtype.sym = fe.td ? fe.td : fe.fd;
break;
case EXP.dotTemplateDeclaration:
mtype.sym = (cast(DotTemplateExp)e).td;
mtype.sym = e.isDotTemplateExp().td;
break;
case EXP.dSymbol:
mtype.sym = (cast(DsymbolExp)e).s;
mtype.sym = e.isDsymbolExp().s;
break;
case EXP.template_:
mtype.sym = (cast(TemplateExp)e).td;
mtype.sym = e.isTemplateExp().td;
break;
case EXP.scope_:
mtype.sym = (cast(ScopeExp)e).sds;
mtype.sym = e.isScopeExp().sds;
break;
case EXP.tuple:
TupleExp te = e.toTupleExp();
@ -1854,13 +1854,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
switch (src.op)
{
case EXP.type:
(*elems)[i] = (cast(TypeExp)src).type;
(*elems)[i] = src.isTypeExp().type;
break;
case EXP.dotType:
(*elems)[i] = (cast(DotTypeExp)src).sym.isType();
(*elems)[i] = src.isDotTypeExp().sym.isType();
break;
case EXP.overloadSet:
(*elems)[i] = (cast(OverExp)src).type;
(*elems)[i] = src.isOverExp().type;
break;
default:
if (auto sym = isDsymbol(src))
@ -1873,13 +1873,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
mtype.sym = td;
break;
case EXP.dotType:
result = (cast(DotTypeExp)e).sym.isType();
result = e.isDotTypeExp().sym.isType();
break;
case EXP.type:
result = (cast(TypeExp)e).type;
result = e.isTypeExp().type;
break;
case EXP.overloadSet:
result = (cast(OverExp)e).type;
result = e.isOverExp().type;
break;
default:
break;
@ -2211,26 +2211,26 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
switch (type.ty)
{
default: return visitType(type);
case Tvector: return visitVector(cast(TypeVector)type);
case Tsarray: return visitSArray(cast(TypeSArray)type);
case Tarray: return visitDArray(cast(TypeDArray)type);
case Taarray: return visitAArray(cast(TypeAArray)type);
case Tpointer: return visitPointer(cast(TypePointer)type);
case Treference: return visitReference(cast(TypeReference)type);
case Tfunction: return visitFunction(cast(TypeFunction)type);
case Tdelegate: return visitDelegate(cast(TypeDelegate)type);
case Tident: return visitIdentifier(cast(TypeIdentifier)type);
case Tinstance: return visitInstance(cast(TypeInstance)type);
case Ttypeof: return visitTypeof(cast(TypeTypeof)type);
case Ttraits: return visitTraits(cast(TypeTraits)type);
case Treturn: return visitReturn(cast(TypeReturn)type);
case Tstruct: return visitStruct(cast(TypeStruct)type);
case Tenum: return visitEnum(cast(TypeEnum)type);
case Tclass: return visitClass(cast(TypeClass)type);
case Ttuple: return visitTuple (cast(TypeTuple)type);
case Tslice: return visitSlice(cast(TypeSlice)type);
case Tmixin: return visitMixin(cast(TypeMixin)type);
case Ttag: return visitTag(cast(TypeTag)type);
case Tvector: return visitVector(type.isTypeVector());
case Tsarray: return visitSArray(type.isTypeSArray());
case Tarray: return visitDArray(type.isTypeDArray());
case Taarray: return visitAArray(type.isTypeAArray());
case Tpointer: return visitPointer(type.isTypePointer());
case Treference: return visitReference(type.isTypeReference());
case Tfunction: return visitFunction(type.isTypeFunction());
case Tdelegate: return visitDelegate(type.isTypeDelegate());
case Tident: return visitIdentifier(type.isTypeIdentifier());
case Tinstance: return visitInstance(type.isTypeInstance());
case Ttypeof: return visitTypeof(type.isTypeTypeof());
case Ttraits: return visitTraits(type.isTypeTraits());
case Treturn: return visitReturn(type.isTypeReturn());
case Tstruct: return visitStruct(type.isTypeStruct());
case Tenum: return visitEnum(type.isTypeEnum());
case Tclass: return visitClass(type.isTypeClass());
case Ttuple: return visitTuple(type.isTypeTuple());
case Tslice: return visitSlice(type.isTypeSlice());
case Tmixin: return visitMixin(type.isTypeMixin());
case Ttag: return visitTag(type.isTypeTag());
}
}
@ -2300,7 +2300,7 @@ extern (C++) Type merge(Type type)
case Tsarray:
// prevents generating the mangle if the array dim is not yet known
if (!(cast(TypeSArray) type).dim.isIntegerExp())
if (!type.isTypeSArray().dim.isIntegerExp())
return type;
goto default;
@ -2308,7 +2308,7 @@ extern (C++) Type merge(Type type)
break;
case Taarray:
if (!(cast(TypeAArray)type).index.merge().deco)
if (!type.isTypeAArray().index.merge().deco)
return type;
goto default;
@ -2761,10 +2761,10 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
visitBasic(cast(TypeBasic)t) :
visitType(t);
case Terror: return visitError (cast(TypeError)t);
case Tvector: return visitVector(cast(TypeVector)t);
case Tenum: return visitEnum (cast(TypeEnum)t);
case Ttuple: return visitTuple (cast(TypeTuple)t);
case Terror: return visitError (t.isTypeError());
case Tvector: return visitVector(t.isTypeVector());
case Tenum: return visitEnum (t.isTypeEnum());
case Ttuple: return visitTuple (t.isTypeTuple());
}
}
@ -2889,7 +2889,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
{
Expression e = cast(Expression)o;
if (e.op == EXP.dSymbol)
return returnSymbol((cast(DsymbolExp)e).s);
return returnSymbol(e.isDsymbolExp().s);
else
return returnExp(e);
}
@ -3154,8 +3154,8 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
* template functions.
*/
}
if (auto f = mt.exp.op == EXP.variable ? (cast( VarExp)mt.exp).var.isFuncDeclaration()
: mt.exp.op == EXP.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null)
if (auto f = mt.exp.op == EXP.variable ? mt.exp.isVarExp().var.isFuncDeclaration()
: mt.exp.op == EXP.dotVariable ? mt.exp.isDotVarExp().var.isFuncDeclaration() : null)
{
// f might be a unittest declaration which is incomplete when compiled
// without -unittest. That causes a segfault in checkForwardRef, see
@ -3350,17 +3350,17 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
switch (mt.ty)
{
default: visitType (mt); break;
case Tsarray: visitSArray (cast(TypeSArray)mt); break;
case Tarray: visitDArray (cast(TypeDArray)mt); break;
case Taarray: visitAArray (cast(TypeAArray)mt); break;
case Tident: visitIdentifier(cast(TypeIdentifier)mt); break;
case Tinstance: visitInstance (cast(TypeInstance)mt); break;
case Ttypeof: visitTypeof (cast(TypeTypeof)mt); break;
case Treturn: visitReturn (cast(TypeReturn)mt); break;
case Tslice: visitSlice (cast(TypeSlice)mt); break;
case Tmixin: visitMixin (cast(TypeMixin)mt); break;
case Ttraits: visitTraits (cast(TypeTraits)mt); break;
default: visitType (mt); break;
case Tsarray: visitSArray (mt.isTypeSArray()); break;
case Tarray: visitDArray (mt.isTypeDArray()); break;
case Taarray: visitAArray (mt.isTypeAArray()); break;
case Tident: visitIdentifier(mt.isTypeIdentifier()); break;
case Tinstance: visitInstance (mt.isTypeInstance()); break;
case Ttypeof: visitTypeof (mt.isTypeTypeof()); break;
case Treturn: visitReturn (mt.isTypeReturn()); break;
case Tslice: visitSlice (mt.isTypeSlice()); break;
case Tmixin: visitMixin (mt.isTypeMixin()); break;
case Ttraits: visitTraits (mt.isTypeTraits()); break;
}
}
@ -4616,16 +4616,16 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
switch (mt.ty)
{
case Tvector: return visitVector (cast(TypeVector)mt);
case Tsarray: return visitSArray (cast(TypeSArray)mt);
case Tstruct: return visitStruct (cast(TypeStruct)mt);
case Tenum: return visitEnum (cast(TypeEnum)mt);
case Terror: return visitError (cast(TypeError)mt);
case Tarray: return visitDArray (cast(TypeDArray)mt);
case Taarray: return visitAArray (cast(TypeAArray)mt);
case Treference: return visitReference(cast(TypeReference)mt);
case Tdelegate: return visitDelegate (cast(TypeDelegate)mt);
case Tclass: return visitClass (cast(TypeClass)mt);
case Tvector: return visitVector (mt.isTypeVector());
case Tsarray: return visitSArray (mt.isTypeSArray());
case Tstruct: return visitStruct (mt.isTypeStruct());
case Tenum: return visitEnum (mt.isTypeEnum());
case Terror: return visitError (mt.isTypeError());
case Tarray: return visitDArray (mt.isTypeDArray());
case Taarray: return visitAArray (mt.isTypeAArray());
case Treference: return visitReference(mt.isTypeReference());
case Tdelegate: return visitDelegate (mt.isTypeDelegate());
case Tclass: return visitClass (mt.isTypeClass());
default: return mt.isTypeBasic()
? visitBasic(cast(TypeBasic)mt)
@ -4786,12 +4786,12 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
switch (mt.ty)
{
case Tvector: return visitVector (cast(TypeVector)mt);
case Tsarray: return visitSArray (cast(TypeSArray)mt);
case Tfunction: return visitFunction(cast(TypeFunction)mt);
case Tstruct: return visitStruct (cast(TypeStruct)mt);
case Tenum: return visitEnum (cast(TypeEnum)mt);
case Ttuple: return visitTuple (cast(TypeTuple)mt);
case Tvector: return visitVector (mt.isTypeVector());
case Tsarray: return visitSArray (mt.isTypeSArray());
case Tfunction: return visitFunction(mt.isTypeFunction());
case Tstruct: return visitStruct (mt.isTypeStruct());
case Tenum: return visitEnum (mt.isTypeEnum());
case Ttuple: return visitTuple (mt.isTypeTuple());
case Tnull: return new NullExp(Loc.initial, Type.tnull);
@ -4803,7 +4803,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
case Treference:
case Tdelegate:
case Tclass: return new NullExp(loc, mt);
case Tnoreturn: return visitNoreturn(cast(TypeNoreturn) mt);
case Tnoreturn: return visitNoreturn(mt.isTypeNoreturn());
default: return mt.isTypeBasic() ?
visitBasic(cast(TypeBasic)mt) :

View file

@ -1477,16 +1477,10 @@ public:
t1 = build_address (t1);
Type *tnext = tb1->isTypePointer ()->next->toBasetype ();
/* This case should have been rewritten to `_d_delstruct` in the
semantic phase. */
if (TypeStruct *ts = tnext->isTypeStruct ())
{
if (ts->sym->dtor)
{
tree ti = build_typeinfo (e->loc, tnext);
this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid,
2, t1, ti);
return;
}
}
gcc_assert (!ts->sym->dtor);
/* Otherwise, the garbage collector is called to immediately free the
memory allocated for the pointer. */

View file

@ -85,8 +85,6 @@ DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
/* Used when calling delete on a pointer. */
DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0)
DEF_D_RUNTIME (DELSTRUCT, "_d_delstruct", RT(VOID),
P2(POINTER_VOIDPTR, TYPEINFO), 0)
/* Used when calling new on an array. The `i' variant is for when the
initializer is nonzero, and the `m' variant is when initializing a

View file

@ -0,0 +1,13 @@
// https://issues.dlang.org/show_bug.cgi?id=22593
struct Foo(T){
this(Rhs, this This)(scope Rhs rhs){
}
this(ref scope typeof(this) rhs){
}
}
struct Bar{
Foo!int foo;
}

View file

@ -1,19 +1,13 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice17074.d(9): Error: identifier expected for C++ namespace
fail_compilation/ice17074.d(9): Error: found `__overloadset` when expecting `)`
fail_compilation/ice17074.d(9): Error: declaration expected, not `)`
---
*/
extern(C++, std.__overloadset) void ice_std_keyword();
/*
TEST_OUTPUT:
---
fail_compilation/ice17074.d(19): Error: identifier expected for C++ namespace
fail_compilation/ice17074.d(19): Error: found `*` when expecting `)`
fail_compilation/ice17074.d(19): Error: declaration expected, not `)`
fail_compilation/ice17074.d(13): Error: identifier expected for C++ namespace
fail_compilation/ice17074.d(13): Error: found `*` when expecting `)`
fail_compilation/ice17074.d(13): Error: declaration expected, not `)`
---
*/
extern(C++, std.*) void ice_std_token();

View file

@ -0,0 +1,23 @@
// https://issues.dlang.org/show_bug.cgi?id=22593
/*
TEST_OUTPUT:
---
fail_compilation/test22593.d(14): Error: Cannot define both an rvalue constructor and a copy constructor for `struct Foo`
fail_compilation/test22593.d(22): Template instance `__ctor!(immutable(Foo!int), immutable(Foo!int))` creates a rvalue constructor for `struct Foo`
fail_compilation/test22593.d(22): Error: template instance `test22593.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` error instantiating
---
*/
struct Foo(T)
{
this(Rhs, this This)(scope Rhs rhs){}
this(ref scope typeof(this) rhs){}
}
void main()
{
immutable Foo!int a;
a.__ctor(a);
}

View file

@ -1,4 +1,4 @@
6364e010bc87f3621028c8ac648133535c126fb3
fd9a45448244fb9dd4326520ad8526c540895eb0
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.

View file

@ -1,11 +1,45 @@
/**********************************************
* This module implements common builtins for the D frontend.
*
* Copyright: Copyright © 2019, The D Language Foundation
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Authors: Walter Bright
* Source: $(DRUNTIMESRC core/builtins.d)
*/
To provide access to features that would be otherwise counterproductive or
difficult to implement, compilers provide an interface consisting of a set
of builtins (also called intrinsics) which can be called like normal functions.
This module exposes builtins both common to all D compilers
(those provided by the frontend) and specific to the host compiler i.e. those
specific to either LLVM or GCC (`ldc.intrinsics` and `gcc.builtins` are publicly imported, respectively).
Host-specific intrinsics cannot be reliably listed here, however listings can be found
at the documentation for the relevant backends, i.e.
$(LINK2 https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html, GCC) and
$(LINK2 https://llvm.org/docs/LangRef.html, LLVM). It should be noted that not all
builtins listed are necessarily supported by the host compiler, please file a bug
if this is the case for your workload.
Use of this module reduces the amount of conditional compilation needed
to use a given builtin. For example, to write a target independent function
that uses prefetching we can write the following:
---
float usePrefetch(float[] x)
{
// There is only one import statement required rather than two (versioned) imports
import core.builtins;
version (GNU)
__builtin_prefetch(x.ptr);
version (LDC)
/+
For the curious: 0, 3, 1 mean `x` will only be read-from (0), it will be used
very often (3), and it should be fetched to the data-cache (1).
+/
llvm_prefetch(x.ptr, 0, 3, 1);
const doMath = blahBlahBlah;
return doMath;
}
---
Copyright: Copyright © 2021, The D Language Foundation
License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
Authors: Walter Bright
Source: $(DRUNTIMESRC core/builtins.d)
*/
module core.builtins;

View file

@ -1545,9 +1545,8 @@ template forward(args...)
{
import core.internal.traits : AliasSeq;
static if (args.length)
template fwd(alias arg)
{
alias arg = args[0];
// by ref || lazy || const/immutable
static if (__traits(isRef, arg) ||
__traits(isOut, arg) ||
@ -1556,15 +1555,16 @@ template forward(args...)
alias fwd = arg;
// (r)value
else
@property auto fwd(){ return move(arg); }
static if (args.length == 1)
alias forward = fwd;
else
alias forward = AliasSeq!(fwd, forward!(args[1..$]));
@property auto fwd(){ pragma(inline, true); return move(arg); }
}
alias Result = AliasSeq!();
static foreach (arg; args)
Result = AliasSeq!(Result, fwd!arg);
static if (Result.length == 1)
alias forward = Result[0];
else
alias forward = AliasSeq!();
alias forward = Result;
}
///
@ -2316,7 +2316,7 @@ template _d_delstructImpl(T)
@system pure nothrow unittest
{
int dtors = 0;
struct S { ~this() { ++dtors; } }
struct S { ~this() nothrow { ++dtors; } }
S *s = new S();
_d_delstructImpl!(typeof(s))._d_delstruct(s);

View file

@ -153,6 +153,9 @@ version (CRuntime_Glibc)
int sched_getcpu();
}
/* Reassociate the calling thread with namespace referred to by fd */
int setns(int fd, int nstype);
enum CLONE_FILES = 0x400;
enum CLONE_FS = 0x200;
enum CLONE_NEWCGROUP = 0x2000000;

View file

@ -4667,17 +4667,33 @@ public import core.internal.switch_: __switch_error;
public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);
// Compare class and interface objects for ordering.
private int __cmp(Obj)(Obj lhs, Obj rhs)
if (is(Obj : Object))
int __cmp(C1, C2)(C1 lhs, C2 rhs)
if ((is(C1 : const(Object)) || (is(C1 == interface) && (__traits(getLinkage, C1) == "D"))) &&
(is(C2 : const(Object)) || (is(C2 == interface) && (__traits(getLinkage, C2) == "D"))))
{
if (lhs is rhs)
static if (is(C1 == typeof(null)) && is(C2 == typeof(null)))
{
return 0;
// Regard null references as always being "less than"
if (!lhs)
}
else static if (is(C1 == typeof(null)))
{
// Regard null references as always being "less than"
return -1;
if (!rhs)
}
else static if (is(C2 == typeof(null)))
{
return 1;
return lhs.opCmp(rhs);
}
else
{
if (lhs is rhs)
return 0;
if (lhs is null)
return -1;
if (rhs is null)
return 1;
return lhs.opCmp(rhs);
}
}
// objects

View file

@ -1,4 +1,4 @@
575b67a9b4f78415f96ca77ad50b2de4c667cc74
495e835c2da47606142ff24c85de707e3b955a9a
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.

View file

@ -1287,3 +1287,26 @@ void formatValue(Writer, T, Char)(auto ref Writer w, auto ref T val, scope const
assertThrown!FormatException(formattedWrite(w, "%(%0*d%)", new int[1]));
}
// https://issues.dlang.org/show_bug.cgi?id=22609
@safe pure unittest
{
static enum State: ubyte { INACTIVE }
static struct S {
State state = State.INACTIVE;
int generation = 1;
alias state this;
// DMDBUG: https://issues.dlang.org/show_bug.cgi?id=16657
auto opEquals(S other) const { return state == other.state && generation == other.generation; }
auto opEquals(State other) const { return state == other; }
}
import std.array : appender;
import std.format.spec : singleSpec;
auto writer = appender!string();
const spec = singleSpec("%s");
S a;
writer.formatValue(a, spec);
assert(writer.data == "0");
}

View file

@ -201,6 +201,9 @@ interface RandomAccessFinite(E) : BidirectionalRange!(E) {
/**Interface for an infinite random access range of type `E`.*/
interface RandomAccessInfinite(E) : ForwardRange!E {
///
enum bool empty = false;
/**Calls $(REF moveAt, std, range, primitives) on the wrapped range, if
* possible. Otherwise, throws an $(LREF UnsupportedRangeMethod) exception.
*/
@ -213,6 +216,12 @@ interface RandomAccessInfinite(E) : ForwardRange!E {
E opIndex(size_t);
}
// https://issues.dlang.org/show_bug.cgi?id=22608
@safe unittest
{
static assert(isRandomAccessRange!(RandomAccessInfinite!int));
}
/**Adds assignable elements to InputRange.*/
interface InputAssignable(E) : InputRange!E {
///

View file

@ -6971,7 +6971,7 @@ mixin template Proxy(alias a)
static if (is(typeof(a.opCmp(b))))
return a.opCmp(b);
else static if (is(typeof(b.opCmp(a))))
return -b.opCmp(b);
return -b.opCmp(a);
else
return a < b ? -1 : a > b ? +1 : 0;
}