Merge branch 'stable' into merge-stable

This commit is contained in:
Dennis Korpel 2024-04-23 14:44:01 +02:00
commit 33c32407c0
14 changed files with 295 additions and 34 deletions

View file

@ -32,11 +32,12 @@ jobs:
os: ubuntu-22.04
model: 32
host_dmd: dmd
- job_name: Ubuntu 22.04 x86, DMD (coverage)
os: ubuntu-22.04
model: 32
host_dmd: dmd
coverage: true
# Disabled because of failure https://issues.dlang.org/show_bug.cgi?id=24518
# - job_name: Ubuntu 22.04 x86, DMD (coverage)
# os: ubuntu-22.04
# model: 32
# host_dmd: dmd
# coverage: true
- job_name: Ubuntu 22.04 x86, DMD (bootstrap)
os: ubuntu-22.04
model: 32
@ -52,10 +53,11 @@ jobs:
- job_name: macOS 13 x64, DMD (latest)
os: macos-13
host_dmd: dmd
- job_name: macOS 13 x64, DMD (coverage)
os: macos-13
host_dmd: dmd
coverage: true
# Disabled because of failure https://issues.dlang.org/show_bug.cgi?id=24518
# - job_name: macOS 13 x64, DMD (coverage)
# os: macos-13
# host_dmd: dmd
# coverage: true
- job_name: macOS 12 x64, DMD (bootstrap)
os: macos-12
# de-facto bootstrap version on OSX

View file

@ -1919,6 +1919,14 @@ final class CParser(AST) : Parser!AST
auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
typedefTab.setDim(typedefTabLengthSave);
symbols = symbolsSave;
if (specifier.mod & MOD.x__stdcall)
{
// If this function is __stdcall, wrap it in a LinkDeclaration so that
// it's extern(Windows) when imported in D.
auto decls = new AST.Dsymbols(1);
(*decls)[0] = s;
s = new AST.LinkDeclaration(s.loc, LINK.windows, decls);
}
symbols.push(s);
return;
}
@ -2071,13 +2079,14 @@ final class CParser(AST) : Parser!AST
}
}
s = applySpecifier(s, specifier);
if (level == LVL.local)
if (level == LVL.local || (specifier.mod & MOD.x__stdcall))
{
// Wrap the declaration in `extern (C) { declaration }`
// Wrap the declaration in `extern (C/Windows) { declaration }`
// Necessary for function pointers, but harmless to apply to all.
auto decls = new AST.Dsymbols(1);
(*decls)[0] = s;
s = new AST.LinkDeclaration(s.loc, linkage, decls);
const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
s = new AST.LinkDeclaration(s.loc, lkg, decls);
}
symbols.push(s);
}
@ -5860,13 +5869,15 @@ final class CParser(AST) : Parser!AST
const(char)* endp = &slice[length - 7];
AST.Dsymbols newSymbols;
size_t[void*] defineTab; // hash table of #define's turned into Symbol's
// indexed by Identifier, returns index into symbols[]
// indexed by Identifier, returns index into newSymbols[]
// The memory for this is leaked
void addVar(AST.Dsymbol s)
void addSym(AST.Dsymbol s)
{
//printf("addVar() %s\n", s.toChars());
//printf("addSym() %s\n", s.toChars());
if (auto v = s.isVarDeclaration())
v.isCmacro(true); // mark it as coming from a C #define
/* If it's already defined, replace the earlier
@ -5874,13 +5885,22 @@ final class CParser(AST) : Parser!AST
*/
if (size_t* pd = cast(void*)s.ident in defineTab)
{
//printf("replacing %s\n", v.toChars());
(*symbols)[*pd] = s;
//printf("replacing %s\n", s.toChars());
newSymbols[*pd] = s;
return;
}
assert(symbols, "symbols is null");
defineTab[cast(void*)s.ident] = symbols.length;
symbols.push(s);
defineTab[cast(void*)s.ident] = newSymbols.length;
newSymbols.push(s);
}
void removeSym(Identifier ident)
{
//printf("removeSym() %s\n", ident.toChars());
if (size_t* pd = cast(void*)ident in defineTab)
{
//printf("removing %s\n", ident.toChars());
newSymbols[*pd] = null;
}
}
while (p < endp)
@ -5924,7 +5944,7 @@ final class CParser(AST) : Parser!AST
*/
AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
addSym(v);
++p;
continue;
}
@ -5947,7 +5967,7 @@ final class CParser(AST) : Parser!AST
*/
AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
addSym(v);
++p;
continue;
}
@ -5965,7 +5985,7 @@ final class CParser(AST) : Parser!AST
*/
AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
addSym(v);
++p;
continue;
}
@ -6001,7 +6021,7 @@ final class CParser(AST) : Parser!AST
AST.TemplateParameters* tpl = new AST.TemplateParameters();
AST.Expression constraint = null;
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
addVar(tempdecl);
addSym(tempdecl);
++p;
continue;
}
@ -6092,7 +6112,7 @@ final class CParser(AST) : Parser!AST
AST.Dsymbols* decldefs = new AST.Dsymbols();
decldefs.push(fd);
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
addVar(tempdecl);
addSym(tempdecl);
++p;
continue;
@ -6103,6 +6123,14 @@ final class CParser(AST) : Parser!AST
}
}
}
else if (p[0 .. 6] == "#undef")
{
p += 6;
nextToken();
//printf("undef %s\n", token.toChars());
if (token.value == TOK.identifier)
removeSym(token.ident);
}
// scan to end of line
while (*p)
++p;
@ -6110,6 +6138,16 @@ final class CParser(AST) : Parser!AST
scanloc.linnum = scanloc.linnum + 1;
}
if (newSymbols.length)
{
assert(symbols, "symbols is null");
symbols.reserve(newSymbols.length);
foreach (sym; newSymbols)
if (sym) // undefined entries are null
symbols.push(sym);
}
scanloc = scanlocSave;
eSink = save;
defines = buf;

