Commit 7d119905 by Jason Merrill Committed by Jason Merrill

Avoid double substitution with complete explicit template arguments.

Previously, when we got a function template with explicit arguments for all
of the template parameters, we still did "deduction", which of course
couldn't deduce anything, but did other deduction-time checking of
non-dependent conversions and such.  This broke down with the unevaluated
lambdas patch (to follow): substituting into the lambda multiple times, once
to get the function type for deduction and then again to generate the actual
decl, doesn't work, since different substitutions of a lambda produce
different types.  I believe that skipping the initial substitution when we
have all the arguments is still conformant, and produces better diagnostics
for some testcases.

	* pt.c (fn_type_unification): If we have a full set of explicit
	arguments, go straight to substitution.

From-SVN: r266055
parent 7c23c87c
2018-11-12 Jason Merrill <jason@redhat.com> 2018-11-12 Jason Merrill <jason@redhat.com>
* pt.c (fn_type_unification): If we have a full set of explicit
arguments, go straight to substitution.
* decl2.c (min_vis_expr_r, expr_visibility): New. * decl2.c (min_vis_expr_r, expr_visibility): New.
(min_vis_r): Call expr_visibility. (min_vis_r): Call expr_visibility.
(constrain_visibility_for_template): Likewise. (constrain_visibility_for_template): Likewise.
......
...@@ -19800,6 +19800,11 @@ fn_type_unification (tree fn, ...@@ -19800,6 +19800,11 @@ fn_type_unification (tree fn,
tsubst_flags_t complain = (explain_p ? tf_warning_or_error : tf_none); tsubst_flags_t complain = (explain_p ? tf_warning_or_error : tf_none);
bool ok; bool ok;
static int deduction_depth; static int deduction_depth;
/* type_unification_real will pass back any access checks from default
template argument substitution. */
vec<deferred_access_check, va_gc> *checks = NULL;
/* We don't have all the template args yet. */
bool incomplete = true;
tree orig_fn = fn; tree orig_fn = fn;
if (flag_new_inheriting_ctors) if (flag_new_inheriting_ctors)
...@@ -19857,7 +19862,7 @@ fn_type_unification (tree fn, ...@@ -19857,7 +19862,7 @@ fn_type_unification (tree fn,
template results in an invalid type, type deduction fails. */ template results in an invalid type, type deduction fails. */
int i, len = TREE_VEC_LENGTH (tparms); int i, len = TREE_VEC_LENGTH (tparms);
location_t loc = input_location; location_t loc = input_location;
bool incomplete = false; incomplete = false;
if (explicit_targs == error_mark_node) if (explicit_targs == error_mark_node)
goto fail; goto fail;
...@@ -19923,33 +19928,52 @@ fn_type_unification (tree fn, ...@@ -19923,33 +19928,52 @@ fn_type_unification (tree fn,
} }
} }
if (!push_tinst_level (fn, explicit_targs)) if (incomplete)
{ {
excessive_deduction_depth = true; if (!push_tinst_level (fn, explicit_targs))
goto fail; {
} excessive_deduction_depth = true;
processing_template_decl += incomplete; goto fail;
input_location = DECL_SOURCE_LOCATION (fn); }
/* Ignore any access checks; we'll see them again in ++processing_template_decl;
instantiate_template and they might have the wrong input_location = DECL_SOURCE_LOCATION (fn);
access path at this point. */ /* Ignore any access checks; we'll see them again in
push_deferring_access_checks (dk_deferred); instantiate_template and they might have the wrong
fntype = tsubst (TREE_TYPE (fn), explicit_targs, access path at this point. */
complain | tf_partial | tf_fndecl_type, NULL_TREE); push_deferring_access_checks (dk_deferred);
pop_deferring_access_checks (); tsubst_flags_t ecomplain = complain | tf_partial | tf_fndecl_type;
input_location = loc; fntype = tsubst (TREE_TYPE (fn), explicit_targs, ecomplain, NULL_TREE);
processing_template_decl -= incomplete; pop_deferring_access_checks ();
pop_tinst_level (); input_location = loc;
--processing_template_decl;
pop_tinst_level ();
if (fntype == error_mark_node) if (fntype == error_mark_node)
goto fail; goto fail;
}
/* Place the explicitly specified arguments in TARGS. */ /* Place the explicitly specified arguments in TARGS. */
explicit_targs = INNERMOST_TEMPLATE_ARGS (explicit_targs); explicit_targs = INNERMOST_TEMPLATE_ARGS (explicit_targs);
for (i = NUM_TMPL_ARGS (explicit_targs); i--;) for (i = NUM_TMPL_ARGS (explicit_targs); i--;)
TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (explicit_targs, i); TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (explicit_targs, i);
if (!incomplete && CHECKING_P
&& !NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT
(targs, NUM_TMPL_ARGS (explicit_targs));
}
if (return_type && strict != DEDUCE_CALL)
{
tree *new_args = XALLOCAVEC (tree, nargs + 1);
new_args[0] = return_type;
memcpy (new_args + 1, args, nargs * sizeof (tree));
args = new_args;
++nargs;
} }
if (!incomplete)
goto deduced;
/* Never do unification on the 'this' parameter. */ /* Never do unification on the 'this' parameter. */
parms = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (fntype)); parms = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (fntype));
...@@ -19963,14 +19987,7 @@ fn_type_unification (tree fn, ...@@ -19963,14 +19987,7 @@ fn_type_unification (tree fn,
} }
else if (return_type) else if (return_type)
{ {
tree *new_args;
parms = tree_cons (NULL_TREE, TREE_TYPE (fntype), parms); parms = tree_cons (NULL_TREE, TREE_TYPE (fntype), parms);
new_args = XALLOCAVEC (tree, nargs + 1);
new_args[0] = return_type;
memcpy (new_args + 1, args, nargs * sizeof (tree));
args = new_args;
++nargs;
} }
/* We allow incomplete unification without an error message here /* We allow incomplete unification without an error message here
...@@ -19988,11 +20005,6 @@ fn_type_unification (tree fn, ...@@ -19988,11 +20005,6 @@ fn_type_unification (tree fn,
goto fail; goto fail;
} }
/* type_unification_real will pass back any access checks from default
template argument substitution. */
vec<deferred_access_check, va_gc> *checks;
checks = NULL;
ok = !type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn), ok = !type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
full_targs, parms, args, nargs, /*subr=*/0, full_targs, parms, args, nargs, /*subr=*/0,
strict, &checks, explain_p); strict, &checks, explain_p);
...@@ -20035,6 +20047,7 @@ fn_type_unification (tree fn, ...@@ -20035,6 +20047,7 @@ fn_type_unification (tree fn,
convs, explain_p)) convs, explain_p))
goto fail; goto fail;
deduced:
/* All is well so far. Now, check: /* All is well so far. Now, check:
[temp.deduct] [temp.deduct]
......
...@@ -6,7 +6,7 @@ template<typename T> struct baz { }; ...@@ -6,7 +6,7 @@ template<typename T> struct baz { };
template<typename T> T bar(); template<typename T> T bar();
template<typename T, typename ... U> template<typename T, typename ... U>
baz<decltype(bar<Int>(bar<U>() ...))> // { dg-error "no match" } baz<decltype(bar<Int>(bar<U>() ...))> // { dg-error "" }
foo(); foo();
int main() int main()
......
...@@ -23,7 +23,7 @@ struct TypeC ...@@ -23,7 +23,7 @@ struct TypeC
// TypeC::fn() // TypeC::fn()
// we don't want to see the template header, return type, or parameter bindings // we don't want to see the template header, return type, or parameter bindings
// for TypeB::fn. // for TypeB::fn.
template <int N> auto fn() -> decltype(b.fn<N>()); // { dg-bogus "typename|with" } template <int N> auto fn() -> decltype(b.fn<N>()); // { dg-bogus "typename" }
}; };
int main() int main()
......
...@@ -12,7 +12,7 @@ struct S { ...@@ -12,7 +12,7 @@ struct S {
template<typename U> template<typename U>
static decltype(*declval<U>()) get(...); // { dg-error "operator*" } static decltype(*declval<U>()) get(...); // { dg-error "operator*" }
typedef decltype(get<T>(declval<T>())) type; // { dg-error "no match" } typedef decltype(get<T>(declval<T>())) type; // { dg-error "" }
}; };
struct X { }; struct X { };
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
template <class F> void g(F); template <class F> void g(F);
template <class... A> template <class... A>
auto h(A &&... a) -> decltype(g(0, g<decltype(a)>(a)...)) { // { dg-error "no matching" } auto h(A &&... a) -> decltype(g(0, g<decltype(a)>(a)...)) { // { dg-error "" }
h([] {}); // { dg-error "no matching" } h([] {}); // { dg-error "no matching" }
} }
......
...@@ -134,21 +134,17 @@ int test_7 (int one, T two, float three); // { dg-line test_7_decl } ...@@ -134,21 +134,17 @@ int test_7 (int one, T two, float three); // { dg-line test_7_decl }
int test_7 (int first, const char *second, float third) int test_7 (int first, const char *second, float third)
{ {
return test_7 <const char **> (first, second, third); // { dg-line test_7_usage } return test_7 <const char **> (first, second, third); // { dg-line test_7_usage }
// { dg-error "no matching function" "" { target *-*-* } test_7_usage } // { dg-message "cannot convert 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } test_7_usage }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return test_7 <const char **> (first, second, third); return test_7 <const char **> (first, second, third);
^ ^~~~~~
|
const char*
{ dg-end-multiline-output "" } */ { dg-end-multiline-output "" } */
// { dg-message "candidate: 'template<class T> int test_7\\(int, T, float\\)'" "" { target *-*-* } test_7_decl } // { dg-message "initializing argument 2 of 'int test_7\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } test_7_decl }
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
int test_7 (int one, T two, float three); int test_7 (int one, T two, float three);
^~~~~~ ~~^~~
{ dg-end-multiline-output "" } */
// { dg-message "template argument deduction/substitution failed:" "" { target *-*-* } test_7_decl }
// { dg-message "cannot convert 'second' \\(type 'const char\\*'\\) to type 'const char\\*\\*'" "" { target *-*-* } test_7_usage }
/* { dg-begin-multiline-output "" }
return test_7 <const char **> (first, second, third);
^~~~~~
{ dg-end-multiline-output "" } */ { dg-end-multiline-output "" } */
} }
......
...@@ -130,18 +130,16 @@ int test_7 (int one, T two, float three); ...@@ -130,18 +130,16 @@ int test_7 (int one, T two, float three);
int test_7 (int first, int second, float third) int test_7 (int first, int second, float third)
{ {
return test_7 <const char *> (first, second, third); // { dg-error "no matching function" } return test_7 <const char *> (first, second, third); // { dg-error "invalid conversion from 'int' to 'const char\\*'" }
/* { dg-begin-multiline-output "" }
return test_7 <const char *> (first, second, third);
^
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
return test_7 <const char *> (first, second, third); return test_7 <const char *> (first, second, third);
^~~~~~ ^~~~~~
|
int
{ dg-end-multiline-output "" } */ { dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" } /* { dg-begin-multiline-output "" }
int test_7 (int one, T two, float three); int test_7 (int one, T two, float three);
^~~~~~ ~~^~~
{ dg-end-multiline-output "" } */ { dg-end-multiline-output "" } */
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment