aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2017-08-29 16:37:15 -0400
committerJason Merrill <jason@gcc.gnu.org>2017-08-29 16:37:15 -0400
commitf44a8dd56f5bfbd0596c39693e268ef880c06221 (patch)
treeb1c3f161803fc2b6d6b610a8db75bddd8b2369d1 /gcc/cp
parent72932ccf0ac4837b020d29b386d75fbceeb88735 (diff)
downloadgcc-f44a8dd56f5bfbd0596c39693e268ef880c06221.zip
gcc-f44a8dd56f5bfbd0596c39693e268ef880c06221.tar.gz
gcc-f44a8dd56f5bfbd0596c39693e268ef880c06221.tar.bz2
Reimplement handling of lambdas in templates.
* cp-tree.h (LAMBDA_FUNCTION_P): Check DECL_DECLARES_FUNCTION_P. * decl.c (start_preparsed_function): Call start_lambda_scope. (finish_function): Call finish_lambda_scope. * init.c (get_nsdmi): Call start/finish_lambda_scope. * lambda.c (start_lambda_scope): Only ignore VAR_DECL in a function. * parser.c (cp_parser_function_definition_after_declarator): Don't call start/finish_lambda_scope. * pt.c (retrieve_specialization): Ignore lambda functions in templates. (find_parameter_packs_r): Ignore capture proxies. Look into lambdas. (check_for_bare_parameter_packs): Allow bare packs in lambdas. (tsubst_default_argument): Call start/finish_lambda_scope. (tsubst_function_decl): Handle lambda functions differently. (tsubst_template_decl): Likewise. (tsubst_expr) [DECL_EXPR]: Skip closure declarations and capture proxies. (tsubst_lambda_expr): Create a new closure rather than instantiate the one from the template. (tsubst_copy_and_build): Don't register a specialization of a pack. (regenerate_decl_from_template): Call start/finish_lambda_scope. (instantiate_decl): Remove special lambda function handling. * semantics.c (process_outer_var_ref): Remove special generic lambda handling. Don't implicitly capture in a lambda in a template. Look for an existing proxy. * class.c (current_nonlambda_class_type): Use decl_type_context. From-SVN: r251433
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog30
-rw-r--r--gcc/cp/class.c25
-rw-r--r--gcc/cp/cp-tree.h10
-rw-r--r--gcc/cp/decl.c12
-rw-r--r--gcc/cp/init.c6
-rw-r--r--gcc/cp/lambda.c83
-rw-r--r--gcc/cp/parser.c82
-rw-r--r--gcc/cp/pt.c1107
-rw-r--r--gcc/cp/semantics.c95
9 files changed, 832 insertions, 618 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index ef7f429..387a275 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,33 @@
+2017-08-23 Jason Merrill <jason@redhat.com>
+
+ Reimplement handling of lambdas in templates.
+ * cp-tree.h (LAMBDA_FUNCTION_P): Check DECL_DECLARES_FUNCTION_P.
+ * decl.c (start_preparsed_function): Call start_lambda_scope.
+ (finish_function): Call finish_lambda_scope.
+ * init.c (get_nsdmi): Call start/finish_lambda_scope.
+ * lambda.c (start_lambda_scope): Only ignore VAR_DECL in a function.
+ * parser.c (cp_parser_function_definition_after_declarator): Don't
+ call start/finish_lambda_scope.
+ * pt.c (retrieve_specialization): Ignore lambda functions in
+ templates.
+ (find_parameter_packs_r): Ignore capture proxies. Look into
+ lambdas.
+ (check_for_bare_parameter_packs): Allow bare packs in lambdas.
+ (tsubst_default_argument): Call start/finish_lambda_scope.
+ (tsubst_function_decl): Handle lambda functions differently.
+ (tsubst_template_decl): Likewise.
+ (tsubst_expr) [DECL_EXPR]: Skip closure declarations and capture
+ proxies.
+ (tsubst_lambda_expr): Create a new closure rather than instantiate
+ the one from the template.
+ (tsubst_copy_and_build): Don't register a specialization of a pack.
+ (regenerate_decl_from_template): Call start/finish_lambda_scope.
+ (instantiate_decl): Remove special lambda function handling.
+ * semantics.c (process_outer_var_ref): Remove special generic lambda
+ handling. Don't implicitly capture in a lambda in a template. Look
+ for an existing proxy.
+ * class.c (current_nonlambda_class_type): Use decl_type_context.
+
2017-08-29 Jason Merrill <jason@redhat.com>
* cp-tree.h (LAMBDA_EXPR_CLOSURE): Use TREE_TYPE.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 28cf7dc..a5f1007 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7709,27 +7709,10 @@ outermost_open_class (void)
tree
current_nonlambda_class_type (void)
{
- int i;
-
- /* We start looking from 1 because entry 0 is from global scope,
- and has no type. */
- for (i = current_class_depth; i > 0; --i)
- {
- tree c;
- if (i == current_class_depth)
- c = current_class_type;
- else
- {
- if (current_class_stack[i].hidden)
- break;
- c = current_class_stack[i].type;
- }
- if (!c)
- continue;
- if (!LAMBDA_TYPE_P (c))
- return c;
- }
- return NULL_TREE;
+ tree type = current_class_type;
+ while (type && LAMBDA_TYPE_P (type))
+ type = decl_type_context (TYPE_NAME (type));
+ return type;
}
/* When entering a class scope, all enclosing class scopes' names with
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ad97be4..41c48ec 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1216,8 +1216,9 @@ struct GTY (()) tree_trait_expr {
(CLASS_TYPE_P (NODE) && CLASSTYPE_LAMBDA_EXPR (NODE))
/* Test if FUNCTION_DECL is a lambda function. */
-#define LAMBDA_FUNCTION_P(FNDECL) \
- (DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR \
+#define LAMBDA_FUNCTION_P(FNDECL) \
+ (DECL_DECLARES_FUNCTION_P (FNDECL) \
+ && DECL_OVERLOADED_OPERATOR_P (FNDECL) == CALL_EXPR \
&& LAMBDA_TYPE_P (CP_DECL_CONTEXT (FNDECL)))
enum cp_lambda_default_capture_mode_type {
@@ -6828,6 +6829,11 @@ extern bool is_lambda_ignored_entity (tree);
extern bool lambda_static_thunk_p (tree);
extern tree finish_builtin_launder (location_t, tree,
tsubst_flags_t);
+extern void start_lambda_scope (tree);
+extern void record_lambda_scope (tree);
+extern void finish_lambda_scope (void);
+extern tree start_lambda_function (tree fn, tree lambda_expr);
+extern void finish_lambda_function (tree body);
/* in tree.c */
extern int cp_tree_operand_length (const_tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 23829b0..d6b80c6 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -15097,6 +15097,8 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
&& !implicit_default_ctor_p (decl1))
cp_ubsan_maybe_initialize_vtbl_ptrs (current_class_ptr);
+ start_lambda_scope (decl1);
+
return true;
}
@@ -15462,6 +15464,8 @@ finish_function (int flags)
if (fndecl == NULL_TREE)
return error_mark_node;
+ finish_lambda_scope ();
+
if (c_dialect_objc ())
objc_finish_function ();
@@ -15565,11 +15569,11 @@ finish_function (int flags)
/* Lambda closure members are implicitly constexpr if possible. */
if (cxx_dialect >= cxx1z
- && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl))
- && (processing_template_decl
+ && LAMBDA_TYPE_P (CP_DECL_CONTEXT (fndecl)))
+ DECL_DECLARED_CONSTEXPR_P (fndecl)
+ = ((processing_template_decl
|| is_valid_constexpr_fn (fndecl, /*complain*/false))
- && potential_constant_expression (DECL_SAVED_TREE (fndecl)))
- DECL_DECLARED_CONSTEXPR_P (fndecl) = true;
+ && potential_constant_expression (DECL_SAVED_TREE (fndecl)));
/* Save constexpr function body before it gets munged by
the NRV transformation. */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 56a5df8..b01d662 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -574,13 +574,17 @@ get_nsdmi (tree member, bool in_ctor, tsubst_flags_t complain)
inject_this_parameter (DECL_CONTEXT (member), TYPE_UNQUALIFIED);
+ start_lambda_scope (member);
+
/* Do deferred instantiation of the NSDMI. */
init = (tsubst_copy_and_build
(init, DECL_TI_ARGS (member),
complain, member, /*function_p=*/false,
/*integral_constant_expression_p=*/false));
init = digest_nsdmi_init (member, init, complain);
-
+
+ finish_lambda_scope ();
+
DECL_INSTANTIATING_NSDMI_P (member) = 0;
if (init != error_mark_node)
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 55d3415..4747a72 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -1253,4 +1253,87 @@ is_lambda_ignored_entity (tree val)
return false;
}
+/* Lambdas that appear in variable initializer or default argument scope
+ get that in their mangling, so we need to record it. We might as well
+ use the count for function and namespace scopes as well. */
+static GTY(()) tree lambda_scope;
+static GTY(()) int lambda_count;
+struct GTY(()) tree_int
+{
+ tree t;
+ int i;
+};
+static GTY(()) vec<tree_int, va_gc> *lambda_scope_stack;
+
+void
+start_lambda_scope (tree decl)
+{
+ tree_int ti;
+ gcc_assert (decl);
+ /* Once we're inside a function, we ignore variable scope and just push
+ the function again so that popping works properly. */
+ if (current_function_decl && TREE_CODE (decl) == VAR_DECL)
+ decl = current_function_decl;
+ ti.t = lambda_scope;
+ ti.i = lambda_count;
+ vec_safe_push (lambda_scope_stack, ti);
+ if (lambda_scope != decl)
+ {
+ /* Don't reset the count if we're still in the same function. */
+ lambda_scope = decl;
+ lambda_count = 0;
+ }
+}
+
+void
+record_lambda_scope (tree lambda)
+{
+ LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;
+ LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
+}
+
+void
+finish_lambda_scope (void)
+{
+ tree_int *p = &lambda_scope_stack->last ();
+ if (lambda_scope != p->t)
+ {
+ lambda_scope = p->t;
+ lambda_count = p->i;
+ }
+ lambda_scope_stack->pop ();
+}
+
+tree
+start_lambda_function (tree fco, tree lambda_expr)
+{
+ /* Let the front end know that we are going to be defining this
+ function. */
+ start_preparsed_function (fco,
+ NULL_TREE,
+ SF_PRE_PARSED | SF_INCLASS_INLINE);
+
+ tree body = begin_function_body ();
+
+ /* Push the proxies for any explicit captures. */
+ for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
+ cap = TREE_CHAIN (cap))
+ build_capture_proxy (TREE_PURPOSE (cap));
+
+ return body;
+}
+
+void
+finish_lambda_function (tree body)
+{
+ finish_function_body (body);
+
+ /* Finish the function and generate code for it if necessary. */
+ tree fn = finish_function (/*inline*/2);
+
+ /* Only expand if the call op is not a template. */
+ if (!DECL_TEMPLATE_INFO (fn))
+ expand_or_defer_fn (fn);
+}
+
#include "gt-cp-lambda.h"
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 9f62b43..d0d71fa 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -9982,57 +9982,6 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
}
}
-/* Lambdas that appear in variable initializer or default argument scope
- get that in their mangling, so we need to record it. We might as well
- use the count for function and namespace scopes as well. */
-static GTY(()) tree lambda_scope;
-static GTY(()) int lambda_count;
-struct GTY(()) tree_int
-{
- tree t;
- int i;
-};
-static GTY(()) vec<tree_int, va_gc> *lambda_scope_stack;
-
-static void
-start_lambda_scope (tree decl)
-{
- tree_int ti;
- gcc_assert (decl);
- /* Once we're inside a function, we ignore other scopes and just push
- the function again so that popping works properly. */
- if (current_function_decl && TREE_CODE (decl) != FUNCTION_DECL)
- decl = current_function_decl;
- ti.t = lambda_scope;
- ti.i = lambda_count;
- vec_safe_push (lambda_scope_stack, ti);
- if (lambda_scope != decl)
- {
- /* Don't reset the count if we're still in the same function. */
- lambda_scope = decl;
- lambda_count = 0;
- }
-}
-
-static void
-record_lambda_scope (tree lambda)
-{
- LAMBDA_EXPR_EXTRA_SCOPE (lambda) = lambda_scope;
- LAMBDA_EXPR_DISCRIMINATOR (lambda) = lambda_count++;
-}
-
-static void
-finish_lambda_scope (void)
-{
- tree_int *p = &lambda_scope_stack->last ();
- if (lambda_scope != p->t)
- {
- lambda_scope = p->t;
- lambda_count = p->i;
- }
- lambda_scope_stack->pop ();
-}
-
/* Parse a lambda expression.
lambda-expression:
@@ -10605,29 +10554,14 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
+ ctor_initializer_opt_and_function_body */
{
tree fco = lambda_function (lambda_expr);
- tree body;
+ tree body = start_lambda_function (fco, lambda_expr);
bool done = false;
tree compound_stmt;
- tree cap;
-
- /* Let the front end know that we are going to be defining this
- function. */
- start_preparsed_function (fco,
- NULL_TREE,
- SF_PRE_PARSED | SF_INCLASS_INLINE);
-
- start_lambda_scope (fco);
- body = begin_function_body ();
matching_braces braces;
if (!braces.require_open (parser))
goto out;
- /* Push the proxies for any explicit captures. */
- for (cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
- cap = TREE_CHAIN (cap))
- build_capture_proxy (TREE_PURPOSE (cap));
-
compound_stmt = begin_compound_stmt (0);
/* 5.1.1.4 of the standard says:
@@ -10691,15 +10625,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
finish_compound_stmt (compound_stmt);
out:
- finish_function_body (body);
- finish_lambda_scope ();
-
- /* Finish the function and generate code for it if necessary. */
- tree fn = finish_function (/*inline*/2);
-
- /* Only expand if the call op is not a template. */
- if (!DECL_TEMPLATE_INFO (fco))
- expand_or_defer_fn (fn);
+ finish_lambda_function (body);
}
restore_omp_privatization_clauses (omp_privatization_save);
@@ -26577,8 +26503,6 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
- start_lambda_scope (current_function_decl);
-
/* If the next token is `try', `__transaction_atomic', or
`__transaction_relaxed`, then we are looking at either function-try-block
or function-transaction-block. Note that all of these include the
@@ -26596,8 +26520,6 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body
(parser, /*in_function_try_block=*/false);
- finish_lambda_scope ();
-
/* Finish the function. */
fn = finish_function ((ctor_initializer_p ? 1 : 0) |
(inline_p ? 2 : 0));
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index e064a11..141b4d7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -220,6 +220,7 @@ static bool complex_alias_template_p (const_tree tmpl);
static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
static tree canonicalize_expr_argument (tree, tsubst_flags_t);
static tree make_argument_pack (tree);
+static void register_parameter_specializations (tree, tree);
/* Make the current scope suitable for access checking when we are
processing T. T can be FUNCTION_DECL for instantiated function
@@ -1190,6 +1191,19 @@ retrieve_specialization (tree tmpl, tree args, hashval_t hash)
if (flag_checking)
verify_unstripped_args (args);
+ /* Lambda functions in templates aren't instantiated normally, but through
+ tsubst_lambda_expr. */
+ if (LAMBDA_FUNCTION_P (tmpl))
+ {
+ bool generic = PRIMARY_TEMPLATE_P (tmpl);
+ if (TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)) > generic)
+ return NULL_TREE;
+
+ /* But generic lambda functions are instantiated normally, once their
+ containing context is fully instantiated. */
+ gcc_assert (generic);
+ }
+
if (optimize_specialization_lookup_p (tmpl))
{
/* The template arguments actually apply to the containing
@@ -3615,6 +3629,12 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
case PARM_DECL:
return NULL_TREE;
+ case DECL_EXPR:
+ /* Ignore the declaration of a capture proxy for a parameter pack. */
+ if (is_capture_proxy (DECL_EXPR_DECL (t)))
+ *walk_subtrees = 0;
+ return NULL_TREE;
+
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
return NULL_TREE;
@@ -3662,6 +3682,15 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data)
*walk_subtrees = 0;
return NULL_TREE;
+ case LAMBDA_EXPR:
+ {
+ tree fn = lambda_function (t);
+ cp_walk_tree (&DECL_SAVED_TREE (fn), &find_parameter_packs_r, ppd,
+ ppd->visited);
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
case DECLTYPE_TYPE:
{
/* When traversing a DECLTYPE_TYPE_EXPR, we need to set
@@ -3849,6 +3878,10 @@ check_for_bare_parameter_packs (tree t)
if (!processing_template_decl || !t || t == error_mark_node)
return false;
+ /* A lambda might use a parameter pack from the containing context. */
+ if (current_function_decl && LAMBDA_FUNCTION_P (current_function_decl))
+ return false;
+
if (TREE_CODE (t) == TYPE_DECL)
t = TREE_TYPE (t);
@@ -12056,6 +12089,8 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,
cp_function_chain->x_current_class_ref = NULL_TREE;
}
+ start_lambda_scope (parm);
+
push_deferring_access_checks(dk_no_deferred);
/* The default argument expression may cause implicitly defined
member functions to be synthesized, which will result in garbage
@@ -12069,6 +12104,8 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,
--function_depth;
pop_deferring_access_checks();
+ finish_lambda_scope ();
+
/* Restore the "this" pointer. */
if (cfun)
{
@@ -12125,415 +12162,466 @@ tsubst_default_arguments (tree fn, tsubst_flags_t complain)
complain);
}
-/* Substitute the ARGS into the T, which is a _DECL. Return the
- result of the substitution. Issue error and warning messages under
- control of COMPLAIN. */
+/* Subroutine of tsubst_decl for the case when T is a FUNCTION_DECL. */
static tree
-tsubst_decl (tree t, tree args, tsubst_flags_t complain)
+tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
+ tree lambda_fntype)
{
-#define RETURN(EXP) do { r = (EXP); goto out; } while(0)
- location_t saved_loc;
- tree r = NULL_TREE;
- tree in_decl = t;
+ tree gen_tmpl, argvec;
hashval_t hash = 0;
+ tree in_decl = t;
- /* Set the filename and linenumber to improve error-reporting. */
- saved_loc = input_location;
- input_location = DECL_SOURCE_LOCATION (t);
+ /* Nobody should be tsubst'ing into non-template functions. */
+ gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);
- switch (TREE_CODE (t))
+ if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
{
- case TEMPLATE_DECL:
- {
- /* We can get here when processing a member function template,
- member class template, or template template parameter. */
- tree decl = DECL_TEMPLATE_RESULT (t);
- tree spec;
- tree tmpl_args;
- tree full_args;
+ /* If T is not dependent, just return it. */
+ if (!uses_template_parms (DECL_TI_ARGS (t)))
+ return t;
- if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
- {
- /* Template template parameter is treated here. */
- tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- if (new_type == error_mark_node)
- r = error_mark_node;
- /* If we get a real template back, return it. This can happen in
- the context of most_specialized_partial_spec. */
- else if (TREE_CODE (new_type) == TEMPLATE_DECL)
- r = new_type;
- else
- /* The new TEMPLATE_DECL was built in
- reduce_template_parm_level. */
- r = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (new_type);
- break;
- }
+ /* Calculate the most general template of which R is a
+ specialization, and the complete set of arguments used to
+ specialize R. */
+ gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
+ argvec = tsubst_template_args (DECL_TI_ARGS
+ (DECL_TEMPLATE_RESULT
+ (DECL_TI_TEMPLATE (t))),
+ args, complain, in_decl);
+ if (argvec == error_mark_node)
+ return error_mark_node;
- /* We might already have an instance of this template.
- The ARGS are for the surrounding class type, so the
- full args contain the tsubst'd args for the context,
- plus the innermost args from the template decl. */
- tmpl_args = DECL_CLASS_TEMPLATE_P (t)
- ? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
- : DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t));
- /* Because this is a template, the arguments will still be
- dependent, even after substitution. If
- PROCESSING_TEMPLATE_DECL is not set, the dependency
- predicates will short-circuit. */
- ++processing_template_decl;
- full_args = tsubst_template_args (tmpl_args, args,
- complain, in_decl);
- --processing_template_decl;
- if (full_args == error_mark_node)
- RETURN (error_mark_node);
+ /* Check to see if we already have this specialization. */
+ if (!lambda_fntype)
+ {
+ hash = hash_tmpl_and_args (gen_tmpl, argvec);
+ if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
+ return spec;
+ }
- /* If this is a default template template argument,
- tsubst might not have changed anything. */
- if (full_args == tmpl_args)
- RETURN (t);
+ /* We can see more levels of arguments than parameters if
+ there was a specialization of a member template, like
+ this:
- hash = hash_tmpl_and_args (t, full_args);
- spec = retrieve_specialization (t, full_args, hash);
- if (spec != NULL_TREE)
- {
- r = spec;
- break;
- }
+ template <class T> struct S { template <class U> void f(); }
+ template <> template <class U> void S<int>::f(U);
- /* Make a new template decl. It will be similar to the
- original, but will record the current template arguments.
- We also create a new function declaration, which is just
- like the old one, but points to this new template, rather
- than the old one. */
- r = copy_decl (t);
- gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
- DECL_CHAIN (r) = NULL_TREE;
+ Here, we'll be substituting into the specialization,
+ because that's where we can find the code we actually
+ want to generate, but we'll have enough arguments for
+ the most general template.
- // Build new template info linking to the original template decl.
- DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+ We also deal with the peculiar case:
- if (TREE_CODE (decl) == TYPE_DECL
- && !TYPE_DECL_ALIAS_P (decl))
- {
- tree new_type;
- ++processing_template_decl;
- new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
- --processing_template_decl;
- if (new_type == error_mark_node)
- RETURN (error_mark_node);
+ template <class T> struct S {
+ template <class U> friend void f();
+ };
+ template <class U> void f() {}
+ template S<int>;
+ template void f<double>();
- TREE_TYPE (r) = new_type;
- /* For a partial specialization, we need to keep pointing to
- the primary template. */
- if (!DECL_TEMPLATE_SPECIALIZATION (t))
- CLASSTYPE_TI_TEMPLATE (new_type) = r;
- DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
- DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
- DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
- }
- else
- {
- tree new_decl;
- ++processing_template_decl;
- new_decl = tsubst (decl, args, complain, in_decl);
- --processing_template_decl;
- if (new_decl == error_mark_node)
- RETURN (error_mark_node);
+ Here, the ARGS for the instantiation of will be {int,
+ double}. But, we only need as many ARGS as there are
+ levels of template parameters in CODE_PATTERN. We are
+ careful not to get fooled into reducing the ARGS in
+ situations like:
- DECL_TEMPLATE_RESULT (r) = new_decl;
- DECL_TI_TEMPLATE (new_decl) = r;
- TREE_TYPE (r) = TREE_TYPE (new_decl);
- DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
- DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
- }
+ template <class T> struct S { template <class U> void f(U); }
+ template <class T> template <> void S<T>::f(int) {}
- SET_DECL_IMPLICIT_INSTANTIATION (r);
- DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
- DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
-
- /* The template parameters for this new template are all the
- template parameters for the old template, except the
- outermost level of parameters. */
- DECL_TEMPLATE_PARMS (r)
- = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
- complain);
-
- if (PRIMARY_TEMPLATE_P (t))
- DECL_PRIMARY_TEMPLATE (r) = r;
-
- if (TREE_CODE (decl) != TYPE_DECL && !VAR_P (decl))
- /* Record this non-type partial instantiation. */
- register_specialization (r, t,
- DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
- false, hash);
- }
- break;
+ which we can spot because the pattern will be a
+ specialization in this case. */
+ int args_depth = TMPL_ARGS_DEPTH (args);
+ int parms_depth =
+ TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t)));
- case FUNCTION_DECL:
+ if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t))
+ args = get_innermost_template_args (args, parms_depth);
+ }
+ else
+ {
+ /* This special case arises when we have something like this:
+
+ template <class T> struct S {
+ friend void f<int>(int, double);
+ };
+
+ Here, the DECL_TI_TEMPLATE for the friend declaration
+ will be an IDENTIFIER_NODE. We are being called from
+ tsubst_friend_function, and we want only to create a
+ new decl (R) with appropriate types so that we can call
+ determine_specialization. */
+ gen_tmpl = NULL_TREE;
+ argvec = NULL_TREE;
+ }
+
+ tree closure = (lambda_fntype ? TYPE_METHOD_BASETYPE (lambda_fntype)
+ : NULL_TREE);
+ tree ctx = closure ? closure : DECL_CONTEXT (t);
+ bool member = ctx && TYPE_P (ctx);
+
+ if (member && !closure)
+ ctx = tsubst_aggr_type (ctx, args,
+ complain, t, /*entering_scope=*/1);
+
+ tree type = (lambda_fntype ? lambda_fntype
+ : tsubst (TREE_TYPE (t), args,
+ complain | tf_fndecl_type, in_decl));
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ /* If we hit excessive deduction depth, the type is bogus even if
+ it isn't error_mark_node, so don't build a decl. */
+ if (excessive_deduction_depth)
+ return error_mark_node;
+
+ /* We do NOT check for matching decls pushed separately at this
+ point, as they may not represent instantiations of this
+ template, and in any case are considered separate under the
+ discrete model. */
+ tree r = copy_decl (t);
+ DECL_USE_TEMPLATE (r) = 0;
+ TREE_TYPE (r) = type;
+ /* Clear out the mangled name and RTL for the instantiation. */
+ SET_DECL_ASSEMBLER_NAME (r, NULL_TREE);
+ SET_DECL_RTL (r, NULL);
+ /* Leave DECL_INITIAL set on deleted instantiations. */
+ if (!DECL_DELETED_FN (r))
+ DECL_INITIAL (r) = NULL_TREE;
+ DECL_CONTEXT (r) = ctx;
+
+ /* OpenMP UDRs have the only argument a reference to the declared
+ type. We want to diagnose if the declared type is a reference,
+ which is invalid, but as references to references are usually
+ quietly merged, diagnose it here. */
+ if (DECL_OMP_DECLARE_REDUCTION_P (t))
+ {
+ tree argtype
+ = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t))));
+ argtype = tsubst (argtype, args, complain, in_decl);
+ if (TREE_CODE (argtype) == REFERENCE_TYPE)
+ error_at (DECL_SOURCE_LOCATION (t),
+ "reference type %qT in "
+ "%<#pragma omp declare reduction%>", argtype);
+ if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)
+ DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),
+ argtype);
+ }
+
+ if (member && DECL_CONV_FN_P (r))
+ /* Type-conversion operator. Reconstruct the name, in
+ case it's the name of one of the template's parameters. */
+ DECL_NAME (r) = make_conv_op_name (TREE_TYPE (type));
+
+ tree parms = DECL_ARGUMENTS (t);
+ if (closure)
+ parms = DECL_CHAIN (parms);
+ parms = tsubst (parms, args, complain, t);
+ for (tree parm = parms; parm; parm = DECL_CHAIN (parm))
+ DECL_CONTEXT (parm) = r;
+ if (closure)
+ {
+ tree tparm = build_this_parm (r, closure, type_memfn_quals (type));
+ DECL_CHAIN (tparm) = parms;
+ parms = tparm;
+ }
+ DECL_ARGUMENTS (r) = parms;
+ DECL_RESULT (r) = NULL_TREE;
+
+ TREE_STATIC (r) = 0;
+ TREE_PUBLIC (r) = TREE_PUBLIC (t);
+ DECL_EXTERNAL (r) = 1;
+ /* If this is an instantiation of a function with internal
+ linkage, we already know what object file linkage will be
+ assigned to the instantiation. */
+ DECL_INTERFACE_KNOWN (r) = !TREE_PUBLIC (r);
+ DECL_DEFER_OUTPUT (r) = 0;
+ DECL_CHAIN (r) = NULL_TREE;
+ DECL_PENDING_INLINE_INFO (r) = 0;
+ DECL_PENDING_INLINE_P (r) = 0;
+ DECL_SAVED_TREE (r) = NULL_TREE;
+ DECL_STRUCT_FUNCTION (r) = NULL;
+ TREE_USED (r) = 0;
+ /* We'll re-clone as appropriate in instantiate_template. */
+ DECL_CLONED_FUNCTION (r) = NULL_TREE;
+
+ /* If we aren't complaining now, return on error before we register
+ the specialization so that we'll complain eventually. */
+ if ((complain & tf_error) == 0
+ && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
+ && !grok_op_properties (r, /*complain=*/false))
+ return error_mark_node;
+
+ /* When instantiating a constrained member, substitute
+ into the constraints to create a new constraint. */
+ if (tree ci = get_constraints (t))
+ if (member)
{
- tree gen_tmpl, argvec;
+ ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);
+ set_constraints (r, ci);
+ }
- /* Nobody should be tsubst'ing into non-template functions. */
- gcc_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE);
+ /* Set up the DECL_TEMPLATE_INFO for R. There's no need to do
+ this in the special friend case mentioned above where
+ GEN_TMPL is NULL. */
+ if (gen_tmpl && !closure)
+ {
+ DECL_TEMPLATE_INFO (r)
+ = build_template_info (gen_tmpl, argvec);
+ SET_DECL_IMPLICIT_INSTANTIATION (r);
+
+ tree new_r
+ = register_specialization (r, gen_tmpl, argvec, false, hash);
+ if (new_r != r)
+ /* We instantiated this while substituting into
+ the type earlier (template/friend54.C). */
+ return new_r;
+
+ /* We're not supposed to instantiate default arguments
+ until they are called, for a template. But, for a
+ declaration like:
+
+ template <class T> void f ()
+ { extern void g(int i = T()); }
+
+ we should do the substitution when the template is
+ instantiated. We handle the member function case in
+ instantiate_class_template since the default arguments
+ might refer to other members of the class. */
+ if (!member
+ && !PRIMARY_TEMPLATE_P (gen_tmpl)
+ && !uses_template_parms (argvec))
+ tsubst_default_arguments (r, complain);
+ }
+ else
+ DECL_TEMPLATE_INFO (r) = NULL_TREE;
- if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
- {
- /* If T is not dependent, just return it. */
- if (!uses_template_parms (DECL_TI_ARGS (t)))
- RETURN (t);
-
- /* Calculate the most general template of which R is a
- specialization, and the complete set of arguments used to
- specialize R. */
- gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
- argvec = tsubst_template_args (DECL_TI_ARGS
- (DECL_TEMPLATE_RESULT
- (DECL_TI_TEMPLATE (t))),
- args, complain, in_decl);
- if (argvec == error_mark_node)
- RETURN (error_mark_node);
+ /* Copy the list of befriending classes. */
+ for (tree *friends = &DECL_BEFRIENDING_CLASSES (r);
+ *friends;
+ friends = &TREE_CHAIN (*friends))
+ {
+ *friends = copy_node (*friends);
+ TREE_VALUE (*friends)
+ = tsubst (TREE_VALUE (*friends), args, complain, in_decl);
+ }
- /* Check to see if we already have this specialization. */
- hash = hash_tmpl_and_args (gen_tmpl, argvec);
- if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash))
- {
- r = spec;
- break;
- }
+ if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))
+ {
+ maybe_retrofit_in_chrg (r);
+ if (DECL_CONSTRUCTOR_P (r) && !grok_ctor_properties (ctx, r))
+ return error_mark_node;
+ /* If this is an instantiation of a member template, clone it.
+ If it isn't, that'll be handled by
+ clone_constructors_and_destructors. */
+ if (PRIMARY_TEMPLATE_P (gen_tmpl))
+ clone_function_decl (r, /*update_methods=*/false);
+ }
+ else if ((complain & tf_error) != 0
+ && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
+ && !grok_op_properties (r, /*complain=*/true))
+ return error_mark_node;
- /* We can see more levels of arguments than parameters if
- there was a specialization of a member template, like
- this:
+ if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
+ SET_DECL_FRIEND_CONTEXT (r,
+ tsubst (DECL_FRIEND_CONTEXT (t),
+ args, complain, in_decl));
- template <class T> struct S { template <class U> void f(); }
- template <> template <class U> void S<int>::f(U);
+ /* Possibly limit visibility based on template args. */
+ DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
+ if (DECL_VISIBILITY_SPECIFIED (t))
+ {
+ DECL_VISIBILITY_SPECIFIED (r) = 0;
+ DECL_ATTRIBUTES (r)
+ = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
+ }
+ determine_visibility (r);
+ if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
+ && !processing_template_decl)
+ defaulted_late_check (r);
- Here, we'll be substituting into the specialization,
- because that's where we can find the code we actually
- want to generate, but we'll have enough arguments for
- the most general template.
+ apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
+ args, complain, in_decl);
+ return r;
+}
- We also deal with the peculiar case:
+/* Subroutine of tsubst_decl for the case when T is a TEMPLATE_DECL. */
- template <class T> struct S {
- template <class U> friend void f();
- };
- template <class U> void f() {}
- template S<int>;
- template void f<double>();
+static tree
+tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
+ tree lambda_fntype)
+{
+ /* We can get here when processing a member function template,
+ member class template, or template template parameter. */
+ tree decl = DECL_TEMPLATE_RESULT (t);
+ tree in_decl = t;
+ tree spec;
+ tree tmpl_args;
+ tree full_args;
+ tree r;
+ hashval_t hash = 0;
- Here, the ARGS for the instantiation of will be {int,
- double}. But, we only need as many ARGS as there are
- levels of template parameters in CODE_PATTERN. We are
- careful not to get fooled into reducing the ARGS in
- situations like:
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+ {
+ /* Template template parameter is treated here. */
+ tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ if (new_type == error_mark_node)
+ r = error_mark_node;
+ /* If we get a real template back, return it. This can happen in
+ the context of most_specialized_partial_spec. */
+ else if (TREE_CODE (new_type) == TEMPLATE_DECL)
+ r = new_type;
+ else
+ /* The new TEMPLATE_DECL was built in
+ reduce_template_parm_level. */
+ r = TEMPLATE_TEMPLATE_PARM_TEMPLATE_DECL (new_type);
+ return r;
+ }
- template <class T> struct S { template <class U> void f(U); }
- template <class T> template <> void S<T>::f(int) {}
+ if (!lambda_fntype)
+ {
+ /* We might already have an instance of this template.
+ The ARGS are for the surrounding class type, so the
+ full args contain the tsubst'd args for the context,
+ plus the innermost args from the template decl. */
+ tmpl_args = DECL_CLASS_TEMPLATE_P (t)
+ ? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
+ : DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t));
+ /* Because this is a template, the arguments will still be
+ dependent, even after substitution. If
+ PROCESSING_TEMPLATE_DECL is not set, the dependency
+ predicates will short-circuit. */
+ ++processing_template_decl;
+ full_args = tsubst_template_args (tmpl_args, args,
+ complain, in_decl);
+ --processing_template_decl;
+ if (full_args == error_mark_node)
+ return error_mark_node;
- which we can spot because the pattern will be a
- specialization in this case. */
- int args_depth = TMPL_ARGS_DEPTH (args);
- int parms_depth =
- TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t)));
+ /* If this is a default template template argument,
+ tsubst might not have changed anything. */
+ if (full_args == tmpl_args)
+ return t;
- if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t))
- args = get_innermost_template_args (args, parms_depth);
- }
- else
- {
- /* This special case arises when we have something like this:
-
- template <class T> struct S {
- friend void f<int>(int, double);
- };
-
- Here, the DECL_TI_TEMPLATE for the friend declaration
- will be an IDENTIFIER_NODE. We are being called from
- tsubst_friend_function, and we want only to create a
- new decl (R) with appropriate types so that we can call
- determine_specialization. */
- gen_tmpl = NULL_TREE;
- argvec = NULL_TREE;
- }
+ hash = hash_tmpl_and_args (t, full_args);
+ spec = retrieve_specialization (t, full_args, hash);
+ if (spec != NULL_TREE)
+ return spec;
+ }
- tree ctx = DECL_CONTEXT (t);
- bool member = ctx && TYPE_P (ctx);
+ /* Make a new template decl. It will be similar to the
+ original, but will record the current template arguments.
+ We also create a new function declaration, which is just
+ like the old one, but points to this new template, rather
+ than the old one. */
+ r = copy_decl (t);
+ gcc_assert (DECL_LANG_SPECIFIC (r) != 0);
+ DECL_CHAIN (r) = NULL_TREE;
- if (member)
- ctx = tsubst_aggr_type (ctx, args,
- complain, t, /*entering_scope=*/1);
+ // Build new template info linking to the original template decl.
+ if (!lambda_fntype)
+ {
+ DECL_TEMPLATE_INFO (r) = build_template_info (t, args);
+ SET_DECL_IMPLICIT_INSTANTIATION (r);
+ }
+ else
+ DECL_TEMPLATE_INFO (r) = NULL_TREE;
- tree type = tsubst (TREE_TYPE (t), args,
- complain | tf_fndecl_type, in_decl);
- if (type == error_mark_node)
- RETURN (error_mark_node);
+ /* The template parameters for this new template are all the
+ template parameters for the old template, except the
+ outermost level of parameters. */
+ DECL_TEMPLATE_PARMS (r)
+ = tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args,
+ complain);
- /* If we hit excessive deduction depth, the type is bogus even if
- it isn't error_mark_node, so don't build a decl. */
- if (excessive_deduction_depth)
- RETURN (error_mark_node);
+ if (TREE_CODE (decl) == TYPE_DECL
+ && !TYPE_DECL_ALIAS_P (decl))
+ {
+ tree new_type;
+ ++processing_template_decl;
+ new_type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ --processing_template_decl;
+ if (new_type == error_mark_node)
+ return error_mark_node;
- /* We do NOT check for matching decls pushed separately at this
- point, as they may not represent instantiations of this
- template, and in any case are considered separate under the
- discrete model. */
- r = copy_decl (t);
- DECL_USE_TEMPLATE (r) = 0;
- TREE_TYPE (r) = type;
- /* Clear out the mangled name and RTL for the instantiation. */
- SET_DECL_ASSEMBLER_NAME (r, NULL_TREE);
- SET_DECL_RTL (r, NULL);
- /* Leave DECL_INITIAL set on deleted instantiations. */
- if (!DECL_DELETED_FN (r))
- DECL_INITIAL (r) = NULL_TREE;
- DECL_CONTEXT (r) = ctx;
+ TREE_TYPE (r) = new_type;
+ /* For a partial specialization, we need to keep pointing to
+ the primary template. */
+ if (!DECL_TEMPLATE_SPECIALIZATION (t))
+ CLASSTYPE_TI_TEMPLATE (new_type) = r;
+ DECL_TEMPLATE_RESULT (r) = TYPE_MAIN_DECL (new_type);
+ DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
+ DECL_CONTEXT (r) = TYPE_CONTEXT (new_type);
+ }
+ else
+ {
+ tree new_decl;
+ ++processing_template_decl;
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ new_decl = tsubst_function_decl (decl, args, complain, lambda_fntype);
+ else
+ new_decl = tsubst (decl, args, complain, in_decl);
+ --processing_template_decl;
+ if (new_decl == error_mark_node)
+ return error_mark_node;
- /* OpenMP UDRs have the only argument a reference to the declared
- type. We want to diagnose if the declared type is a reference,
- which is invalid, but as references to references are usually
- quietly merged, diagnose it here. */
- if (DECL_OMP_DECLARE_REDUCTION_P (t))
- {
- tree argtype
- = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (t))));
- argtype = tsubst (argtype, args, complain, in_decl);
- if (TREE_CODE (argtype) == REFERENCE_TYPE)
- error_at (DECL_SOURCE_LOCATION (t),
- "reference type %qT in "
- "%<#pragma omp declare reduction%>", argtype);
- if (strchr (IDENTIFIER_POINTER (DECL_NAME (t)), '~') == NULL)
- DECL_NAME (r) = omp_reduction_id (ERROR_MARK, DECL_NAME (t),
- argtype);
- }
+ DECL_TEMPLATE_RESULT (r) = new_decl;
+ TREE_TYPE (r) = TREE_TYPE (new_decl);
+ DECL_CONTEXT (r) = DECL_CONTEXT (new_decl);
+ if (lambda_fntype)
+ {
+ tree args = template_parms_to_args (DECL_TEMPLATE_PARMS (r));
+ DECL_TEMPLATE_INFO (new_decl) = build_template_info (r, args);
+ }
+ else
+ {
+ DECL_TI_TEMPLATE (new_decl) = r;
+ DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
+ }
+ }
- if (member && DECL_CONV_FN_P (r))
- /* Type-conversion operator. Reconstruct the name, in
- case it's the name of one of the template's parameters. */
- DECL_NAME (r) = make_conv_op_name (TREE_TYPE (type));
-
- DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args,
- complain, t);
- for (tree parm = DECL_ARGUMENTS (r); parm; parm = DECL_CHAIN (parm))
- DECL_CONTEXT (parm) = r;
- DECL_RESULT (r) = NULL_TREE;
-
- TREE_STATIC (r) = 0;
- TREE_PUBLIC (r) = TREE_PUBLIC (t);
- DECL_EXTERNAL (r) = 1;
- /* If this is an instantiation of a function with internal
- linkage, we already know what object file linkage will be
- assigned to the instantiation. */
- DECL_INTERFACE_KNOWN (r) = !TREE_PUBLIC (r);
- DECL_DEFER_OUTPUT (r) = 0;
- DECL_CHAIN (r) = NULL_TREE;
- DECL_PENDING_INLINE_INFO (r) = 0;
- DECL_PENDING_INLINE_P (r) = 0;
- DECL_SAVED_TREE (r) = NULL_TREE;
- DECL_STRUCT_FUNCTION (r) = NULL;
- TREE_USED (r) = 0;
- /* We'll re-clone as appropriate in instantiate_template. */
- DECL_CLONED_FUNCTION (r) = NULL_TREE;
-
- /* If we aren't complaining now, return on error before we register
- the specialization so that we'll complain eventually. */
- if ((complain & tf_error) == 0
- && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
- && !grok_op_properties (r, /*complain=*/false))
- RETURN (error_mark_node);
+ DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
+ DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
- /* When instantiating a constrained member, substitute
- into the constraints to create a new constraint. */
- if (tree ci = get_constraints (t))
- if (member)
- {
- ci = tsubst_constraint_info (ci, argvec, complain, NULL_TREE);
- set_constraints (r, ci);
- }
+ if (PRIMARY_TEMPLATE_P (t))
+ DECL_PRIMARY_TEMPLATE (r) = r;
- /* Set up the DECL_TEMPLATE_INFO for R. There's no need to do
- this in the special friend case mentioned above where
- GEN_TMPL is NULL. */
- if (gen_tmpl)
- {
- DECL_TEMPLATE_INFO (r)
- = build_template_info (gen_tmpl, argvec);
- SET_DECL_IMPLICIT_INSTANTIATION (r);
+ if (TREE_CODE (decl) != TYPE_DECL && !VAR_P (decl)
+ && !lambda_fntype)
+ /* Record this non-type partial instantiation. */
+ register_specialization (r, t,
+ DECL_TI_ARGS (DECL_TEMPLATE_RESULT (r)),
+ false, hash);
- tree new_r
- = register_specialization (r, gen_tmpl, argvec, false, hash);
- if (new_r != r)
- /* We instantiated this while substituting into
- the type earlier (template/friend54.C). */
- RETURN (new_r);
-
- /* We're not supposed to instantiate default arguments
- until they are called, for a template. But, for a
- declaration like:
-
- template <class T> void f ()
- { extern void g(int i = T()); }
-
- we should do the substitution when the template is
- instantiated. We handle the member function case in
- instantiate_class_template since the default arguments
- might refer to other members of the class. */
- if (!member
- && !PRIMARY_TEMPLATE_P (gen_tmpl)
- && !uses_template_parms (argvec))
- tsubst_default_arguments (r, complain);
- }
- else
- DECL_TEMPLATE_INFO (r) = NULL_TREE;
+ return r;
+}
- /* Copy the list of befriending classes. */
- for (tree *friends = &DECL_BEFRIENDING_CLASSES (r);
- *friends;
- friends = &TREE_CHAIN (*friends))
- {
- *friends = copy_node (*friends);
- TREE_VALUE (*friends)
- = tsubst (TREE_VALUE (*friends), args, complain, in_decl);
- }
+/* Substitute the ARGS into the T, which is a _DECL. Return the
+ result of the substitution. Issue error and warning messages under
+ control of COMPLAIN. */
- if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r))
- {
- maybe_retrofit_in_chrg (r);
- if (DECL_CONSTRUCTOR_P (r) && !grok_ctor_properties (ctx, r))
- RETURN (error_mark_node);
- /* If this is an instantiation of a member template, clone it.
- If it isn't, that'll be handled by
- clone_constructors_and_destructors. */
- if (PRIMARY_TEMPLATE_P (gen_tmpl))
- clone_function_decl (r, /*update_methods=*/false);
- }
- else if ((complain & tf_error) != 0
- && IDENTIFIER_ANY_OP_P (DECL_NAME (r))
- && !grok_op_properties (r, /*complain=*/true))
- RETURN (error_mark_node);
+static tree
+tsubst_decl (tree t, tree args, tsubst_flags_t complain)
+{
+#define RETURN(EXP) do { r = (EXP); goto out; } while(0)
+ location_t saved_loc;
+ tree r = NULL_TREE;
+ tree in_decl = t;
+ hashval_t hash = 0;
- if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
- SET_DECL_FRIEND_CONTEXT (r,
- tsubst (DECL_FRIEND_CONTEXT (t),
- args, complain, in_decl));
+ /* Set the filename and linenumber to improve error-reporting. */
+ saved_loc = input_location;
+ input_location = DECL_SOURCE_LOCATION (t);
- /* Possibly limit visibility based on template args. */
- DECL_VISIBILITY (r) = VISIBILITY_DEFAULT;
- if (DECL_VISIBILITY_SPECIFIED (t))
- {
- DECL_VISIBILITY_SPECIFIED (r) = 0;
- DECL_ATTRIBUTES (r)
- = remove_attribute ("visibility", DECL_ATTRIBUTES (r));
- }
- determine_visibility (r);
- if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r)
- && !processing_template_decl)
- defaulted_late_check (r);
+ switch (TREE_CODE (t))
+ {
+ case TEMPLATE_DECL:
+ r = tsubst_template_decl (t, args, complain, /*lambda*/NULL_TREE);
+ break;
- apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0,
- args, complain, in_decl);
- }
+ case FUNCTION_DECL:
+ r = tsubst_function_decl (t, args, complain, /*lambda*/NULL_TREE);
break;
case PARM_DECL:
@@ -15862,6 +15950,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
instantiate the elements directly as needed. */
break;
}
+ else if (is_capture_proxy (decl)
+ && !DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+ {
+ /* We're in tsubst_lambda_expr, we've already inserted new capture
+ proxies, and uses will find them with lookup_name. */
+ break;
+ }
+ else if (DECL_IMPLICIT_TYPEDEF_P (decl)
+ && LAMBDA_TYPE_P (TREE_TYPE (decl)))
+ /* Don't copy the old closure; we'll create a new one in
+ tsubst_lambda_expr. */
+ break;
else
{
init = DECL_INITIAL (decl);
@@ -16659,6 +16759,149 @@ tsubst_non_call_postfix_expression (tree t, tree args,
return t;
}
+/* T is a LAMBDA_EXPR. Generate a new LAMBDA_EXPR for the current
+ instantiation context. Instantiating a pack expansion containing a lambda
+ might result in multiple lambdas all based on the same lambda in the
+ template. */
+
+tree
+tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ tree oldfn = lambda_function (t);
+ in_decl = oldfn;
+
+ tree r = build_lambda_expr ();
+
+ LAMBDA_EXPR_LOCATION (r)
+ = LAMBDA_EXPR_LOCATION (t);
+ LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
+ = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
+ LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
+
+ if (LAMBDA_EXPR_EXTRA_SCOPE (t) == NULL_TREE)
+ LAMBDA_EXPR_EXTRA_SCOPE (r) = NULL_TREE;
+ else
+ record_lambda_scope (r);
+
+ gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
+ && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
+
+ for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (t); cap;
+ cap = TREE_CHAIN (cap))
+ {
+ tree field = TREE_PURPOSE (cap);
+ if (PACK_EXPANSION_P (field))
+ field = PACK_EXPANSION_PATTERN (field);
+ field = tsubst_decl (field, args, complain);
+
+ if (field == error_mark_node)
+ return error_mark_node;
+
+ tree init = TREE_VALUE (cap);
+ if (PACK_EXPANSION_P (init))
+ init = tsubst_pack_expansion (init, args, complain, in_decl);
+ else
+ init = tsubst_copy_and_build (init, args, complain, in_decl,
+ /*fn*/false, /*constexpr*/false);
+
+ if (TREE_CODE (field) == TREE_VEC)
+ {
+ int len = TREE_VEC_LENGTH (field);
+ gcc_assert (TREE_CODE (init) == TREE_VEC
+ && TREE_VEC_LENGTH (init) == len);
+ for (int i = 0; i < len; ++i)
+ LAMBDA_EXPR_CAPTURE_LIST (r)
+ = tree_cons (TREE_VEC_ELT (field, i),
+ TREE_VEC_ELT (init, i),
+ LAMBDA_EXPR_CAPTURE_LIST (r));
+ }
+ else
+ {
+ LAMBDA_EXPR_CAPTURE_LIST (r)
+ = tree_cons (field, init, LAMBDA_EXPR_CAPTURE_LIST (r));
+
+ if (id_equal (DECL_NAME (field), "__this"))
+ LAMBDA_EXPR_THIS_CAPTURE (r) = field;
+ }
+ }
+
+ tree type = begin_lambda_type (r);
+
+ /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
+ determine_visibility (TYPE_NAME (type));
+
+ register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (r));
+
+ tree oldtmpl = (generic_lambda_fn_p (oldfn)
+ ? DECL_TI_TEMPLATE (oldfn)
+ : NULL_TREE);
+
+ tree fntype = static_fn_type (oldfn);
+ if (oldtmpl)
+ ++processing_template_decl;
+ fntype = tsubst (fntype, args, complain, in_decl);
+ if (oldtmpl)
+ --processing_template_decl;
+
+ if (fntype == error_mark_node)
+ r = error_mark_node;
+ else
+ {
+ /* Fix the type of 'this'. */
+ fntype = build_memfn_type (fntype, type,
+ type_memfn_quals (fntype),
+ type_memfn_rqual (fntype));
+ tree fn, tmpl;
+ if (oldtmpl)
+ {
+ tmpl = tsubst_template_decl (oldtmpl, args, complain, fntype);
+ fn = DECL_TEMPLATE_RESULT (tmpl);
+ finish_member_declaration (tmpl);
+ }
+ else
+ {
+ tmpl = NULL_TREE;
+ fn = tsubst_function_decl (oldfn, args, complain, fntype);
+ finish_member_declaration (fn);
+ }
+
+ /* Let finish_function set this. */
+ DECL_DECLARED_CONSTEXPR_P (fn) = false;
+
+ bool nested = cfun;
+ if (nested)
+ push_function_context ();
+
+ tree body = start_lambda_function (fn, r);
+
+ local_specialization_stack s (lss_copy);
+
+ register_parameter_specializations (oldfn, fn);
+
+ tsubst_expr (DECL_SAVED_TREE (oldfn), args, complain, r,
+ /*constexpr*/false);
+
+ finish_lambda_function (body);
+
+ if (nested)
+ pop_function_context ();
+
+ /* The capture list was built up in reverse order; fix that now. */
+ LAMBDA_EXPR_CAPTURE_LIST (r)
+ = nreverse (LAMBDA_EXPR_CAPTURE_LIST (r));
+
+ LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;
+
+ maybe_add_lambda_conv_op (type);
+ }
+
+ finish_struct (type, /*attr*/NULL_TREE);
+
+ insert_pending_capture_proxies ();
+
+ return r;
+}
+
/* Like tsubst but deals with expressions and performs semantic
analysis. FUNCTION_P is true if T is the "F" in "F (ARGS)". */
@@ -17861,7 +18104,7 @@ tsubst_copy_and_build (tree t,
else if (outer_automatic_var_p (r))
{
r = process_outer_var_ref (r, complain);
- if (is_capture_proxy (r))
+ if (is_capture_proxy (r) && !DECL_PACK_P (t))
register_local_specialization (r, t);
}
@@ -17929,59 +18172,7 @@ tsubst_copy_and_build (tree t,
case LAMBDA_EXPR:
{
- tree r = build_lambda_expr ();
-
- tree type = tsubst (LAMBDA_EXPR_CLOSURE (t), args, complain, NULL_TREE);
- LAMBDA_EXPR_CLOSURE (r) = type;
- CLASSTYPE_LAMBDA_EXPR (type) = r;
-
- LAMBDA_EXPR_LOCATION (r)
- = LAMBDA_EXPR_LOCATION (t);
- LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (r)
- = LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (t);
- LAMBDA_EXPR_MUTABLE_P (r) = LAMBDA_EXPR_MUTABLE_P (t);
- LAMBDA_EXPR_DISCRIMINATOR (r)
- = (LAMBDA_EXPR_DISCRIMINATOR (t));
- tree scope = LAMBDA_EXPR_EXTRA_SCOPE (t);
- if (!scope)
- /* No substitution needed. */;
- else if (VAR_OR_FUNCTION_DECL_P (scope))
- /* For a function or variable scope, we want to use tsubst so that we
- don't complain about referring to an auto before deduction. */
- scope = tsubst (scope, args, complain, in_decl);
- else if (TREE_CODE (scope) == PARM_DECL)
- {
- /* Look up the parameter we want directly, as tsubst_copy
- doesn't do what we need. */
- tree fn = tsubst (DECL_CONTEXT (scope), args, complain, in_decl);
- tree parm = FUNCTION_FIRST_USER_PARM (fn);
- while (DECL_PARM_INDEX (parm) != DECL_PARM_INDEX (scope))
- parm = DECL_CHAIN (parm);
- scope = parm;
- /* FIXME Work around the parm not having DECL_CONTEXT set. */
- if (DECL_CONTEXT (scope) == NULL_TREE)
- DECL_CONTEXT (scope) = fn;
- }
- else if (TREE_CODE (scope) == FIELD_DECL)
- /* For a field, use tsubst_copy so that we look up the existing field
- rather than build a new one. */
- scope = RECUR (scope);
- else
- gcc_unreachable ();
- LAMBDA_EXPR_EXTRA_SCOPE (r) = scope;
-
- gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (t) == NULL_TREE
- && LAMBDA_EXPR_PENDING_PROXIES (t) == NULL);
-
- /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
- determine_visibility (TYPE_NAME (type));
- /* Now that we know visibility, instantiate the type so we have a
- declaration of the op() for later calls to lambda_function. */
- complete_type (type);
-
- LAMBDA_EXPR_THIS_CAPTURE (r) = NULL_TREE;
-
- insert_pending_capture_proxies ();
+ tree r = tsubst_lambda_expr (t, args, complain, in_decl);
RETURN (build_lambda_object (r));
}
@@ -22434,10 +22625,12 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args)
}
else if (VAR_P (decl))
{
+ start_lambda_scope (decl);
DECL_INITIAL (decl) =
tsubst_expr (DECL_INITIAL (code_pattern), args,
tf_error, DECL_TI_TEMPLATE (decl),
/*integral_constant_expression_p=*/false);
+ finish_lambda_scope ();
if (VAR_HAD_UNKNOWN_BOUND (decl))
TREE_TYPE (decl) = tsubst (TREE_TYPE (code_pattern), args,
tf_error, DECL_TI_TEMPLATE (decl));
@@ -22605,6 +22798,38 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
return true;
}
+/* We're starting to process the function INST, an instantiation of PATTERN;
+ add their parameters to local_specializations. */
+
+static void
+register_parameter_specializations (tree pattern, tree inst)
+{
+ tree tmpl_parm = DECL_ARGUMENTS (pattern);
+ tree spec_parm = DECL_ARGUMENTS (inst);
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (inst))
+ {
+ register_local_specialization (spec_parm, tmpl_parm);
+ spec_parm = skip_artificial_parms_for (inst, spec_parm);
+ tmpl_parm = skip_artificial_parms_for (pattern, tmpl_parm);
+ }
+ for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
+ {
+ if (!DECL_PACK_P (tmpl_parm))
+ {
+ register_local_specialization (spec_parm, tmpl_parm);
+ spec_parm = DECL_CHAIN (spec_parm);
+ }
+ else
+ {
+ /* Register the (value) argument pack as a specialization of
+ TMPL_PARM, then move on. */
+ tree argpack = extract_fnparm_pack (tmpl_parm, &spec_parm);
+ register_local_specialization (argpack, tmpl_parm);
+ }
+ }
+ gcc_assert (!spec_parm);
+}
+
/* Produce the definition of D, a _DECL generated from a template. If
DEFER_OK is true, then we don't have to actually do the
instantiation now; we just have to do it sometime. Normally it is
@@ -22939,10 +23164,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
else if (TREE_CODE (d) == FUNCTION_DECL)
{
hash_map<tree, tree> *saved_local_specializations;
- tree tmpl_parm;
- tree spec_parm;
tree block = NULL_TREE;
- tree lambda_ctx = NULL_TREE;
/* Save away the current list, in case we are instantiating one
template from within the body of another. */
@@ -22956,23 +23178,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
&& TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
block = push_stmt_list ();
else
- {
- if (push_to_top && LAMBDA_FUNCTION_P (d))
- {
- /* When instantiating a lambda's templated function
- operator, we need to push the non-lambda class scope
- of the lambda itself so that the nested function
- stack is sufficiently correct to deal with this
- capture. */
- lambda_ctx = DECL_CONTEXT (d);
- do
- lambda_ctx = decl_type_context (TYPE_NAME (lambda_ctx));
- while (lambda_ctx && LAMBDA_TYPE_P (lambda_ctx));
- if (lambda_ctx)
- push_nested_class (lambda_ctx);
- }
- start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
- }
+ start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
/* Some typedefs referenced from within the template code need to be
access checked at template instantiation time, i.e now. These
@@ -22982,30 +23188,7 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
args);
/* Create substitution entries for the parameters. */
- tmpl_parm = DECL_ARGUMENTS (code_pattern);
- spec_parm = DECL_ARGUMENTS (d);
- if (DECL_NONSTATIC_MEMBER_FUNCTION_P (d))
- {
- register_local_specialization (spec_parm, tmpl_parm);
- spec_parm = skip_artificial_parms_for (d, spec_parm);
- tmpl_parm = skip_artificial_parms_for (code_pattern, tmpl_parm);
- }
- for (; tmpl_parm; tmpl_parm = DECL_CHAIN (tmpl_parm))
- {
- if (!DECL_PACK_P (tmpl_parm))
- {
- register_local_specialization (spec_parm, tmpl_parm);
- spec_parm = DECL_CHAIN (spec_parm);
- }
- else
- {
- /* Register the (value) argument pack as a specialization of
- TMPL_PARM, then move on. */
- tree argpack = extract_fnparm_pack (tmpl_parm, &spec_parm);
- register_local_specialization (argpack, tmpl_parm);
- }
- }
- gcc_assert (!spec_parm);
+ register_parameter_specializations (code_pattern, d);
/* Substitute into the body of the function. */
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
@@ -23040,8 +23223,6 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
d = finish_function (0);
expand_or_defer_fn (d);
}
- if (lambda_ctx)
- pop_nested_class ();
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
cp_check_omp_declare_reduction (d);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index fe118cd..8f28221 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3301,40 +3301,56 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
if (!mark_used (decl, complain))
return error_mark_node;
- bool saw_generic_lambda = false;
if (parsing_nsdmi ())
containing_function = NULL_TREE;
- else
- /* If we are in a lambda function, we can move out until we hit
- 1. the context,
- 2. a non-lambda function, or
- 3. a non-default capturing lambda function. */
- while (context != containing_function
- /* containing_function can be null with invalid generic lambdas. */
- && containing_function
- && LAMBDA_FUNCTION_P (containing_function))
- {
- tree closure = DECL_CONTEXT (containing_function);
- lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure);
- if (generic_lambda_fn_p (containing_function))
- saw_generic_lambda = true;
+ if (containing_function && DECL_TEMPLATE_INFO (context)
+ && LAMBDA_FUNCTION_P (containing_function))
+ {
+ /* Check whether we've already built a proxy;
+ insert_pending_capture_proxies doesn't update
+ local_specializations. */
+ tree d = lookup_name (DECL_NAME (decl));
+ if (d && is_capture_proxy (d)
+ && DECL_CONTEXT (d) == containing_function)
+ return d;
+ }
- if (TYPE_CLASS_SCOPE_P (closure))
- /* A lambda in an NSDMI (c++/64496). */
- break;
+ /* If we are in a lambda function, we can move out until we hit
+ 1. the context,
+ 2. a non-lambda function, or
+ 3. a non-default capturing lambda function. */
+ while (context != containing_function
+ /* containing_function can be null with invalid generic lambdas. */
+ && containing_function
+ && LAMBDA_FUNCTION_P (containing_function))
+ {
+ tree closure = DECL_CONTEXT (containing_function);
+ lambda_expr = CLASSTYPE_LAMBDA_EXPR (closure);
- if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
- == CPLD_NONE)
- break;
+ if (TYPE_CLASS_SCOPE_P (closure))
+ /* A lambda in an NSDMI (c++/64496). */
+ break;
- lambda_stack = tree_cons (NULL_TREE,
- lambda_expr,
- lambda_stack);
+ if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
+ == CPLD_NONE)
+ break;
- containing_function
- = decl_function_context (containing_function);
- }
+ lambda_stack = tree_cons (NULL_TREE,
+ lambda_expr,
+ lambda_stack);
+
+ containing_function
+ = decl_function_context (containing_function);
+ }
+
+ /* In a lambda within a template, wait until instantiation
+ time to implicitly capture. */
+ if (context == containing_function
+ && DECL_TEMPLATE_INFO (containing_function)
+ && any_dependent_template_arguments_p (DECL_TI_ARGS
+ (containing_function)))
+ return decl;
/* Core issue 696: "[At the July 2009 meeting] the CWG expressed
support for an approach in which a reference to a local
@@ -3343,26 +3359,11 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
the complexity of the problem"
FIXME update for final resolution of core issue 696. */
- if (decl_maybe_constant_var_p (decl))
- {
- if (processing_template_decl && !saw_generic_lambda)
- /* In a non-generic lambda within a template, wait until instantiation
- time to decide whether to capture. For a generic lambda, we can't
- wait until we instantiate the op() because the closure class is
- already defined at that point. FIXME to get the semantics exactly
- right we need to partially-instantiate the lambda body so the only
- dependencies left are on the generic parameters themselves. This
- probably means moving away from our current model of lambdas in
- templates (instantiating the closure type) to one based on creating
- the closure type when instantiating the lambda context. That is
- probably also the way to handle lambdas within pack expansions. */
- return decl;
- else if (decl_constant_var_p (decl))
- {
- tree t = maybe_constant_value (convert_from_reference (decl));
- if (TREE_CONSTANT (t))
- return t;
- }
+ if (decl_constant_var_p (decl))
+ {
+ tree t = maybe_constant_value (convert_from_reference (decl));
+ if (TREE_CONSTANT (t))
+ return t;
}
if (lambda_expr && VAR_P (decl)