Merge remote-tracking branch 'upstream/stable' into merge_stable

This commit is contained in:
MoonlightSentinel 2022-03-27 03:52:44 +02:00
commit 48db76398c
No known key found for this signature in database
GPG key ID: C66F4751A7498694
26 changed files with 471 additions and 32 deletions

View file

@ -93,6 +93,8 @@ macos12_task:
OS: osx
# 12 CPU cores and 24 GB of memory are available
N: 12
# FIXME: Temporarily use LDC until a release with a fix for issue 22942 is available (probably 2.101)
HOST_DMD: ldc
matrix:
- TASK_NAME_SUFFIX: DMD (latest)
- TASK_NAME_SUFFIX: DMD (coverage)

View file

@ -0,0 +1,33 @@
Special case for `__traits(parameters)` in foreach loops was removed
Previously, when used inside a `foreach` using an overloaded `opApply`, the trait
would yield the parameters to the delegate and not the function the foreach appears within.
This behaviour is unintuitive, especially when the type of the `foreach` aggregate
depends on a template parameter. Hence `__traits(parameters)` was changed to consistently
return the parameters of the lexically enclosing function.
---
class Tree {
int opApply(int delegate(size_t, Tree) dg) {
if (dg(0, this)) return 1;
return 0;
}
}
void useOpApply(Tree top, int x)
{
foreach(idx; 0..5)
{
static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
}
foreach(idx, elem; top)
{
// Previously:
// static assert(is(typeof(__traits(parameters)) == AliasSeq!(size_t, Tree)));
// Now:
static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
}
}
---

View file

@ -547,7 +547,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
if (overflow) assert(0);
// Skip no-op for noreturn without custom aligment
if (memsize != 0 || !alignment.isDefault())
if (memalignsize != 0 || !alignment.isDefault())
alignmember(alignment, memalignsize, &ofs);
uint memoffset = ofs;

View file