View file

@ -5335,7 +5335,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
lowering = new DotIdExp(exp.loc, lowering, Id.object);
auto tbn = exp.type.nextOf();
while (tbn.ty == Tarray)
size_t i = nargs;
while (tbn.ty == Tarray && --i)
tbn = tbn.nextOf();
auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
MODFlags.immutable_ | MODFlags.shared_);

View file

@ -868,11 +868,13 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
* by the initializer syntax. if a CInitializer has a Designator, it is probably
* a nested anonymous struct
*/
if (cix.initializerList.length)
int found;
foreach (dix; cix.initializerList)
{
DesigInit dix = cix.initializerList[0];
Designators* dlistx = dix.designatorList;
if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident)
if (!dlistx)
continue;
if ((*dlistx).length == 1 && (*dlistx)[0].ident)
{
auto id = (*dlistx)[0].ident;
foreach (k, f; sd.fields[]) // linear search for now
@ -883,11 +885,18 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
si.addInit(id, dix.initializer);
++fieldi;
++index;
continue Loop1;
++found;
break;
}
}
}
else {
error(ci.loc, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci));
}
}
if (found == cix.initializerList.length)
continue Loop1;
}
VarDeclaration field;

View file

@ -1246,7 +1246,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
// @@@DEPRECATION 2.100.2
if (auto td = s.isTemplateDeclaration())
{
if (td.overnext || td.overroot)
if (td.overnext)
{
deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", td.ident.toChars());
deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from");

View file

@ -0,0 +1,17 @@
typedef void (*CFunctionPointer)();
typedef void (__stdcall *StdCallFunctionPointer)();
void cFunction()
{}
void __stdcall stdcallFunction()
{}
void __stdcall takesCFunctionPointer(CFunctionPointer f)
{}
void takesStdCallFunctionPointer(StdCallFunctionPointer f)
{}
typedef void (__stdcall *StdCallFunctionPointerTakingCFunctionPointer)(CFunctionPointer f);
typedef void (*CFunctionPointerTakingStdCallFunctionPointer)(StdCallFunctionPointer f);

View file

@ -6,6 +6,10 @@ __stdcall int foostdcall(int a) { return a; }
int __stdcall foostdcall2(int a) { return a; }
#if _MSC_VER
int _stdcall foostdcall3(int a) { return a; } // test issue 24509
#endif
int __stdcall (*fp1)(int a) = &foostdcall;
int (__stdcall *fp2)(int a) = &foostdcall2;

View file

@ -0,0 +1,35 @@
// https://issues.dlang.org/show_bug.cgi?id=24479
/*
TEST_OUTPUT:
---
1
2
---
*/
struct S
{
@1
S opBinary(string op: "-")(S rhs) const pure nothrow @nogc
{
return rhs;
}
@2
S opBinary(string op: "*")(S dur) const pure nothrow @nogc
{
return dur;
}
}
private enum hasExternalUDA(alias A) = is(A == External) || is(typeof(A) == External);
void foo()
{
static foreach (t; __traits(getOverloads, S, "opBinary", true))
static foreach(attr; __traits(getAttributes, t))
pragma(msg, attr);
static assert(__traits(getOverloads, S, "opBinary", true).length == 2);
alias A = __traits(getAttributes, __traits(getOverloads, S, "opBinary", true)[1]);
}

View file

@ -0,0 +1,15 @@
// https://issues.dlang.org/show_bug.cgi?id=24505
// PERMUTE_ARGS:
struct stat { int x; };
void __stat(int x, int y);
#define stat(x, y) __stat(x, y)
// reversed order:
#define stat2(x, y) __stat(x, y)
struct stat2 { int x; };
#undef stat
#undef stat2

View file

@ -0,0 +1,28 @@
// REQUIRED_ARGS: -os=windows
// EXTRA_SOURCES: imports/test24511_c.c
// DISABLED: osx
// This is disabled on macOS because ld complains about _main being undefined
// when clang attempts to preprocess the C file.
import test24511_c;
static assert(__traits(getLinkage, CFunctionPointer) == "C");
static assert(__traits(getLinkage, StdCallFunctionPointer) == "Windows");
static assert(__traits(getLinkage, cFunction) == "C");
static assert(__traits(getLinkage, stdcallFunction) == "Windows");
static assert(__traits(getLinkage, takesCFunctionPointer) == "Windows");
static if (is(typeof(&takesCFunctionPointer) ParamsA == __parameters))
static assert(__traits(getLinkage, ParamsA[0]) == "C");
static assert(__traits(getLinkage, takesStdCallFunctionPointer) == "C");
static if (is(typeof(&takesStdCallFunctionPointer) ParamsB == __parameters))
static assert(__traits(getLinkage, ParamsB[0]) == "Windows");
static assert(__traits(getLinkage, StdCallFunctionPointerTakingCFunctionPointer) == "Windows");
static if (is(typeof(&StdCallFunctionPointerTakingCFunctionPointer) ParamsC == __parameters))
static assert(__traits(getLinkage, ParamsC[0]) == "C");
static assert(__traits(getLinkage, CFunctionPointerTakingStdCallFunctionPointer) == "C");
static if (is(typeof(&CFunctionPointerTakingStdCallFunctionPointer) ParamsD == __parameters))
static assert(__traits(getLinkage, ParamsD[0]) == "Windows");

View file

@ -124,6 +124,83 @@ void test6()
assert(t.abc[3] == 7);
}
/**************************************/
// https://issues.dlang.org/show_bug.cgi?id=24495
struct Subitem {
int x;
int y;
};
struct Item {
int a;
struct {
int b1;
struct Subitem b2;
int b3;
};
};
void test7() {
struct Item first = {
.a = 1,
.b1 = 2,
.b3 = 3,
};
struct Item second = {
.a = 1,
{
.b1 = 2,
.b2 = { 1, 2 },
.b3 = 3
}
};
assert(second.a == 1);
assert(second.b1 == 2);
assert(second.b2.x == 1);
assert(second.b2.y == 2);
assert(second.b3 == 3);
}
/**************************************/
// https://issues.dlang.org/show_bug.cgi?id=24277
struct S8
{
int s;
struct
{
int vis;
int count;
int id;
struct
{
int symbol;
int state;
} leaf;
};
};
struct S8 s8 = (struct S8) {
.s = 10,
{
.count = 20,
.id = 30,
.leaf = {.symbol = 40, .state = 50},
}
};
void test8()
{
assert(s8.id == 30);
assert(s8.leaf.symbol == 40);
assert(s8.leaf.state == 50);
}
/**************************************/
int main()
@ -134,5 +211,7 @@ int main()
test4();
test5();
test6();
test7();
test8();
return 0;
}

