d: Merge upstream dmd 76e3b41375, druntime 1462ebd1, phobos 5fef0d28f.

Updates D language version to v2.100.1.

D front-end changes:

    - Fix delegate literal with inferred return value that requires
      following alias-this to not use class cast.
    - Fix internal error on variadic template type instantiated with two
      arrays of classes.
    - `scope(failure)' blocks that contain `return' statements are now
      deprecated.
    - Fix regression where wrong cast was inserted for ternary operator
      and non-int enums.
    - Fix internal error in code generation trying to reference
      _d_arraysetctor.
    - Fix memory corruption when array literal is passed to map in
      lambda, then returned from nested function.
    - Generate invariant id on the basis of location rather than a
      global counter.
    - Make `noreturn' conversions work.
    - Fix segfault when `.stringof' of template alias overloaded with
      function accessed by trait.
    - Empty array literal passed to scope param not 'falsey' anymore.

Phobos changes:

    - Avoid copying ranges in std.algorithm.comparison.equal.

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 76e3b41375.
	* dmd/VERSION: Bump version to v2.100.1.
	* decl.cc (DeclVisitor::visit (VarDeclaration *)): Evaluate RHS
	  of noreturn declaration expressions first.
	* expr.cc (ExprVisitor::visit (AssignExp *)): Don't generate
	  assignment for noreturn types.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 1462ebd1.
	* src/MERGE: Merge upstream phobos 5fef0d28f.
This commit is contained in:
Iain Buclaw 2022-07-26 18:13:54 +02:00
parent 2009850b2b
commit 81a0fa31ce
31 changed files with 408 additions and 37 deletions

View File

@ -645,9 +645,12 @@ public:
if (!d->isDataseg () && !d->isMember ()
&& d->_init && !d->_init->isVoidInitializer ())
{
/* Evaluate RHS for side effects first. */
Expression *ie = initializerToExpression (d->_init);
add_stmt (build_expr (ie));
Expression *e = d->type->defaultInitLiteral (d->loc);
tree exp = build_expr (e);
add_stmt (exp);
add_stmt (build_expr (e));
}
return;

View File

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

View File

@ -1 +1 @@
v2.100.0
v2.100.1

View File

@ -1107,9 +1107,14 @@ MATCH implicitConvTo(Expression e, Type t)
MATCH visitCond(CondExp e)
{
auto result = visit(e);
if (result != MATCH.nomatch)
return result;
e.econd = e.econd.optimize(WANTvalue);
const opt = e.econd.toBool();
if (opt.isPresent())
{
auto result = visit(e);
if (result != MATCH.nomatch)
return result;
}
MATCH m1 = e.e1.implicitConvTo(t);
MATCH m2 = e.e2.implicitConvTo(t);
@ -2954,6 +2959,9 @@ Lagain:
t1 = Type.basic[ty1];
t2 = Type.basic[ty2];
if (!(t1 && t2))
return null;
e1 = e1.castTo(sc, t1);
e2 = e2.castTo(sc, t2);
return Lret(Type.basic[ty]);

View File

@ -4407,7 +4407,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
invd.semanticRun < PASS.semantic &&
!ad.isUnionDeclaration() // users are on their own with union fields
)
{
invd.fixupInvariantIdent(ad.invs.length);
ad.invs.push(invd);
}
if (!invd.type)
invd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, invd.storage_class);

View File

