diff --git a/src/expr.c b/src/expr.c index 67283dbc3a..7a2ea1a866 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, qualified_member_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 2181e28d1f..63b431279f 100644 --- a/src/exprutil.c +++ b/src/exprutil.c @@ -26874,12 +26874,15 @@ block pointer. } /* if */ push_instantiation_scope_for_rescan(symbol_for(templ)); scope_stack_top().in_concept_rescan = TRUE; + /* An access-checking scope may have been pushed above this scope, so + record the arguments on the instantiation scope itself. */ + scope_stack[depth_innermost_instantiation_scope] + .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); @@ -27535,6 +27538,12 @@ non-NULL (it's NULL by default), update *diag_list accordingly. clear_diag_list(&local_diag_list); diag_list = &local_diag_list; } /* if */ + /* Keep the concept arguments bound while checking the constraint. + Nested lambda rescans restore parameter symbols from this scope; an + access-checking scope may have been pushed above it. */ + scope_stack[depth_innermost_instantiation_scope].deduced_template_args = + new_args; + update_template_param_symbols(params, new_args); /* Evaluate the constraint. */ result = constraint_satisfied(expr, new_args, params, diag_list); } /* if */ diff --git a/src/il.c b/src/il.c index 25bab95cd2..2518263b1b 100644 --- a/src/il.c +++ b/src/il.c @@ -20524,6 +20524,216 @@ TRUE. } /* substituted_cast_is_valid */ +static void examine_type_for_instantiation_dependence( + a_type_ptr type, + an_expr_or_stmt_traversal_block_ptr tblock) +/* +Called from traverse_expr to check whether the type is instantiation-dependent. +*/ +{ + if (is_instantiation_dependent_type(type)) { + tblock->result = TRUE; + tblock->terminate = TRUE; + } /* if */ +} /* examine_type_for_instantiation_dependence */ + + +static void examine_var_init_for_instantiation_dependence( + a_variable_ptr vp, + an_expr_or_stmt_traversal_block_ptr tblock) +/* +Helper function to determine whether a given expression or constant is +instantiation-dependent. Specifically, if the given variable is local to a +function template, this function traverses the variable's initializer to see +if it is instantiation-dependent. +*/ +{ + if (vp->is_prototype_instantiation || + (vp->source_corresp.enclosing_routine != NULL && + vp->source_corresp.enclosing_routine->is_prototype_instantiation)) { + an_init_kind init_kind, saved_init_kind = vp->init_kind; + an_initializer_ptr initializer; + get_variable_initializer(vp, (a_scope_ptr)NULL, &init_kind, &initializer); + /* Temporarily disable the initializer to avoid unbounded recursion. */ + vp->init_kind = (an_init_kind)initk_none; + if (init_kind == (an_init_kind)initk_static) { + traverse_constant(initializer->constant, tblock); + } else if (init_kind == (an_init_kind)initk_dynamic) { + traverse_dynamic_init(initializer->dynamic, tblock); + } else if (init_kind == (an_init_kind)initk_binding) { + traverse_expr(initializer->bound_expr, tblock); + } /* if */ + vp->init_kind = saved_init_kind; + } /* if */ +} /* examine_var_init_for_instantiation_dependence */ + + +static void examine_constant_for_instantiation_dependence( + a_constant_ptr con, + an_expr_or_stmt_traversal_block_ptr tblock) +/* +Called from traverse_expr to check whether the constant is +instantiation-dependent. +*/ +{ + if (constant_is(con, ck_template_param) || con->is_generic_initializer) { + tblock->result = TRUE; + tblock->terminate = TRUE; + } else if (constant_is(con, ck_address)) { + if (con->variant.address.kind == (an_address_base_kind)abk_variable) { + /* Check if the given variable's initializer makes it instantiation- + dependent. */ + a_variable *vp = con->variant.address.variant.variable; + if (vp->source_corresp.is_class_member && + parent_class_of(vp)->variant.class_struct_union.is_nonreal_class) { + tblock->result = TRUE; + tblock->terminate = TRUE; + } else { + examine_var_init_for_instantiation_dependence(vp, tblock); + } /* if */ + } /* if */ + tblock->suppress_subtree_walk = TRUE; + } else if (constant_is(con, ck_aggregate) || + constant_is(con, ck_dynamic_init) || + constant_is(con, ck_init_repeat)) { + /* Aggregate constants can contain dynamic members, which might be + instantiation-dependent, so walk the subtree for those. */ + } else { + /* Other constants are known not to be dependent. */ + tblock->suppress_subtree_walk = TRUE; + } /* if */ +} /* examine_constant_for_instantiation_dependence */ + + +static void examine_expr_for_instantiation_dependence( + an_expr_node_ptr expr, + an_expr_or_stmt_traversal_block_ptr tblock) +/* +Called from traverse_expr to check whether the expression is +instantiation-dependent. +*/ +{ + a_boolean skip_typecheck = FALSE; + + /* Most cases are resolved by the type, but a routine node that is the + address of a static member of the current instantiation is not. */ + if (expr_is_dep_static_member_of_current_instantiation(expr)) { + tblock->result = TRUE; + tblock->terminate = TRUE; + } else if (is_variable_node(expr)) { + /* Treat local variables of function templates as "instantiation + dependent". */ + a_variable *vp = node_variable(expr); + if (vp->is_nonreal) { + tblock->result = TRUE; + tblock->terminate = TRUE; + } else { + examine_var_init_for_instantiation_dependence(vp, tblock); + } /* if */ + } else if (node_is(expr, enk_type_operand)) { + /* enk_type_operand nodes have "void" type, but the instantiation + dependence is in the operand type. */ + examine_type_for_instantiation_dependence(expr->variant.type_operand.type, + tblock); + skip_typecheck = TRUE; + } /* if */ + if (skip_typecheck || tblock->terminate) { + /* No need to check the type. */ + } else { + examine_type_for_instantiation_dependence(expr->type, tblock); + } /* if */ +} /* examine_expr_for_instantiation_dependence */ + + +static void examine_dyn_init_for_instantiation_dependence( + a_dynamic_init_ptr dip, + an_expr_or_stmt_traversal_block_ptr tblock) +/* +Check if the given dynamic initializer is instantiation-dependent. Called +indirectly by expr_is_instantiation_dependent and +lambda_body_is_instantiation_dependent. +*/ +{ + if (dyn_init_is(dip, dik_constructor)) { + if (dip->variant.constructor.ptr == NULL) { + /* An unknown constructor only occurs when it is template-dependent. */ + tblock->result = TRUE; + tblock->terminate = TRUE; + } /* if */ + } /* if */ +} /* examine_dyn_init_for_instantiation_dependence */ + + +static void examine_statement_for_instantiation_dependence( + a_statement_ptr stmt, + an_expr_or_stmt_traversal_block_ptr tblock) +/* +Called from traverse_statement to check declarations that are not otherwise +visited by the expression and statement traversal. +*/ +{ + if (stmt->kind == stmk_decl) { + an_il_entity_list_entry_ptr entry = stmt->variant.decl.entities; + for (; entry != NULL && !tblock->terminate; entry = entry->next) { + a_type_ptr type = NULL; + switch (entry->entity.kind) { + case iek_type: + type = (a_type_ptr)entry->entity.ptr; + break; + case iek_variable: + type = ((a_variable_ptr)entry->entity.ptr)->type; + break; + case iek_routine: + type = ((a_routine_ptr)entry->entity.ptr)->type; + break; + default: + break; + } /* switch */ + if (entity_is_nonreal((a_source_correspondence_ptr)entry->entity.ptr, + (an_il_entry_kind)entry->entity.kind)) { + tblock->result = TRUE; + tblock->terminate = TRUE; + } else if (type != NULL) { + examine_type_for_instantiation_dependence(type, tblock); + } /* if */ + if (!tblock->terminate && entry->entity.kind == iek_variable) { + traverse_variable_init((a_variable_ptr)entry->entity.ptr, tblock); + } /* if */ + } /* for */ + } /* if */ +} /* examine_statement_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 (!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_statement = + examine_statement_for_instantiation_dependence; + 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 */ + + static an_expr_node_ptr copy_template_param_lambda_expr( an_expr_node_ptr expr, a_template_arg_ptr template_arg_list, @@ -20560,12 +20770,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 +20788,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 +20846,29 @@ 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 (new_lambda != NULL && + 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 +20877,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 +22730,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 @@ -27329,87 +27542,6 @@ associated with the statement expression from its parent's scopes list. #endif /* GENERATE_SOURCE_SEQUENCE_LISTS */ -static void examine_type_for_instantiation_dependence( - a_type_ptr type, - an_expr_or_stmt_traversal_block_ptr tblock) -/* -Called from traverse_expr to check whether the type is instantiation-dependent. -*/ -{ - if (is_instantiation_dependent_type(type)) { - tblock->result = TRUE; - tblock->terminate = TRUE; - } /* if */ -} /* examine_type_for_instantiation_dependence */ - - -static void examine_var_init_for_instantiation_dependence( - a_variable_ptr vp, - an_expr_or_stmt_traversal_block_ptr tblock) -/* -Helper function to determine whether a given expression or constant is -instantiation-dependent. Specifically, if the given variable is local to a -function template, this function traverses the variable's initializer to see -if it is instantiation-dependent. -*/ -{ - if (vp->is_prototype_instantiation || - (vp->source_corresp.enclosing_routine != NULL && - vp->source_corresp.enclosing_routine->is_prototype_instantiation)) { - an_init_kind init_kind, saved_init_kind = vp->init_kind; - an_initializer_ptr initializer; - get_variable_initializer(vp, (a_scope_ptr)NULL, &init_kind, &initializer); - /* Temporarily disable the initializer to avoid unbounded recursion. */ - vp->init_kind = (an_init_kind)initk_none; - if (init_kind == (an_init_kind)initk_static) { - traverse_constant(initializer->constant, tblock); - } else if (init_kind == (an_init_kind)initk_dynamic) { - traverse_dynamic_init(initializer->dynamic, tblock); - } else if (init_kind == (an_init_kind)initk_binding) { - traverse_expr(initializer->bound_expr, tblock); - } /* if */ - vp->init_kind = saved_init_kind; - } /* if */ -} /* examine_var_init_for_instantiation_dependence */ - - -static void examine_constant_for_instantiation_dependence( - a_constant_ptr con, - an_expr_or_stmt_traversal_block_ptr tblock) -/* -Called from traverse_expr to check whether the constant is -instantiation-dependent. -*/ -{ - if (constant_is(con, ck_template_param) || con->is_generic_initializer) { - tblock->result = TRUE; - tblock->terminate = TRUE; - } else if (constant_is(con, ck_address)) { - if (con->variant.address.kind == (an_address_base_kind)abk_variable) { - /* Check if the given variable's initializer makes it instantiation- - dependent. */ - a_variable *vp = con->variant.address.variant.variable; - if (vp->source_corresp.is_class_member && - parent_class_of(vp)->variant.class_struct_union.is_nonreal_class) { - tblock->result = TRUE; - tblock->terminate = TRUE; - } else { - examine_var_init_for_instantiation_dependence(vp, tblock); - } /* if */ - } /* if */ - tblock->suppress_subtree_walk = TRUE; - } else if (constant_is(con, ck_aggregate) || - constant_is(con, ck_dynamic_init) || - constant_is(con, ck_init_repeat)) { - /* Aggregate constants can contain dynamic members, which might be - instantiation-dependent, so walk the subtree for those. */ - } else { - /* Other constants are known not to be dependent. */ - tblock->suppress_subtree_walk = TRUE; - } /* if */ -} /* examine_constant_for_instantiation_dependence */ - - a_boolean expr_is_dep_static_member_of_current_instantiation( an_expr_node_ptr expr) /* @@ -27433,64 +27565,6 @@ dependent. } /* expr_is_dep_static_member_of_current_instantiation */ -static void examine_expr_for_instantiation_dependence( - an_expr_node_ptr expr, - an_expr_or_stmt_traversal_block_ptr tblock) -/* -Called from traverse_expr to check whether the expression is -instantiation-dependent. -*/ -{ - a_boolean skip_typecheck = FALSE; - - /* Most cases are resolved by the type, but a routine node that is the - address of a static member of the current instantiation is not. */ - if (expr_is_dep_static_member_of_current_instantiation(expr)) { - tblock->result = TRUE; - tblock->terminate = TRUE; - } else if (is_variable_node(expr)) { - /* Treat local variables of function templates as "instantiation - dependent". */ - a_variable *vp = node_variable(expr); - if (vp->is_nonreal) { - tblock->result = TRUE; - tblock->terminate = TRUE; - } else { - examine_var_init_for_instantiation_dependence(vp, tblock); - } /* if */ - } else if (node_is(expr, enk_type_operand)) { - /* enk_type_operand nodes have "void" type, but the instantiation - dependence is in the operand type. */ - examine_type_for_instantiation_dependence(expr->variant.type_operand.type, - tblock); - skip_typecheck = TRUE; - } /* if */ - if (skip_typecheck || tblock->terminate) { - /* No need to check the type. */ - } else { - examine_type_for_instantiation_dependence(expr->type, tblock); - } /* if */ -} /* examine_expr_for_instantiation_dependence */ - - -static void examine_dyn_init_for_instantiation_dependence( - a_dynamic_init_ptr dip, - ARG_UNUSED an_expr_or_stmt_traversal_block_ptr tblock) -/* -Check if the given dynamic initializer is instantiation-dependent. Called -indirectly by expr_is_instantiation_dependent. -*/ -{ - if (dyn_init_is(dip, dik_constructor)) { - if (dip->variant.constructor.ptr == NULL) { - /* An unknown constructor only occurs when it is template-dependent. */ - tblock->result = TRUE; - tblock->terminate = TRUE; - } /* if */ - } /* if */ -} /* examine_dyn_init_for_instantiation_dependence */ - - 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/il_walk.c b/src/il_walk.c index 12b733b2cd..c8268826c9 100644 --- a/src/il_walk.c +++ b/src/il_walk.c @@ -3773,20 +3773,25 @@ list. } /* traverse_local_expr_node_ref_list */ -static void traverse_variable_init(a_variable_ptr var, - an_expr_or_stmt_traversal_block_ptr tblock) +void traverse_variable_init(a_variable_ptr var, + an_expr_or_stmt_traversal_block_ptr tblock) /* -The specified variable (which may be NULL) may have a dynamic initialization. -Such dynamic initializations are not pointed to by stmk_init statements, so -they are traversed here. Call user-provided routines as specified in the -control block. +Traverse the initializer of the specified variable (which may be NULL). +Some initializers are not pointed to by stmk_init statements and must be +traversed through the variable instead. Call user-provided routines as +specified in the control block. */ { if (var != NULL) { - if (var->initializer.dynamic != NULL) { - /* These variables should only have dynamic initialization. */ - check_assertion(var->init_kind == (an_init_kind)initk_dynamic); - traverse_dynamic_init(var->initializer.dynamic, tblock); + an_init_kind init_kind; + an_initializer_ptr initializer; + get_variable_initializer(var, (a_scope_ptr)NULL, &init_kind, &initializer); + if (init_kind == (an_init_kind)initk_dynamic) { + traverse_dynamic_init(initializer->dynamic, tblock); + } else if (init_kind == (an_init_kind)initk_static) { + traverse_constant(initializer->constant, tblock); + } else if (init_kind == (an_init_kind)initk_binding) { + traverse_expr(initializer->bound_expr, tblock); } /* if */ } /* if */ } /* traverse_variable_init */ diff --git a/src/il_walk.h b/src/il_walk.h index ddb850c90d..c399d84d96 100644 --- a/src/il_walk.h +++ b/src/il_walk.h @@ -449,6 +449,10 @@ extern a_boolean constant_is_recursive(a_constant *cp); extern void traverse_dynamic_init(a_dynamic_init_ptr dip, an_expr_or_stmt_traversal_block_ptr tblock); +extern void traverse_variable_init( + a_variable_ptr var, + an_expr_or_stmt_traversal_block_ptr tblock); + extern void traverse_expr_list(an_expr_node_ptr expr_list, an_expr_or_stmt_traversal_block_ptr tblock); 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..3186ace56f --- /dev/null +++ b/src/pending_changes/gh-338-lambda-template-param.txt @@ -0,0 +1,16 @@ +[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. + } + +Concept type-constraint checks also retain their bound arguments across nested +lambda rescans, including template-template arguments used by generic lambdas. diff --git a/src/scope_stk.c b/src/scope_stk.c index 0e103d5532..c079b2313d 100644 --- a/src/scope_stk.c +++ b/src/scope_stk.c @@ -2025,7 +2025,9 @@ static a_boolean template_arg_can_update_param_symbol(a_template_arg_ptr tap) /* Return TRUE if tap has a value that can be used to update a template parameter symbol. Missing entries can occur in deduction and partial-ordering argument -lists that are not complete instantiation argument lists. +lists that are not complete instantiation argument lists. An array bound of +unknown type is also treated as missing because its bound is not a usable +value. */ { a_boolean result = TRUE; @@ -2033,7 +2035,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 +2144,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 +2231,200 @@ 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 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) { + restore_default_template_param(tpp); + } /* for */ + } 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) { + for (a_scope_depth 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 (a_scope_depth 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 +5972,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 +10612,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 +12151,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 +13383,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 d630c1d6a8..676c5368a5 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..0c67fe2ff7 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,22 @@ 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); + /* An access-checking scope may have been pushed above this scope. */ + scope_stack[depth_innermost_instantiation_scope].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 +11745,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 +19274,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 +19307,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)) && diff --git a/tests/expectations/edg_x86_64/imported.log b/tests/expectations/edg_x86_64/imported.log index 1e83804c54..d7d37c644c 100644 --- a/tests/expectations/edg_x86_64/imported.log +++ b/tests/expectations/edg_x86_64/imported.log @@ -7114,14 +7114,12 @@ gnu/cpp/cpp2a/lambda-generic2.sft.cpp:fn:-DTEST_NUMBER=1 --c++17:FAIL: gnu/cpp/cpp2a/lambda-generic3.sft.cpp:fn:-DTEST_NUMBER=1 --c++17:FAIL: gnu/cpp/cpp2a/lambda-generic7.sft.cpp:fn:-DTEST_NUMBER=1 --c++20:FAIL: gnu/cpp/cpp2a/lambda-targ1.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: -gnu/cpp/cpp2a/lambda-targ4.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: gnu/cpp/cpp2a/lambda-targ7.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:ABORT: gnu/cpp/cpp2a/lambda-targ8.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: gnu/cpp/cpp2a/lambda-this3.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:FAIL: gnu/cpp/cpp2a/lambda-uneval11.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: gnu/cpp/cpp2a/lambda-uneval13.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: gnu/cpp/cpp2a/lambda-uneval3.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: -gnu/cpp/cpp2a/lambda-uneval7.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: gnu/cpp/cpp2a/lambda-uneval8.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL: gnu/cpp/cpp2a/linkage-spec1.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL: gnu/cpp/cpp2a/nontype-class17.sft.cpp:fn:-DTEST_NUMBER=1 --c++20:FAIL: diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx2a.rto/edg_x86_32.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx2a.rto/edg_x86_32.1.1.txt deleted file mode 100644 index 055c6eb1dc..0000000000 --- a/tests/tests/imported/clang/cpp/SemaCXX/.constant-expression-cxx2a.rto/edg_x86_32.1.1.txt +++ /dev/null @@ -1,496 +0,0 @@ -fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 --exceptions Test_name.c -"SemaCXX/constant-expression-cxx2a.cpp", line 45: warning: expression has no effect - constexpr int k = (1 <=> 1, 0); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 121: error: expression must have a constant value - constexpr bool tc9 = (&dummy <=> &dummy2) != 0; - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 121: note: pointer values cannot be compared because they do not point into the same complete object or they point to subobjects with different accessibility - constexpr bool tc9 = (&dummy <=> &dummy2) != 0; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 176: error: static assertion failed - static_assert(d.ba == 'B'); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 176: note: the final comparison was 65 == 66 - static_assert(d.ba == 'B'); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 181: error: static assertion failed - static_assert(a.f() == 'D'); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 181: note: the final comparison was 65 == 68 - static_assert(a.f() == 'D'); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 182: error: static assertion failed - static_assert(b.f() == 'D'); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 182: note: the final comparison was 66 == 68 - static_assert(b.f() == 'D'); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 199: error: return type is not identical to nor covariant with return type "const Virtual::A *" of overridden virtual function "Virtual::Covariant1::f" - constexpr virtual const D *f() const { return &this->d; } - ^ - detected during instantiation of class "Virtual::Covariant3 [with T=Virtual::B]" at line 202 - -"SemaCXX/constant-expression-cxx2a.cpp", line 199: error: return type is not identical to nor covariant with return type "const Virtual::A *" of overridden virtual function "Virtual::Covariant1::f" - constexpr virtual const D *f() const { return &this->d; } - ^ - detected during instantiation of class "Virtual::Covariant3 [with T=Virtual::C]" at line 203 - -"SemaCXX/constant-expression-cxx2a.cpp", line 209: error: static assertion failed - static_assert(cb1->f()->f() == 'D'); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 209: note: the final comparison was 65 == 68 - static_assert(cb1->f()->f() == 'D'); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 212: error: static assertion failed - static_assert(cb2->f()->f() == 'D'); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 212: note: the final comparison was 66 == 68 - static_assert(cb2->f()->f() == 'D'); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 232: error: initialization is not constant - constexpr PureVirtualCall pure_virtual_call; - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 229: note: cannot call non-constexpr function "Virtual::PureVirtualCall::f" (declared at line 231) - constexpr void do_it() { f(); } - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 228: note: called from: - constexpr Abstract() { do_it(); } - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 231: note: called from: - struct PureVirtualCall : Abstract { void f(); }; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 259: error: expression must have a constant value - constexpr int d_a = (dynamic_cast(static_cast(g)), 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 259: note: base class "DynamicCast::A" is ambiguous - constexpr int d_a = (dynamic_cast(static_cast(g)), 0); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 267: error: expression must have a constant value - static_assert(&dynamic_cast((D&)g) == &(A&)(B&)g); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 267: note: base class "DynamicCast::A" is ambiguous - static_assert(&dynamic_cast((D&)g) == &(A&)(B&)g); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 278: error: expression must have a constant value - constexpr int b_e = (dynamic_cast((B&)g), 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 278: note: conversion to inaccessible base class "DynamicCast::E" is not allowed - constexpr int b_e = (dynamic_cast((B&)g), 0); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 282: error: expression must have a constant value - constexpr int b_unrelated = (dynamic_cast((B&)g), 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 282: note: dynamic_cast to subobject of type "DynamicCast::Unrelated" is invalid (most-derived type is "DynamicCast::G") - constexpr int b_unrelated = (dynamic_cast((B&)g), 0); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 284: error: expression must have a constant value - constexpr int e_unrelated = (dynamic_cast((E&)g), 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 284: note: dynamic_cast to subobject of type "DynamicCast::Unrelated" is invalid (most-derived type is "DynamicCast::G") - constexpr int e_unrelated = (dynamic_cast((E&)g), 0); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 315: error: static assertion failed - static_assert(&typeid(b1) == &typeid(B2)); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 324: warning: variable "a2" was set but never used - A2 a2; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 334: warning: variable "b2" was set but never used - B2 b2; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 380: error: expression must have a constant value - static_assert(read_uninitialized() == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 378: note: access to uninitialized object - return *p; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 411: error: expression must have a constant value - constexpr B uninit = return_uninit(); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 409: note: access to uninitialized object - return b; - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 409: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 412: error: expression must have a constant value - static_assert(return_uninit().a.x == 2); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 409: note: access to uninitialized object - return b; - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 409: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 424: error: expression must have a constant value - static_assert(return_uninit_struct().x == 2); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 416: note: access to uninitialized object - return b.a; - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 416: note: access to uninitialized object - return b.a; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 434: error: expression must have a constant value - static_assert(return_init_all().a.x == 2); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 435: error: expression must have a constant value - static_assert(return_init_all().a.y == 3); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 436: error: expression must have a constant value - static_assert(return_init_all().a.arr[0] == 4); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 437: error: expression must have a constant value - static_assert(return_init_all().a.arr[1] == 5); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 438: error: expression must have a constant value - static_assert(return_init_all().a.arr[2] == 6); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 439: error: expression must have a constant value - static_assert(return_init_all().a.p == 7); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 440: error: expression must have a constant value - static_assert(return_init_all().a.q == 8); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 441: error: expression must have a constant value - constexpr B init_all = return_init_all(); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 432: note: access to uninitialized object - return b; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 445: warning: variable "u1" was set but never used - U u1; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 457: warning: variable "s" was set but never used - S3 s; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 472: warning: variable "r" was set but never used - ref_member_3 r = {.a = {.r = {.a = 1}}}; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 478: warning: variable "r" was set but never used - ref_member_3 r = {.a = {.r = {.a = 1}}}; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 518: warning: missing return statement at end of non-void function "Union::PR43762::test" - } - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 551: error: expression must have a constant value - static_assert(f(false) == 1); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 548: note: access to uninitialized object - return a; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 560: error: expression must have a constant value - constinit X x2(false); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 560: note: access to uninitialized subobject (member "Uninit::X::n") - constinit X x2(false); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 586: error: expression must have a constant value - static_assert(Y(0,0).z1.n == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 586: note: access to uninitialized object - static_assert(Y(0,0).z1.n == 0); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 587: error: expression must have a constant value - static_assert(Y(0,0).z3.n == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 587: note: access to uninitialized object - static_assert(Y(0,0).z3.n == 0); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 589: error: expression must have a constant value - static_assert(copy(Y(0,0)).z2.n == 0); - ^ -Note: access to uninitialized object - -"SemaCXX/constant-expression-cxx2a.cpp", line 593: warning: variable "c" is used before its value is set - return c; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 595: error: expression must have a constant value - constexpr unsigned char x = not_even_unsigned_char(); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 593: note: access to uninitialized object - return c; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 608: warning: missing return statement at end of non-void function "Uninit::switch_var" - } - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 609: error: expression must have a constant value - constexpr int s1 = switch_var(1); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 601: note: attempt to access run-time storage - a = n; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 610: error: expression must have a constant value - constexpr int s2 = switch_var(2); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 605: note: attempt to access run-time storage - a = n; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 615: warning: statement is unreachable - if (int n; false) { - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 623: warning: missing return statement at end of non-void function "Uninit::switch_into_init_stmt" - } - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 624: error: expression must have a constant value - static_assert(switch_into_init_stmt()); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 618: note: attempt to access run-time storage - n = m = 1; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 685: error: expression must have a constant value - static_assert(dtor_calls_dtor()); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 656: note: invalid access to inactive member "U::u" of union (no field is active) - constexpr ~U() { u.buf += 'U'; } - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 677: note: called from: - B b(buf); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 677: note: called from: - B b(buf); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 689: warning: local class member function "Indestructible::~Indestructible" requires a definition - constexpr ~Indestructible(); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 732: error: static assertion failed - static_assert(check_abnormal_termination()); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 752: error: expression must have a constant value - new int; - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 752: note: invalid use of address of interpreter storage - new int; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 834: error: expression must have a constant value - static_assert(vdtor_3(0) == 3); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 818: note: deallocation does not match allocation kind (one is for an array and the other not) - delete p; - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 815: note: allocation occurred here - S *p = new T[3]{&a, &a, &a}; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 835: error: expression must have a constant value - static_assert(vdtor_3(1) == 3); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 823: note: deallocation of storage that was not dynamically allocated - delete[] p; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 836: error: expression must have a constant value - static_assert(vdtor_3(2) == 3); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 812: note: access to uninitialized object - constexpr ~T() { ++*p; } - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 826: note: called from: - delete (T*)p; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 859: error: expression must have a constant value - static_assert(dynarray(4, 4) == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 851: note: attempt to access storage one position past the end of an array of 4 elements - T n = p[i]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 861: error: expression must have a constant value - static_assert(dynarray(3, 3) == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 851: note: attempt to access storage one position past the end of an array of 3 elements - T n = p[i]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 862: error: expression must have a constant value - static_assert(dynarray(2, 1) == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 850: note: number of dynamically-allocated elements (2) too small for initializer - p = new T[elems]{1, 2, 3}; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 868: error: expression must have a constant value - static_assert(dynarray(5, 5) == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 851: note: attempt to access storage one position past the end of an array of 5 elements - T n = p[i]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 873: error: expression must have a constant value - static_assert(dynarray(4, 4) == 0); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 851: note: attempt to access storage one position past the end of an array of 4 elements - T n = p[i]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 874: error: expression must have a constant value - static_assert(dynarray(3, 2) == 'x'); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 848: note: number of dynamically-allocated elements (3) too small for initializer - p = new T[elems]{"fox"}; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 892: error: expression must have a constant value - static_assert(erroneous_array_bound(-1)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 887: note: number of elements (-1) too large for dynamic allocation - delete[] new int[n]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 893: error: expression must have a constant value - static_assert(erroneous_array_bound(1LL << 62)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 887: note: number of elements (0) too large for dynamic allocation - delete[] new int[n]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 901: error: expression must have a constant value - static_assert(erroneous_array_bound_nothrow(3)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 896: note: a placement new-expression cannot be constant-evaluated - int *p = new (std::nothrow) int[n]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 902: error: expression must have a constant value - static_assert(erroneous_array_bound_nothrow(0)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 896: note: a placement new-expression cannot be constant-evaluated - int *p = new (std::nothrow) int[n]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 903: error: expression must have a constant value - static_assert(!erroneous_array_bound_nothrow(-1)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 896: note: number of elements (-1) too large for dynamic allocation - int *p = new (std::nothrow) int[n]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 904: error: expression must have a constant value - static_assert(!erroneous_array_bound_nothrow(1LL << 62)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 896: note: number of elements (0) too large for dynamic allocation - int *p = new (std::nothrow) int[n]; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 911: error: expression must have a constant value - static_assert(evaluate_nothrow_arg()); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 908: note: a placement new-expression cannot be constant-evaluated - delete new ((ok = true, std::nothrow)) int; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 925: error: expression must have a constant value - static_assert(super_secret_double_delete()); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 925: note: expression not folded to a constant due to excessive constexpr function call complexity - static_assert(super_secret_double_delete()); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 1020: error: expression must have a constant value - static_assert(bad(0)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 996: note: a placement new-expression cannot be constant-evaluated - delete new (placement_new_arg{}) int; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 1021: error: expression must have a constant value - static_assert(bad(1)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 1000: note: a new-expression calling a class-specific allocation function cannot be constant-evaluated - delete new ClassSpecificNew; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 1024: error: expression must have a constant value - static_assert(bad(4)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 1014: note: a placement new-expression cannot be constant-evaluated - delete new (std::align_val_t{64}) Overaligned; - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 1031: error: expression must have a constant value - static_assert((delete &n, true)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 1031: note: deallocation of storage that was not dynamically allocated - static_assert((delete &n, true)); - ^ - -"SemaCXX/constant-expression-cxx2a.cpp", line 1033: error: expression must have a constant value - static_assert((delete &(new A)->n, true)); - ^ -"SemaCXX/constant-expression-cxx2a.cpp", line 1033: note: deleting through a subobject pointer requires a virtual destructor - static_assert((delete &(new A)->n, true)); - ^ - -eccp: front end returned an exit status of 139 diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.1.1.txt index e86a8f1dcb..a8b7824651 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.1.1.txt @@ -32,24 +32,12 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers void use_f() { f({}); } // expected-error {{ambiguous}} ^ -"Test_name.c", line 67: error: identifier "N" is undefined - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ - -"Test_name.c", line 66: error: identifier "N" is undefined - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ - -"Test_name.c", line 68: error: no instance of overloaded function "PR52073::g" matches the argument list +"Test_name.c", line 68: error: more than one instance of overloaded function "PR52073::g" matches the argument list: + function template "void PR52073::g(const char (*)[])" (declared at line 66) + function template "void PR52073::g(const char (*)[])" (declared at line 67) argument types are: (const char (*)[6]) void use_g() { g<6>(&"hello"); } // expected-error {{ambiguous}} ^ -"Test_name.c", line 67: note: substituting explicit template arguments "<6>" for function template "PR52073::g(const char (*)[])" failed - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ -"Test_name.c", line 66: note: substituting explicit template arguments "<6>" for function template "PR52073::g(const char (*)[])" failed - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ "Test_name.c", line 79: error: declaration is incompatible with "void GH51416::A::spam(decltype(()))" (declared at line 75) void A::spam(decltype([] {})) // expected-error{{out-of-line definition of 'spam' does not match}} @@ -226,4 +214,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr auto Ret = ICE()(1); ^ -28 errors detected in the compilation of "Test_name.c". +26 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.2.1.txt index 0955c9f228..1a5d8a6ddb 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.lambda-unevaluated.rto/default.2.1.txt @@ -32,24 +32,12 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers void use_f() { f({}); } // expected-error {{ambiguous}} ^ -"Test_name.c", line 67: error: identifier "N" is undefined - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ - -"Test_name.c", line 66: error: identifier "N" is undefined - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ - -"Test_name.c", line 68: error: no instance of overloaded function "PR52073::g" matches the argument list +"Test_name.c", line 68: error: more than one instance of overloaded function "PR52073::g" matches the argument list: + function template "void PR52073::g(const char (*)[])" (declared at line 66) + function template "void PR52073::g(const char (*)[])" (declared at line 67) argument types are: (const char (*)[6]) void use_g() { g<6>(&"hello"); } // expected-error {{ambiguous}} ^ -"Test_name.c", line 67: note: substituting explicit template arguments "<6>" for function template "PR52073::g(const char (*)[])" failed - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ -"Test_name.c", line 66: note: substituting explicit template arguments "<6>" for function template "PR52073::g(const char (*)[])" failed - template void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}} - ^ "Test_name.c", line 79: error: declaration is incompatible with "void GH51416::A::spam(decltype(()))" (declared at line 75) void A::spam(decltype([] {})) // expected-error{{out-of-line definition of 'spam' does not match}} @@ -150,4 +138,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr auto Ret = ICE()(1); ^ -28 errors detected in the compilation of "Test_name.c". +26 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaTemplate/.alias-template-with-lambdas.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaTemplate/.alias-template-with-lambdas.rto/default.1.1.txt index e7ef7010c5..21ecb4bea5 100644 --- a/tests/tests/imported/clang/cpp/SemaTemplate/.alias-template-with-lambdas.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaTemplate/.alias-template-with-lambdas.rto/default.1.1.txt @@ -88,6 +88,27 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers instantiation of "lambda [](char, int, long, unsigned int)->auto" based on template argument at line 43 instantiation of type "lambda_calls::MeowMeow" at line 81 +"Test_name.c", line 43: error: argument list for alias template "lambda_calls::U" is missing + using MeowMeow = decltype([](U...) {}.template operator()(U()...)); + ^ + detected during: + instantiation of "lambda [](char, int, long, unsigned int)->auto" based on template argument at line 43 + instantiation of type "lambda_calls::MeowMeow" at line 81 + +"Test_name.c", line 43: error: argument list for alias template "lambda_calls::U" is missing + using MeowMeow = decltype([](U...) {}.template operator()(U()...)); + ^ + detected during: + instantiation of "lambda [](char, int, long, unsigned int)->auto" based on template argument at line 43 + instantiation of type "lambda_calls::MeowMeow" at line 81 + +"Test_name.c", line 43: error: argument list for alias template "lambda_calls::U" is missing + using MeowMeow = decltype([](U...) {}.template operator()(U()...)); + ^ + detected during: + instantiation of "lambda [](char, int, long, unsigned int)->auto" based on template argument at line 43 + instantiation of type "lambda_calls::MeowMeow" at line 81 + "Test_name.c", line 43: error: cannot deduce the return type of function "lambda [](char, int, long, unsigned int)->auto [with =char]" (declared at line 43); it has not been defined using MeowMeow = decltype([](U...) {}.template operator()(U()...)); ^ @@ -97,14 +118,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers int x = T11()(); ^ -"Test_name.c", line 100: error: identifier "T" is undefined - return Value + V + (int)sizeof(Param); - ^ - detected during: - instantiation of function "lambda [](auto)->auto [with V=0, =const char *]" at line 101 - instantiation of type "lambda_calls::GH82104::T14" at line 103 - instantiation of type "lambda_calls::GH82104::T15" at line 105 - "Test_name.c", line 100: error: argument list for alias template "lambda_calls::U" is missing return Value + V + (int)sizeof(Param); ^ @@ -113,14 +126,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers instantiation of type "lambda_calls::GH82104::T14" at line 103 instantiation of type "lambda_calls::GH82104::T15" at line 105 -"Test_name.c", line 100: error: expected a ">" - return Value + V + (int)sizeof(Param); - ^ - detected during: - instantiation of function "lambda [](auto)->auto [with V=0, =const char *]" at line 101 - instantiation of type "lambda_calls::GH82104::T14" at line 103 - instantiation of type "lambda_calls::GH82104::T15" at line 105 - "Test_name.c", line 121: warning: constant "m" is not used in declaring the parameter types of function template "lambda_calls::GH89853::lambda []()->auto::operator auto (*)()" static constexpr auto innocuous = [] { return m; }; ^ @@ -164,4 +169,4 @@ At end of source: error: expected a "}" namespace lambda_calls { ^ -19 errors detected in the compilation of "Test_name.c". +20 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.1.1.txt index 62f78483c2..6e0e775c1a 100644 --- a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.1.1.txt @@ -7,14 +7,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers static_assert(ConstructibleWithN); ^ -"Test_name.c", line 102: error: Template is not a template - { [] (Template &) {}(declare()) }; - ^ - -"Test_name.c", line 114: error: incomplete type "LambdaInConcept::GH56556::Adapter>" is not allowed - template struct Adapter>; - ^ - "Test_name.c", line 125: error: identifier "V" is undefined [](V w) {}(v); ^ @@ -44,21 +36,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers auto caller = make_caller.operator()<&S1::f1>(); ^ -"Test_name.c", line 218: error: no instance of function template "lambda [](auto, auto...)->auto" matches the argument list - argument types are: (int) - object type is: lambda [](auto, auto...)->auto - return [](auto obj, auto... params) - ^ -"Test_name.c", line 218: note: substituting "" for function template "lambda [](auto, auto...)->auto" failed constraints - return [](auto obj, auto... params) - ^ -"Test_name.c", line 219: note: atomic constraint evaluates to false - requires requires { - ^ - detected during: - instantiation of function "lambda [](auto)->auto [with =int]" at line 226 - instantiation of function "lambda [](auto)->auto [with =int]" at line 227 - "Test_name.c", line 249: error: a requires-clause is not allowed here (not a templated function) requires requires { sink(y..., z); } ^ @@ -111,4 +88,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr auto bar = foo(seq<0>()); ^ -15 errors detected in the compilation of "Test_name.c". +12 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.2.1.txt index 6dd7c48331..1b470eb466 100644 --- a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/default.2.1.txt @@ -7,14 +7,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers static_assert(ConstructibleWithN); ^ -"Test_name.c", line 102: error: Template is not a template - { [] (Template &) {}(declare()) }; - ^ - -"Test_name.c", line 114: error: incomplete type "LambdaInConcept::GH56556::Adapter>" is not allowed - template struct Adapter>; - ^ - "Test_name.c", line 125: error: identifier "V" is undefined [](V w) {}(v); ^ @@ -44,21 +36,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers auto caller = make_caller.operator()<&S1::f1>(); ^ -"Test_name.c", line 218: error: no instance of function template "lambda [](auto, auto...)->auto" matches the argument list - argument types are: (int) - object type is: lambda [](auto, auto...)->auto - return [](auto obj, auto... params) - ^ -"Test_name.c", line 218: note: substituting "" for function template "lambda [](auto, auto...)->auto" failed constraints - return [](auto obj, auto... params) - ^ -"Test_name.c", line 219: note: atomic constraint evaluates to false - requires requires { - ^ - detected during: - instantiation of function "lambda [](auto)->auto [with =int]" at line 226 - instantiation of function "lambda [](auto)->auto [with =int]" at line 227 - "Test_name.c", line 249: error: a requires-clause is not allowed here (not a templated function) requires requires { sink(y..., z); } ^ @@ -111,4 +88,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr auto bar = foo(seq<0>()); ^ -15 errors detected in the compilation of "Test_name.c". +12 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.1.1.txt b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.1.1.txt index c6767d36b8..ecb12c289a 100644 --- a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.1.1.txt @@ -7,14 +7,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers static_assert(ConstructibleWithN); ^ -"Test_name.c", line 102: error: Template is not a template - { [] (Template &) {}(declare()) }; - ^ - -"Test_name.c", line 114: error: incomplete type "LambdaInConcept::GH56556::Adapter>" is not allowed - template struct Adapter>; - ^ - "Test_name.c", line 125: error: identifier "V" is undefined [](V w) {}(v); ^ @@ -44,21 +36,6 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers auto caller = make_caller.operator()<&S1::f1>(); ^ -"Test_name.c", line 218: error: no instance of function template "lambda [](auto, auto...)->auto" matches the argument list - argument types are: (int) - object type is: lambda [](auto, auto...)->auto - return [](auto obj, auto... params) - ^ -"Test_name.c", line 218: note: substituting "" for function template "lambda [](auto, auto...)->auto" failed constraints - return [](auto obj, auto... params) - ^ -"Test_name.c", line 219: note: atomic constraint evaluates to false - requires requires { - ^ - detected during: - instantiation of function "lambda [](auto)->auto [with =int]" at line 226 - instantiation of function "lambda [](auto)->auto [with =int]" at line 227 - "Test_name.c", line 249: error: a requires-clause is not allowed here (not a templated function) requires requires { sink(y..., z); } ^ @@ -111,4 +88,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr auto bar = foo(seq<0>()); ^ -15 errors detected in the compilation of "Test_name.c". +12 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.2.1.txt b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.2.1.txt index 59596584d7..c3e7e448da 100644 --- a/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaTemplate/.concepts-lambda.rto/edg_x86_64_cp.2.1.txt @@ -7,14 +7,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers static_assert(ConstructibleWithN); ^ -"Test_name.c", line 102: error: Template is not a template - { [] (Template &) {}(declare()) }; - ^ - -"Test_name.c", line 114: error: incomplete type "LambdaInConcept::GH56556::Adapter>" is not allowed - template struct Adapter>; - ^ - "Test_name.c", line 125: error: identifier "V" is undefined [](V w) {}(v); ^ @@ -44,21 +36,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers auto caller = make_caller.operator()<&S1::f1>(); ^ -"Test_name.c", line 218: error: no instance of function template "lambda [](auto, auto...)->auto" matches the argument list - argument types are: (int) - object type is: lambda [](auto, auto...)->auto - return [](auto obj, auto... params) - ^ -"Test_name.c", line 218: note: substituting "" for function template "lambda [](auto, auto...)->auto" failed constraints - return [](auto obj, auto... params) - ^ -"Test_name.c", line 219: note: atomic constraint evaluates to false - requires requires { - ^ - detected during: - instantiation of function "lambda [](auto)->auto [with =int]" at line 226 - instantiation of function "lambda [](auto)->auto [with =int]" at line 227 - "Test_name.c", line 249: error: a requires-clause is not allowed here (not a templated function) requires requires { sink(y..., z); } ^ @@ -111,4 +88,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers constexpr auto bar = foo(seq<0>()); ^ -15 errors detected in the compilation of "Test_name.c". +12 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/gnu/cpp/cpp2a/.lambda-targ4.rto/default.1.1.txt b/tests/tests/imported/gnu/cpp/cpp2a/.lambda-targ4.rto/default.1.1.txt index c37094bcb4..2ed4eaf390 100644 --- a/tests/tests/imported/gnu/cpp/cpp2a/.lambda-targ4.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/cpp/cpp2a/.lambda-targ4.rto/default.1.1.txt @@ -1,6 +1 @@ fe_only -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics --c++20 Test_name.c -"Test_name.c", line 8: error: identifier "T" is undefined - template - ^ - -1 error detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/gnu/cpp/cpp2a/.lambda-uneval7.rto/default.1.1.txt b/tests/tests/imported/gnu/cpp/cpp2a/.lambda-uneval7.rto/default.1.1.txt index 98832623f9..2ed4eaf390 100644 --- a/tests/tests/imported/gnu/cpp/cpp2a/.lambda-uneval7.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/cpp/cpp2a/.lambda-uneval7.rto/default.1.1.txt @@ -1,6 +1 @@ fe_only -DTEST_NUMBER=1 --gnu_version=999999 -tused -e 200 --no_wrap --no_wrap_diagnostics --c++20 Test_name.c -"Test_name.c", line 9: error: identifier "N" is undefined - void g(A<[]{return N;}()>) {} - ^ - -1 error detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-338-diag.rto/default.1.1.txt b/tests/tests/regressions/.gh-338-diag.rto/default.1.1.txt new file mode 100644 index 0000000000..211ad1f590 --- /dev/null +++ b/tests/tests/regressions/.gh-338-diag.rto/default.1.1.txt @@ -0,0 +1,34 @@ +fe_only -DTEST_NUMBER=1 --c++20 Test_name.c +"Test_name.c", line 14: error: no instance of function template "lambda_parameter_type_mismatch::f" matches the argument list + argument types are: (char (*)[4]) + f(&a); + ^ +"Test_name.c", line 8: note: function template "lambda_parameter_type_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](T x) { return x; }(T{}))]) {} + ^ + +"Test_name.c", line 26: error: no instance of function template "unnamed_lambda_parameter_mismatch::f" matches the argument list + argument types are: (char (*)[5]) + f(&a); + ^ +"Test_name.c", line 21: note: function template "unnamed_lambda_parameter_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](T) { return T(); }(1))]) {} + ^ + +"Test_name.c", line 38: error: no instance of function template "lambda_body_type_mismatch::f" matches the argument list + argument types are: (char (*)[5]) + f(&a); + ^ +"Test_name.c", line 33: note: function template "lambda_body_type_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](int) { return T(); }(1))]) {} + ^ + +"Test_name.c", line 52: error: no instance of function template "indirect_template_parameter_dependency::f" matches the argument list + argument types are: (long long, char (*)[8]) + f(1LL, &a); + ^ +"Test_name.c", line 47: note: function template "indirect_template_parameter_dependency::f" does not match because argument #2 does not match parameter + void f(T x, char (*)[sizeof([](decltype(x) y) { return y; }(x))]) {} + ^ + +4 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-338-diag.rto/default.2.1.txt b/tests/tests/regressions/.gh-338-diag.rto/default.2.1.txt new file mode 100644 index 0000000000..cafe6521dc --- /dev/null +++ b/tests/tests/regressions/.gh-338-diag.rto/default.2.1.txt @@ -0,0 +1,65 @@ +fe_only -DTEST_NUMBER=2 --c++20 --gnu_version=150200 Test_name.c +"Test_name.c", line 14: error: no instance of function template "lambda_parameter_type_mismatch::f" matches the argument list + argument types are: (char (*)[4]) + f(&a); + ^ +"Test_name.c", line 8: note: function template "lambda_parameter_type_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](T x) { return x; }(T{}))]) {} + ^ + +"Test_name.c", line 26: error: no instance of function template "unnamed_lambda_parameter_mismatch::f" matches the argument list + argument types are: (char (*)[5]) + f(&a); + ^ +"Test_name.c", line 21: note: function template "unnamed_lambda_parameter_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](T) { return T(); }(1))]) {} + ^ + +"Test_name.c", line 38: error: no instance of function template "lambda_body_type_mismatch::f" matches the argument list + argument types are: (char (*)[5]) + f(&a); + ^ +"Test_name.c", line 33: note: function template "lambda_body_type_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](int) { return T(); }(1))]) {} + ^ + +"Test_name.c", line 52: error: no instance of function template "indirect_template_parameter_dependency::f" matches the argument list + argument types are: (long long, char (*)[8]) + f(1LL, &a); + ^ +"Test_name.c", line 47: note: function template "indirect_template_parameter_dependency::f" does not match because argument #2 does not match parameter + void f(T x, char (*)[sizeof([](decltype(x) y) { return y; }(x))]) {} + ^ + +"Test_name.c", line 66: error: no instance of function template "non_type_template_argument_mismatch::f" matches the argument list + argument types are: (non_type_template_argument_mismatch::A<2>) + f<1>(A<2>{}); + ^ +"Test_name.c", line 60: note: function template "non_type_template_argument_mismatch::f" does not match because argument #1 does not match parameter + template void f(A<[] { return N; }()>) {} + ^ + +"Test_name.c", line 79: error: no instance of function template "nested_lambda_array_bound_mismatch::f" matches the argument list + argument types are: (char (*)[6]) + f<1, int>(&b); + ^ +"Test_name.c", line 73: note: function template "nested_lambda_array_bound_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[([] { return [] { return N + int(sizeof(T)); }(); }())]) {} + ^ + +"Test_name.c", line 92: error: more than one instance of overloaded function "incomplete_template_arguments::f" matches the argument list: + function template "void incomplete_template_arguments::f(const char (*)[])" (declared at line 88) + function template "void incomplete_template_arguments::f(const char (*)[])" (declared at line 90) + argument types are: (const char (*)[6]) + void test() { f<6>(&"hello"); } + ^ + +"Test_name.c", line 106: error: no instance of function template "undeduced_parameter_hides_outer_name::f" matches the argument list + argument types are: (char (*)[7], double) + f<6>(&a, 1.0); + ^ +"Test_name.c", line 101: note: function template "undeduced_parameter_hides_outer_name::f" does not match because argument #1 does not match parameter + void f(char (*)[([] { return N + sizeof(U); }())], U) {} + ^ + +8 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-338-diag.rto/default.3.1.txt b/tests/tests/regressions/.gh-338-diag.rto/default.3.1.txt new file mode 100644 index 0000000000..62df63eab6 --- /dev/null +++ b/tests/tests/regressions/.gh-338-diag.rto/default.3.1.txt @@ -0,0 +1,70 @@ +fe_only -DTEST_NUMBER=3 --c++20 --clang_version=210000 Test_name.c +"Test_name.c", line 14: error: no instance of function template "lambda_parameter_type_mismatch::f" matches the argument list + argument types are: (char (*)[4]) + f(&a); + ^ +"Test_name.c", line 8: note: function template "lambda_parameter_type_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](T x) { return x; }(T{}))]) {} + ^ + +"Test_name.c", line 26: error: no instance of function template "unnamed_lambda_parameter_mismatch::f" matches the argument list + argument types are: (char (*)[5]) + f(&a); + ^ +"Test_name.c", line 21: note: function template "unnamed_lambda_parameter_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](T) { return T(); }(1))]) {} + ^ + +"Test_name.c", line 38: error: no instance of function template "lambda_body_type_mismatch::f" matches the argument list + argument types are: (char (*)[5]) + f(&a); + ^ +"Test_name.c", line 33: note: function template "lambda_body_type_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[sizeof([](int) { return T(); }(1))]) {} + ^ + +"Test_name.c", line 52: error: no instance of function template "indirect_template_parameter_dependency::f" matches the argument list + argument types are: (long long, char (*)[8]) + f(1LL, &a); + ^ +"Test_name.c", line 47: note: function template "indirect_template_parameter_dependency::f" does not match because argument #2 does not match parameter + void f(T x, char (*)[sizeof([](decltype(x) y) { return y; }(x))]) {} + ^ + +"Test_name.c", line 66: error: no instance of function template "non_type_template_argument_mismatch::f" matches the argument list + argument types are: (non_type_template_argument_mismatch::A<2>) + f<1>(A<2>{}); + ^ +"Test_name.c", line 60: note: function template "non_type_template_argument_mismatch::f" does not match because argument #1 does not match parameter + template void f(A<[] { return N; }()>) {} + ^ + +"Test_name.c", line 79: error: no instance of function template "nested_lambda_array_bound_mismatch::f" matches the argument list + argument types are: (char (*)[6]) + f<1, int>(&b); + ^ +"Test_name.c", line 73: note: function template "nested_lambda_array_bound_mismatch::f" does not match because argument #1 does not match parameter + void f(char (*)[([] { return [] { return N + int(sizeof(T)); }(); }())]) {} + ^ + +"Test_name.c", line 92: error: more than one instance of overloaded function "incomplete_template_arguments::f" matches the argument list: + function template "void incomplete_template_arguments::f(const char (*)[])" (declared at line 88) + function template "void incomplete_template_arguments::f(const char (*)[])" (declared at line 90) + argument types are: (const char (*)[6]) + void test() { f<6>(&"hello"); } + ^ + +"Test_name.c", line 106: error: no instance of function template "undeduced_parameter_hides_outer_name::f" matches the argument list + argument types are: (char (*)[7], double) + f<6>(&a, 1.0); + ^ +"Test_name.c", line 101: note: function template "undeduced_parameter_hides_outer_name::f" does not match because argument #1 does not match parameter + void f(char (*)[([] { return N + sizeof(U); }())], U) {} + ^ + +"Test_name.c", line 121: error: no instance of function template "enable_if_condition_not_satisfied::pick" matches the argument list + argument types are: (int) + pick(1); + ^ + +9 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-338-rescan.rto/default.1.1.txt b/tests/tests/regressions/.gh-338-rescan.rto/default.1.1.txt new file mode 100644 index 0000000000..0a78e06664 --- /dev/null +++ b/tests/tests/regressions/.gh-338-rescan.rto/default.1.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=1 --c++20 --no_c++11_sfinae_ignore_access Test_name.c diff --git a/tests/tests/regressions/.gh-338-rescan.rto/default.2.1.txt b/tests/tests/regressions/.gh-338-rescan.rto/default.2.1.txt new file mode 100644 index 0000000000..3e092c473c --- /dev/null +++ b/tests/tests/regressions/.gh-338-rescan.rto/default.2.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=2 --c++20 --c++11_sfinae_ignore_access Test_name.c diff --git a/tests/tests/regressions/.gh-338.rto/default.1.1.txt b/tests/tests/regressions/.gh-338.rto/default.1.1.txt new file mode 100644 index 0000000000..36fccf0e2d --- /dev/null +++ b/tests/tests/regressions/.gh-338.rto/default.1.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=1 -w --c++20 Test_name.c diff --git a/tests/tests/regressions/.gh-338.rto/default.2.1.txt b/tests/tests/regressions/.gh-338.rto/default.2.1.txt new file mode 100644 index 0000000000..c0d7143ac0 --- /dev/null +++ b/tests/tests/regressions/.gh-338.rto/default.2.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=2 -w --c++20 --gnu_version=150200 Test_name.c diff --git a/tests/tests/regressions/.gh-338.rto/default.3.1.txt b/tests/tests/regressions/.gh-338.rto/default.3.1.txt new file mode 100644 index 0000000000..9d5307bb89 --- /dev/null +++ b/tests/tests/regressions/.gh-338.rto/default.3.1.txt @@ -0,0 +1 @@ +fe_only -DTEST_NUMBER=3 -w --c++20 --clang_version=210000 Test_name.c diff --git a/tests/tests/regressions/gh-338-diag.sft.cpp b/tests/tests/regressions/gh-338-diag.sft.cpp new file mode 100644 index 0000000000..efc22ceae2 --- /dev/null +++ b/tests/tests/regressions/gh-338-diag.sft.cpp @@ -0,0 +1,124 @@ +//type:fn +//options:--c++20:--c++20 --gnu_version=150200:--c++20 --clang_version=210000 +//remark:[GH #338] Diagnose invalid calls after substituting lambdas in template signatures. + +namespace lambda_parameter_type_mismatch +{ + template + void f(char (*)[sizeof([](T x) { return x; }(T{}))]) {} + + void test() + { + char a[sizeof(int)]; + f(&a); + f(&a); + } +} + +namespace unnamed_lambda_parameter_mismatch +{ + template + void f(char (*)[sizeof([](T) { return T(); }(1))]) {} + + void test() + { + char a[sizeof(int) + 1]; + f(&a); + } +} + +namespace lambda_body_type_mismatch +{ + template + void f(char (*)[sizeof([](int) { return T(); }(1))]) {} + + void test() + { + char a[sizeof(int) + 1]; + f(&a); + } +} + +namespace indirect_template_parameter_dependency +{ + // Known limitation: T is used only indirectly through decltype(x), rather + // than named in the lambda. This valid call is still rejected. + template + void f(T x, char (*)[sizeof([](decltype(x) y) { return y; }(x))]) {} + + void test() + { + char a[sizeof(long long)]; + f(1LL, &a); + } +} + +#if defined(__GNUC__) || defined(__clang__) +namespace non_type_template_argument_mismatch +{ + template struct A {}; + template void f(A<[] { return N; }()>) {} + + void test() + { + f<1>(A<1>{}); + f<2>(A<2>{}); + f<1>(A<2>{}); + } +} + +namespace nested_lambda_array_bound_mismatch +{ + template + void f(char (*)[([] { return [] { return N + int(sizeof(T)); }(); }())]) {} + + void test() + { + char a[1 + sizeof(int)], b[2 + sizeof(int)]; + f<1, int>(&a); + f<1, int>(&b); + } +} + +namespace incomplete_template_arguments +{ + // The two lambdas have distinct closure types, so these declare distinct + // templates. Substitution with N not yet deduced must not crash. + template + void f(const char (*)[([] { return N; })()]); + template + void f(const char (*)[([] { return N; })()]) {} + + void test() { f<6>(&"hello"); } +} + +namespace undeduced_parameter_hides_outer_name +{ + // U has no argument during the initial substitution of f<6>. It must not + // resolve to the enclosing struct U, which would incorrectly accept a. + struct U {}; + template + void f(char (*)[([] { return N + sizeof(U); }())], U) {} + + void test() + { + char a[6 + sizeof(U)]; + f<6>(&a, 1.0); + } +} +#endif + +#ifdef __clang__ +namespace enable_if_condition_not_satisfied +{ + template + __attribute__((enable_if(sizeof([] { return T{}; }()) == sizeof(char), ""))) + int pick(T) { return 1; } + + void test() + { + pick('a'); + pick(1); + } +} +#endif diff --git a/tests/tests/regressions/gh-338-rescan.sft.cpp b/tests/tests/regressions/gh-338-rescan.sft.cpp new file mode 100644 index 0000000000..bed1f122bf --- /dev/null +++ b/tests/tests/regressions/gh-338-rescan.sft.cpp @@ -0,0 +1,100 @@ +//type:fp +//options:--c++20 --no_c++11_sfinae_ignore_access:--c++20 --c++11_sfinae_ignore_access + +namespace dependent_declarations +{ + // Substituting T before deducing U must leave these closures nonreal. + // No expression in their bodies refers to U: only declarations do. + template + constexpr bool variable(T, U, + char (*)[([] { [[maybe_unused]] U x; return 1; }())]) { return true; } + + template + constexpr bool array(T, U, + char (*)[([] { [[maybe_unused]] U x[2]; return 1; }())]) { return true; } + + template + constexpr bool pointer(T, U, + char (*)[([] { [[maybe_unused]] U *p; return 1; }())]) { return true; } + + template + constexpr bool alias(T, U, + char (*)[([] { using A = U; return 1; }())]) { return true; } + + template + constexpr bool routine(T, U, + char (*)[([] { void local(U); return 1; }())]) { return true; } + + // These types are nondependent; only their initializers refer to U. + template + constexpr bool initializer(T, U, + char (*)[([] { [[maybe_unused]] constexpr int x = sizeof(U); + return 1; }())]) { return true; } + + template + constexpr bool dynamic_initializer(T, U, + char (*)[([] { [[maybe_unused]] int x = sizeof(U); + return 1; }())]) { return true; } + + constexpr bool test() + { + char a[1]{}; + variable(1, 2L, &a); + variable(1, 'x', &a); + array(1, 2L, &a); + array(1, 'x', &a); + pointer(1, 2L, &a); + pointer(1, 'x', &a); + alias(1, 2L, &a); + alias(1, 'x', &a); + routine(1, 2L, &a); + routine(1, 'x', &a); + initializer(1, 2L, &a); + initializer(1, 'x', &a); + dynamic_initializer(1, 2L, &a); + dynamic_initializer(1, 'x', &a); + return true; + } + static_assert(test()); +} + +namespace concept_template_binding +{ + // A lambda rescan must restore the concept's arguments, so instantiating + // its generic call operator still sees the bound template-template argument. + template T declare(); + + template class Template> + concept D = requires { + [](Template&) {}(declare()); + }; + + template struct B {}; + template struct Other {}; + template struct Adapter; + template T> struct Adapter {}; + + template struct Adapter>; + template struct Adapter>; + static_assert(D, B>); + static_assert(D, Other>); + static_assert(!D); +} + +namespace nested_pack_constraint +{ + // The first lambda rescan must restore the concrete arguments on the + // instantiation scope, even when an access-checking scope is above it. + // Instantiating the generic lambda then needs those enclosing arguments. + template + requires ([] { return (sizeof(Ts) + ... + 0); }() > 0) + && requires { + []() { return sizeof...(Ts); } + .template operator()(); + } + struct C { static constexpr int value = sizeof...(Ts); }; + + static_assert(C::value == 2); + static_assert(C::value == 1); + static_assert(C::value == 2); +} diff --git a/tests/tests/regressions/gh-338.sft.cpp b/tests/tests/regressions/gh-338.sft.cpp new file mode 100644 index 0000000000..f86f3d652b --- /dev/null +++ b/tests/tests/regressions/gh-338.sft.cpp @@ -0,0 +1,462 @@ +//type:fp +//options:--c++20:--c++20 --gnu_version=150200:--c++20 --clang_version=210000 +//options_all:-w +//remark:[GH #338] Lambdas in template signatures can name enclosing template parameters. + +namespace test_support +{ + template constexpr bool same_type = false; + template constexpr bool same_type = true; +} + +// Rescanning a lambda during substitution must use the template arguments of +// the current instance, and restore the template parameters afterwards. +namespace lambda_parameter_type +{ + template + constexpr void f(char (*)[sizeof([](T x) { return x; }(T{}))]) {} + + constexpr bool test() + { + char a[sizeof(char)]{}, b[sizeof(int)]{}, c[sizeof(long)]{}; + f(&a); + f(&b); + f(&c); + f(&a); + return true; + } + static_assert(test()); +} + +namespace unnamed_lambda_parameter +{ + template + constexpr void f(char (*)[sizeof([](T) { return T(); }(1))]) {} + + constexpr bool test() + { + char a[sizeof(int)]{}, b[sizeof(long long)]{}; + f(&a); + f(&b); + return true; + } + static_assert(test()); +} + +namespace template_parameter_in_body_only +{ + template + constexpr void f(char (*)[sizeof([](int) { return T(); }(1))]) {} + + constexpr bool test() + { + char a[sizeof(int)]{}, b[sizeof(long long)]{}; + f(&a); + f(&b); + return true; + } + static_assert(test()); +} + +namespace generic_lambda +{ + template + constexpr void f(char (*)[sizeof([](auto x) { return T(x); }(1))]) {} + + template + constexpr void g(char (*)[sizeof([](auto) { return T(); }(1))]) {} + + constexpr bool test() + { + char a[sizeof(int)]{}, b[sizeof(long long)]{}; + f(&a); + f(&b); + g(&a); + g(&b); + return true; + } + static_assert(test()); +} + +namespace trailing_return_type +{ + template + constexpr auto f(T x) -> decltype([](T y) { return y; }(x)) { return x; } + + static_assert(test_support::same_type); + static_assert(test_support::same_type); + + static_assert(f(1) == 1); + static_assert(f(2) == 2); +} + +namespace requires_clause +{ + template + requires (sizeof([] { return T{}; }()) == sizeof(int)) + constexpr void f(T) {} + + constexpr bool test() + { + f(1); + f(2u); + return true; + } + static_assert(test()); +} + +namespace default_template_argument +{ + template + constexpr U f() { return U{}; } + + static_assert(test_support::same_type()), int>); + static_assert(test_support::same_type()), char>); + + static_assert(f() == 0); + static_assert(f() == '\0'); +} + +namespace exception_specification +{ + template + constexpr void f(T) noexcept(noexcept([] { return T{}; }())) {} + + constexpr bool test() + { + f(1); + f('a'); + return true; + } + static_assert(test()); +} + +namespace recursive_constraint_substitution +{ + // Checking f finds f by ADL in the constraint. Use long + // long rather than long, whose size might make its constraint recursive. + template struct W {}; + + template + requires (sizeof([] { static_assert(sizeof(T) >= 4); return T{}; }()) >= 4) + && (sizeof(T) > 4 || requires { f(W{}); }) + constexpr int f(W) { return sizeof(T); } + + static_assert(f(W{}) == sizeof(int)); + static_assert(f(W{}) == sizeof(long long)); +} + +namespace recursive_lambda_substitution +{ + // Unlike recursive_constraint_substitution, nested deduction happens inside + // the lambda. T must still denote int when scanning the following assertion. + // The long long specialization short-circuits without entering the lambda. + template struct W {}; + + template + requires (sizeof(T) > sizeof(int) || [] { + (void)sizeof(f(W{})); + static_assert(sizeof(T) == sizeof(int)); + return true; + }()) + constexpr int f(W) { return sizeof(T); } + + static_assert(f(W{}) == sizeof(int)); + static_assert(f(W{}) == sizeof(long long)); + static_assert(f(W{}) == sizeof(int)); +} + +namespace nested_template_substitution +{ + // Substituting the outer lambda also substitutes a lambda in g's signature. + template + constexpr auto g(U u) -> decltype([](U v) { return v; }(u)) { return u; } + + template + constexpr auto f(T x) -> decltype([] { return g(T{}); }()) { return g(x); } + + static_assert(f(1) == 1); + static_assert(f(2) == 2); +} + +namespace member_template +{ + template struct C + { + template + constexpr void f(char (*)[sizeof([] { return T{} + U{}; }())]) {} + + template + constexpr void g(char (*)[sizeof([](U x) { return x; }(U{}))]) {} + }; + + constexpr bool test() + { + char a[sizeof(int)]{}, b[sizeof(long)]{}; + C c; + c.f(&a); + c.f(&b); + c.g(&a); + c.g(&b); + return true; + } + static_assert(test()); +} + +namespace partial_specialization_with_pack +{ + template struct B {}; + template struct S + { + static constexpr int value = 0; + }; + + template + struct S, Args...> + { + static constexpr int value = 1; + }; + + static_assert(S, long, char>::value == 1); + static_assert(S, long, char>::value == 0); +} + +namespace successive_lambdas +{ + template + constexpr void f(char (*)[sizeof([] { return T{}; }())], + char (*)[sizeof([](auto x) { return T(x); }(1))]) {} + + constexpr bool test() + { + char a[sizeof(int)]{}, b[sizeof(long long)]{}; + f(&a, &a); + f(&b, &b); + return true; + } + static_assert(test()); +} + +namespace template_parameter_pack +{ + template + constexpr void f(char (*)[([] { return (sizeof(Ts) + ... + 0); }())]) {} + + constexpr bool test() + { + char a[sizeof(int) + sizeof(long long)]{}; + f(&a); + return true; + } + static_assert(test()); +} + +namespace successive_lambdas_with_pack +{ + template + constexpr void f(char (*)[sizeof([] { return T{}; }())], + char (*)[([] { return sizeof(T) + (sizeof(Ts) + ... + 0); }())]) {} + + constexpr bool test() + { + char a[sizeof(int)]{}, b[sizeof(int) + sizeof(long long)]{}; + f(&a, &b); + return true; + } + static_assert(test()); +} + +namespace label_name +{ + // U is a label, not a reference to the still-undeduced template parameter. + // Discarding the first overload would silently select the ellipsis overload. + template + constexpr char f(char (*)[sizeof([] { U: return 1; }())], U) { return 0; } + template constexpr long f(char (*)[sizeof(int)], ...) { return 1; } + + char a[sizeof(int)]{}; + static_assert(sizeof(f<1>(&a, 1.0)) == sizeof(char)); + static_assert(f<1>(&a, 1.0) == 0); +} + +namespace attribute_name +{ + // An attribute token spelled U likewise does not name the template parameter. + // Suppress its expected warning, but retain the overload-selection checks. + template + constexpr char f(char (*)[sizeof([] { [[U]]; return 1; }())], U) { return 0; } + template constexpr long f(char (*)[sizeof(int)], ...) { return 1; } + + char a[sizeof(int)]{}; + static_assert(sizeof(f<1>(&a, 1.0)) == sizeof(char)); + static_assert(f<1>(&a, 1.0) == 0); +} + +namespace partially_explicit_template_arguments +{ + // Substituting N must leave the lambda dependent until U is deduced from + // the second argument, then complete the bound with that deduced type. + template + constexpr void f(char (*)[N + sizeof([] { return U{}; }())], U) {} + + constexpr bool test() + { + char a[1 + sizeof(double)]{}, b[1 + sizeof(char)]{}; + f<1>(&a, 1.0); + f<1>(&b, 'a'); + f<1>(&a, 2.0); + return true; + } + static_assert(test()); +} + +#if defined(__GNUC__) || defined(__clang__) +// These cases require compatibility mode to fold the lambda call when +// checking the substituted function type. +namespace non_type_template_argument +{ + template struct A {}; + template constexpr void f(A<[] { return N; }()>) {} + + constexpr bool test() + { + f<1>({}); + f<2>({}); + f<1>(A<1>{}); + f<2>(A<2>{}); + return true; + } + static_assert(test()); +} + +namespace nested_lambda_array_bound +{ + template + constexpr void f(char (*)[([] { return [] { return N + int(sizeof(T)); }(); }())]) {} + + constexpr bool test() + { + char a[1 + sizeof(int)]{}, b[1 + sizeof(long)]{}, c[4 + sizeof(long)]{}; + f<1, int>(&a); + f<1, long>(&b); + f<4, long>(&c); + return true; + } + static_assert(test()); +} + +namespace undeduced_parameter_overload +{ + // An undeduced U must not resolve to the enclosing U and make the first + // overload viable before U is deduced as double. + struct U {}; + template + constexpr char f(char (*)[([] { return N + sizeof(U); }())], U) { return 0; } + template constexpr long f(char (*)[7], ...) { return 1; } + + char a[7]{}; + static_assert(sizeof(f<6>(&a, 1.0)) == sizeof(long)); + static_assert(f<6>(&a, 1.0) == 1); +} + +namespace qualified_type_name +{ + // A qualified name spelled like an undeduced parameter is not that + // parameter, and must not prevent substitution of the lambda. + struct T { char c[3]; }; + template + constexpr char f(char (*)[sizeof([] { return ::qualified_type_name::T{}; }())], T) + { return 0; } + template constexpr long f(char (*)[3], ...) { return 1; } + + char a[3]{}; + static_assert(sizeof(f<6>(&a, 1.0)) == sizeof(char)); + static_assert(f<6>(&a, 1.0) == 0); +} + +namespace data_member_name +{ + struct G { int T; }; + template + constexpr void f(char (*)[sizeof([] { return G{}.T; }())], T) {} + + constexpr bool test() + { + char a[sizeof(int)]{}; + f<6>(&a, 1.0); + return true; + } + static_assert(test()); +} + +namespace namespace_member_name +{ + namespace NS { struct U { char c[5]; }; } + template + constexpr void f(char (*)[sizeof([] { return NS::U{}; }())], U) {} + + constexpr bool test() + { + char a[5]{}; + f<6>(&a, 1.0); + return true; + } + static_assert(test()); +} + +namespace qualified_member_template_name +{ + struct G { template static constexpr int T = 3; }; + template + constexpr char f(char (*)[([] { return G::template T; }())], T) { return 0; } + template constexpr long f(char (*)[3], ...) { return 1; } + + char a[3]{}; + static_assert(sizeof(f<6>(&a, 1.0)) == sizeof(char)); + static_assert(f<6>(&a, 1.0) == 0); +} + +namespace object_member_template_name +{ + struct G { template static constexpr int T() { return 3; } }; + template + constexpr char f(char (*)[([] { return G{}.template T(); }())], T) { return 0; } + template constexpr long f(char (*)[3], ...) { return 1; } + + char a[3]{}; + static_assert(sizeof(f<6>(&a, 1.0)) == sizeof(char)); + static_assert(f<6>(&a, 1.0) == 0); +} +#endif + +#ifdef __clang__ +namespace enable_if_overloads +{ + template + __attribute__((enable_if(sizeof([] { return T{}; }()) == sizeof(char), ""))) + constexpr int pick(T) { return 1; } + template + __attribute__((enable_if(sizeof([](T x) { return x; }(T{})) == sizeof(int), ""))) + constexpr int pick(T) { return 2; } + + static_assert(pick('a') == 1); + static_assert(pick(1) == 2); + static_assert(pick('b') == 1); + static_assert(pick(2) == 2); +} + +namespace enable_if_access_context +{ + class C + { + static constexpr int priv = 1; + public: + template + __attribute__((enable_if(sizeof([] { return priv + T{}; }()) > 0, ""))) + static constexpr int f(T) { return 1; } + }; + + static_assert(C::f(1) == 1); + static_assert(C::f('a') == 1); +} +#endif