diff options
author | Patrick Palka <ppalka@redhat.com> | 2023-02-05 21:35:33 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2023-02-05 21:35:33 -0500 |
commit | 31924665c86d47af6b1f22a74f594f2e1dc0ed2d (patch) | |
tree | 2b92f40ff91d210b9a3e34b77d7097bc619a5fb5 /gcc/cp/tree.cc | |
parent | e4421a770d42477736a6598ee2cf61c6c737cc37 (diff) | |
download | gcc-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.cc | 24 |
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; |