* This change triggered a latent FUNCTION_DECL pretty printing issue
in cpp0x/error2.C -- since we now resolve the call to foo<0> ahead
of time, the error now looks like:
error: expansion pattern ‘foo()()=0’ contains no parameter pack
where the FUNCTION_DECL foo is clearly misprinted. But this
pretty-printing issue could be reproduced without this patch if
we replace foo with an ordinary function. Since this testcase was
added to verify pretty printing of TEMPLATE_ID_EXPR, I work around
this test failure by making the call to foo type-dependent and thus
immune to this ahead of time pruning.
* We now reject parts of cpp0x/fntmp-equiv1.C because we notice that
the call d(f, b) in
template <unsigned long f, unsigned b, typename> e<d(f, b)> d();
isn't constexpr because the (resolved) d isn't. I tried fixing this
by making d constexpr, but then the call to d from main becomes
ambiguous. So I settled with removing this part of the testcase.
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk? Also tested on cmcstl2 and range-v3.
gcc/cp/ChangeLog:
* call.c (build_new_method_call): For a non-dependent call
expression inside a template, returning a templated tree
whose overload set contains just the selected function.
* pt.c (register_specialization): Check only the innermost
template args for dependence in the early exit test.
(tsubst_function_decl): Simplify obtaining the template arguments
for a partial instantiation.
* semantics.c (finish_call_expr): As with build_new_method_call.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/error2.C: Make the call to foo type-dependent in
order to avoid latent pretty-printing issue for FUNCTION_DECL
inside MODOP_EXPR.
* g++.dg/cpp0x/fntmp-equiv1.C: Remove ill-formed parts of
testcase that we now diagnose.
* g++.dg/template/non-dependent16.C: New test.
* g++.dg/template/non-dependent16a.C: New test.
---
gcc/cp/call.c | 17 +++++++++
gcc/cp/pt.c | 18 ++-------
gcc/cp/semantics.c | 15 ++++++++
gcc/testsuite/g++.dg/cpp0x/error2.C | 4 +-
gcc/testsuite/g++.dg/cpp0x/fntmp-equiv1.C | 4 --
.../g++.dg/template/non-dependent16.C | 37 +++++++++++++++++++
.../g++.dg/template/non-dependent16a.C | 36 ++++++++++++++++++
7 files changed, 111 insertions(+), 20 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/non-dependent16.C
create mode 100644 gcc/testsuite/g++.dg/template/non-dependent16a.C
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 53a391cbc6b..92d96c19f5c 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -11165,6 +11165,23 @@ build_new_method_call (tree instance, tree fns, vec<tree,
va_gc> **args,
}
if (INDIRECT_REF_P (call))
call = TREE_OPERAND (call, 0);
+
+ /* Prune all but the selected function from the original overload
+ set so that we can avoid some duplicate work at instantiation time. */
+ if (really_overloaded_fn (fns))
+ {
+ if (DECL_TEMPLATE_INFO (fn)
+ && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn))
+ && dependent_type_p (DECL_CONTEXT (fn)))
+ /* FIXME: We're not prepared to fully instantiate "inverted"
+ partial instantiations such as A<T>::f<int>(). */;
+ else
+ {
+ orig_fns = copy_node (orig_fns);
+ BASELINK_FUNCTIONS (orig_fns) = fn;
+ }
+ }
+
call = (build_min_non_dep_call_vec
(call,
build_min (COMPONENT_REF, TREE_TYPE (CALL_EXPR_FN (call)),
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2340139b238..b114114e617 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1566,18 +1566,10 @@ register_specialization (tree spec, tree tmpl, tree
args, bool is_friend,
&& TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK));
if (TREE_CODE (spec) == FUNCTION_DECL
- && uses_template_parms (DECL_TI_ARGS (spec)))
+ && uses_template_parms (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (spec))))
/* This is the FUNCTION_DECL for a partial instantiation. Don't
- register it; we want the corresponding TEMPLATE_DECL instead.
- We use `uses_template_parms (DECL_TI_ARGS (spec))' rather than
- the more obvious `uses_template_parms (spec)' to avoid problems
- with default function arguments. In particular, given
- something like this:
-
- template <class T> void f(T t1, T t = T())
-
- the default argument expression is not substituted for in an
- instantiation unless and until it is actually needed. */
+ register it; we want to register the corresponding TEMPLATE_DECL
+ instead. */
return spec;
if (optimize_specialization_lookup_p (tmpl))
@@ -13960,9 +13952,7 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t
complain,
/* Calculate the complete set of arguments used to
specialize R. */
- argvec = tsubst_template_args (DECL_TI_ARGS
- (DECL_TEMPLATE_RESULT
- (DECL_TI_TEMPLATE (t))),
+ argvec = tsubst_template_args (DECL_TI_ARGS (t),
args, complain, in_decl);
if (argvec == error_mark_node)
return error_mark_node;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7078af03d3c..57f689042b9 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2893,6 +2893,21 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool
disallow_virtual,
{
if (INDIRECT_REF_P (result))
result = TREE_OPERAND (result, 0);
+
+ /* Prune all but the selected function from the original overload
+ set so that we can avoid some duplicate work at instantiation time. */
+ if (TREE_CODE (result) == CALL_EXPR
+ && really_overloaded_fn (orig_fn))
+ {
+ orig_fn = CALL_EXPR_FN (result);
+ if (TREE_CODE (orig_fn) == COMPONENT_REF)
+ {
+ /* The result of build_new_method_call. */
+ orig_fn = TREE_OPERAND (orig_fn, 1);
+ gcc_assert (BASELINK_P (orig_fn));
+ }
+ }
+
result = build_call_vec (TREE_TYPE (result), orig_fn, orig_args);
SET_EXPR_LOCATION (result, input_location);
KOENIG_LOOKUP_P (result) = koenig_p;
diff --git a/gcc/testsuite/g++.dg/cpp0x/error2.C
b/gcc/testsuite/g++.dg/cpp0x/error2.C
index e6af294c180..eb966362ccb 100644
--- a/gcc/testsuite/g++.dg/cpp0x/error2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/error2.C
@@ -3,7 +3,7 @@
template<int> int foo();
-template<typename F> void bar(F f)
+template<typename F, int N> void bar(F f)
{
- f((foo<0>()=0)...); // { dg-error "pattern '\\(foo\\<0\\>\\)\\(\\)=0'" }
+ f((foo<N>()=0)...); // { dg-error "pattern '\\(foo\\<N\\>\\)\\(\\)=0'" }
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/fntmp-equiv1.C
b/gcc/testsuite/g++.dg/cpp0x/fntmp-equiv1.C
index 833ae6fc85c..60ebad8d1d3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/fntmp-equiv1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/fntmp-equiv1.C
@@ -1,10 +1,7 @@
// PR c++/86946, DR 1321
// { dg-do compile { target c++11 } }
-int d(int, int);
template <long> class e {};
-template <unsigned long f, unsigned b, typename> e<sizeof(d(f, b))> d();
-template <unsigned long f, unsigned b, typename> e<d(f, b)> d();
template <class T, class U> constexpr T d2(T, U) { return 42; }
template <unsigned long f, unsigned b, typename> e<d2(f, b)> d2();
@@ -17,7 +14,6 @@ template <unsigned long f, unsigned b, typename> e<sizeof(d3(f,
b))> d3();
int main()
{
- d<1,2,int>();
d2<1,2,int>();
d3<1,2,int>();
}
diff --git a/gcc/testsuite/g++.dg/template/non-dependent16.C
b/gcc/testsuite/g++.dg/template/non-dependent16.C
new file mode 100644
index 00000000000..ee8ef902529
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent16.C
@@ -0,0 +1,37 @@
+// This test verifies that after resolving a non-dependent call expression
+// ahead of time, we prune all but the selected candidate from the overload
+// set. Without this optimization, overload resolution for the final call to
+// f<void>() would be exponential in the size of the overload set.
+
+// { dg-do compile { target c++11 } }
+
+template<class T> void f();
+template<class T> auto f() -> decltype(f<void>(), 1, *T());
+template<class T> auto f() -> decltype(f<void>(), 2, *T());
+template<class T> auto f() -> decltype(f<void>(), 3, *T());
+template<class T> auto f() -> decltype(f<void>(), 4, *T());
+template<class T> auto f() -> decltype(f<void>(), 5, *T());
+template<class T> auto f() -> decltype(f<void>(), 6, *T());
+template<class T> auto f() -> decltype(f<void>(), 7, *T());
+template<class T> auto f() -> decltype(f<void>(), 8, *T());
+template<class T> auto f() -> decltype(f<void>(), 9, *T());
+template<class T> auto f() -> decltype(f<void>(), 10, *T());
+template<class T> auto f() -> decltype(f<void>(), 11, *T());
+template<class T> auto f() -> decltype(f<void>(), 12, *T());
+template<class T> auto f() -> decltype(f<void>(), 13, *T());
+template<class T> auto f() -> decltype(f<void>(), 14, *T());
+template<class T> auto f() -> decltype(f<void>(), 15, *T());
+template<class T> auto f() -> decltype(f<void>(), 16, *T());
+template<class T> auto f() -> decltype(f<void>(), 17, *T());
+template<class T> auto f() -> decltype(f<void>(), 18, *T());
+template<class T> auto f() -> decltype(f<void>(), 19, *T());
+template<class T> auto f() -> decltype(f<void>(), 20, *T());
+template<class T> auto f() -> decltype(f<void>(), 21, *T());
+template<class T> auto f() -> decltype(f<void>(), 22, *T());
+template<class T> auto f() -> decltype(f<void>(), 23, *T());
+template<class T> auto f() -> decltype(f<void>(), 24, *T());
+template<class T> auto f() -> decltype(f<void>(), 25, *T());
+
+int main() {
+ f<void>();
+}
diff --git a/gcc/testsuite/g++.dg/template/non-dependent16a.C
b/gcc/testsuite/g++.dg/template/non-dependent16a.C
new file mode 100644
index 00000000000..0e04d646c0b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/non-dependent16a.C
@@ -0,0 +1,36 @@
+// Like non-dependent16.C, but using member functions.
+
+// { dg-do compile { target c++11 } }
+
+struct A {
+ template<class T> static void f();
+ template<class T> static auto f() -> decltype(f<void>(), 1, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 2, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 3, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 4, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 5, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 6, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 7, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 8, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 9, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 10, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 11, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 12, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 13, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 14, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 15, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 16, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 17, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 18, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 19, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 20, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 21, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 22, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 23, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 24, *T());
+ template<class T> static auto f() -> decltype(f<void>(), 25, *T());
+};
+
+int main() {
+ A::f<void>();
+}