diff options
author | Jason Merrill <jason@redhat.com> | 2020-03-30 16:09:43 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2020-03-30 17:04:09 -0400 |
commit | 5830f753559f25a5dabcc3507bffa611c6b575a6 (patch) | |
tree | 5ca1ab73bcd732cdb0aea5bb7213c150f67f2ee7 /gcc | |
parent | 1cb1986cb596336e688c079b821205ec212a46a3 (diff) | |
download | gcc-5830f753559f25a5dabcc3507bffa611c6b575a6.zip gcc-5830f753559f25a5dabcc3507bffa611c6b575a6.tar.gz gcc-5830f753559f25a5dabcc3507bffa611c6b575a6.tar.bz2 |
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.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/tree.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/dependent-name14.C | 38 |
3 files changed, 57 insertions, 1 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index be22bc0..cc79ece 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index b85967e..a2172de 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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); diff --git a/gcc/testsuite/g++.dg/template/dependent-name14.C b/gcc/testsuite/g++.dg/template/dependent-name14.C new file mode 100644 index 0000000..52d2e72 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/dependent-name14.C @@ -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, ""); + |