c++: Fix ICE from op_unqualified_lookup [PR97582]

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.
This commit is contained in:
Patrick Palka 2021-02-11 10:59:54 -05:00
parent 38c5703449
commit cb168f779c
2 changed files with 23 additions and 3 deletions

View 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);
}
}

View File

@ -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" }