c++: Fix ICE from op_unqualified_lookup [PR97582]
authorPatrick Palka <ppalka@redhat.com>
Thu, 11 Feb 2021 15:59:54 +0000 (10:59 -0500)
committerPatrick Palka <ppalka@redhat.com>
Thu, 11 Feb 2021 15:59:54 +0000 (10:59 -0500)
In this testcase, we're crashing because the lookup of operator+ from
within the generic lambda via lookup_name finds multiple bindings
(C1::operator+ and C2::operator+) and returns a TREE_LIST thereof,
something which op_unqualified_lookup (and push_operator_bindings) isn't
prepared to handle.

This patch extends op_unqualified_lookup and push_operator_bindings
to handle such an ambiguous lookup result in the natural way.

gcc/cp/ChangeLog:

PR c++/97582
* name-lookup.c (op_unqualified_lookup): Handle an ambiguous
lookup result by discarding it if the first element is a
class-scope declaration, otherwise return it.
(push_operator_bindings): Handle an ambiguous lookup result by
doing push_local_binding on each element in the list.

gcc/testsuite/ChangeLog:

PR c++/97582
* g++.dg/cpp0x/lambda/lambda-template17.C: New test.

gcc/cp/name-lookup.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template17.C [new file with mode: 0644]

index 1f4a7ac1d0cb559e9c649d6784ca4d2372e485fd..1cd4f67b8b217c688d31788377e4c02b4fe16eb1 100644 (file)
@@ -9219,11 +9219,15 @@ op_unqualified_lookup (tree fnname)
     /* Remember we found nothing!  */
     return error_mark_node;
 
-  tree d = is_overloaded_fn (fns) ? get_first_fn (fns) : fns;
+  tree d = fns;
+  if (TREE_CODE (d) == TREE_LIST)
+    d = TREE_VALUE (d);
+  if (is_overloaded_fn (d))
+    d = get_first_fn (d);
   if (DECL_CLASS_SCOPE_P (d))
     /* We don't need to remember class-scope functions or declarations,
        normal unqualified lookup will find them again.  */
-    fns = NULL_TREE;
+    return NULL_TREE;
 
   return fns;
 }
@@ -9302,7 +9306,11 @@ push_operator_bindings ()
       if (tree val = TREE_VALUE (binds))
        {
          tree name = TREE_PURPOSE (binds);
-         push_local_binding (name, val, /*using*/true);
+         if (TREE_CODE (val) == TREE_LIST)
+           for (tree v = val; v; v = TREE_CHAIN (v))
+             push_local_binding (name, TREE_VALUE (v), /*using*/true);
+         else
+           push_local_binding (name, val, /*using*/true);
        }
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template17.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template17.C
new file mode 100644 (file)
index 0000000..ac6c2e2
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/97582
+// { dg-do compile { target c++11 } }
+
+struct C1 { void operator+(); };
+struct C2 { void operator+(); };
+struct C3 : C1, C2 {
+  template <class T> void get() { [] (T x) { +x; }; } // { dg-error "ambiguous" }
+};
+
+template void C3::get<C1>(); // { dg-bogus "" }
+template void C3::get<C2>(); // { dg-bogus "" }
+template void C3::get<C3>(); // { dg-message "required from here" }