aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-03-30 16:09:43 -0400
committerJason Merrill <jason@redhat.com>2020-03-30 17:04:09 -0400
commit5830f753559f25a5dabcc3507bffa611c6b575a6 (patch)
tree5ca1ab73bcd732cdb0aea5bb7213c150f67f2ee7 /gcc
parent1cb1986cb596336e688c079b821205ec212a46a3 (diff)
downloadgcc-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/ChangeLog6
-rw-r--r--gcc/cp/tree.c14
-rw-r--r--gcc/testsuite/g++.dg/template/dependent-name14.C38
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, "");
+