@ -4553,6 +4553,38 @@ else
{ // ES:DI points past what we want
cdb.genc2(0x81,(rex << 16) | modregrm(3,5,DI), type_size(e.ET)); // SUB DI,numbytes
const tym = tybasic(e.Ety);
if (tym == TYucent && I64)
{
/* https://issues.dlang.org/show_bug.cgi?id=22175
* The trouble happens when the struct size does not fit exactly into
* 2 registers. Then the type of e becomes a TYucent, not a TYstruct,
* and we need to dereference DI to get the ucent
*/
// dereference DI
code cs;
cs.Iop = 0x8B;
regm_t retregs = *pretregs;
reg_t reg;
allocreg(cdb,&retregs,&reg,tym);
reg_t msreg = findregmsw(retregs);
buildEA(&cs,DI,-1,1,REGSIZE);
code_newreg(&cs,msreg);
cs.Irex |= REX_W;
cdb.gen(&cs); // MOV msreg,REGSIZE[DI] // msreg is never DI
reg_t lsreg = findreglsw(retregs);
buildEA(&cs,DI,-1,1,0);
code_newreg(&cs,lsreg);
cs.Irex |= REX_W;
cdb.gen(&cs); // MOV lsreg,[DI];
fixresult(cdb,e,retregs,pretregs);
return;
}
regm_t retregs = mDI;
if (*pretregs & mMSW && !(config.exe & EX_flat))
retregs |= mES;

View file

@ -871,7 +871,7 @@ version (SCPP)
section_64 *psechdr = &SecHdrTab64[pseg.SDshtidx]; // corresponding section
// Do zero-fill the second time through this loop
if (i ^ (psechdr.flags == S_ZEROFILL))
if (i ^ (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL))
continue;
int align_ = 1 << psechdr._align;
@ -882,7 +882,7 @@ version (SCPP)
}
foffset = elf_align(align_, foffset);
vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
if (psechdr.flags == S_ZEROFILL)
if (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL)
{
psechdr.offset = 0;
psechdr.size = pseg.SDoffset; // accumulated size
@ -909,7 +909,7 @@ version (SCPP)
section *psechdr = &SecHdrTab[pseg.SDshtidx]; // corresponding section
// Do zero-fill the second time through this loop
if (i ^ (psechdr.flags == S_ZEROFILL))
if (i ^ (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL))
continue;
int align_ = 1 << psechdr._align;
@ -920,7 +920,7 @@ version (SCPP)
}
foffset = elf_align(align_, foffset);
vmaddr = (vmaddr + align_ - 1) & ~(align_ - 1);
if (psechdr.flags == S_ZEROFILL)
if (psechdr.flags == S_ZEROFILL || psechdr.flags == S_THREAD_LOCAL_ZEROFILL)
{
psechdr.offset = 0;
psechdr.size = cast(uint)pseg.SDoffset; // accumulated size
@ -1896,7 +1896,7 @@ int MachObj_getsegment(const(char)* sectname, const(char)* segname,
if (!pseg.SDbuf)
{
if (flags != S_ZEROFILL)
if (flags != S_ZEROFILL && flags != S_THREAD_LOCAL_ZEROFILL)
{
pseg.SDbuf = cast(OutBuffer*) calloc(1, OutBuffer.sizeof);
assert(pseg.SDbuf);
@ -2421,7 +2421,9 @@ void MachObj_lidata(int seg,targ_size_t offset,targ_size_t count)
{
//printf("MachObj_lidata(%d,%x,%d)\n",seg,offset,count);
size_t idx = SegData[seg].SDshtidx;
if ((I64 ? SecHdrTab64[idx].flags : SecHdrTab[idx].flags) == S_ZEROFILL)
const flags = (I64 ? SecHdrTab64[idx].flags : SecHdrTab[idx].flags);
if (flags == S_ZEROFILL || flags == S_THREAD_LOCAL_ZEROFILL)
{ // Use SDoffset to record size of bss section
SegData[seg].SDoffset += count;
}

View file

@ -816,7 +816,7 @@ dmd -cov -unittest myprog.d
Feature("field", "vfield",
"list all non-mutable fields which occupy an object instance"),
Feature("complex", "vcomplex",
"give deprecation messages about all usages of complex or imaginary types", false, true),
"give deprecation messages about all usages of complex or imaginary types", true, true),
Feature("tls", "vtls",
"list all variables going into thread local storage"),
Feature("vmarkdown", "vmarkdown",
@ -927,8 +927,6 @@ struct CLIUsage
"Enables all available " ~ description)] ~ features;
foreach (t; allTransitions)
{
if (t.deprecated_)
continue;
if (!t.documented)
continue;
buf ~= " =";
@ -938,6 +936,8 @@ struct CLIUsage
foreach (i; lineLength .. maxFlagLength)
buf ~= " ";
buf ~= t.helpText;
if (t.deprecated_)
buf ~= " [DEPRECATED]";
buf ~= "\n";
}
return buf;

View file

@ -708,6 +708,31 @@ struct Scope
return null;
}
/********************************************
* Find the lexically enclosing function (if any).
*
* This function skips through generated FuncDeclarations,
* e.g. rewritten foreach bodies.
*
* Returns: the function or null
*/
inout(FuncDeclaration) getEnclosingFunction() inout
{
if (!this.func)
return null;
auto fd = cast(FuncDeclaration) this.func;
// Look through foreach bodies rewritten as delegates
while (fd.fes)
{
assert(fd.fes.func);
fd = fd.fes.func;
}
return cast(inout(FuncDeclaration)) fd;
}
/*******************************************
* For TemplateDeclarations, we need to remember the Scope
* where it was declared. So mark the Scope as not

View file

@ -1444,13 +1444,6 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
Expression ex = condexp.expressionSemantic(sc);
if (ex.op == EXP.error)
e = ex;
else if (e.op == EXP.function_ || e.op == EXP.delegate_)
{
// https://issues.dlang.org/show_bug.cgi?id=21285
// Functions and delegates don't convert correctly with castTo below
exps[i] = condexp.e1;
e = condexp.e2;
}
else
{
// Convert to common type
@ -3743,7 +3736,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
if (sd.hasRegularCtor() && nargs)
// https://issues.dlang.org/show_bug.cgi?id=22639
// If the new expression has arguments, we either should call a
// regular constructor of a copy constructor if the first argument
// is the same type as the struct
if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
{
FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
if (!f || f.errors)
@ -4504,7 +4501,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
If all constructors are copy constructors, then
try default construction.
*/
if (!sd.hasRegularCtor)
if (!sd.hasRegularCtor &&
// https://issues.dlang.org/show_bug.cgi?id=22639
// we might still have a copy constructor that could be called
(*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
goto Lx;
auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);

View file

@ -2761,9 +2761,15 @@ bool stcToBuffer(OutBuffer* buf, StorageClass stc)
bool result = false;
if (stc & STC.scopeinferred)
{
//buf.writestring("scope-inferred ");
stc &= ~(STC.scope_ | STC.scopeinferred);
}
if (stc & STC.returninferred)
{
//buf.writestring("return-inferred ");
stc &= ~(STC.return_ | STC.returninferred);
}
/* Put scope ref return into a standard order
*/

View file

@ -564,7 +564,12 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params)
}
if (params.addMain && !global.hasMainFunction)
modules.push(moduleWithEmptyMain());
{
auto mainModule = moduleWithEmptyMain();
modules.push(mainModule);
if (!params.oneobj || modules.length == 1)
params.objfiles.push(mainModule.objfile.toChars());
}
generateCodeAndWrite(modules[], libmodules[], params.libname, params.objdir,
params.lib, params.obj, params.oneobj, params.multiobj,

View file

@ -6272,9 +6272,6 @@ extern (C++) final class TypeClass : Type
override MOD deduceWild(Type t, bool isRef)
{
// If sym is forward referenced:
if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
sym.dsymbolSemantic(null);
ClassDeclaration cd = t.isClassHandle();
if (cd && (sym == cd || cd.isBaseOf(sym, null)))
return Type.deduceWild(t, isRef);
@ -7030,6 +7027,17 @@ extern (C++) final class Parameter : ASTNode
extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
{
// Workaround for failing covariance when finding a common type of delegates,
// some of which have parameters with inferred scope
// https://issues.dlang.org/show_bug.cgi?id=21285
// The root cause is that scopeinferred is not part of the mangle, and mangle
// is used for type equality checks
if (to & STC.returninferred)
to &= ~STC.return_;
// note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope
if (to & STC.scopeinferred && !(to & STC.return_))
to &= ~STC.scope_;
if (from == to)
return true;

View file

@ -3651,7 +3651,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.traits:
if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp())
if (te.ident && te.args)
if (te.ident)
{
t = new AST.TypeTraits(token.loc, te);
break;

View file

@ -2101,13 +2101,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
return ErrorExp.get();
}
if (sc.func is null)
auto fd = sc.getEnclosingFunction();
if (!fd)
{
e.error("`__traits(parameters)` may only be used inside a function");
return ErrorExp.get();
}
assert(sc.func && sc.parent.isFuncDeclaration());
auto tf = sc.parent.isFuncDeclaration.type.isTypeFunction();
auto tf = fd.type.isTypeFunction();
assert(tf);
auto exps = new Expressions(0);
int addParameterDG(size_t idx, Parameter x)

View file

@ -1793,6 +1793,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
mtype.exp.ident != Id.derivedMembers &&
mtype.exp.ident != Id.getMember &&
mtype.exp.ident != Id.parent &&
mtype.exp.ident != Id.parameters &&
mtype.exp.ident != Id.child &&
mtype.exp.ident != Id.toType &&
mtype.exp.ident != Id.getOverloads &&

View file

@ -1,4 +1,5 @@
// REQUIRED_ARGS: -unittest
// PERMUTE_ARGS: -preview=dip1000
// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
unittest
{
@ -25,3 +26,36 @@ unittest
static assert(is(typeof(a[0]) == dg));
static assert(is(typeof(ab[0]) == fn));
}
int f(string s) { throw new Exception(""); }
void main()
{
string path;
int bank, preset;
void delegate(string value)[string] aa = [
"path": (string arg) {
path = arg;
},
"bank": (string arg) {
bank = f(arg);
},
"preset": (string arg) {
preset = f(arg);
},
];
string delegate(string value)[string] aa2 = [
"path": (string arg) {
path = arg;
return arg;
},
"bank": (string arg) {
bank = f(arg);
return arg;
},
"preset": (string arg) {
preset = f(arg);
return arg;
},
];
}

View file

@ -20,6 +20,33 @@ int echoPlusOne(int x)
return x;
}
static assert(echoPlusOne(1) == 2);
void nesting(double d, int i)
{
alias EXP = AliasSeq!(d, i);
if (d)
{
static assert(__traits(isSame, __traits(parameters), EXP));
while (d)
{
static assert(__traits(isSame, __traits(parameters), EXP));
switch (i)
{
static assert(__traits(isSame, __traits(parameters), EXP));
case 1:
static assert(__traits(isSame, __traits(parameters), EXP));
break;
default:
static assert(__traits(isSame, __traits(parameters), EXP));
break;
}
}
}
}
class Tree {
int opApply(int delegate(size_t, Tree) dg) {
if (dg(0, this)) return 1;
@ -34,7 +61,22 @@ void useOpApply(Tree top, int x)
}
foreach(idx, elem; top)
{
static assert(is(typeof(__traits(parameters)) == AliasSeq!(size_t, Tree)));
static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
}
foreach(idx, elem; top)
{
foreach (idx2, elem2; elem)
static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
}
foreach(idx, elem; top)
{
static void foo(char[] text)
{
foreach (const char c; text)
static assert(is(typeof(__traits(parameters)) == AliasSeq!(char[])));
}
}
}
class Test
@ -131,3 +173,65 @@ T testTemplate(T)(scope T input)
}
static assert(testTemplate!long(420) == 0);
void qualifiers(immutable int a, const bool b)
{
static assert(is(typeof(__traits(parameters)) == AliasSeq!(immutable int, const bool)));
}
int makeAggregate(int a, bool b)
{
struct S
{
typeof(__traits(parameters)) members;
}
S s = S(__traits(parameters));
assert(s.members[0] == a);
assert(s.members[1] == b);
return 1;
}
static assert(makeAggregate(5, true));
int makeAlias(int a, bool b)
{
alias Params = __traits(parameters);
assert(Params[0] == 3);
assert(Params[1] == true);
return 1;
}
static assert(makeAlias(3, true));
mixin template nestedCheckParameters(int unique)
{
alias NestedNames = __traits(parameters);
version (Fixed)
alias Types = typeof(Names);
}
mixin template checkParameters(int unique)
{
mixin nestedCheckParameters!unique;
alias Names = __traits(parameters);
alias Types = typeof(Names);
}
int makeAggregateMixin(immutable int a, const bool b)
{
mixin checkParameters!0;
struct S
{
mixin checkParameters!1;
typeof(Names) members;
}
S s = S(Names);
assert(s.members[0] == a);
assert(s.members[1] == b);
return 1;
}

View file

@ -229,3 +229,19 @@ struct EmptyStruct2
static assert(EmptyStruct2.sizeof == 1);
static assert(EmptyStruct2.noRet.offsetof == 0);
// https://issues.dlang.org/show_bug.cgi?id=22858
// Shouldn't mess with the alignment of other zero-sized types.
struct S22858
{
int a;
void*[0] arr;
char c;
noreturn[0] arr2;
char c2;
}
static assert (S22858.arr.offsetof % size_t.sizeof == 0);
static assert (S22858.arr2.offsetof == S22858.c.offsetof + 1);
static assert (S22858.arr2.offsetof == S22858.c2.offsetof);

View file

@ -0,0 +1,26 @@
// https://issues.dlang.org/show_bug.cgi?id=22639
struct A
{
this(ref return scope A rhs) inout {}
this(ref return scope const A rhs, int b = 7) inout
{
if (b != 7) {
this.b = b;
}
}
this(this) @disable;
int a=4;
int b=3;
}
void main()
{
A a = A();
A c = A(a, 10);
A d = void;
d.__ctor(a, 200);
A* b = new A(a, 10);
}

View file

@ -1,2 +1,3 @@
// EXTRA_FILES: imports/test22714a.d imports/test22714b.d
// https://issues.dlang.org/show_bug.cgi?id=22714
import imports.test22714a;

View file

@ -0,0 +1,40 @@
// https://issues.dlang.org/show_bug.cgi?id=22859
private struct __InoutWorkaroundStruct {}
@property T rvalueOf(T)(T val) { return val; }
@property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
@property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
// taken from std.traits.isAssignable
template isAssignable(Lhs, Rhs = Lhs)
{
enum isAssignable = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs) && __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs);
}
// taken from std.meta.allSatisfy
template allSatisfy(alias F, T...)
{
static foreach (Ti; T)
{
static if (!is(typeof(allSatisfy) == bool) && // not yet defined
!F!(Ti))
{
enum allSatisfy = false;
}
}
static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
{
enum allSatisfy = true;
}
}
struct None{}
class C1
{
static if(allSatisfy!(isAssignable, None, C2)) {}
}
class C2
{
static if(allSatisfy!(isAssignable, None, C1, C2)) {}
}