@ -2048,7 +2048,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (global.params.useDIP1000 == FeatureState.enabled)
err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
}
else if (!(pStc & STC.return_))
else if (!(pStc & STC.return_) &&
((global.params.useDIP1000 == FeatureState.enabled) || !(p.storageClass & STC.scopeinferred)))
{
/* Argument value cannot escape from the called function.
*/
@ -2058,10 +2059,10 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
ArrayLiteralExp ale;
if (p.type.toBasetype().ty == Tarray &&
(ale = a.isArrayLiteralExp()) !is null)
(ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
{
// allocate the array literal as temporary static array on the stack
ale.type = ale.type.nextOf().sarrayOf(ale.elements ? ale.elements.length : 0);
ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
auto declareTmp = new DeclarationExp(ale.loc, tmp);
auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
@ -9926,9 +9927,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
ae.e2.type.nextOf &&
ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf);
/* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal,
* then we do want to make a temporary for it and call its destructor.
*/
const isArraySetCtor =
(ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
ae.e2.isLvalue &&
(ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) &&
ae.e1.type.nextOf &&
ae.e1.type.nextOf.equivalent(ae.e2.type);
@ -12535,7 +12538,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
e = new CommaExp(exp.loc, eleft, e);
e.type = Type.tvoid; // ambiguous type?
}
return e;
return e.expressionSemantic(sc);
}
if (auto o = s.isOverloadSet())
{

View File

@ -3748,9 +3748,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
{
Expression exp = s.exp;
if (exp && !exp.type.equals(tret))
{
s.exp = exp.castTo(sc, tret);
}
s.exp = exp.implicitCastTo(sc, tret);
}
}
@ -4150,6 +4148,7 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration
{
extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
{
// Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
this.fbody = fbody;
}
@ -4186,6 +4185,15 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration
{
v.visit(this);
}
extern (D) void fixupInvariantIdent(size_t offset)
{
OutBuffer idBuf;
idBuf.writestring("__invariant");
idBuf.print(offset);
ident = Identifier.idPool(idBuf[]);
}
}

View File

@ -64,6 +64,57 @@ enum ImpCnvTab impCnvTab = generateImpCnvTab();
ImpCnvTab generateImpCnvTab()
{
TY[TMAX] typeTYs =
[
Tarray,
Tsarray,
Taarray,
Tpointer,
Treference,
Tfunction,
Tident,
Tclass,
Tstruct,
Tenum,
Tdelegate,
Tnone,
Tvoid,
Tint8,
Tuns8,
Tint16,
Tuns16,
Tint32,
Tuns32,
Tint64,
Tuns64,
Tfloat32,
Tfloat64,
Tfloat80,
Timaginary32,
Timaginary64,
Timaginary80,
Tcomplex32,
Tcomplex64,
Tcomplex80,
Tbool,
Tchar,
Twchar,
Tdchar,
Terror,
Tinstance,
Ttypeof,
Ttuple,
Tslice,
Treturn,
Tnull,
Tvector,
Tint128,
Tuns128,
Ttraits,
Tmixin,
Tnoreturn,
Ttag,
];
ImpCnvTab impCnvTab;
// Set conversion tables
@ -375,5 +426,9 @@ ImpCnvTab generateImpCnvTab()
X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80);
// "No type is implicitly convertible to noreturn, but noreturn is implicitly convertible to every other type"
foreach(convertToTy; typeTYs)
X(Tnoreturn, convertToTy, convertToTy, convertToTy, convertToTy);
return impCnvTab;
}

View File

@ -6184,6 +6184,11 @@ extern (C++) final class TypeClass : Type
if (t && t.ty == Tclass)
{
ClassDeclaration cd = (cast(TypeClass)t).sym;
if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
cd.dsymbolSemantic(null);
if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
sym.dsymbolSemantic(null);
if (sym.isBaseOf(cd, poffset))
return true;
}

View File

