https://gcc.gnu.org/g:1f7a21c6e85d553e7b5114e5ca1395118478dddf

commit r15-2004-g1f7a21c6e85d553e7b5114e5ca1395118478dddf
Author: Nathaniel Shead <nathanielosh...@gmail.com>
Date:   Fri Jul 5 13:52:01 2024 +1000

    c++/modules: Handle redefinitions of using-decls
    
    This fixes an ICE exposed by supporting exported non-function
    using-decls.  Sometimes when preparing to define a class, xref_tag will
    find a using-decl belonging to a different namespace, which triggers the
    checking_assert in modules handling.
    
    Ideally I feel that 'lookup_and_check_tag' should be told whether we're
    about to define the type and handle erroring on redefinitions itself to
    avoid this issue (and provide better diagnostics by acknowledging the
    using-declaration), but this is complicated with the current
    fragmentation of definition checking.  So for this patch we just fixup
    the assertion and ensure that pushdecl properly errors on the
    conflicting declaration later.
    
    gcc/cp/ChangeLog:
    
            * decl.cc (xref_tag): Move assertion into condition.
            * name-lookup.cc (check_module_override): Check for conflicting
            types and using-decls.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/modules/using-19_a.C: New test.
            * g++.dg/modules/using-19_b.C: New test.
    
    Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>

Diff:
---
 gcc/cp/decl.cc                            |  6 ++++--
 gcc/cp/name-lookup.cc                     | 32 +++++++++++++++++++++----------
 gcc/testsuite/g++.dg/modules/using-19_a.C | 18 +++++++++++++++++
 gcc/testsuite/g++.dg/modules/using-19_b.C | 10 ++++++++++
 4 files changed, 54 insertions(+), 12 deletions(-)

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 4ffc9a6dad25..e7bb4fa30892 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -16737,12 +16737,14 @@ xref_tag (enum tag_types tag_code, tree name,
          if (CLASS_TYPE_P (t) && CLASSTYPE_IS_TEMPLATE (t))
            maybe_tmpl = CLASSTYPE_TI_TEMPLATE (t);
 
+         /* FIXME: we should do a more precise check for redefinitions
+            of a conflicting using-declaration here, as these diagnostics
+            are not ideal.  */
          if (DECL_LANG_SPECIFIC (decl)
              && DECL_MODULE_IMPORT_P (decl)
-             && TREE_CODE (CP_DECL_CONTEXT (decl)) == NAMESPACE_DECL)
+             && CP_DECL_CONTEXT (decl) == current_namespace)
            {
              /* Push it into this TU's symbol slot.  */
-             gcc_checking_assert (current_namespace == CP_DECL_CONTEXT (decl));
              if (maybe_tmpl != decl)
                /* We're in the template parm binding level.
                   Pushtag has logic to slide under that, but we're
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index e5f8562105e1..361dc3d953d1 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -3782,18 +3782,30 @@ check_module_override (tree decl, tree mvec, bool 
hiding,
          /* Errors could cause there to be nothing.  */
          continue;
 
+       tree type = NULL_TREE;
        if (STAT_HACK_P (bind))
-         /* We do not have to check STAT_TYPE here, the xref_tag
-            machinery deals with that problem. */
-         bind = STAT_VISIBLE (bind);
+         {
+           /* If there was a matching STAT_TYPE here then xref_tag
+              should have found it, but we need to check anyway because
+              a conflicting using-declaration may exist.  */
+           if (STAT_TYPE_VISIBLE_P (bind))
+             type = STAT_TYPE (bind);
+           bind = STAT_VISIBLE (bind);
+         }
 
-       for (ovl_iterator iter (bind); iter; ++iter)
-         if (!iter.using_p ())
-           {
-             match = duplicate_decls (decl, *iter, hiding);
-             if (match)
-               goto matched;
-           }
+       if (type)
+         {
+           match = duplicate_decls (decl, strip_using_decl (type), hiding);
+           if (match)
+             goto matched;
+         }
+
+       for (ovl_iterator iter (strip_using_decl (bind)); iter; ++iter)
+         {
+           match = duplicate_decls (decl, *iter, hiding);
+           if (match)
+             goto matched;
+         }
       }
 
   if (TREE_PUBLIC (scope) && TREE_PUBLIC (STRIP_TEMPLATE (decl))
diff --git a/gcc/testsuite/g++.dg/modules/using-19_a.C 
b/gcc/testsuite/g++.dg/modules/using-19_a.C
new file mode 100644
index 000000000000..693a70ce7d46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-19_a.C
@@ -0,0 +1,18 @@
+// { dg-additional-options "-fmodules-ts -Wno-global-module" }
+// { dg-module-cmi M }
+
+module;
+
+namespace hidden {
+  struct S {};
+  enum E { e };
+  void f();
+}
+
+export module M;
+export namespace exposed {
+  using hidden::S;
+  using hidden::E;
+  using hidden::e;
+  using hidden::f;
+}
diff --git a/gcc/testsuite/g++.dg/modules/using-19_b.C 
b/gcc/testsuite/g++.dg/modules/using-19_b.C
new file mode 100644
index 000000000000..dbe8d9f3c01e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/using-19_b.C
@@ -0,0 +1,10 @@
+// { dg-additional-options "-fmodules-ts" }
+
+import M;
+
+namespace exposed {
+  struct S {};  // { dg-error "redefinition" }
+  enum E { x };  // { dg-error "multiple definition" }
+  int e();  // { dg-error "redeclared" }
+  int f;  // { dg-error "redeclared" }
+}

Reply via email to