From 2b7147e48564679d53b3c6629714991c5506d614 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Wed, 16 Sep 2020 07:14:14 -0700 Subject: [PATCH] c++: Break out actual instantiation from instantiate_decl This refactors instantiate_decl, breaking out the actual instantiation work to instantiate_body. That'll allow me to address the OMP UDR issue, but it also means we have slightly neater code in instantiate_decl anyway. gcc/cp/ * pt.c (instantiate_body): New, broken out of .. (instantiate_decl): ... here. Call it. --- gcc/cp/pt.c | 305 +++++++++++++++++++++++++++------------------------- 1 file changed, 157 insertions(+), 148 deletions(-) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1aea105edd5..e8aa950b8fa 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -25447,6 +25447,158 @@ register_parameter_specializations (tree pattern, tree inst) 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 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 @@ -25684,162 +25836,19 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) /* 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 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 (); -- 2.30.2