c++: Fix comparison of fn() and ns::fn() [PR90711]
The resolution of CWG issue 1321 clarified that when deciding whether two expressions involving template parameters are equivalent, two dependent function calls where the function is named with an unqualified-id are considered to be equivalent if the name is the same, even if unqualified lookup finds different sets of functions. We were wrongly treating qualified-ids the same way, so that EXISTS and test::EXISTS were considered to be equivalent even though they are looking up the name in different scopes. This also causes a mangling bug, but I don't think it's safe to fix that for GCC 10; this patch just fixes the comparison. gcc/cp/ChangeLog 2020-03-30 Jason Merrill <jason@redhat.com> PR c++/90711 * tree.c (cp_tree_equal) [CALL_EXPR]: Compare KOENIG_LOOKUP_P. (called_fns_equal): Check DECL_CONTEXT.
This commit is contained in:
parent
1cb1986cb5
commit
5830f75355
@ -1,3 +1,9 @@
|
||||
2020-03-30 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/90711
|
||||
* tree.c (cp_tree_equal) [CALL_EXPR]: Compare KOENIG_LOOKUP_P.
|
||||
(called_fns_equal): Check DECL_CONTEXT.
|
||||
|
||||
2020-03-30 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/94385
|
||||
|
@ -2464,6 +2464,8 @@ is_overloaded_fn (tree x)
|
||||
tree
|
||||
dependent_name (tree x)
|
||||
{
|
||||
/* FIXME a dependent name must be unqualified, but this function doesn't
|
||||
distinguish between qualified and unqualified identifiers. */
|
||||
if (identifier_p (x))
|
||||
return x;
|
||||
if (TREE_CODE (x) == TEMPLATE_ID_EXPR)
|
||||
@ -3581,6 +3583,15 @@ called_fns_equal (tree t1, tree t2)
|
||||
if (name1 != name2)
|
||||
return false;
|
||||
|
||||
/* FIXME dependent_name currently returns an unqualified name regardless
|
||||
of whether the function was named with a qualified- or unqualified-id.
|
||||
Until that's fixed, check that we aren't looking at overload sets from
|
||||
different scopes. */
|
||||
if (is_overloaded_fn (t1) && is_overloaded_fn (t2)
|
||||
&& (DECL_CONTEXT (get_first_fn (t1))
|
||||
!= DECL_CONTEXT (get_first_fn (t2))))
|
||||
return false;
|
||||
|
||||
if (TREE_CODE (t1) == TEMPLATE_ID_EXPR)
|
||||
targs1 = TREE_OPERAND (t1, 1);
|
||||
if (TREE_CODE (t2) == TEMPLATE_ID_EXPR)
|
||||
@ -3677,7 +3688,8 @@ cp_tree_equal (tree t1, tree t2)
|
||||
{
|
||||
tree arg1, arg2;
|
||||
call_expr_arg_iterator iter1, iter2;
|
||||
if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
|
||||
if (KOENIG_LOOKUP_P (t1) != KOENIG_LOOKUP_P (t2)
|
||||
|| !called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
|
||||
return false;
|
||||
for (arg1 = first_call_expr_arg (t1, &iter1),
|
||||
arg2 = first_call_expr_arg (t2, &iter2);
|
||||
|
38
gcc/testsuite/g++.dg/template/dependent-name14.C
Normal file
38
gcc/testsuite/g++.dg/template/dependent-name14.C
Normal file
@ -0,0 +1,38 @@
|
||||
// PR c++/90711
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
namespace test {
|
||||
void EXISTS(int);
|
||||
}
|
||||
|
||||
template<typename... ARGS>
|
||||
struct stub_void {
|
||||
typedef void type;
|
||||
};
|
||||
template<typename... ARGS>
|
||||
using stub_void_t = typename stub_void<ARGS...>::type;
|
||||
|
||||
#if !defined(SUPPRESS)
|
||||
template<typename O, typename = void>
|
||||
struct has_to_string {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<typename O>
|
||||
struct has_to_string<O, stub_void_t<decltype(EXISTS(O{}))>> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename O, typename = void>
|
||||
struct has_std_to_string {
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<typename O>
|
||||
struct has_std_to_string<O, stub_void_t<decltype(test::EXISTS(O{}))>> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
static_assert (has_std_to_string<int>::value, "");
|
||||
|
Loading…
Reference in New Issue
Block a user