diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 495dcdd77b3b8cfa89406c88c38655bfd2dfec95..1fbfc580a1e7ef5cc8bd0c001c428d130c228043 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -11163,6 +11163,33 @@ 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 "inside-out" + partial instantiations such as A<T>::f<int>(). So instead + use the selected template, not the specialization. */ + + if (OVL_SINGLE_P (fns)) + /* If the original overload set consists of a single function + template, this isn't beneficial. */ + goto skip_prune; + + fn = ovl_make (DECL_TI_TEMPLATE (fn)); + if (template_only) + fn = lookup_template_function (fn, explicit_targs); + } + orig_fns = copy_node (orig_fns); + BASELINK_FUNCTIONS (orig_fns) = fn; + } + +skip_prune: call = (build_min_non_dep_call_vec (call, build_min (COMPONENT_REF, TREE_TYPE (CALL_EXPR_FN (call)), diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6603066c6207b226a0130f69b2f366c797f78745..6ffd82cb0ecf7e1140447d5c9888fe1b60af1a7f 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 non-dependent 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 e6af294c1803b40a05fbbc9acf44264af8d496c5..eb966362ccbb869ea04ebc985873fc9ca1363f5d 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 833ae6fc85c515853deaf2730c7ac7780c089673..c7d7d60481e61208e4f4f2d02e53cb37f2e5c69b 100644 --- a/gcc/testsuite/g++.dg/cpp0x/fntmp-equiv1.C +++ b/gcc/testsuite/g++.dg/cpp0x/fntmp-equiv1.C @@ -3,21 +3,21 @@ 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> e<sizeof(d(T{}, T{}))> d(...); +template <class T> e<d(T{}, T{})> 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(); -template <unsigned long f, unsigned b, typename> e<d2(f, b)> d2(); +template <class T> e<d2(T{}, T{})> d2(...); +template <class T> e<d2(T{}, T{})> d2(...); template <typename a, typename c> a d3(a, c); -template <unsigned long f, unsigned b, typename> e<sizeof(d3(f, b))> d3(); -template <unsigned long f, unsigned b, typename> e<sizeof(d3(f, b))> d3(); +template <class T> e<sizeof(d3(T{}, T{}))> d3(...); +template <class T> e<sizeof(d3(T{}, T{}))> d3(...); int main() { - d<1,2,int>(); - d2<1,2,int>(); - d3<1,2,int>(); + d<int>(); + d2<int>(); + d3<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 0000000000000000000000000000000000000000..ee8ef902529ea1e4c0088949ef1764b3c62618e1 --- /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 0000000000000000000000000000000000000000..0e04d646c0beb28ab0e0bd245b9eae5cae4cc0d7 --- /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>(); +} diff --git a/gcc/testsuite/g++.dg/template/non-dependent17.C b/gcc/testsuite/g++.dg/template/non-dependent17.C new file mode 100644 index 0000000000000000000000000000000000000000..6b62dd2a60dd0f2c98ac1fd755a5fd870d46895d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/non-dependent17.C @@ -0,0 +1,21 @@ +// A variant of deduce4.C with multiple overloads of foo. Verify we don't +// crash after ahead-of-time pruning of the overload set for the non-dependent +// call to foo. +// { dg-do compile } + +template <typename T> +struct S { + template <typename U, typename V> + static void foo(V) { } + template <typename U> + static void foo(...) { } + + void bar () { foo<int>(10); } +}; + +void +test () +{ + S<int> s; + s.bar (); +}