c++: Fix ICE after ambiguous inline namespace reopen [PR94257]
authorNathan Sidwell <nathan@acm.org>
Fri, 27 Mar 2020 14:54:33 +0000 (07:54 -0700)
committerNathan Sidwell <nathan@acm.org>
Fri, 27 Mar 2020 14:54:33 +0000 (07:54 -0700)
Following DR2061, 'namespace F', looks for 'F's inside inline namespaces.
That can result in ambiguous lookups that we failed to diagnose early enough,
leading us to push a new namespace and ICE later.  Diagnose the ambiguity
earlier, and then pick one.

PR c++/94257
* name-lookup.c (push_namespace): Triage ambiguous lookups that
contain namespaces.

gcc/cp/ChangeLog
gcc/cp/name-lookup.c

index 5b8c5e3..7224ff1 100644 (file)
@@ -1,3 +1,9 @@
+2020-03-27  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/94257
+       * name-lookup.c (push_namespace): Triage ambiguous lookups that
+       contain namespaces.
+
 2020-03-27  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/94326
index d00bb5f..e6dfb9c 100644 (file)
@@ -7372,23 +7372,59 @@ push_namespace (tree name, bool make_inline)
     name_lookup lookup (name, 0);
     if (!lookup.search_qualified (current_namespace, /*usings=*/false))
       ;
-    else if (TREE_CODE (lookup.value) != NAMESPACE_DECL)
-      ;
-    else if (tree dna = DECL_NAMESPACE_ALIAS (lookup.value))
+    else if (TREE_CODE (lookup.value) == TREE_LIST)
       {
-       /* A namespace alias is not allowed here, but if the alias
-          is for a namespace also inside the current scope,
-          accept it with a diagnostic.  That's better than dying
-          horribly.  */
-       if (is_nested_namespace (current_namespace, CP_DECL_CONTEXT (dna)))
+       /* An ambiguous lookup.  If exactly one is a namespace, we
+          want that.  If more than one is a namespace, error, but
+          pick one of them.  */
+       /* DR2061 can cause us to find multiple namespaces of the same
+          name.  We must treat that carefully and avoid thinking we
+          need to push a new (possibly) duplicate namespace.  Hey,
+          if you want to use the same identifier within an inline
+          nest, knock yourself out.  */
+       for (tree *chain = &lookup.value, next; (next = *chain);)
+         {
+           tree decl = TREE_VALUE (next);
+           if (TREE_CODE (decl) == NAMESPACE_DECL)
+             {
+               if (!ns)
+                 ns = decl;
+               else if (SCOPE_DEPTH (ns) >= SCOPE_DEPTH (decl))
+                 ns = decl;
+
+               /* Advance.  */
+               chain = &TREE_CHAIN (next);
+             }
+           else
+             /* Stitch out.  */
+             *chain = TREE_CHAIN (next);
+         }
+
+       if (TREE_CHAIN (lookup.value))
          {
-           error ("namespace alias %qD not allowed here, "
-                  "assuming %qD", lookup.value, dna);
-           ns = dna;
+           error ("%<namespace %E%> is ambiguous", name);
+           print_candidates (lookup.value);
          }
       }
-    else
+    else if (TREE_CODE (lookup.value) == NAMESPACE_DECL)
       ns = lookup.value;
+
+    if (ns)
+      if (tree dna = DECL_NAMESPACE_ALIAS (ns))
+       {
+         /* A namespace alias is not allowed here, but if the alias
+            is for a namespace also inside the current scope,
+            accept it with a diagnostic.  That's better than dying
+            horribly.  */
+         if (is_nested_namespace (current_namespace, CP_DECL_CONTEXT (dna)))
+           {
+             error ("namespace alias %qD not allowed here, "
+                    "assuming %qD", ns, dna);
+             ns = dna;
+           }
+         else
+           ns = NULL_TREE;
+       }
   }
 
   bool new_ns = false;