gcc_assert (!spec_parm);
}
+/* Instantiate the body of D using PATTERN with ARGS. We have
+ already determined PATTERN is the correct template to use. */
+
+static void
+instantiate_body (tree pattern, tree args, tree d)
+{
+ gcc_checking_assert (TREE_CODE (pattern) == TEMPLATE_DECL);
+
+ tree td = pattern;
+ tree code_pattern = DECL_TEMPLATE_RESULT (td);
+
+ tree fn_context = decl_function_context (d);
+ if (LAMBDA_FUNCTION_P (d))
+ /* tsubst_lambda_expr resolved any references to enclosing functions. */
+ fn_context = NULL_TREE;
+ bool nested = current_function_decl != NULL_TREE;
+ bool push_to_top = !(nested && fn_context == current_function_decl);
+
+ vec<tree> omp_privatization_save;
+ if (nested)
+ save_omp_privatization_clauses (omp_privatization_save);
+
+ if (push_to_top)
+ push_to_top_level ();
+ else
+ {
+ gcc_assert (!processing_template_decl);
+ push_function_context ();
+ cp_unevaluated_operand = 0;
+ c_inhibit_evaluation_warnings = 0;
+ }
+
+ if (VAR_P (d))
+ {
+ /* The variable might be a lambda's extra scope, and that
+ lambda's visibility depends on D's. */
+ maybe_commonize_var (d);
+ determine_visibility (d);
+ }
+
+ /* Mark D as instantiated so that recursive calls to
+ instantiate_decl do not try to instantiate it again. */
+ DECL_TEMPLATE_INSTANTIATED (d) = 1;
+
+ /* Regenerate the declaration in case the template has been modified
+ by a subsequent redeclaration. */
+ regenerate_decl_from_template (d, td, args);
+
+ /* We already set the file and line above. Reset them now in case
+ they changed as a result of calling regenerate_decl_from_template. */
+ input_location = DECL_SOURCE_LOCATION (d);
+
+ if (VAR_P (d))
+ {
+ tree init;
+ bool const_init = false;
+
+ /* Clear out DECL_RTL; whatever was there before may not be right
+ since we've reset the type of the declaration. */
+ SET_DECL_RTL (d, NULL);
+ DECL_IN_AGGR_P (d) = 0;
+
+ /* The initializer is placed in DECL_INITIAL by
+ regenerate_decl_from_template so we don't need to
+ push/pop_access_scope again here. Pull it out so that
+ cp_finish_decl can process it. */
+ init = DECL_INITIAL (d);
+ DECL_INITIAL (d) = NULL_TREE;
+ DECL_INITIALIZED_P (d) = 0;
+
+ /* Clear DECL_EXTERNAL so that cp_finish_decl will process the
+ initializer. That function will defer actual emission until
+ we have a chance to determine linkage. */
+ DECL_EXTERNAL (d) = 0;
+
+ /* Enter the scope of D so that access-checking works correctly. */
+ bool enter_context = DECL_CLASS_SCOPE_P (d);
+ if (enter_context)
+ push_nested_class (DECL_CONTEXT (d));
+
+ const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
+ cp_finish_decl (d, init, const_init, NULL_TREE, 0);
+
+ if (enter_context)
+ pop_nested_class ();
+ }
+ else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern))
+ synthesize_method (d);
+ else if (TREE_CODE (d) == FUNCTION_DECL)
+ {
+ /* Set up the list of local specializations. */
+ local_specialization_stack lss (push_to_top ? lss_blank : lss_copy);
+ tree block = NULL_TREE;
+
+ /* Set up context. */
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
+ && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
+ block = push_stmt_list ();
+ else
+ start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
+
+ perform_instantiation_time_access_checks (code_pattern, args);
+
+ /* Create substitution entries for the parameters. */
+ register_parameter_specializations (code_pattern, d);
+
+ /* Substitute into the body of the function. */
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
+ tsubst_omp_udr (DECL_SAVED_TREE (code_pattern), args,
+ tf_warning_or_error, DECL_TI_TEMPLATE (d));
+ else
+ {
+ tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
+ tf_warning_or_error, DECL_TI_TEMPLATE (d),
+ /*integral_constant_expression_p=*/false);
+
+ /* Set the current input_location to the end of the function
+ so that finish_function knows where we are. */
+ input_location
+ = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus;
+
+ /* Remember if we saw an infinite loop in the template. */
+ current_function_infinite_loop
+ = DECL_STRUCT_FUNCTION (code_pattern)->language->infinite_loop;
+ }
+
+ /* Finish the function. */
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
+ && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
+ DECL_SAVED_TREE (d) = pop_stmt_list (block);
+ else
+ {
+ d = finish_function (/*inline_p=*/false);
+ expand_or_defer_fn (d);
+ }
+
+ if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
+ cp_check_omp_declare_reduction (d);
+ }
+
+ /* We're not deferring instantiation any more. */
+ TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (d)) = 0;
+
+ if (push_to_top)
+ pop_from_top_level ();
+ else
+ pop_function_context ();
+
+ if (nested)
+ restore_omp_privatization_clauses (omp_privatization_save);
+}
+
/* 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
/* If we're in unevaluated context, we just wanted to get the
constant value; this isn't an odr use, so don't queue
a full instantiation. */
- if (cp_unevaluated_operand != 0)
- goto out;
- /* ??? Historically, we have instantiated inline functions, even
- when marked as "extern template". */
- if (!(external_p && VAR_P (d)))
+ if (!cp_unevaluated_operand
+ /* ??? Historically, we have instantiated inline functions, even
+ when marked as "extern template". */
+ && !(external_p && VAR_P (d)))
add_pending_template (d);
- goto out;
}
-
- bool push_to_top, nested;
- tree fn_context;
- fn_context = decl_function_context (d);
- if (LAMBDA_FUNCTION_P (d))
- /* tsubst_lambda_expr resolved any references to enclosing functions. */
- fn_context = NULL_TREE;
- nested = current_function_decl != NULL_TREE;
- push_to_top = !(nested && fn_context == current_function_decl);
-
- vec<tree> omp_privatization_save;
- if (nested)
- save_omp_privatization_clauses (omp_privatization_save);
-
- if (push_to_top)
- push_to_top_level ();
else
{
- gcc_assert (!processing_template_decl);
- push_function_context ();
- cp_unevaluated_operand = 0;
- c_inhibit_evaluation_warnings = 0;
- }
-
- if (VAR_P (d))
- {
- /* The variable might be a lambda's extra scope, and that
- lambda's visibility depends on D's. */
- maybe_commonize_var (d);
- determine_visibility (d);
- }
-
- /* Mark D as instantiated so that recursive calls to
- instantiate_decl do not try to instantiate it again. */
- DECL_TEMPLATE_INSTANTIATED (d) = 1;
-
- /* Regenerate the declaration in case the template has been modified
- by a subsequent redeclaration. */
- regenerate_decl_from_template (d, td, args);
-
- /* We already set the file and line above. Reset them now in case
- they changed as a result of calling regenerate_decl_from_template. */
- input_location = DECL_SOURCE_LOCATION (d);
-
- if (VAR_P (d))
- {
- tree init;
- bool const_init = false;
-
- /* Clear out DECL_RTL; whatever was there before may not be right
- since we've reset the type of the declaration. */
- SET_DECL_RTL (d, NULL);
- DECL_IN_AGGR_P (d) = 0;
-
- /* The initializer is placed in DECL_INITIAL by
- regenerate_decl_from_template so we don't need to
- push/pop_access_scope again here. Pull it out so that
- cp_finish_decl can process it. */
- init = DECL_INITIAL (d);
- DECL_INITIAL (d) = NULL_TREE;
- DECL_INITIALIZED_P (d) = 0;
-
- /* Clear DECL_EXTERNAL so that cp_finish_decl will process the
- initializer. That function will defer actual emission until
- we have a chance to determine linkage. */
- DECL_EXTERNAL (d) = 0;
-
- /* Enter the scope of D so that access-checking works correctly. */
- bool enter_context = DECL_CLASS_SCOPE_P (d);
- if (enter_context)
- push_nested_class (DECL_CONTEXT (d));
-
- const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern);
- cp_finish_decl (d, init, const_init, NULL_TREE, 0);
-
- if (enter_context)
- pop_nested_class ();
-
if (variable_template_p (gen_tmpl))
note_variable_template_instantiation (d);
- }
- else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern))
- synthesize_method (d);
- else if (TREE_CODE (d) == FUNCTION_DECL)
- {
- /* Set up the list of local specializations. */
- local_specialization_stack lss (push_to_top ? lss_blank : lss_copy);
- tree block = NULL_TREE;
-
- /* Set up context. */
- if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
- && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
- block = push_stmt_list ();
- else
- start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
-
- perform_instantiation_time_access_checks (DECL_TEMPLATE_RESULT (td),
- args);
-
- /* Create substitution entries for the parameters. */
- register_parameter_specializations (code_pattern, d);
-
- /* Substitute into the body of the function. */
- if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
- tsubst_omp_udr (DECL_SAVED_TREE (code_pattern), args,
- tf_warning_or_error, tmpl);
- else
- {
- tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
- tf_warning_or_error, tmpl,
- /*integral_constant_expression_p=*/false);
-
- /* Set the current input_location to the end of the function
- so that finish_function knows where we are. */
- input_location
- = DECL_STRUCT_FUNCTION (code_pattern)->function_end_locus;
-
- /* Remember if we saw an infinite loop in the template. */
- current_function_infinite_loop
- = DECL_STRUCT_FUNCTION (code_pattern)->language->infinite_loop;
- }
-
- /* Finish the function. */
- if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
- && TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
- DECL_SAVED_TREE (d) = pop_stmt_list (block);
- else
- {
- d = finish_function (/*inline_p=*/false);
- expand_or_defer_fn (d);
- }
-
- if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern))
- cp_check_omp_declare_reduction (d);
+ instantiate_body (td, args, d);
}
- /* We're not deferring instantiation any more. */
- TI_PENDING_TEMPLATE_FLAG (DECL_TEMPLATE_INFO (d)) = 0;
-
- if (push_to_top)
- pop_from_top_level ();
- else
- pop_function_context ();
-
- if (nested)
- restore_omp_privatization_clauses (omp_privatization_save);
-
-out:
pop_deferring_access_checks ();
timevar_pop (TV_TEMPLATE_INST);
pop_tinst_level ();