From 8141f66dcef8782909cb207c3fa73bfc9ee82e14 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Mon, 11 Dec 2023 00:28:53 -0800 Subject: [PATCH] fix Issue 24274 - [REG master] ImportC: unrecognized C initializer with array in struct --- compiler/src/dmd/dsymbolsem.d | 2 +- compiler/src/dmd/initsem.d | 72 ++++++++++++++++++++---------- compiler/test/runnable/test24042.c | 70 ++++++++++++++++++++++++++++- 3 files changed, 119 insertions(+), 25 deletions(-) diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index ca6a2edad8..784df94a06 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -572,7 +572,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null"); printf(" stc = x%llx\n", dsym.storage_class); printf(" storage_class = x%llx\n", dsym.storage_class); - printf("linkage = %d\n", dsym.linkage); + printf("linkage = %d\n", dsym._linkage); //if (strcmp(toChars(), "mul") == 0) assert(0); } //if (semanticRun > PASS.initial) diff --git a/compiler/src/dmd/initsem.d b/compiler/src/dmd/initsem.d index 0a91c393e9..1d7f56ed44 100644 --- a/compiler/src/dmd/initsem.d +++ b/compiler/src/dmd/initsem.d @@ -803,9 +803,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ Loop1: for (size_t index = 0; index < ci.initializerList.length; ) { - CInitializer cprev; - size_t indexprev; - L1: DesigInit di = ci.initializerList[index]; Designators* dlist = di.designatorList; if (dlist) @@ -833,15 +830,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ continue Loop1; } } - if (cprev) - { - /* The peeling didn't work, so unpeel it - */ - ci = cprev; - index = indexprev; - di = ci.initializerList[index]; - goto L2; - } error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars()); return err(); } @@ -849,18 +837,55 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { if (fieldi == nfields) break; - if (index + 1 == ci.initializerList.length && di.initializer.isCInitializer()) + + auto ix = di.initializer; + + /* If a C initializer is wrapped in a C initializer, with no designators, + * peel off the outer one + */ + if (ix.isCInitializer()) { - /* Try peeling off this set of { } and see if it works - */ - cprev = ci; - ci = di.initializer.isCInitializer(); - indexprev = index; - index = 0; - goto L1; + CInitializer cix = ix.isCInitializer(); + if (cix.initializerList.length == 1) + { + DesigInit dix = cix.initializerList[0]; + if (!dix.designatorList) + { + Initializer inix = dix.initializer; + if (inix.isCInitializer()) + ix = inix; + } + } + } + + if (auto cix = ix.isCInitializer()) + { + /* ImportC loses the structure from anonymous structs, but this is retained + * by the initializer syntax. if a CInitializer has a Designator, it is probably + * a nested anonymous struct + */ + if (cix.initializerList.length) + { + DesigInit dix = cix.initializerList[0]; + Designators* dlistx = dix.designatorList; + if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident) + { + auto id = (*dlistx)[0].ident; + foreach (k, f; sd.fields[]) // linear search for now + { + if (f.ident == id) + { + fieldi = k; + si.addInit(id, dix.initializer); + ++fieldi; + ++index; + continue Loop1; + } + } + } + } } - L2: VarDeclaration field; while (1) // skip field if it overlaps with previously seen fields { @@ -871,10 +896,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (fieldi == nfields) break; } + auto tn = field.type.toBasetype(); auto tnsa = tn.isTypeSArray(); auto tns = tn.isTypeStruct(); - auto ix = di.initializer; + if (tnsa && ix.isExpInitializer()) { ExpInitializer ei = ix.isExpInitializer(); @@ -1013,7 +1039,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { - error(ci.loc, "unrecognized C initializer `%s`", toChars(ci)); + error(ci.loc, "unrecognized C initializer `%s` for type `%s`", toChars(ci), t.toChars()); return err(); } } diff --git a/compiler/test/runnable/test24042.c b/compiler/test/runnable/test24042.c index c2db46b19d..c6cde72c53 100644 --- a/compiler/test/runnable/test24042.c +++ b/compiler/test/runnable/test24042.c @@ -55,10 +55,75 @@ struct S3 void test3() { - struct S3 tn = (struct S3) {{0}, 4}; + struct S3 tn = (struct S3) {{1}, 4}; + assert(tn.context[0] == 1); + assert(tn.context[1] == 0); + assert(tn.context[2] == 0); + assert(tn.context[3] == 0); assert(tn.id == 4); } +/**************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24274 + +struct S0 +{ + struct + { + char short_data[24]; + }; + int length; +}; + +void test4() +{ + struct S0 s0 = { {.short_data = {1}}, .length = 2}; + assert(s0.short_data[0] == 1); + assert(s0.length == 2); +} + +/**************************************/ + +struct S1 +{ + struct + { + int long_data; + char short_data[24]; + }; + int length; +}; + +void test5() +{ + struct S1 s1 = { {.short_data = {7}}, .length = 8}; + assert(s1.long_data == 0); + assert(s1.short_data[0] == 7); + assert(s1.length == 8); +} + +/**************************************/ + +struct S6 +{ + int abc[4]; +}; + +void test6() +{ + struct S6 s = {{4},5,6,7}; + assert(s.abc[0] == 4); + assert(s.abc[1] == 0); + assert(s.abc[2] == 0); + assert(s.abc[3] == 0); + + struct S6 t = {4,{5},6,7}; + assert(t.abc[0] == 4); + assert(t.abc[1] == 5); + assert(t.abc[2] == 6); + assert(t.abc[3] == 7); +} + /**************************************/ int main() @@ -66,5 +131,8 @@ int main() test1(); test2(); test3(); + test4(); + test5(); + test6(); return 0; }