diff --git a/src/expr.c b/src/expr.c index 67283dbc3a..7c4195db3b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -10785,9 +10785,26 @@ a left parenthesis in the source. sym = symbol_for(var); } /* if */ } else if (is_routine_node(member_op)) { - /* Static member function. */ + /* Static member function or lambda call operator. */ a_routine_ptr rp = node_routine(member_op); - if (rp->assoc_template != NULL) { + if (rp->source_corresp.is_class_member && + is_immediate_class_type(class_struct_union_type) && + is_lambda_closure_type(class_struct_union_type) && + parent_class_of(rp) != skip_typerefs(class_struct_union_type)) { + /* The object operand is a rescanned lambda closure with a newly + created closure class; look up the corresponding member (such as + operator()) in the new closure class. */ + a_symbol_locator loc; + clear_locator(&loc, &locator->source_position); + loc.symbol_header = symbol_for(rp)->header; + sym = look_up_selection_name(&loc, class_struct_union_type); + if (rp->is_template_function && rp->expl_template_arg_list_used && + rp->template_arg_list != NULL) { + is_template_id = TRUE; + expl_templ_arg_list = + copy_template_arg_list(rp->template_arg_list); + } /* if */ + } else if (rp->assoc_template != NULL) { sym = copy_template_routine_with_substitution( rp, rcblock->template_arg_list, rcblock->template_param_list, @@ -18952,34 +18969,6 @@ used for the stack entry to be pushed. } /* push_expr_stack_for_expr_rescan */ -static void restore_template_param_symbols_after_expr_rescan( - a_template_param_ptr template_param_list) -/* -Restore the template parameter symbols for template_param_list after a -temporary update for an expression rescan. If an enclosing instantiation for -the same parameter list is active, restore those argument values; otherwise -restore the default template parameter values. -*/ -{ - a_scope_depth scope_depth; - - for (scope_depth = depth_scope_stack; scope_depth >= 0; --scope_depth) { - if (scope_is(&scope_stack[scope_depth], sck_template_instantiation) && - scope_stack[scope_depth].template_decl_info != NULL && - scope_stack[scope_depth].template_decl_info->parameters == - template_param_list) { - break; - } /* if */ - } /* for */ - if (scope_depth != NO_SCOPE_DEPTH) { - update_template_param_symbols(template_param_list, - scope_stack[scope_depth].template_arg_list); - } else { - restore_default_template_params(template_param_list, FALSE); - } /* if */ -} /* restore_template_param_symbols_after_expr_rescan */ - - a_type_ptr decltype_of_expr_with_substitution( a_type_ptr type, an_expr_node_ptr expr, @@ -18999,12 +18988,12 @@ state block. This routine is intended to be called from outside of the expression-processing routines. */ { - a_type_ptr new_type; - a_rescan_control_block rcblock; - a_saved_expr_rescan_context saved_context; - an_expr_stack_entry expr_stack_entry; - a_boolean is_typeof = FALSE, is_splice = FALSE; - a_boolean updated_template_params = FALSE; + a_type_ptr new_type; + a_rescan_control_block rcblock; + a_saved_expr_rescan_context saved_context; + an_expr_stack_entry expr_stack_entry; + a_rescan_param_binding_state param_binding_state; + a_boolean is_typeof = FALSE, is_splice = FALSE; /* __underlying_type constructs don't allow expression arguments. */ check_assertion(type_is(type , tk_typeref) && @@ -19023,13 +19012,12 @@ expression-processing routines. rcblock.options = options; rcblock.ctws_state = ctws_state; rcblock.expr = expr; - if (template_param_list != NULL && template_arg_list != NULL) { - /* Some rescan paths, notably CTAD for a type template template parameter, - consult the template parameter symbols. */ - update_template_param_symbols(template_param_list, template_arg_list, - /*partial_argument_list=*/TRUE); - updated_template_params = TRUE; - } /* if */ + /* Some rescan paths, notably CTAD for a type template template parameter or + a generic lambda call, consult the template parameter symbols. */ + begin_rescan_param_binding(template_param_list, template_arg_list, + /*push_decl_scope=*/FALSE, + /*enable_variadic=*/FALSE, + ¶m_binding_state); push_expr_rescan_context_if_necessary(&rcblock, &saved_context); push_expr_stack_for_expr_rescan((an_expression_kind)ek_sizeof, &rcblock, @@ -19043,9 +19031,7 @@ expression-processing routines. } /* if */ pop_expr_stack(); pop_expr_rescan_context_if_necessary(&saved_context); - if (updated_template_params) { - restore_template_param_symbols_after_expr_rescan(template_param_list); - } /* if */ + end_rescan_param_binding(¶m_binding_state); if (rcblock.error_detected || is_error_type(new_type)) { *copy_error = TRUE; } /* if */ diff --git a/src/exprutil.c b/src/exprutil.c index db22dd4b7b..abf454d99f 100644 --- a/src/exprutil.c +++ b/src/exprutil.c @@ -26823,12 +26823,12 @@ block pointer. } /* if */ push_instantiation_scope_for_rescan(symbol_for(templ)); scope_stack_top().in_concept_rescan = TRUE; + scope_stack_top().deduced_template_args = args; update_template_param_symbols(params, args); result = constraint_satisfied(expr, args, params, (diag_list != NULL) ? diag_list : &concept_diag_list, options, ctws_state, p_fatal); - restore_default_template_params(params, /*packs_only=*/FALSE); pop_instantiation_scope_for_rescan(); if (diag_list == NULL) { discard_more_info_list(&concept_diag_list); diff --git a/src/il.c b/src/il.c index 25bab95cd2..e8ad4c8fb5 100644 --- a/src/il.c +++ b/src/il.c @@ -20524,6 +20524,8 @@ TRUE. } /* substituted_cast_is_valid */ +static a_boolean lambda_body_is_instantiation_dependent(a_lambda_ptr lambda); + static an_expr_node_ptr copy_template_param_lambda_expr( an_expr_node_ptr expr, a_template_arg_ptr template_arg_list, @@ -20560,12 +20562,12 @@ copy_template_param_expr for the parameter descriptions. severe error cases). Substitution cannot proceed. */ subst_fail(*copy_error); } else { - an_operand result_operand; - an_expr_stack_entry expr_stack_entry; - an_expr_stack_entry_ptr saved_expr_stack; - a_boolean pushed_template_decl_scope = FALSE; - a_scope_ptr lambda_enclosing_scope = NULL; - a_scope_depth scope_depth_before_local_reactivation = + an_operand result_operand; + an_expr_stack_entry expr_stack_entry; + an_expr_stack_entry_ptr saved_expr_stack; + a_rescan_param_binding_state param_binding_state; + a_scope_ptr lambda_enclosing_scope = NULL; + a_scope_depth scope_depth_before_local_reactivation = NO_SCOPE_DEPTH; /* Set up a fresh expression and lexical context so that the lambda tokens can be rescanned without interfering with the surrounding state, then @@ -20578,28 +20580,15 @@ copy_template_param_expr for the parameter descriptions. expr_stack_entry.suppress_diagnostics = TRUE; expr_stack_entry.possible_rescan_context = TRUE; push_lexical_state_stack(); - if (template_param_list != NULL && - template_param_list->cache.decl_info != NULL && - template_param_list->param_symbol != NULL) { - /* Make the template parameters being substituted visible during the - rescan so that names that refer to them can be resolved. The scope - is pushed reusing the original declaration scope number so that the - template parameter symbols are visible to ordinary name lookup. */ - push_template_declaration_scope_full( - template_param_list->cache.decl_info, - template_param_list->param_symbol->decl_scope, - /*is_template_template_param=*/FALSE, - /*is_template_param_rescan=*/FALSE); - scope_stack_top().is_reactivation = TRUE; - pushed_template_decl_scope = TRUE; - /* Force the template parameter symbols to refer to the values - specified by the actual template arguments so that name - lookup of those parameters during the rescan returns the - substituted values directly (their state will be restored - by the enclosing instantiation scope when it is left). */ - update_template_param_symbols(template_param_list, - template_arg_list); - } /* if */ + /* Bind any template parameters that have known arguments so that ordinary + name lookup during the rescan resolves them to their substituted values, + while leaving any not-yet-deduced parameters at their resting dependent + values. */ + begin_rescan_param_binding(template_param_list, template_arg_list, + /*push_decl_scope=*/TRUE, + /*enable_variadic=*/ + (options & CTWS_PRESERVE_DEDUCED_PACKS) == 0, + ¶m_binding_state); /* If the lambda was originally declared in a local scope (i.e., inside a function body), reactivate that scope so that local variables and other names declared in the enclosing function are visible to ordinary name @@ -20649,13 +20638,28 @@ copy_template_param_expr for the parameter descriptions. scan_lambda_expression(&result_operand); if (is_immediate_class_type(result_operand.type) && is_lambda_closure_type(result_operand.type)) { - /* Pushing a template declaration scope above (to reactivate the - template parameters) unfortunately causes make_closure_class to mark - the closure as nonreal. In some situations with class template - argument deduction, we get a spuriously nonreal class even when we - didn't push the template declaration scope above. Just reset - the flag here. */ - result_operand.type->variant.class_struct_union.is_nonreal_class = FALSE; + /* In some situations with class template argument deduction, we get a + spuriously nonreal class. Reset the flag here unless the rescanned + lambda body still references un-substituted template parameters, and + associate the new closure class with the cached tokens in case a + subsequent substitution pass needs to rescan it again. */ + a_lambda_ptr new_lambda = NULL; + if (is_expression_operand(&result_operand) && + node_is(result_operand.variant.expression, enk_lambda)) { + new_lambda = + result_operand.variant.expression->variant.init.source.lambda; + } /* if */ + if (lambda_body_is_instantiation_dependent(new_lambda)) { + result_operand.type->variant.class_struct_union.is_nonreal_class = + TRUE; + new_lambda->lambda_routine->is_prototype_instantiation = TRUE; + } else { + result_operand.type->variant.class_struct_union.is_nonreal_class = + FALSE; + } /* if */ + if (cached_lambdas->get(result_operand.type) == NULL) { + cached_lambdas->map(result_operand.type, tokens); + } /* if */ } /* if */ flush_past_token_cache_terminator(); if (scope_depth_before_local_reactivation != NO_SCOPE_DEPTH) { @@ -20664,9 +20668,7 @@ copy_template_param_expr for the parameter descriptions. pop_scope(); } /* while */ } /* if */ - if (pushed_template_decl_scope) { - pop_scope(); - } /* if */ + end_rescan_param_binding(¶m_binding_state); pop_lexical_state_stack(); pop_expr_stack(); restore_expr_stack(saved_expr_stack); @@ -22519,6 +22521,8 @@ options. /* con_copy and constant are already set correctly. */ } else if ((!cpp11_sfinae_enabled && !expr_copy->is_lvalue) || (options & CTWS_IN_PARENT_SUBSTITUTION) != 0 || + ((options & CTWS_MAY_BE_RESCANNED) != 0 && + expr_is_instantiation_dependent(expr_copy)) || keep_tpck_expression) { /* The expression remains an expression. If the expression changed, make a new tpck_expression constant for it. With @@ -27491,6 +27495,36 @@ indirectly by expr_is_instantiation_dependent. } /* examine_dyn_init_for_instantiation_dependence */ +static a_boolean lambda_body_is_instantiation_dependent(a_lambda_ptr lambda) +/* +Return TRUE if lambda is a non-generic lambda whose call operator body is +instantiation-dependent. +*/ +{ + a_boolean result = FALSE; + + if (!C_mode() && lambda != NULL && !lambda->is_generic && + lambda->lambda_routine != NULL) { + a_scope_ptr func_scope = + scope_for_routine_or_null(lambda->lambda_routine); + if (func_scope != NULL && func_scope->assoc_block != NULL) { + an_expr_or_stmt_traversal_block tblock; + clear_expr_or_stmt_traversal_block(&tblock); + tblock.process_expr = examine_expr_for_instantiation_dependence; + tblock.process_constant = examine_constant_for_instantiation_dependence; + tblock.process_dynamic_init = + examine_dyn_init_for_instantiation_dependence; + tblock.process_type = examine_type_for_instantiation_dependence; + tblock.process_non_dynamic_constants = TRUE; + tblock.skip_expr_process_type = TRUE; + traverse_statement(func_scope->assoc_block, &tblock); + result = tblock.result; + } /* if */ + } /* if */ + return result; +} /* lambda_body_is_instantiation_dependent */ + + a_boolean expr_is_instantiation_dependent(an_expr_node_ptr expr) /* Return TRUE if expr is instantiation-dependent. This normally includes type- diff --git a/src/overload.c b/src/overload.c index 866e72bb56..48d0611a2e 100644 --- a/src/overload.c +++ b/src/overload.c @@ -5641,10 +5641,12 @@ is used in the constraint, its evaluation will fail. a_template_ptr templ = rp->assoc_template; check_assertion(templ != NULL); init_ctws_state(&ctws_state); + push_instantiation_scope_for_rescan(symbol_for(templ)); expr = copy_expr_with_substitutions(expr, t_args, templ_params_of(symbol_for(templ)), CTWS_NO_OPTIONS, &failed, &ctws_state); + pop_instantiation_scope_for_rescan(); if (failed) { /* If substitution failed, the function is discarded as a candidate. No need to try another attribute. */ @@ -31226,7 +31228,7 @@ TRUE and FALSE is returned. /* The initializer is a braced-init-list, so its type is not known. */ arg_type = NULL; } /* if */ - if (is_template_dependent_context()) { + if (is_template_dependent_context() || scope_stack_top().is_rescan) { /* See whether deduction can be done. */ if (arg_type != NULL ? is_template_dependent_type(arg_type) : arg_list_is_dependent(initializer_alep)) { diff --git a/src/pending_changes/gh-338-lambda-template-param.txt b/src/pending_changes/gh-338-lambda-template-param.txt new file mode 100644 index 0000000000..6b17e9e602 --- /dev/null +++ b/src/pending_changes/gh-338-lambda-template-param.txt @@ -0,0 +1,13 @@ +[GH #338] +Spurious substitution failure for lambda naming template parameter in signature + +Previously, a lambda expression appearing in a function template signature +(or an enable_if attribute) that referenced an enclosing template parameter +failed template argument substitution. For example, with --c++20: + + template + void f(char (*)[sizeof([] { return T{}; }())]) {} + void g() { + char a[sizeof(int)]; + f(&a); // Previously a spurious error, now okay. + } diff --git a/src/scope_stk.c b/src/scope_stk.c index c4b12ca1a9..4a733d0c5d 100644 --- a/src/scope_stk.c +++ b/src/scope_stk.c @@ -2033,7 +2033,7 @@ lists that are not complete instantiation argument lists. if (is_type_templ_arg(tap)) { result = tap->variant.type != NULL; } else if (is_nontype_templ_arg(tap)) { - result = tap->is_array_bound_of_unknown_type || + result = !tap->is_array_bound_of_unknown_type && tap->variant.constant != NULL; } else if (is_template_templ_arg(tap)) { result = tap->variant.templ.ptr != NULL; @@ -2142,7 +2142,9 @@ skip the initial not_visible pass and error coercion. break; } /* if */ if (tap_to_update != NULL && partial_argument_list && - !template_arg_can_update_param_symbol(tap_to_update)) { + (!template_arg_can_update_param_symbol(tap_to_update) || + (tpp->is_pack && pack_expansion_stack != NULL && + pack_expansion_stack->is_suppression))) { tap_to_update = NULL; } /* if */ if (tap_to_update != NULL) { @@ -2227,6 +2229,196 @@ for parameter packs are reset. } /* restore_default_template_params */ +void restore_template_param_symbols_for_param_list( + a_template_param_ptr template_param_list, + a_scope_depth starting_depth) +/* +Restore the template parameter symbols for template_param_list by searching +the scope stack downward from starting_depth for an active instantiation scope +with the same parameter list. If one is found, update the symbols from its +template arguments (or its bound rescan arguments if it is a rescan scope); +otherwise restore the default template parameter values. +*/ +{ + a_scope_depth scope_depth = NO_SCOPE_DEPTH; + a_scope_depth d; + + for (d = starting_depth; d >= 0; --d) { + if (scope_is(&scope_stack[d], sck_template_instantiation) && + scope_stack[d].template_decl_info != NULL && + scope_stack[d].template_decl_info->parameters == template_param_list) { + scope_depth = d; + break; + } /* if */ + } /* for */ + if (scope_depth == NO_SCOPE_DEPTH) { + restore_default_template_params(template_param_list, /*packs_only=*/FALSE); + } else if (scope_stack[scope_depth].template_arg_list == NULL && + scope_stack[scope_depth].deduced_template_args != NULL) { + a_template_param_ptr tpp; + for (tpp = template_param_list; tpp != NULL; tpp = tpp->next) { + if (tpp->param_symbol != NULL && + tpp->param_symbol->template_param_not_visible) { + restore_default_template_param(tpp); + } /* if */ + } /* for */ + update_template_param_symbols( + template_param_list, + scope_stack[scope_depth].deduced_template_args, + /*partial_argument_list=*/TRUE); + } else { + update_template_param_symbols(template_param_list, + scope_stack[scope_depth].template_arg_list); + } /* if */ +} /* restore_template_param_symbols_for_param_list */ + + +void begin_rescan_param_binding( + a_template_param_ptr template_param_list, + a_template_arg_ptr template_arg_list, + a_boolean push_decl_scope, + a_boolean enable_variadic, + a_rescan_param_binding_state *state) +/* +Bind the template parameter symbols in template_param_list to the values in +template_arg_list for a rescan or substitution operation, recording the prior +state in *state so that end_rescan_param_binding can restore it. Parameters +without a value in template_arg_list are left at their resting dependent +values. When push_decl_scope is TRUE and no instantiation or declaration +scope for template_param_list is currently on the scope stack, push a +reactivated template declaration scope so that ordinary lookup can find the +parameter symbols. When enable_variadic is TRUE and template_param_list +contains a parameter pack, mark the current and instantiation scopes as +variadic so that pack expansions in rescanned tokens are expanded. +*/ +{ + memzero((char *)state, sizeof(*state)); + state->template_param_list = template_param_list; + state->inst_scope_depth = NO_SCOPE_DEPTH; + if (template_param_list != NULL && + template_param_list->param_symbol != NULL) { + a_scope_depth d; + for (d = depth_scope_stack; d >= 0; --d) { + if (scope_is(&scope_stack[d], sck_template_instantiation) && + scope_stack[d].template_decl_info != NULL && + scope_stack[d].template_decl_info->parameters == + template_param_list) { + state->inst_scope_depth = d; + break; + } /* if */ + } /* for */ + if (state->inst_scope_depth != NO_SCOPE_DEPTH) { + a_scope_stack_entry_ptr inst_ssep = + &scope_stack[state->inst_scope_depth]; + state->saved_deduced_template_args = inst_ssep->deduced_template_args; + if (inst_ssep->template_arg_list == NULL) { + inst_ssep->deduced_template_args = template_arg_list; + } /* if */ + if (push_decl_scope) { + if (!enable_variadic && template_arg_list != NULL) { + a_template_arg_ptr tap; + for (tap = template_arg_list; tap != NULL; tap = tap->next) { + if (tap->is_pack_element) { + enable_variadic = TRUE; + break; + } /* if */ + } /* for */ + } /* if */ + { a_template_param_ptr tpp; + for (tpp = template_param_list; tpp != NULL; tpp = tpp->next) { + if (tpp->is_pack) { + state->saved_inst_in_variadic = inst_ssep->in_variadic_template; + state->saved_top_in_variadic = + scope_stack_top().in_variadic_template; + state->variadic_updated = TRUE; + inst_ssep->in_variadic_template = TRUE; + scope_stack_top().in_variadic_template = TRUE; + if (!enable_variadic) { + push_expansion_suppression(&state->pack_suppression); + } /* if */ + break; + } /* if */ + } /* for */ + } + } /* if */ + } else if (push_decl_scope) { + a_boolean decl_scope_active = FALSE; + for (d = depth_scope_stack; d >= 0; --d) { + if (scope_is(&scope_stack[d], sck_template_declaration) && + scope_stack[d].number == + template_param_list->param_symbol-> + decl_scope) { + decl_scope_active = TRUE; + break; + } /* if */ + } /* for */ + if (!decl_scope_active) { + a_scope_depth orig_depth_template_decl_scope = + depth_template_declaration_scope; + a_template_decl_info_ptr decl_info = + template_param_list->cache.decl_info; + if (decl_info == NULL) { + decl_info = alloc_template_decl_info(); + decl_info->parameters = template_param_list; + decl_info->declaration_scope = + template_param_list->param_symbol->decl_scope; + template_param_list->cache.decl_info = decl_info; + } /* if */ + push_template_declaration_scope_full( + decl_info, + template_param_list->param_symbol->decl_scope, + /*is_template_template_param=*/FALSE, + /*is_template_param_rescan=*/TRUE); + scope_stack_top().is_reactivation = TRUE; + scope_stack_top().depth_template_declaration_scope = + depth_template_declaration_scope = orig_depth_template_decl_scope; + state->pushed_decl_scope = TRUE; + } /* if */ + } /* if */ + { a_template_param_ptr tpp; + for (tpp = template_param_list; tpp != NULL; tpp = tpp->next) { + if (tpp->param_symbol != NULL && + tpp->param_symbol->template_param_not_visible) { + restore_default_template_param(tpp); + } /* if */ + } /* for */ + } + if (template_arg_list != NULL) { + update_template_param_symbols(template_param_list, template_arg_list, + /*partial_argument_list=*/TRUE); + } /* if */ + state->updated_symbols = TRUE; + } /* if */ +} /* begin_rescan_param_binding */ + + +void end_rescan_param_binding(a_rescan_param_binding_state *state) +/* +Restore the scope stack and template parameter symbol state saved by a prior +call to begin_rescan_param_binding. +*/ +{ + if (state->pack_suppression != NULL) { + pop_expansion_suppression(state->pack_suppression); + } /* if */ + if (state->pushed_decl_scope) { + pop_scope(); + } /* if */ + if (state->inst_scope_depth != NO_SCOPE_DEPTH) { + a_scope_stack_entry_ptr inst_ssep = &scope_stack[state->inst_scope_depth]; + inst_ssep->deduced_template_args = state->saved_deduced_template_args; + if (state->variadic_updated) { + inst_ssep->in_variadic_template = state->saved_inst_in_variadic; + scope_stack_top().in_variadic_template = state->saved_top_in_variadic; + } /* if */ + } /* if */ + if (state->updated_symbols) { + restore_template_param_symbols_for_param_list(state->template_param_list, + depth_scope_stack); + } /* if */ +} /* end_rescan_param_binding */ + + static void reset_enclosing_pack_values(void) /* Go through the scope stack and reset the template parameters associated @@ -5774,9 +5966,20 @@ class to be defined. } /* if */ } else if (is_lambda_body) { /* A real instantiation of a generic lambda. If we are still in the - function in which the lambda was defined, use the existing context. */ - if (lambda_scope->depth_in_scope_stack == orig_depth && - orig_depth != DEPTH_OF_FILE_SCOPE) { + function or enclosing template instantiation/rescan scope in which the + lambda was defined, use the existing context. */ + if ((lambda_scope->depth_in_scope_stack == orig_depth && + orig_depth != DEPTH_OF_FILE_SCOPE) || + (scope_stack[orig_depth].depth_innermost_function_scope == + NO_SCOPE_DEPTH && + depth_innermost_instantiation_scope != NO_SCOPE_DEPTH && + lambda_scope->depth_in_scope_stack != NO_SCOPE_DEPTH && + template_supplement_for_symbol(template_sym)->cache->decl_info != + NULL && + template_supplement_for_symbol(template_sym)->cache->decl_info-> + enclosing_template_decl == + scope_stack[depth_innermost_instantiation_scope]. + template_decl_info)) { use_existing_context = TRUE; } /* if */ is_real_lambda_instantiation = TRUE; @@ -10403,37 +10606,15 @@ being popped. instantiation, however, this requires restoring the values from the previous instantiation. */ if (kind == (a_scope_kind)sck_template_instantiation) { - a_scope_depth prev_depth; - a_template_decl_info_ptr template_decl_info = - ssep->template_decl_info; + a_template_decl_info_ptr template_decl_info = ssep->template_decl_info; check_assertion(template_decl_info != NULL); - prev_depth = NO_SCOPE_DEPTH; - /* Loop through the scope stack looking for a previous instantiation - scope that uses the same template parameter list as the one being - popped. This is necessary because template parameter lists are - shared between a class and the member functions defined inside the - class. */ - for (scope_depth = depth_scope_stack - 1; - scope_depth >= 0; - scope_depth--) { - if (scope_stack[scope_depth].kind == - (a_scope_kind)sck_template_instantiation && - scope_stack[scope_depth].template_decl_info->parameters == - template_decl_info->parameters) { - prev_depth = scope_depth; - break; - } /* if */ - } /* for */ - if (prev_depth == NO_SCOPE_DEPTH) { - /* Restore the default values of the parameters. */ - restore_default_template_params(template_decl_info->parameters, - /*packs_only=*/FALSE); - } else { - /* Restore the parameter values from the previous instantiation. */ - update_template_param_symbols(template_decl_info->parameters, - scope_stack[prev_depth].template_arg_list); - } /* if */ + /* Restore the parameter values from any enclosing instantiation or rescan + scope that shares this template parameter list, or reset them to their + default values. */ + restore_template_param_symbols_for_param_list( + template_decl_info->parameters, + depth_scope_stack - 1); } /* if */ if (ssep->packs_referenced != NULL) { /* If there were any variadic parameter packs that were referenced but @@ -11964,7 +12145,11 @@ template that is being instantiated. tdip = ssep->template_decl_info; *templ_param_list = tdip->parameters; check_assertion(*templ_param_list != NULL); - *templ_arg_list = ssep->template_arg_list; + if (ssep->template_arg_list != NULL) { + *templ_arg_list = ssep->template_arg_list; + } else { + *templ_arg_list = ssep->deduced_template_args; + } /* if */ } /* get_curr_template_params_and_args */ @@ -13192,7 +13377,10 @@ entries. { a_pack_expansion_stack_entry_ptr pesep = NULL; - if (is_prototype_instantiation_context() && is_variadic_template_context()) { + if ((is_prototype_instantiation_context() || + (depth_innermost_instantiation_scope != NO_SCOPE_DEPTH && + scope_stack[depth_innermost_instantiation_scope].is_rescan)) && + is_variadic_template_context()) { pesep = push_pack_expansion_stack(); pesep->is_suppression = TRUE; } /* if */ diff --git a/src/scope_stk.h b/src/scope_stk.h index 1c8607988e..573216ec9d 100644 --- a/src/scope_stk.h +++ b/src/scope_stk.h @@ -2453,6 +2453,62 @@ extern void update_template_param_symbols( a_template_arg_ptr arg_list, a_boolean partial_argument_list = FALSE); +extern void restore_template_param_symbols_for_param_list( + a_template_param_ptr template_param_list, + a_scope_depth starting_depth); + +/* +State block saving the scope stack and template parameter binding state across +a temporary template parameter binding during a rescan or substitution. +*/ +typedef struct a_rescan_param_binding_state { + a_template_param_ptr + template_param_list; + /* The template parameter list whose symbols were + bound. */ + a_template_arg_ptr + saved_deduced_template_args; + /* The prior deduced_template_args value on the + matching instantiation scope, if any. */ + a_pack_expansion_stack_entry_ptr + pack_suppression; + /* Pack expansion suppression entry pushed when + preserving un-deduced packs during a rescan, or + NULL if none was pushed. */ + a_scope_depth inst_scope_depth; + /* Depth of the matching instantiation scope, or + NO_SCOPE_DEPTH if none is on the scope stack. */ + a_byte_boolean + updated_symbols; + /* TRUE if the template parameter symbols were updated + and must be restored on exit. */ + a_byte_boolean + pushed_decl_scope; + /* TRUE if a reactivated template declaration scope was + pushed and must be popped on exit. */ + a_byte_boolean + variadic_updated; + /* TRUE if in_variadic_template was updated and must be + restored on exit. */ + a_byte_boolean + saved_inst_in_variadic; + /* Prior in_variadic_template flag on the matching + instantiation scope. */ + a_byte_boolean + saved_top_in_variadic; + /* Prior in_variadic_template flag on the top scope + stack entry. */ +} a_rescan_param_binding_state; + +extern void begin_rescan_param_binding( + a_template_param_ptr template_param_list, + a_template_arg_ptr template_arg_list, + a_boolean push_decl_scope, + a_boolean enable_variadic, + a_rescan_param_binding_state *state); + +extern void end_rescan_param_binding(a_rescan_param_binding_state *state); + extern void finish_function_processing_for_function_def( a_function_def_number n, a_boolean only_inline); diff --git a/src/templates.c b/src/templates.c index a3a732d79d..77a49f07b7 100644 --- a/src/templates.c +++ b/src/templates.c @@ -3122,6 +3122,8 @@ Otherwise it is zero. *templ_arg_list, rout_templ_sym, templ_param_list, ctws_options, param_count)) { /* Substitute the template arguments in the routine type. */ + a_scope_depth inst_scope_depth = NO_SCOPE_DEPTH; + a_template_arg_ptr saved_deduced_template_args = NULL; if (depth_innermost_instantiation_scope != NO_SCOPE_DEPTH && scope_stack_entry_for(depth_innermost_instantiation_scope)-> template_sym == rout_templ_sym && @@ -3130,12 +3132,18 @@ Otherwise it is zero. /* We know the template arguments for this instance now; save them in the scope stack entry in case they are needed for the substitution below. */ - scope_stack_entry_for(depth_innermost_instantiation_scope)-> - deduced_template_args = *templ_arg_list; + inst_scope_depth = depth_innermost_instantiation_scope; + saved_deduced_template_args = + scope_stack[inst_scope_depth].deduced_template_args; + scope_stack[inst_scope_depth].deduced_template_args = *templ_arg_list; } /* if */ new_type = substitute_template_arguments(rout_templ_sym, *templ_arg_list, (a_template_arg_ptr*)NULL, templ_param_list, ctws_options); + if (inst_scope_depth != NO_SCOPE_DEPTH) { + scope_stack[inst_scope_depth].deduced_template_args = + saved_deduced_template_args; + } /* if */ if (new_type != NULL && (microsoft_mode || gpp_mode)) { /* Normally, a function type will have been considered invalid if a parameter or return type was an abstract class type, but in @@ -11669,8 +11677,20 @@ is added to the substitution state. scope_pushed = !(scope_is(&scope_stack_top(), sck_function_access) && scope_stack_top().is_rescan && scope_stack_top().template_sym == template_sym); + a_scope_depth inst_scope_depth = NO_SCOPE_DEPTH; + a_template_arg_ptr saved_deduced_template_args = NULL; if (scope_pushed) { push_instantiation_scope_for_rescan(template_sym); + scope_stack_top().deduced_template_args = args; + } else if (depth_innermost_instantiation_scope != NO_SCOPE_DEPTH && + scope_stack[depth_innermost_instantiation_scope]. + template_arg_list == NULL && + scope_stack[depth_innermost_instantiation_scope]. + template_decl_info->parameters == params) { + inst_scope_depth = depth_innermost_instantiation_scope; + saved_deduced_template_args = + scope_stack[inst_scope_depth].deduced_template_args; + scope_stack[inst_scope_depth].deduced_template_args = args; } /* if */ clear_diag_list(&diag_list); init_ctws_state(&ctws_state); @@ -11723,9 +11743,14 @@ is added to the substitution state. result = FALSE; } /* if */ free_list_of_variadic_param_info(ctws_state.variadic_param_info); - restore_default_template_params(params, FALSE); if (scope_pushed) { pop_instantiation_scope_for_rescan(); + } else { + if (inst_scope_depth != NO_SCOPE_DEPTH) { + scope_stack[inst_scope_depth].deduced_template_args = + saved_deduced_template_args; + } /* if */ + restore_template_param_symbols_for_param_list(params, depth_scope_stack); } /* if */ return result; } /* requires_constraint_satisfied */ @@ -19247,11 +19272,23 @@ are flags passed down to the substitution routines. template argument list. Create a new type. */ a_ctws_state ctws_state; a_scope_stack_entry_ptr ssep = &scope_stack_top(); + a_scope_depth inst_scope_depth = NO_SCOPE_DEPTH; + a_template_arg_ptr saved_deduced_template_args = NULL; a_boolean scope_pushed = FALSE; init_ctws_state(&ctws_state); ctws_state.preserve_deduced_packs = preserve_deduced_packs; templ_rout_type = skip_typerefs(tssp->variant.function.routine->type); ++(tssp->variant.function.pending_deductions); + if (depth_innermost_instantiation_scope != NO_SCOPE_DEPTH && + scope_stack_entry_for(depth_innermost_instantiation_scope)-> + template_sym == templ_sym && + scope_stack_entry_for(depth_innermost_instantiation_scope)-> + template_arg_list == NULL) { + inst_scope_depth = depth_innermost_instantiation_scope; + saved_deduced_template_args = + scope_stack[inst_scope_depth].deduced_template_args; + scope_stack[inst_scope_depth].deduced_template_args = templ_arg_list; + } /* if */ /* Ensure any access checks can find the routine's friends. If a function access scope has already been pushed for this template then there's no need to push another. */ @@ -19268,6 +19305,10 @@ are flags passed down to the substitution routines. &templ_sym->decl_position, ctws_options, ©_error, &ctws_state); + if (inst_scope_depth != NO_SCOPE_DEPTH) { + scope_stack[inst_scope_depth].deduced_template_args = + saved_deduced_template_args; + } /* if */ if (!(ctws_options & CTWS_IS_PARTIAL_ORDER_CHECK)) { if (concepts_enabled && !copy_error && (ms_version_is(any_version) || clang_version_is(any_version)) &&