@ -2829,10 +2829,20 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
rs.error("`return` statements cannot be in contracts");
errors = true;
}
if (sc.os && sc.os.tok != TOK.onScopeFailure)
if (sc.os)
{
rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok));
errors = true;
// @@@DEPRECATED_2.112@@@
// Deprecated in 2.100, transform into an error in 2.112
if (sc.os.tok == TOK.onScopeFailure)
{
rs.deprecation("`return` statements cannot be in `scope(failure)` bodies.");
deprecationSupplemental(rs.loc, "Use try-catch blocks for this purpose");
}
else
{
rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok));
errors = true;
}
}
if (sc.tf)
{

View File

@ -916,6 +916,17 @@ public:
gcc_unreachable ();
}
/* Look for exp = noreturn; */
if (e->e2->type->isTypeNoreturn ())
{
/* If the RHS is a `noreturn' expression, there is no point generating
any code for the assignment, just evaluate side effects. */
tree t1 = build_expr (e->e1);
tree t2 = build_expr (e->e2);
this->result_ = compound_expr (t1, t2);
return;
}
/* Look for array[] = n; */
if (e->e1->op == EXP::slice)
{

View File

@ -0,0 +1,10 @@
// REQUIRED_ARGS: -O -inline
//https://issues.dlang.org/show_bug.cgi?id=20143
real fun(int x) { return 0.0; }
double bug()
{
// value passed to fun is irrelevant
return 0.0 / fun(420);
}

View File

@ -122,3 +122,31 @@ noreturn testdg(noreturn delegate() dg)
{
dg();
}
noreturn func()
{
while(1)
{
}
}
alias AliasSeq(T...) = T;
alias Types = AliasSeq!(bool, byte, ubyte, short, ushort, int, uint,
long, ulong, char, wchar, dchar, float, double,
real);
void noreturnImplicit()
{
/*
Testing both ways because, although the underlying table
is symmetrical the code that calls into it may be buggy.
*/
{
int x = 2 + func();
int y = func() + 2;
}
foreach(T; Types)
{
T value;
auto x = value + throw new Exception("Hello");
auto y = (throw new Exception("wow")) + value;
}
}

View File

@ -0,0 +1,17 @@
// https://issues.dlang.org/show_bug.cgi?id=23082
/*
TEST_OUTPUT:
---
bar
---
*/
void foo()() {}
alias bar = foo;
void bar() { }
void main()
{
pragma(msg, __traits(parent, main).bar.stringof);
}

View File

@ -0,0 +1,22 @@
// REQUIRED_ARGS: -inline
// https://issues.dlang.org/show_bug.cgi?id=23166
// seg fault with -inline
bool __equals(scope const char[] lhs, scope const char[] rhs)
{
if (lhs.length != rhs.length)
return false;
{
import core.stdc.string : memcmp;
return lhs.length == 0;
}
return true;
}
int test(string type)
{
return __equals(type, "as-is");
}

View File

@ -0,0 +1,33 @@
// https://issues.dlang.org/show_bug.cgi?id=23172
enum E : ubyte { // `ubyte` is needed to trigger the bug
A,
B,
}
struct S {
E e;
}
void compiles(bool b, S s) {
E e = b ? E.A : s.e;
}
void errors(bool b, const ref S s) {
E e = b ? E.A : s.e;
}
// from https://issues.dlang.org/show_bug.cgi?id=23188
enum Status : byte
{
A, B, C
}
Status foo()
{
Status t = Status.A;
const Status s = t;
return (s == Status.A) ? Status.B : s; // <-- here
}

View File

@ -0,0 +1,21 @@
// https://issues.dlang.org/show_bug.cgi?id=23258
struct SumType(Types...)
{
this(Types[0])
{
}
this(Types[1])
{
}
}
alias A2 = SumType!(C1[], C2[]);
class C1
{
}
class C2
{
}

View File

@ -0,0 +1,16 @@
/* https://issues.dlang.org/show_bug.cgi?id=23181
TEST_OUTPUT:
---
$p:druntime/import/core/lifetime.d$($n$): Error: struct `fail23181.fail23181.NoPostblit` is not copyable because it has a disabled postblit
$p:druntime/import/core/internal/array/construction.d$($n$): Error: template instance `core.lifetime.copyEmplace!(NoPostblit, NoPostblit)` error instantiating
fail_compilation/fail23181.d(15): instantiated from here: `_d_arraysetctor!(NoPostblit[], NoPostblit)`
---
*/
void fail23181()
{
struct NoPostblit
{
@disable this(this);
}
NoPostblit[4] noblit23181 = NoPostblit();
}

View File

@ -55,7 +55,7 @@ L1:
scope(failure) { L2: goto L1; } // OK
goto L2; // NG
scope(failure) { return; } // OK
foreach (i; 0..1)
{

View File

@ -9,12 +9,12 @@ fail_compilation/fail7848.d(21): `fail7848.func` is declared here
fail_compilation/fail7848.d(27): Error: `@nogc` function `fail7848.C.__unittest_L25_C30` cannot call non-@nogc function `fail7848.func`
fail_compilation/fail7848.d(27): Error: function `fail7848.func` is not `nothrow`
fail_compilation/fail7848.d(25): Error: function `fail7848.C.__unittest_L25_C30` may throw but is marked as `nothrow`
fail_compilation/fail7848.d(32): Error: `pure` function `fail7848.C.__invariant1` cannot call impure function `fail7848.func`
fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant1` cannot call `@system` function `fail7848.func`
fail_compilation/fail7848.d(32): Error: `pure` function `fail7848.C.__invariant0` cannot call impure function `fail7848.func`
fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant0` cannot call `@system` function `fail7848.func`
fail_compilation/fail7848.d(21): `fail7848.func` is declared here
fail_compilation/fail7848.d(32): Error: `@nogc` function `fail7848.C.__invariant1` cannot call non-@nogc function `fail7848.func`
fail_compilation/fail7848.d(32): Error: `@nogc` function `fail7848.C.__invariant0` cannot call non-@nogc function `fail7848.func`
fail_compilation/fail7848.d(32): Error: function `fail7848.func` is not `nothrow`
fail_compilation/fail7848.d(30): Error: function `fail7848.C.__invariant1` may throw but is marked as `nothrow`
fail_compilation/fail7848.d(30): Error: function `fail7848.C.__invariant0` may throw but is marked as `nothrow`
---
*/

View File

@ -0,0 +1,21 @@
// https://issues.dlang.org/show_bug.cgi?id=21443
// REQUIRED_ARGS: -de
/*
TEST_OUTPUT:
---
fail_compilation/test21443.d(14): Deprecation: `return` statements cannot be in `scope(failure)` bodies.
fail_compilation/test21443.d(14): Use try-catch blocks for this purpose
---
*/
ulong get () @safe nothrow
{
scope (failure) return 10;
throw new Error("");
}
void main () @safe
{
assert(get() == 10); // passes
}

View File

@ -0,0 +1,12 @@
/*
TEST_OUTPUT:
---
fail_compilation/test23170.d(10): Error: array literal in `@nogc` delegate `test23170.__lambda5` may cause a GC allocation
---
*/
// https://issues.dlang.org/show_bug.cgi?id=23170
@nogc:
enum lambda = () => badAlias([1, 2, 3]);
alias badAlias = (int[] array) => id(array);
int[] id(int[] array) { return array; }

View File

@ -261,6 +261,37 @@ void testThrowDtor()
/*****************************************/
noreturn func()
{
throw new Exception("B");
}
// https://issues.dlang.org/show_bug.cgi?id=23120
void test23120()
{
string a;
try
{
noreturn q = throw new Exception ("A");
}
catch(Exception e)
{
a ~= e.msg;
}
try
{
noreturn z = func();
}
catch(Exception e)
{
a ~= e.msg;
}
assert(a == "AB");
}
/*****************************************/
int main()
{
test1();
@ -269,5 +300,6 @@ int main()
testThrowExpression();
testThrowSideEffect();
testThrowDtor();
test23120();
return 0;
}

View File

@ -16,6 +16,7 @@ extern(C) int main() nothrow @nogc @safe
{
takeScopeSlice([ S(1), S(2) ]); // @nogc => no GC allocation
(() @trusted { assert(numDtor == 2); })(); // stack-allocated array literal properly destructed
assert23100([]);
return 0;
}
@ -26,3 +27,9 @@ void test23098() @safe
{
f23098([10, 20]);
}
// https://issues.dlang.org/show_bug.cgi?id=23100
void assert23100(scope int[] d) @safe nothrow @nogc
{
assert(!d);
}

View File

@ -0,0 +1,27 @@
// https://issues.dlang.org/show_bug.cgi?id=23181
void main()
{
int count;
struct HasDtor
{
~this() { ++count; }
}
// array[] = elem()
// -> creates temporary to construct array and calls destructor.
{
count = 0;
HasDtor[4] dtor1 = HasDtor();
assert(count == 1);
}
assert(count == 5);
// array[] = array[elem()]
// -> constructs array using direct emplacement.
{
count = 0;
HasDtor[2] dtor2 = [HasDtor(), HasDtor()];
assert(count == 0);
}
assert(count == 2);
}

View File

@ -0,0 +1,22 @@
// https://issues.dlang.org/show_bug.cgi?id=23234
class Bar
{
}
class Foo
{
Bar get() { return new Bar; }
alias get this;
}
void main()
{
auto foo = new Foo;
void test(Bar delegate() dg)
{
assert(dg() !is null);
}
test(() => foo);
}

View File

@ -133,15 +133,6 @@ void test6518()
}
}
/******************************************/
// https://issues.dlang.org/show_bug.cgi?id=7232
bool test7232()
{
scope(failure) return false;
return true;
}
/***************************************************/
struct S9332

View File

@ -1,4 +1,4 @@
9c0d4f914e0817c9ee4eafc5a45c41130aa6b981
1462ebd188c0ab5181a0a75e3576754bb0b81a16
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.

View File

@ -1,4 +1,4 @@
604534d7cb29d49a6474f0aaaa5d166057a44f72
5fef0d28fc873fb5a0dbfb9149759d76a7b9f1b7
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.

View File

@ -1027,7 +1027,7 @@ template equal(alias pred = "a == b")
}
}
private bool equalLoop(Rs...)(Rs rs)
private bool equalLoop(Rs...)(ref Rs rs)
{
for (; !rs[0].empty; rs[0].popFront)
static foreach (r; rs[1 .. $])

View File

@ -4905,8 +4905,14 @@ if (is(Interface == interface) && is(BaseClass == class))
// - try default first
// - only on a failure run & return fallback
enum fallback = q{
scope (failure) return fallback.%1$s(args);
return default_.%1$s(args);
try
{
return default_.%1$s(args);
}
catch (Exception)
{
return fallback.%1$s(args);
}
}.format(__traits(identifier, func));
}