View file

@ -0,0 +1,62 @@
// https://issues.dlang.org/show_bug.cgi?id=22860
class C1
{
SumType!(C1, C2) field;
}
class C2
{
SumType!(SumType!(C1, C2)) field;
}
alias AliasSeq(TList...) = TList;
template allSatisfy(alias F, T...)
{
static foreach (Ti; T)
{
static if (!F!Ti)
enum allSatisfy = false;
}
}
struct This {}
enum isAssignableTo(T) = isAssignable!T;
enum isHashable(T) = __traits(compiles, { T.init; });
struct SumType(Types...)
{
alias Types = AliasSeq!(ReplaceTypeUnless!(isSumTypeInstance, This, typeof(this), TemplateArgsOf!SumType));
static foreach (T; Types)
{
static if (isAssignableTo!T)
{
}
}
static if (allSatisfy!(isAssignableTo, Types))
{
}
static if (allSatisfy!(isHashable, Types))
size_t toHash;
}
bool isSumTypeInstance;
alias TemplateArgsOf(T : Base!Args, alias Base, Args...) = Args;
enum isAssignable(Lhs, Rhs = Lhs) = isRvalueAssignable!(Lhs, Rhs) ;
enum isRvalueAssignable(Lhs, Rhs ) = __traits(compiles, { lvalueOf!Lhs = Rhs; });
struct __InoutWorkaroundStruct{}
T lvalueOf(T)(__InoutWorkaroundStruct );
template ReplaceTypeUnless(alias pred, From, To, T...)
{
static if (T.length == 1)
alias ReplaceTypeUnless = T;
static if (T.length > 1)
alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[1 ]));
}

