diff mbox series

[committed] d: Merge upstream dmd 0fcdaab32

Message ID 20201027105133.931480-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd 0fcdaab32 | expand

Commit Message

Iain Buclaw Oct. 27, 2020, 10:51 a.m. UTC
Hi,

This patch merges the D front-end implementation with upstream dmd
0fcdaab32, fixing a bug where there was undefined template references
when compiling upstream dmd mainline.

In `TemplateInstance::semantic`, there exists special handling of
matching template instances for the same template declaration to ensure
that only at most one instance gets codegen'd.

If the primary instance `inst` originated from a non-root module, the
`minst` field will be updated so it is now coming from a root module,
however all Dsymbol `inst->members` of the instance still have their
`_scope->minst` pointing at the original non-root module. We must now
propagate `minst` to all members so that forward referenced dependencies
that get instantiated will also be appended to the root module,
otherwise there will be undefined references at link-time.

This doesn't affect compilations where all modules are compiled
together, as every module is a root module in that situation.  What this
primarily affects are cases where there is a mix of root and non-root
modules, and a template was first instantiated in a non-root context,
then later instantiated again in a root context.

Regstrapped on x86_64-linux-gnu/-m32/-mx32, committed to mainline.

Regards
Iain

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 0fcdaab32
---
 gcc/d/dmd/MERGE                               |  2 +-
 gcc/d/dmd/dtemplate.c                         | 66 ++++++++++++-
 .../compilable/imports/test21299/func.d       |  8 ++
 .../compilable/imports/test21299/mtype.d      |  8 ++
 .../imports/test21299/rootstringtable.d       | 96 +++++++++++++++++++
 .../gdc.test/compilable/test21299a.d          |  4 +
 .../gdc.test/compilable/test21299b.d          |  4 +
 .../gdc.test/compilable/test21299c.d          |  5 +
 .../gdc.test/compilable/test21299d.d          | 27 ++++++
 9 files changed, 216 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test21299/func.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test21299/mtype.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/imports/test21299/rootstringtable.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test21299a.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test21299b.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test21299c.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test21299d.d
diff mbox series

Patch

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 5f6193f76b7..7b561e4044e 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-70aabfb511d55f2bfbdccbac7868519d9d4b63da
+0fcdaab32c7645820820f6e1474343ccfb7560e5
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c
index a86daeee633..caa8a5ba9f4 100644
--- a/gcc/d/dmd/dtemplate.c
+++ b/gcc/d/dmd/dtemplate.c
@@ -33,6 +33,7 @@ 
 #include "hdrgen.h"
 #include "id.h"
 #include "attrib.h"
+#include "cond.h"
 #include "tokens.h"
 
 #define IDX_NOTFOUND (0x12345678)               // index is not found