View file

@ -0,0 +1,21 @@
import core.memory;
void main()
{
{
int[][] a = new int[][](2, 2);
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
assert(GC.getAttr(a[0].ptr) & GC.BlkAttr.NO_SCAN);
}
{
void*[][] a = new void*[][](2, 2);
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
assert(!(GC.getAttr(a[0].ptr) & GC.BlkAttr.NO_SCAN));
}
{
int[][][] a = new int[][][](2, 2);
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
assert(!(GC.getAttr(a[0].ptr) & GC.BlkAttr.NO_SCAN));
assert(a[0][0].ptr is null);
}
}

View file

@ -526,7 +526,7 @@ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust
auto dim = dims[0];
debug(PRINTF) printf("__allocateInnerArray(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length);
debug(PRINTF) printf("__allocateInnerArray(UnqT = %s, dim = %lu, ndims = %lu\n", UnqT.stringof.ptr, dim, dims.length);
if (dims.length == 1)
{
auto r = _d_newarrayT!UnqT(dim, isShared);
@ -534,8 +534,9 @@ Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust
}
auto allocSize = (void[]).sizeof * dim;
auto info = __arrayAlloc!UnqT(allocSize);
__setArrayAllocLength!UnqT(info, allocSize, isShared);
// the array-of-arrays holds pointers! Don't use UnqT here!
auto info = __arrayAlloc!(void[])(allocSize);
__setArrayAllocLength!(void[])(info, allocSize, isShared);
auto p = __arrayStart(info)[0 .. dim];
foreach (i; 0..dim)
@ -579,6 +580,16 @@ unittest
}
}
// https://issues.dlang.org/show_bug.cgi?id=24436
@system unittest
{
import core.memory : GC;
int[][] a = _d_newarraymTX!(int[][], int)([2, 2]);
assert(!(GC.getAttr(a.ptr) & GC.BlkAttr.NO_SCAN));
}
version (D_ProfileGC)
{
/**

View file

@ -134,6 +134,7 @@ typedef unsigned long long __uint64_t;
#define __ptr64
#define __unaligned
#define _NO_CRT_STDIO_INLINE 1
#define _stdcall __stdcall
// This header disables the Windows API Annotations macros
// Need to include sal.h to get the pragma once to prevent macro redefinition.