aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/tree.cc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2023-02-05 21:35:33 -0500
committerPatrick Palka <ppalka@redhat.com>2023-02-05 21:35:33 -0500
commit31924665c86d47af6b1f22a74f594f2e1dc0ed2d (patch)
tree2b92f40ff91d210b9a3e34b77d7097bc619a5fb5 /gcc/cp/tree.cc
parente4421a770d42477736a6598ee2cf61c6c737cc37 (diff)
downloadgcc-31924665c86d47af6b1f22a74f594f2e1dc0ed2d.zip
gcc-31924665c86d47af6b1f22a74f594f2e1dc0ed2d.tar.gz
gcc-31924665c86d47af6b1f22a74f594f2e1dc0ed2d.tar.bz2
c++: equivalence of non-dependent calls [PR107461]
After r13-5684-g59e0376f607805 the (pruned) callee of a non-dependent CALL_EXPR is a bare FUNCTION_DECL rather than ADDR_EXPR of FUNCTION_DECL. This innocent change revealed that cp_tree_equal doesn't first check dependence of a CALL_EXPR before treating a FUNCTION_DECL callee as a dependent name, which leads to us incorrectly accepting the first two testcases below and rejecting the third: * In the first testcase, cp_tree_equal incorrectly returns true for the two non-dependent CALL_EXPRs f(0) and f(0) (whose CALL_EXPR_FN are different FUNCTION_DECLs) which causes us to treat #2 as a redeclaration of #1. * Same issue in the second testcase, for f<int*>() and f<char>(). * In the third testcase, cp_tree_equal incorrectly returns true for f<int>() and f<void(*)(int)>() which causes us to conflate the two dependent specializations A<decltype(f<int>()(U()))> and A<decltype(f<void(*)(int)>()(U()))>. This patch fixes this by making called_fns_equal treat two callees as dependent names only if the overall CALL_EXPRs are dependent, via a new convenience function call_expr_dependent_name that is like dependent_name but also checks dependence of the overall CALL_EXPR. PR c++/107461 gcc/cp/ChangeLog: * cp-tree.h (call_expr_dependent_name): Declare. * pt.cc (iterative_hash_template_arg) <case CALL_EXPR>: Use call_expr_dependent_name instead of dependent_name. * tree.cc (call_expr_dependent_name): Define. (called_fns_equal): Adjust to take two CALL_EXPRs instead of CALL_EXPR_FNs thereof. Use call_expr_dependent_name instead of dependent_name. (cp_tree_equal) <case CALL_EXPR>: Adjust call to called_fns_equal. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/overload5.C: New test. * g++.dg/cpp0x/overload5a.C: New test. * g++.dg/cpp0x/overload6.C: New test.
Diffstat (limited to 'gcc/cp/tree.cc')
-rw-r--r--gcc/cp/tree.cc24
1 files changed, 19 insertions, 5 deletions
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index c1da868..cd0dd96 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -2608,6 +2608,18 @@ dependent_name (tree x)
return NULL_TREE;
}
+/* Like dependent_name, but instead takes a CALL_EXPR and also checks
+ its dependence. */
+
+tree
+call_expr_dependent_name (tree x)
+{
+ if (TREE_TYPE (x) != NULL_TREE)
+ /* X isn't dependent, so its callee isn't a dependent name. */
+ return NULL_TREE;
+ return dependent_name (CALL_EXPR_FN (x));
+}
+
/* Returns true iff X is an expression for an overloaded function
whose type cannot be known without performing overload
resolution. */
@@ -3870,16 +3882,18 @@ decl_internal_context_p (const_tree decl)
return !TREE_PUBLIC (decl);
}
-/* Subroutine of cp_tree_equal: t1 and t2 are the CALL_EXPR_FNs of two
- CALL_EXPRS. Return whether they are equivalent. */
+/* Subroutine of cp_tree_equal: t1 and t2 are two CALL_EXPRs.
+ Return whether their CALL_EXPR_FNs are equivalent. */
static bool
called_fns_equal (tree t1, tree t2)
{
/* Core 1321: dependent names are equivalent even if the overload sets
are different. But do compare explicit template arguments. */
- tree name1 = dependent_name (t1);
- tree name2 = dependent_name (t2);
+ tree name1 = call_expr_dependent_name (t1);
+ tree name2 = call_expr_dependent_name (t2);
+ t1 = CALL_EXPR_FN (t1);
+ t2 = CALL_EXPR_FN (t2);
if (name1 || name2)
{
tree targs1 = NULL_TREE, targs2 = NULL_TREE;
@@ -4037,7 +4051,7 @@ cp_tree_equal (tree t1, tree t2)
if (KOENIG_LOOKUP_P (t1) != KOENIG_LOOKUP_P (t2))
return false;
- if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
+ if (!called_fns_equal (t1, t2))
return false;
call_expr_arg_iterator iter1, iter2;