Merge pull request #14280 from ibuclaw/merge_stable

merge stable
This commit is contained in:
Mathias LANG 2022-07-09 18:31:42 +02:00 committed by GitHub
commit 20bd0cacbd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 414 additions and 27 deletions

View file

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

View file

@ -0,0 +1,23 @@
`scope(failure)` blocks that contain `return` statements are now deprecated
Starting with this release, having a `return` statement in the body of a `scope(failure)`
statement is deprecated. Having the ability to `return` from such blocks is error prone since currently, Errors are also handled by `scope(failure)`. This leads to the following situation:
---
ulong get () @safe nothrow
{
scope (failure) return 10;
throw new Error("");
}
void main () @safe
{
assert(get() == 10); // passes
}
---
where an error is circumvented by a return. If a return is indeed desired
in such situations, then the solution is to simply use a try-catch block
for the function body.
Note: `scope(exit)` and `scope(success)` already present this restriction.

View file

@ -716,7 +716,7 @@ struct ASTBase
{ {
extern (D) this(const ref Loc loc, Loc endloc, StorageClass stc, Identifier id, Statement fbody) extern (D) this(const ref Loc loc, Loc endloc, StorageClass stc, Identifier id, Statement fbody)
{ {
super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null); super(loc, endloc, id ? id : Identifier.generateIdWithLoc("__invariant", loc), stc, null);
this.fbody = fbody; this.fbody = fbody;
} }

View file

@ -1348,6 +1348,7 @@ void cddiv(ref CodeBuilder cdb,elem *e,regm_t *pretregs)
code cs = void; code cs = void;
cs.Iflags = 0; cs.Iflags = 0;
cs.IFL2 = 0;
cs.Irex = 0; cs.Irex = 0;
switch (e2.Eoper) switch (e2.Eoper)

View file

@ -984,6 +984,10 @@ static if (0)
case TYdouble_alias: case TYdouble_alias:
e.EV.Vdouble = e1.EV.Vdouble / e2.EV.Vdouble; e.EV.Vdouble = e1.EV.Vdouble / e2.EV.Vdouble;
break; break;
case TYldouble:
// cast is required because Vldouble is a soft type on windows
e.EV.Vdouble = cast(double)(e1.EV.Vdouble / e2.EV.Vldouble);
break;
case TYidouble: case TYidouble:
e.EV.Vdouble = -e1.EV.Vdouble / e2.EV.Vdouble; e.EV.Vdouble = -e1.EV.Vdouble / e2.EV.Vdouble;
break; break;

View file

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

View file

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

View file

@ -2077,6 +2077,15 @@ elem* toElem(Expression e, IRState *irs)
return e; return e;
} }
/*
https://issues.dlang.org/show_bug.cgi?id=23120
If rhs is a noreturn expression, then there is no point
to generate any code for the noreturen variable.
*/
if (ae.e2.type.isTypeNoreturn())
return setResult(toElem(ae.e2, irs));
Type t1b = ae.e1.type.toBasetype(); Type t1b = ae.e1.type.toBasetype();
// Look for array.length = n // Look for array.length = n
@ -6077,7 +6086,10 @@ Lagain:
/* Need to do postblit/destructor. /* Need to do postblit/destructor.
* void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti); * void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti);
*/ */
assert(op != EXP.construct, "Trying reference _d_arraysetctor, this should not happen!"); if (op == EXP.construct)
{
assert(0, "Trying reference _d_arraysetctor, this should not happen!");
}
r = RTLSYM.ARRAYSETASSIGN; r = RTLSYM.ARRAYSETASSIGN;
evalue = el_una(OPaddr, TYnptr, evalue); evalue = el_una(OPaddr, TYnptr, evalue);
// This is a hack so we can call postblits on const/immutable objects. // This is a hack so we can call postblits on const/immutable objects.

View file

@ -9896,9 +9896,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
ae.e2.type.nextOf && ae.e2.type.nextOf &&
ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf); 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 = const isArraySetCtor =
(ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
ae.e2.isLvalue &&
(ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) && (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) &&
ae.e1.type.nextOf && ae.e1.type.nextOf &&
ae.e1.type.nextOf.equivalent(ae.e2.type); ae.e1.type.nextOf.equivalent(ae.e2.type);
@ -12638,7 +12640,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
e = new CommaExp(exp.loc, eleft, e); e = new CommaExp(exp.loc, eleft, e);
e.type = Type.tvoid; // ambiguous type? e.type = Type.tvoid; // ambiguous type?
} }
return e; return e.expressionSemantic(sc);
} }
if (auto o = s.isOverloadSet()) if (auto o = s.isOverloadSet())
{ {

View file

@ -4222,6 +4222,7 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration
{ {
extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody) 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); super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
this.fbody = fbody; this.fbody = fbody;
} }
@ -4258,6 +4259,15 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration
{ {
v.visit(this); 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() 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; ImpCnvTab impCnvTab;
// Set conversion tables // Set conversion tables
@ -375,5 +426,9 @@ ImpCnvTab generateImpCnvTab()
X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80); 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; return impCnvTab;
} }

View file