@@ -6088,17 +6089,18 @@  Lerror:
         if (minst && minst->isRoot() && !(inst->minst && inst->minst->isRoot()))
         {
             /* Swap the position of 'inst' and 'this' in the instantiation graph.
-             * Then, the primary instance `inst` will be changed to a root instance.
+             * Then, the primary instance `inst` will be changed to a root instance,
+             * along with all members of `inst` having their scopes updated.
              *
              * Before:
-             *  non-root -> A!() -> B!()[inst] -> C!()
+             *  non-root -> A!() -> B!()[inst] -> C!() { members[non-root] }
              *                      |
              *  root     -> D!() -> B!()[this]
              *
              * After:
              *  non-root -> A!() -> B!()[this]
              *                      |
-             *  root     -> D!() -> B!()[inst] -> C!()
+             *  root     -> D!() -> B!()[inst] -> C!() { members[root] }
              */
             Module *mi = minst;
             TemplateInstance *ti = tinst;
@@ -6107,6 +6109,64 @@  Lerror:
             inst->minst = mi;
             inst->tinst = ti;
 
+            /* https://issues.dlang.org/show_bug.cgi?id=21299
+               `minst` has been updated on the primary instance `inst` so it is
+               now coming from a root module, however all Dsymbol `inst.members`
+               of the instance still have their `_scope.minst` pointing at the
+               original non-root module. We must now propagate `minst` to all
+               members so that forward referenced dependencies that get
+               instantiated will also be appended to the root module, otherwise
+               there will be undefined references at link-time.  */
+            class InstMemberWalker : public Visitor
+            {
+            public:
+                TemplateInstance *inst;
+
+                InstMemberWalker(TemplateInstance *inst)
+                    : inst(inst) { }
+
+                void visit(Dsymbol *d)
+                {
+                    if (d->_scope)
+                        d->_scope->minst = inst->minst;
+                }
+
+                void visit(ScopeDsymbol *sds)
+                {
+                    if (!sds->members)
+                        return;
+                    for (size_t i = 0; i < sds->members->length; i++)
+                    {
+                        Dsymbol *s = (*sds->members)[i];
+                        s->accept(this);
+                    }
+                    visit((Dsymbol *)sds);
+                }
+
+                void visit(AttribDeclaration *ad)
+                {
+                    Dsymbols *d = ad->include(NULL);
+                    if (!d)
+                        return;
+                    for (size_t i = 0; i < d->length; i++)
+                    {
+                        Dsymbol *s = (*d)[i];
+                        s->accept(this);
+                    }
+                    visit((Dsymbol *)ad);
+                }
+
+                void visit(ConditionalDeclaration *cd)
+                {
+                    if (cd->condition->inc)
+                        visit((AttribDeclaration *)cd);
+                    else
+                        visit((Dsymbol *)cd);
+                }
+            };
+            InstMemberWalker v(inst);
+            inst->accept(&v);
+
             if (minst)  // if inst was not speculative
             {
                 /* Add 'inst' once again to the root module members[], then the
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test21299/func.d b/gcc/testsuite/gdc.test/compilable/imports/test21299/func.d
new file mode 100644
index 00000000000..fe3321faff7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test21299/func.d
@@ -0,0 +1,8 @@ 
+module imports.test21299.func;
+import imports.test21299.mtype;
+import imports.test21299.rootstringtable;
+class FuncDeclaration {
+    StringTable!Type stringtable;
+    StringTable2!Type stringtable2;
+    StringTable3!Type stringtable3;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test21299/mtype.d b/gcc/testsuite/gdc.test/compilable/imports/test21299/mtype.d
new file mode 100644
index 00000000000..01bac82c2e4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test21299/mtype.d
@@ -0,0 +1,8 @@ 
+module imports.test21299.mtype;
+import imports.test21299.func;
+import imports.test21299.rootstringtable;
+class Type {
+    StringTable!Type stringtable;
+    StringTable2!Type stringtable2;
+    StringTable3!Type stringtable3;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test21299/rootstringtable.d b/gcc/testsuite/gdc.test/compilable/imports/test21299/rootstringtable.d
new file mode 100644
index 00000000000..12a2d92899b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test21299/rootstringtable.d
@@ -0,0 +1,96 @@ 
+module imports.test21299.rootstringtable;
+struct StringValue(T)
+{
+    char* lstring()
+    {
+        return cast(char*)&this;
+    }
+}
+
+struct StringTable(T)
+{
+    StringValue!T* insert()
+    {
+        allocValue;
+        return getValue;
+    }
+
+    uint allocValue()
+    {
+        StringValue!(T) sv;
+        sv.lstring[0] = 0;
+        return 0;
+    }
+
+    StringValue!T* getValue()
+    {
+        return cast(StringValue!T*)&this;
+    }
+}
+
+// Other tests are the same as the original issue, but use other kinds of
+// nesting Dsymbols that need to be handled by templateInstanceSemantic().
+struct StringValue2(T)
+{
+    char* lstring()
+    {
+        return cast(char*)&this;
+    }
+}
+
+struct StringTable2(T)
+{
+  @nogc // AttribDeclaration (also covers pragma, extern(), static foreach, ...)
+  {
+    StringValue2!T* insert()
+    {
+        allocValue;
+        return getValue;
+    }
+
+    uint allocValue()
+    {
+        StringValue2!(T) sv;
+        sv.lstring[0] = 0;
+        return 0;
+    }
+
+    StringValue2!T* getValue()
+    {
+        return cast(StringValue2!T*)&this;
+    }
+  }
+}
+
+//
+struct StringValue3(T)
+{
+    char* lstring()
+    {
+        return cast(char*)&this;
+    }
+}
+
+struct StringTable3(T)
+{
+  static if (true) // ConditionalDeclaration (static if)
+  {
+    StringValue3!T* insert()
+    {
+        allocValue;
+        return getValue;
+    }
+
+    uint allocValue()
+    {
+        StringValue3!(T) sv;
+        sv.lstring[0] = 0;
+        return 0;
+    }
+
+    StringValue3!T* getValue()
+    {
+        return cast(StringValue3!T*)&this;
+    }
+  }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21299a.d b/gcc/testsuite/gdc.test/compilable/test21299a.d
new file mode 100644
index 00000000000..049ee6ae35b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21299a.d
@@ -0,0 +1,4 @@ 
+// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/rootstringtable.d
+// REQUIRED_ARGS: -main
+// LINK
+module test21299a;
diff --git a/gcc/testsuite/gdc.test/compilable/test21299b.d b/gcc/testsuite/gdc.test/compilable/test21299b.d
new file mode 100644
index 00000000000..b9d992acfb9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21299b.d
@@ -0,0 +1,4 @@ 
+// EXTRA_SOURCES: imports/test21299/func.d imports/test21299/rootstringtable.d
+// REQUIRED_ARGS: -main
+// LINK:
+module test21299b;
diff --git a/gcc/testsuite/gdc.test/compilable/test21299c.d b/gcc/testsuite/gdc.test/compilable/test21299c.d
new file mode 100644
index 00000000000..88ed21f3ea6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21299c.d
@@ -0,0 +1,5 @@ 
+// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/func.d imports/test21299/rootstringtable.d
+// COMPILE_SEPARATELY:
+// LINK:
+module test21299c;
+void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/test21299d.d b/gcc/testsuite/gdc.test/compilable/test21299d.d
new file mode 100644
index 00000000000..67ec60a582b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21299d.d
@@ -0,0 +1,27 @@ 
+// REQUIRED_ARGS: -main
+// LINK:
+module test21299d;
+
+struct DefaultPredicates
+{
+    struct IsEqual(T)
+    {
+        static opCall(in T, in T)
+        {
+            return 0;
+        }
+    }
+}
+
+void moveToEnd(T, Pred = DefaultPredicates.IsEqual!T)(T[] array, T element, Pred pred = Pred.init)
+{
+    pred(array[0], element);
+}
+
+class Task
+{
+    void removeTerminationHook(void delegate() hook)
+    {
+        moveToEnd([], hook);
+    }
+}