View file

@ -6,6 +6,7 @@ TEST_OUTPUT:
Language transitions listed by -transition=name:
=all Enables all available language transitions
=field list all non-mutable fields which occupy an object instance
=complex give deprecation messages about all usages of complex or imaginary types [DEPRECATED]
=tls list all variables going into thread local storage
=vmarkdown list instances of Markdown replacements in Ddoc
=in list all usages of 'in' on parameter

View file

@ -4,8 +4,6 @@
TEST_OUTPUT:
---
fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop`
fail_compilation/imports/foo10727a.d(26): Error: template instance `foo10727a.CirBuff!(Foo)` error instantiating
fail_compilation/imports/foo10727a.d(31): instantiated from here: `Bar!(Foo)`
---
*/

View file

@ -4,8 +4,6 @@
TEST_OUTPUT:
---
fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop`
fail_compilation/imports/foo10727b.d(17): Error: template instance `foo10727b.CirBuff!(Foo)` error instantiating
fail_compilation/imports/foo10727b.d(22): instantiated from here: `Bar!(Foo)`
---
*/

32
test/runnable/test22175.d Normal file
View file

@ -0,0 +1,32 @@
// https://issues.dlang.org/show_bug.cgi?id=22175
struct Struct
{
short a = 24, b = 25, c = 26, d = 27;
ubyte e = 28;
}
Struct foo() { Struct s; s.a = 60; s.b = 61; s.c = 62, s.d = 63; s.e = 64; return s; }
Struct test(int i) {
Struct var = i ? Struct() : foo();
Struct nest() { return var; }
return nest();
}
int main()
{
auto s = test(0);
assert(s.a == 60);
assert(s.b == 61);
assert(s.c == 62);
assert(s.d == 63);
assert(s.e == 64);
s = test(1);
assert(s.a == 24);
assert(s.b == 25);
assert(s.c == 26);
assert(s.d == 27);
assert(s.e == 28);
return 0;
}

View file

@ -0,0 +1,12 @@
#!/usr/bin/env bash
# -main doesn't work anymore when used for linking only (without source modules)
# https://issues.dlang.org/show_bug.cgi?id=22863
set -e
FOO=${OUTPUT_BASE}/foo${OBJ}
$DMD -m"${MODEL}" -c ${TEST_DIR}/testmain.d -of=$FOO
$DMD -m"${MODEL}" -main $FOO -of=${OUTPUT_BASE}/result
rm_retry -r ${OUTPUT_BASE}