@ -237,7 +237,7 @@ public:
auto e1 = doInlineAs!Expression(ifs.ifbody, ids); auto e1 = doInlineAs!Expression(ifs.ifbody, ids);
assert(ids.foundReturn); assert(ids.foundReturn);
auto e2 = doInlineAs!Expression(s3, ids); auto e2 = doInlineAs!Expression(s3, ids);
assert(e2);
Expression e = new CondExp(econd.loc, econd, e1, e2); Expression e = new CondExp(econd.loc, econd, e1, e2);
e.type = e1.type; e.type = e1.type;
if (e.type.ty == Ttuple) if (e.type.ty == Ttuple)
@ -250,6 +250,7 @@ public:
} }
else else
{ {
ids.foundReturn = false;
auto e = doInlineAs!Expression(sx, ids); auto e = doInlineAs!Expression(sx, ids);
result = Expression.combine(result, e); result = Expression.combine(result, e);
} }
@ -375,6 +376,7 @@ public:
override void visit(ImportStatement s) override void visit(ImportStatement s)
{ {
//printf("ImportStatement.doInlineAs!%s()\n", Result.stringof.ptr);
} }
override void visit(ForStatement s) override void visit(ForStatement s)

View file

@ -156,6 +156,7 @@ nothrow @nogc pure:
static if (op == "+") return longdouble_soft(rhs).ld_add(this); static if (op == "+") return longdouble_soft(rhs).ld_add(this);
else static if (op == "-") return longdouble_soft(rhs).ld_sub(this); else static if (op == "-") return longdouble_soft(rhs).ld_sub(this);
else static if (op == "*") return longdouble_soft(rhs).ld_mul(this); else static if (op == "*") return longdouble_soft(rhs).ld_mul(this);
else static if (op == "/") return longdouble_soft(rhs).ld_div(this);
else static if (op == "%") return longdouble_soft(rhs).ld_mod(this); else static if (op == "%") return longdouble_soft(rhs).ld_mod(this);
else static assert(false, "Operator `"~op~"` is not implemented"); else static assert(false, "Operator `"~op~"` is not implemented");
} }

View file

@ -2845,11 +2845,21 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
rs.error("`return` statements cannot be in contracts"); rs.error("`return` statements cannot be in contracts");
errors = true; errors = true;
} }
if (sc.os && sc.os.tok != TOK.onScopeFailure) if (sc.os)
{
// @@@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)); rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok));
errors = true; errors = true;
} }
}
if (sc.tf) if (sc.tf)
{ {
rs.error("`return` statements cannot be in `finally` bodies"); rs.error("`return` statements cannot be in `finally` bodies");

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

@ -85,7 +85,7 @@ class C : Object
} }
invariant invariant
{ {
this.__invariant1() , this.__invariant2(); this.__invariant0() , this.__invariant1();
} }
} }
enum __c_wchar_t : dchar; enum __c_wchar_t : dchar;

View file

@ -122,3 +122,31 @@ noreturn testdg(noreturn delegate() dg)
{ {
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,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 scope(failure) { L2: goto L1; } // OK
goto L2; // NG goto L2; // NG
scope(failure) { return; } // OK
foreach (i; 0..1) 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: `@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(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(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: `pure` function `fail7848.C.__invariant0` 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: `@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(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(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

@ -0,0 +1,3 @@
import lib21723b;
alias Struct = lib21723b.Struct;

View file

@ -0,0 +1,4 @@
struct Struct {
invariant { void call() { } }
void templfun()() { }
}

View file

@ -0,0 +1,10 @@
struct Struct {
SumType!() v1;
}
void foo()() { SumType!() v2; }
struct SumType() {
~this() { }
invariant { alias a = {}; match!a(); }
}
void match(alias handler)() { }

View file

@ -0,0 +1,5 @@
import lib21723a;
void trigger(Struct val) { val.templfun; }
void main() { alias lambda = a => a; }

View file

@ -0,0 +1,6 @@
import lib23148;
alias l = _ => 0;
void main() {
foo!()();
}

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() int main()
{ {
test1(); test1();
@ -269,5 +300,6 @@ int main()
testThrowExpression(); testThrowExpression();
testThrowSideEffect(); testThrowSideEffect();
testThrowDtor(); testThrowDtor();
test23120();
return 0; return 0;
} }

View file

@ -16,6 +16,7 @@ extern(C) int main() nothrow @nogc @safe
{ {
takeScopeSlice([ S(1), S(2) ]); // @nogc => no GC allocation takeScopeSlice([ S(1), S(2) ]); // @nogc => no GC allocation
(() @trusted { assert(numDtor == 2); })(); // stack-allocated array literal properly destructed (() @trusted { assert(numDtor == 2); })(); // stack-allocated array literal properly destructed
assert23100([]);
return 0; return 0;
} }
@ -26,3 +27,9 @@ void test23098() @safe
{ {
f23098([10, 20]); 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,6 @@
#!/usr/bin/env bash
$DMD -m${MODEL} -I${EXTRA_FILES} -of${OUTPUT_BASE}${LIBEXT} -lib ${EXTRA_FILES}/lib21723a.d ${EXTRA_FILES}/lib21723b.d
$DMD -m${MODEL} -I${EXTRA_FILES} -of${OUTPUT_BASE}${EXE} -inline ${EXTRA_FILES}/test21723.d ${OUTPUT_BASE}${LIBEXT}
rm_retry ${OUTPUT_BASE}{${LIBEXT},${EXE}}

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
$DMD -m${MODEL} -I${EXTRA_FILES} -of${OUTPUT_BASE}${LIBEXT} -lib ${EXTRA_FILES}/lib23148.d
$DMD -m${MODEL} -I${EXTRA_FILES} -of${OUTPUT_BASE}${EXE} ${EXTRA_FILES}/test23148.d ${OUTPUT_BASE}${LIBEXT}
rm_retry ${OUTPUT_BASE}{${LIBEXT},${EXE}}

27
test/runnable/test23181.d Normal file
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

@ -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 struct S9332