Skip to content

Commit 3192466

Browse files
author
Patrick Palka
committed
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 riscvarchive#2 as a redeclaration of riscvarchive#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.
1 parent e4421a7 commit 3192466

File tree

6 files changed

+59
-6
lines changed

6 files changed

+59
-6
lines changed

gcc/cp/cp-tree.h

+1
Original file line numberDiff line numberDiff line change
@@ -7902,6 +7902,7 @@ extern tree lookup_maybe_add (tree fns, tree lookup,
79027902
extern int is_overloaded_fn (tree) ATTRIBUTE_PURE;
79037903
extern bool really_overloaded_fn (tree) ATTRIBUTE_PURE;
79047904
extern tree dependent_name (tree);
7905+
extern tree call_expr_dependent_name (tree);
79057906
extern tree maybe_get_fns (tree) ATTRIBUTE_PURE;
79067907
extern tree get_fns (tree) ATTRIBUTE_PURE;
79077908
extern tree get_first_fn (tree) ATTRIBUTE_PURE;

gcc/cp/pt.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1841,7 +1841,7 @@ iterative_hash_template_arg (tree arg, hashval_t val)
18411841
case CALL_EXPR:
18421842
{
18431843
tree fn = CALL_EXPR_FN (arg);
1844-
if (tree name = dependent_name (fn))
1844+
if (tree name = call_expr_dependent_name (arg))
18451845
{
18461846
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
18471847
val = iterative_hash_template_arg (TREE_OPERAND (fn, 1), val);

gcc/cp/tree.cc

+19-5
Original file line numberDiff line numberDiff line change
@@ -2608,6 +2608,18 @@ dependent_name (tree x)
26082608
return NULL_TREE;
26092609
}
26102610

2611+
/* Like dependent_name, but instead takes a CALL_EXPR and also checks
2612+
its dependence. */
2613+
2614+
tree
2615+
call_expr_dependent_name (tree x)
2616+
{
2617+
if (TREE_TYPE (x) != NULL_TREE)
2618+
/* X isn't dependent, so its callee isn't a dependent name. */
2619+
return NULL_TREE;
2620+
return dependent_name (CALL_EXPR_FN (x));
2621+
}
2622+
26112623
/* Returns true iff X is an expression for an overloaded function
26122624
whose type cannot be known without performing overload
26132625
resolution. */
@@ -3870,16 +3882,18 @@ decl_internal_context_p (const_tree decl)
38703882
return !TREE_PUBLIC (decl);
38713883
}
38723884

3873-
/* Subroutine of cp_tree_equal: t1 and t2 are the CALL_EXPR_FNs of two
3874-
CALL_EXPRS. Return whether they are equivalent. */
3885+
/* Subroutine of cp_tree_equal: t1 and t2 are two CALL_EXPRs.
3886+
Return whether their CALL_EXPR_FNs are equivalent. */
38753887

38763888
static bool
38773889
called_fns_equal (tree t1, tree t2)
38783890
{
38793891
/* Core 1321: dependent names are equivalent even if the overload sets
38803892
are different. But do compare explicit template arguments. */
3881-
tree name1 = dependent_name (t1);
3882-
tree name2 = dependent_name (t2);
3893+
tree name1 = call_expr_dependent_name (t1);
3894+
tree name2 = call_expr_dependent_name (t2);
3895+
t1 = CALL_EXPR_FN (t1);
3896+
t2 = CALL_EXPR_FN (t2);
38833897
if (name1 || name2)
38843898
{
38853899
tree targs1 = NULL_TREE, targs2 = NULL_TREE;
@@ -4037,7 +4051,7 @@ cp_tree_equal (tree t1, tree t2)
40374051
if (KOENIG_LOOKUP_P (t1) != KOENIG_LOOKUP_P (t2))
40384052
return false;
40394053

4040-
if (!called_fns_equal (CALL_EXPR_FN (t1), CALL_EXPR_FN (t2)))
4054+
if (!called_fns_equal (t1, t2))
40414055
return false;
40424056

40434057
call_expr_arg_iterator iter1, iter2;
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// PR c++/107461
2+
// { dg-do compile { target c++11 } }
3+
4+
int f(...);
5+
template<class T> decltype(T() + f(0)) g(); // #1
6+
7+
char f(int);
8+
template<class T> decltype(T() + f(0)) g(); // #2, distinct from #1
9+
10+
int main() {
11+
g<int>(); // { dg-error "ambiguous" }
12+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// PR c++/107461
2+
// { dg-do compile { target c++11 } }
3+
4+
template<class T> T f();
5+
template<class T> decltype(T() + f<int*>()) g(); // #1
6+
template<class T> decltype(T() + f<char>()) g(); // #2, distinct from #1
7+
8+
int main() {
9+
g<int>(); // { dg-error "ambiguous" }
10+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// PR c++/107461
2+
// { dg-do compile { target c++11 } }
3+
4+
template<class T> T f();
5+
6+
template<class> struct A { };
7+
8+
template<class T> struct B {
9+
template<class U, class = A<decltype(f<T>()(U()))>>
10+
static void g(U);
11+
};
12+
13+
int main() {
14+
B<int> b;
15+
B<void(*)(int)>::g(0); // { dg-bogus "no match" }
16+
}

0 commit comments

Comments
 (0)