Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/stable' into merge_stable
Browse files Browse the repository at this point in the history
  • Loading branch information
MoonlightSentinel committed Apr 9, 2021
2 parents e81c45b + 6552783 commit 1ed089a
Show file tree
Hide file tree
Showing 26 changed files with 682 additions and 96 deletions.
20 changes: 14 additions & 6 deletions src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -1454,14 +1454,22 @@ extern (C++) class VarDeclaration : Declaration
//if (cd.isInterfaceDeclaration())
// error("interface `%s` cannot be scope", cd.toChars());

// Destroying C++ scope classes crashes currently. Since C++ class dtors are not currently supported, simply do not run dtors for them.
// See https://issues.dlang.org/show_bug.cgi?id=13182
if (cd.classKind == ClassKind.cpp)
{
break;
}
if (mynew || onstack) // if any destructors
{
// delete'ing C++ classes crashes (and delete is deprecated anyway)
if (cd.classKind == ClassKind.cpp)
{
// Don't call non-existant dtor
if (!cd.dtor)
break;

e = new VarExp(loc, this);
e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances
e = new DotVarExp(loc, e, cd.dtor, false);
e = new CallExp(loc, e);
break;
}

// delete this;
Expression ec;
ec = new VarExp(loc, this);
Expand Down
24 changes: 19 additions & 5 deletions src/dmd/dinterpret.d
Original file line number Diff line number Diff line change
Expand Up @@ -5722,12 +5722,26 @@ public:
auto cre = cast(ClassReferenceExp)result;
auto cd = cre.originalClass();

if (cd.dtor)
// Find dtor(s) in inheritance chain
do
{
result = interpretFunction(pue, cd.dtor, istate, null, cre);
if (exceptionOrCant(result))
return;
}
if (cd.dtor)
{
result = interpretFunction(pue, cd.dtor, istate, null, cre);
if (exceptionOrCant(result))
return;

// Dtors of Non-extern(D) classes use implicit chaining (like structs)
import dmd.aggregate : ClassKind;
if (cd.classKind != ClassKind.d)
break;
}

// Emulate manual chaining as done in rt_finalize2
cd = cd.baseClass;

} while (cd); // Stop after Object

break;

case Tpointer:
Expand Down
87 changes: 45 additions & 42 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3960,61 +3960,64 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Linterfaces:
bool foundVtblMatch = false;

foreach (b; cd.interfaces)
for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass)
{
vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim);
switch (vi)
foreach (b; bcd.interfaces)
{
case -1:
break;

case -2:
// can't determine because of forward references
funcdecl.errors = true;
return;

default:
vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim);
switch (vi)
{
auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi];
Type ti = null;
case -1:
break;

foundVtblMatch = true;
case -2:
// can't determine because of forward references
funcdecl.errors = true;
return;

/* Remember which functions this overrides
*/
funcdecl.foverrides.push(fdv);
default:
{
auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi];
Type ti = null;

/* Should we really require 'override' when implementing
* an interface function?
*/
//if (!isOverride())
// warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars());
foundVtblMatch = true;

if (fdv.tintro)
ti = fdv.tintro;
else if (!funcdecl.type.equals(fdv.type))
{
/* Only need to have a tintro if the vptr
* offsets differ
/* Remember which functions this overrides
*/
int offset;
if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset))
{
ti = fdv.type;
}
}
if (ti)
{
if (funcdecl.tintro)
funcdecl.foverrides.push(fdv);

/* Should we really require 'override' when implementing
* an interface function?
*/
//if (!isOverride())
// warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars());

if (fdv.tintro)
ti = fdv.tintro;
else if (!funcdecl.type.equals(fdv.type))
{
if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null))
/* Only need to have a tintro if the vptr
* offsets differ
*/
int offset;
if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset))
{
funcdecl.error("incompatible covariant types `%s` and `%s`", funcdecl.tintro.toChars(), ti.toChars());
ti = fdv.type;
}
}
else
if (ti)
{
funcdecl.tintro = ti;
if (funcdecl.tintro)
{
if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null))
{
funcdecl.error("incompatible covariant types `%s` and `%s`", funcdecl.tintro.toChars(), ti.toChars());
}
}
else
{
funcdecl.tintro = ti;
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -1931,6 +1931,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
}
else if (global.params.rvalueRefParam)
{
// Allow implicit conversion to ref
}
else
return nomatch();
}
Expand Down
18 changes: 9 additions & 9 deletions src/dmd/escape.d
Original file line number Diff line number Diff line change
Expand Up @@ -881,34 +881,34 @@ ByRef:

/* Do not allow slicing of a static array returned by a function
*/
if (va && ee.op == TOK.call && ee.type.toBasetype().ty == Tsarray && va.type.toBasetype().ty == Tarray &&
!(va.storage_class & STC.temp))
if (ee.op == TOK.call && ee.type.toBasetype().ty == Tsarray && e1.type.toBasetype().ty == Tarray &&
!(va && va.storage_class & STC.temp))
{
if (!gag)
deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`",
ee.toChars(), va.toChars());
ee.toChars(), e1.toChars());
//result = true;
continue;
}

if (va && ee.op == TOK.call && ee.type.toBasetype().ty == Tstruct &&
!(va.storage_class & STC.temp) && va.ident != Id.withSym &&
if (ee.op == TOK.call && ee.type.toBasetype().ty == Tstruct &&
(!va || (!(va.storage_class & STC.temp) && va.ident != Id.withSym)) &&
sc.func.setUnsafe())
{
if (!gag)
error(ee.loc, "address of struct temporary returned by `%s` assigned to longer lived variable `%s`",
ee.toChars(), va.toChars());
ee.toChars(), e1.toChars());
result = true;
continue;
}

if (va && ee.op == TOK.structLiteral &&
!(va.storage_class & STC.temp) && va.ident != Id.withSym &&
if (ee.op == TOK.structLiteral &&
(!va || (!(va.storage_class & STC.temp) && va.ident != Id.withSym)) &&
sc.func.setUnsafe())
{
if (!gag)
error(ee.loc, "address of struct literal `%s` assigned to longer lived variable `%s`",
ee.toChars(), va.toChars());
ee.toChars(), e1.toChars());
result = true;
continue;
}
Expand Down
28 changes: 26 additions & 2 deletions src/dmd/expression.d
Original file line number Diff line number Diff line change
Expand Up @@ -4782,9 +4782,31 @@ extern (C++) final class DotVarExp : UnaExp
if (sc.func && sc.func.isCtorDeclaration())
{
// if inside a constructor scope and e1 of this DotVarExp
// is a DotVarExp, then check if e1.e1 is a `this` identifier
// is another DotVarExp, then check if the leftmost expression is a `this` identifier
if (auto dve = e1.isDotVarExp())
{
// Iterate the chain of DotVarExp to find `this`
// Keep track whether access to fields was limited to union members
// s.t. one can initialize an entire struct inside nested unions
// (but not its members)
bool onlyUnion = true;
while (true)
{
auto v = dve.var.isVarDeclaration();
assert(v);

// Accessing union member?
auto t = v.type.isTypeStruct();
if (!t || !t.sym.isUnionDeclaration())
onlyUnion = false;

// Another DotVarExp left?
if (!dve.e1 || dve.e1.op != TOK.dotVariable)
break;

dve = cast(DotVarExp) dve.e1;
}

if (dve.e1.op == TOK.this_)
{
scope v = dve.var.isVarDeclaration();
Expand All @@ -4802,7 +4824,9 @@ extern (C++) final class DotVarExp : UnaExp
*/
scope modifyLevel = v.checkModify(loc, sc, dve.e1, flag);
// reflect that assigning a field of v is not initialization of v
v.ctorinit = false;
// unless v is a (potentially nested) union
if (!onlyUnion)
v.ctorinit = false;
if (modifyLevel == Modifiable.initialization)
return Modifiable.yes;
return modifyLevel;
Expand Down
5 changes: 5 additions & 0 deletions src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -6104,6 +6104,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Rewriting CallExp's also avoids some issues with the inliner/debug generation
if (op.hasSideEffect(true))
{
// Don't create an invalid temporary for void-expressions
// Further semantic will issue an appropriate error
if (op.type.ty == ENUMTY.Tvoid)
return op;

// https://issues.dlang.org/show_bug.cgi?id=21590
// Don't create unnecessary temporaries and detect `assert(a = b)`
if (op.isAssignExp() || op.isBinAssignExp())
Expand Down
7 changes: 6 additions & 1 deletion src/dmd/initsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, Type t,
return new ErrorInitializer();
}
uint olderrors = global.errors;
/* Save the expression before ctfe
* Otherwise the error message would contain for example "&[0][0]" instead of "new int"
* Regression: https://issues.dlang.org/show_bug.cgi?id=21687
*/
Expression currExp = i.exp;
if (needInterpret)
{
// If the result will be implicitly cast, move the cast into CTFE
Expand Down Expand Up @@ -421,7 +426,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, Type t,
// Make sure all pointers are constants
if (needInterpret && hasNonConstPointers(i.exp))
{
i.exp.error("cannot use non-constant CTFE pointer in an initializer `%s`", i.exp.toChars());
i.exp.error("cannot use non-constant CTFE pointer in an initializer `%s`", currExp.toChars());
return new ErrorInitializer();
}
Type tb = t.toBasetype();
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/semantic3.d
Original file line number Diff line number Diff line change
Expand Up @@ -1369,7 +1369,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
* https://issues.dlang.org/show_bug.cgi?id=14246
*/
AggregateDeclaration ad = ctor.isMemberDecl();
if (ctor.fbody && ad && ad.fieldDtor && global.params.dtorFields && !ctor.type.toTypeFunction.isnothrow)
if (ctor.fbody && ad && ad.fieldDtor && global.params.dtorFields && !global.params.betterC && !ctor.type.toTypeFunction.isnothrow)
{
/* Generate:
* this.fieldDtor()
Expand Down
4 changes: 2 additions & 2 deletions test/compilable/ctfe_math.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import std.math;

void main()
{
static assert(isClose(sin(2.0L), 0.9092974268L));
static assert(isClose(sin(2.0L), 0.9092974268));
static assert(isClose(cos(2.0), -0.4161468365));
static assert(isClose(tan(2.0f), -2.185040f, 1e-5));
static assert(isClose(sqrt(2.0L), 1.4142135623L));
static assert(isClose(sqrt(2.0L), 1.4142135623));
static assert(fabs(-2.0) == 2.0);
static assert(ldexp(2.5f, 3) == 20.0f);

Expand Down
3 changes: 3 additions & 0 deletions test/compilable/dtorfields.d
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// REQUIRED_ARGS: -preview=dtorfields
//
// https://issues.dlang.org/show_bug.cgi?id=21709
// PERMUTE_ARGS: -betterC

/******************************************
* https://issues.dlang.org/show_bug.cgi?id=20934
Expand Down
16 changes: 16 additions & 0 deletions test/compilable/issue20705.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// REQUIRED_ARGS: -preview=rvaluerefparam
struct Foo
{
int[] a;
}

void bar (T) (const ref T arg) {}
T foo (T) (ref T arg) { return arg; }
void goo()(ref long x) { x = 1; }
void main ()
{
bar(Foo([42]));
auto x = foo(Foo([42]));
int y;
static assert(!__traits(compiles, goo(y)));
}
13 changes: 13 additions & 0 deletions test/compilable/scope.d
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,19 @@ void test(scope ref D d) @safe
da ~= D(d.pos, null);
}

/************************************/

void withEscapes()
{
static D get() @safe;

with (get())
{
}
}

/************************************/

// https://issues.dlang.org/show_bug.cgi?id=20682

int f1_20682(return scope ref D d) @safe
Expand Down

0 comments on commit 1ed089a

Please sign in to comment.