diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 339 | ||||
-rw-r--r-- | gcc/cp/call.cc | 29 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 235 | ||||
-rw-r--r-- | gcc/cp/constraint.cc | 6 | ||||
-rw-r--r-- | gcc/cp/contracts.cc | 9 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 21 | ||||
-rw-r--r-- | gcc/cp/cp-gimplify.cc | 11 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 3 | ||||
-rw-r--r-- | gcc/cp/decl.cc | 9 | ||||
-rw-r--r-- | gcc/cp/error.cc | 59 | ||||
-rw-r--r-- | gcc/cp/init.cc | 4 | ||||
-rw-r--r-- | gcc/cp/lambda.cc | 32 | ||||
-rw-r--r-- | gcc/cp/lex.cc | 3 | ||||
-rw-r--r-- | gcc/cp/mangle.cc | 6 | ||||
-rw-r--r-- | gcc/cp/module.cc | 126 | ||||
-rw-r--r-- | gcc/cp/name-lookup.cc | 55 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 85 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 76 | ||||
-rw-r--r-- | gcc/cp/rtti.cc | 15 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 27 |
20 files changed, 871 insertions, 279 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fe8aa4b..d9f0298 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,342 @@ +2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com> + + * name-lookup.cc (lookup_imported_hidden_friend): Remove + unnecessary lazy_load_pendings. + +2025-04-22 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119863 + * name-lookup.cc (get_mergeable_namespace_binding): Remove + no-longer-used function. + (lookup_imported_hidden_friend): Also look for hidden imported + decls in an attached decl's module. + +2025-04-21 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Move + verify_constant later. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/118775 + * constexpr.cc (cxx_eval_call_expression): Add assert. + (fold_to_constant): Handle processing_template_decl. + * init.cc (build_new_1): Use fold_to_constant. + +2025-04-21 Jason Merrill <jason@redhat.com> + + PR c++/99456 + * constexpr.cc (cxx_eval_constant_expression): Check strict + instead of manifestly_const_eval. + (maybe_constant_init_1): Be strict for static constexpr vars. + +2025-04-19 Jason Merrill <jason@redhat.com> + + * coroutines.cc (coro_build_expr_stmt) + (coro_build_cvt_void_expr_stmt): Remove. + (build_actor_fn): Use finish_expr_stmt. + * semantics.cc (finish_expr_stmt): Avoid wrapping statement in + EXPR_STMT. + (finish_stmt_expr_expr): Add comment. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (is_valid_constexpr_fn): Improve diagnostic. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * constexpr.cc (cxx_eval_outermost_constant_expr): Give both + expression and allocation location in allocated storage diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * name-lookup.cc (name_lookup::preserve_state): Fix reserve call. + * rtti.cc (get_tinfo_desc): Use vec_safe_grow_cleared. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * semantics.cc (finish_type_pack_element): Add more info + to diagnostics. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * decl.cc (cp_make_fname_decl): Prevent silent failure. + +2025-04-17 Jason Merrill <jason@redhat.com> + + * lex.cc (unqualified_name_lookup_error): Handle 'requires' better. + +2025-04-17 Jason Merrill <jason@redhat.com> + + PR c++/113360 + * cp-tree.h (struct language_function): Add erroneous bit. + * constexpr.cc (explain_invalid_constexpr_fn): Return if set. + (cxx_eval_call_expression): Quiet if set. + * parser.cc (cp_parser_function_definition_after_declarator) + * pt.cc (instantiate_body): Set it. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/114772 + PR c++/101180 + * pt.cc (apply_late_template_attributes): Also override + target_option_current_node. + +2025-04-16 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Preserve flags + on the attribute list. + +2025-04-15 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119755 + * lambda.cc (prune_lambda_captures): Remove pruned capture from + function's BLOCK_VARS and BIND_EXPR_VARS. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/111075 + * constexpr.cc (cxx_eval_call_expression): Allow trivial + call from a thunk. + +2025-04-15 Patrick Palka <ppalka@redhat.com> + + PR c++/119807 + PR c++/112288 + * pt.cc (tsubst_friend_function): Skip remapping an + existing specialization if it doesn't match the shape of + the new friend definition. + +2025-04-15 Jason Merrill <jason@redhat.com> + + PR c++/113835 + * constexpr.cc (cxx_eval_outermost_constant_expr): Bail out early + for std::vector(N). + +2025-04-14 Patrick Palka <ppalka@redhat.com> + + PR c++/99214 + * constraint.cc (satisfy_declaration_constraints): Pass the + original ARGS to push_tinst_level. + +2025-04-13 Patrick Palka <ppalka@redhat.com> + + PR c++/115639 + * constexpr.cc (struct constexpr_call): Add NSDMIs to each + field. Replace 'result' data member with 3-element 'results' + array and a 'result' accessor function. Remove + 'manifestly_const_eval' data member. + (constexpr_call_hasher::equal): Adjust after constexpr_call + layout change. + (cxx_eval_call_expression): Likewise. Define some local + variables closer to their first use. Use unknown_type_node + instead of NULL_TREE as the "in progress" result. After + successully evaluating a call with mce_unknown, also cache the + result in the corresponding mce_true and mce_false slots. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Don't check for + mismatches when importing a DECL_MAYBE_DELETED function over one + that's already finished. + +2025-04-13 Nathaniel Shead <nathanieloshead@gmail.com> + + * module.cc (trees_in::is_matching_decl): Add custom errors for + different kinds of mismatches. + +2025-04-12 Patrick Palka <ppalka@redhat.com> + + PR c++/116416 + * constexpr.cc (maybe_constant_init_1): Generalize type of + of manifestly_const_eval parameter from bool to mce_value. + (maybe_constant_init): Define 3-parameter version taking a + manifestly_const_eval instead of bool parameter. + (cxx_constant_init): Adjust. + * cp-gimplify.cc (cp_fold_r) <case TARGET_EXPR>: Pass mce_false + to maybe_constant_init during prvalue folding if ff_mce_false is + set. + * cp-tree.h (maybe_constant_init): Declare new overload. + +2025-04-11 Jason Merrill <jason@redhat.com> + + PR c++/114970 + * cp-gimplify.cc (cp_build_init_expr_for_ctor): Suppress warnings on + return_this COMPOUND_EXPR. + +2025-04-10 Jason Merrill <jason@redhat.com> + + PR c++/119345 + * pt.cc (add_extra_args): Also register a specialization + of the captured variable. + +2025-04-10 Patrick Palka <ppalka@redhat.com> + + PR c++/119687 + * pt.cc (alias_ctad_tweaks): Use lkp_range / lkp_iterator + instead of ovl_iterator. + +2025-04-10 Jakub Jelinek <jakub@redhat.com> + + PR translation/119684 + * error.cc (cp_print_error_function): Use G_ instead of _ for + pp_printf arguments. + (function_category): Use G_ instead of _. + (print_instantiation_full_context): Use G_ instead of _ in pp_verbatim + arguments. + (print_location): Likewise. + (print_instantiation_partial_context): Likewise. + (maybe_print_constexpr_context): Likewise. + (print_constrained_decl_info): Use G_() around pp_verbatim argument. + (print_concept_check_info): Likewise. + (print_constraint_context_head): Likewise. + (print_requires_expression_info): Likewise. Merge separate pp_verbatim + "in requirements " and "with " into one with conditional messages. + +2025-04-10 Jason Merrill <jason@redhat.com> + + PR c++/119175 + * mangle.cc (decl_mangling_context): Look through lambda type. + +2025-04-09 Patrick Palka <ppalka@redhat.com> + + PR c++/119574 + * pt.cc (add_extra_args): Remove checking assert. + +2025-04-09 Jason Merrill <jason@redhat.com> + + PR c++/118698 + * constraint.cc (struct norm_info): Add tf_partial. + * pt.cc (any_template_parm_r): Handle LAMBDA_EXPR_EXTRA_ARGS. + +2025-04-08 Jason Merrill <jason@redhat.com> + + PR c++/117530 + * pt.cc (instantiate_template): Check retrieve_specialization after + tsubst. + +2025-04-07 Jason Merrill <jason@redhat.com> + + PR c++/119652 + * constexpr.cc (cxx_eval_outermost_constant_expr): Also don't add a + TARGET_EXPR around AGGR_INIT_EXPR. + +2025-04-06 Patrick Palka <ppalka@redhat.com> + + PR c++/118626 + * pt.cc (maybe_dependent_member_ref): Restrict TYPENAME_TYPE + shortcut to non-typedef TYPE_DECL. + +2025-04-06 Patrick Palka <ppalka@redhat.com> + + PR c++/118626 + * pt.cc (maybe_dependent_member_ref): Substitute and return the + stripped type if we decided to not rewrite it directly. + +2025-04-05 Patrick Palka <ppalka@redhat.com> + + PR c++/118249 + * constexpr.cc (potential_constant_expression_1) + <case INDIRECT_REF>: Remove obsolete *this handling. + +2025-04-05 Jason Merrill <jason@redhat.com> + + PR c++/118629 + * name-lookup.cc (pushdecl_outermost_localscope): Look for an + sk_block. + +2025-04-04 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119564 + * decl.cc (cp_tree_node_structure): Add TU_LOCAL_ENTITY; fix + formatting. + +2025-04-04 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119608 + * module.cc (trees_out::decl_node): Maybe require by-value + walking not just when streaming. + +2025-04-04 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119462 + * module.cc (trees_in::is_matching_decl): Propagate exception + spec and constexpr to DECL_MAYBE_DELETED; clear if appropriate. + +2025-04-04 Jason Merrill <jason@redhat.com> + + PR c++/99546 + PR c++/113925 + PR c++/106976 + PR c++/109961 + PR c++/117336 + * lambda.cc (build_lambda_object): Handle fake + requires-expr processing_template_decl. + * parser.cc (cp_parser_lambda_expression): Likewise. + +2025-04-04 Patrick Palka <ppalka@redhat.com> + + PR c++/117849 + * semantics.cc (finish_id_expression_1): Allow use of constraint + variable outside an unevaluated context. + +2025-04-03 Patrick Palka <ppalka@redhat.com> + + PR c++/119387 + * constexpr.cc (p2280_active_p): New. + (cxx_eval_constant_expression) <case VAR_DECL>: Use it to + restrict P2280 relaxations. + <case PARM_DECL>: Likewise. + +2025-04-03 Jason Merrill <jason@redhat.com> + + * module.cc (module_state::read_cluster) + (post_load_processing): Clear DECL_EXTERNAL if DECL_COMDAT. + +2025-04-03 Jason Merrill <jason@redhat.com> + + * call.cc (add_candidates): Re-lookup ne_fns if we move into + another namespace. + +2025-04-03 Andrew Pinski <quic_apinski@quicinc.com> + Jakub Jelinek <jakub@redhat.com> + + PR c++/119563 + * call.cc (build_list_conv): Fix a typo in loop gathering + summary information from subsubconvs. + +2025-04-02 Sandra Loosemore <sloosemore@baylibre.com> + + PR middle-end/118965 + * parser.cc (c_parser_omp_clause_init_modifiers): Adjust + error message. + (cp_parser_omp_clause_init): Remove code for recognizing clauses + without modifiers. Diagnose missing target/targetsync modifier. + (cp_finish_omp_declare_variant): Diagnose missing target/targetsync + modifier. + +2025-04-01 Nathaniel Shead <nathanieloshead@gmail.com> + + PR c++/119551 + * module.cc (trees_out::write_var_def): Only ignore non-inline + variable initializers. + +2025-04-01 Nathaniel Shead <nathanieloshead@gmail.com> + + * parser.cc (cp_parser_diagnose_invalid_type_name): Replace + fmodules-ts with fmodules. + (cp_parser_template_declaration): Likewise. + +2025-04-01 Marek Polacek <polacek@redhat.com> + + PR c++/119383 + * call.cc (build_over_call): Use force_lvalue to ensure op= returns + an lvalue. + * cp-tree.h (force_lvalue): Declare. + * cvt.cc (force_lvalue): New. + * typeck.cc (cp_build_indirect_ref_1): Revert r15-8011. + 2025-03-31 Jason Merrill <jason@redhat.com> PR c++/119401 diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index b1469cb..6caac89 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -917,7 +917,7 @@ build_list_conv (tree type, tree ctor, int flags, tsubst_flags_t complain) t->rank = cr_exact; for (j = 0; j < (unsigned) RAW_DATA_LENGTH (val); ++j) { - sub = subsubconvs[i]; + sub = subsubconvs[j]; if (sub->rank > t->rank) t->rank = sub->rank; if (sub->user_conv_p) @@ -6673,6 +6673,7 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args, bool check_list_ctor = false; bool check_converting = false; unification_kind_t strict; + tree ne_context = NULL_TREE; tree ne_fns = NULL_TREE; if (!fns) @@ -6719,6 +6720,7 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args, tree ne_name = ovl_op_identifier (false, NE_EXPR); if (DECL_CLASS_SCOPE_P (fn)) { + ne_context = DECL_CONTEXT (fn); ne_fns = lookup_fnfields (TREE_TYPE ((*args)[0]), ne_name, 1, tf_none); if (ne_fns == error_mark_node || ne_fns == NULL_TREE) @@ -6728,8 +6730,9 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args, } else { - tree context = decl_namespace_context (fn); - ne_fns = lookup_qualified_name (context, ne_name, LOOK_want::NORMAL, + ne_context = decl_namespace_context (fn); + ne_fns = lookup_qualified_name (ne_context, ne_name, + LOOK_want::NORMAL, /*complain*/false); if (ne_fns == error_mark_node || !is_overloaded_fn (ne_fns)) @@ -6828,8 +6831,26 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args, /* When considering reversed operator==, if there's a corresponding operator!= in the same scope, it's not a rewrite target. */ - if (ne_fns) + if (ne_context) { + if (TREE_CODE (ne_context) == NAMESPACE_DECL) + { + /* With argument-dependent lookup, fns can span multiple + namespaces; make sure we look in the fn's namespace for a + corresponding operator!=. */ + tree fn_ns = decl_namespace_context (fn); + if (fn_ns != ne_context) + { + ne_context = fn_ns; + tree ne_name = ovl_op_identifier (false, NE_EXPR); + ne_fns = lookup_qualified_name (ne_context, ne_name, + LOOK_want::NORMAL, + /*complain*/false); + if (ne_fns == error_mark_node + || !is_overloaded_fn (ne_fns)) + ne_fns = NULL_TREE; + } + } bool found = false; for (lkp_iterator ne (ne_fns); !found && ne; ++ne) if (0 && !ne.using_p () diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 4820bcc..8a11e62 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -307,7 +307,14 @@ is_valid_constexpr_fn (tree fun, bool complain) { ret = false; if (complain) - error ("%q#T has virtual base classes", DECL_CONTEXT (fun)); + { + if (DECL_CONSTRUCTOR_P (fun)) + error ("%<constexpr%> constructor in %q#T that has " + "virtual base classes", DECL_CONTEXT (fun)); + else + error ("%<constexpr%> destructor in %q#T that has " + "virtual base classes", DECL_CONTEXT (fun)); + } } return ret; @@ -1048,6 +1055,12 @@ explain_invalid_constexpr_fn (tree fun) { static hash_set<tree> *diagnosed; tree body; + + /* Don't try to explain a function we already complained about. */ + if (function *f = DECL_STRUCT_FUNCTION (fun)) + if (f->language->erroneous) + return; + /* In C++23, a function marked 'constexpr' may not actually be a constant expression. We haven't diagnosed the problem yet: -Winvalid-constexpr wasn't enabled. The function was called, so diagnose why it cannot be @@ -1119,20 +1132,22 @@ explain_invalid_constexpr_fn (tree fun) struct GTY((for_user)) constexpr_call { /* Description of the constexpr function definition. */ - constexpr_fundef *fundef; + constexpr_fundef *fundef = nullptr; /* Parameter bindings environment. A TREE_VEC of arguments. */ - tree bindings; - /* Result of the call. - NULL means the call is being evaluated. + tree bindings = NULL_TREE; + /* Result of the call, indexed by the value of + constexpr_ctx::manifestly_const_eval. + unknown_type_node means the call is being evaluated. error_mark_node means that the evaluation was erroneous or otherwise uncacheable (e.g. because it depends on the caller). Otherwise, the actual value of the call. */ - tree result; + tree results[3] = { NULL_TREE, NULL_TREE, NULL_TREE }; /* The hash of this call; we remember it here to avoid having to recalculate it when expanding the hash table. */ - hashval_t hash; - /* The value of constexpr_ctx::manifestly_const_eval. */ - enum mce_value manifestly_const_eval; + hashval_t hash = 0; + + /* The result slot corresponding to the given mce_value. */ + tree& result (mce_value mce) { return results[1 + int(mce)]; } }; struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call> @@ -1294,6 +1309,22 @@ struct constexpr_ctx { mce_value manifestly_const_eval; }; +/* True if the constexpr relaxations afforded by P2280R4 for unknown + references and objects are in effect. */ + +static bool +p2280_active_p (const constexpr_ctx *ctx) +{ + if (ctx->manifestly_const_eval != mce_true) + /* Disable these relaxations during speculative constexpr folding, + as it can significantly increase compile time/memory use + (PR119387). */ + return false; + + /* P2280R4 was accepted as a DR against C++11. */ + return cxx_dialect >= cxx11; +} + /* Remove T from the global values map, checking for attempts to destroy a value that has already finished its lifetime. */ @@ -1411,8 +1442,6 @@ constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs) return true; if (lhs->hash != rhs->hash) return false; - if (lhs->manifestly_const_eval != rhs->manifestly_const_eval) - return false; if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef)) return false; return cp_tree_equal (lhs->bindings, rhs->bindings); @@ -2839,9 +2868,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, { location_t loc = cp_expr_loc_or_input_loc (t); tree fun = get_function_named_in_call (t); - constexpr_call new_call - = { NULL, NULL, NULL, 0, ctx->manifestly_const_eval }; - int depth_ok; if (fun == NULL_TREE) return cxx_eval_internal_function (ctx, t, lval, @@ -2930,12 +2956,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, gcc_assert (arg0); if (new_op_p) { - /* FIXME: We should not get here; the VERIFY_CONSTANT above - should have already caught it. But currently a conversion - from pointer type to arithmetic type is only considered - non-constant for CONVERT_EXPRs, not NOP_EXPRs. */ if (!tree_fits_uhwi_p (arg0)) { + /* We should not get here; the VERIFY_CONSTANT above + should have already caught it. */ + gcc_checking_assert (false); if (!ctx->quiet) error_at (loc, "cannot allocate array: size not constant"); *non_constant_p = true; @@ -3066,6 +3091,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } constexpr_ctx new_ctx = *ctx; + ctx = &new_ctx; if (DECL_CONSTRUCTOR_P (fun) && !ctx->object && TREE_CODE (t) == AGGR_INIT_EXPR) { @@ -3075,27 +3101,26 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, tree ctor = new_ctx.ctor = build_constructor (DECL_CONTEXT (fun), NULL); CONSTRUCTOR_NO_CLEARING (ctor) = true; ctx->global->put_value (new_ctx.object, ctor); - ctx = &new_ctx; } /* An immediate invocation is manifestly constant evaluated including the arguments of the call, so use mce_true even for the argument evaluation. */ if (DECL_IMMEDIATE_FUNCTION_P (fun)) - { - new_ctx.manifestly_const_eval = mce_true; - new_call.manifestly_const_eval = mce_true; - ctx = &new_ctx; - } + new_ctx.manifestly_const_eval = mce_true; /* We used to shortcut trivial constructor/op= here, but nowadays we can only get a trivial function here with -fno-elide-constructors. */ gcc_checking_assert (!trivial_fn_p (fun) || !flag_elide_constructors + /* Or it's a call from maybe_thunk_body (111075). */ + || (TREE_CODE (t) == CALL_EXPR ? CALL_FROM_THUNK_P (t) + : AGGR_INIT_FROM_THUNK_P (t)) /* We don't elide constructors when processing a noexcept-expression. */ || cp_noexcept_operand); bool non_constant_args = false; + constexpr_call new_call; new_call.bindings = cxx_bind_parameters_in_call (ctx, t, fun, non_constant_p, overflow_p, &non_constant_args); @@ -3169,7 +3194,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, } } - depth_ok = push_cx_call_context (t); + /* Don't complain about problems evaluating an ill-formed function. */ + if (function *f = DECL_STRUCT_FUNCTION (fun)) + if (f->language->erroneous) + new_ctx.quiet = true; + + int depth_ok = push_cx_call_context (t); /* Remember the object we are constructing or destructing. */ tree new_obj = NULL_TREE; @@ -3211,8 +3241,6 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, new_call.hash = constexpr_fundef_hasher::hash (new_call.fundef); new_call.hash = iterative_hash_template_arg (new_call.bindings, new_call.hash); - new_call.hash - = iterative_hash_object (ctx->manifestly_const_eval, new_call.hash); /* If we have seen this call before, we are done. */ maybe_initialize_constexpr_call_table (); @@ -3230,22 +3258,23 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, the slot can move during evaluation of the body. */ *slot = entry = ggc_alloc<constexpr_call> (); *entry = new_call; + entry->result (ctx->manifestly_const_eval) = unknown_type_node; fb.preserve (); } } - /* Calls that are in progress have their result set to NULL, so that we - can detect circular dependencies. Now that we only cache up to - constexpr_cache_depth this won't catch circular dependencies that + /* Calls that are in progress have their result set to unknown_type_node, + so that we can detect circular dependencies. Now that we only cache + up to constexpr_cache_depth this won't catch circular dependencies that start deeper, but they'll hit the recursion or ops limit. */ - else if (entry->result == NULL) + else if (entry->result (ctx->manifestly_const_eval) == unknown_type_node) { if (!ctx->quiet) error ("call has circular dependency"); *non_constant_p = true; - entry->result = result = error_mark_node; + entry->result (ctx->manifestly_const_eval) = result = error_mark_node; } else - result = entry->result; + result = entry->result (ctx->manifestly_const_eval); } if (!depth_ok) @@ -3466,7 +3495,22 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, else if (!result) result = void_node; if (entry) - entry->result = cacheable ? result : error_mark_node; + { + entry->result (ctx->manifestly_const_eval) + = cacheable ? result : error_mark_node; + + if (result != error_mark_node + && ctx->manifestly_const_eval == mce_unknown) + { + /* Evaluation succeeded and was independent of whether we're in a + manifestly constant-evaluated context, so we can also reuse + this result when evaluating this call with a fixed context. */ + if (!entry->result (mce_true)) + entry->result (mce_true) = entry->result (mce_unknown); + if (!entry->result (mce_false)) + entry->result (mce_false) = entry->result (mce_unknown); + } + } } /* The result of a constexpr function must be completely initialized. @@ -7792,7 +7836,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = TARGET_EXPR_INITIAL (r); if (DECL_P (r) /* P2280 allows references to unknown. */ - && !(VAR_P (t) && TYPE_REF_P (TREE_TYPE (t)))) + && !(p2280_active_p (ctx) && VAR_P (t) && TYPE_REF_P (TREE_TYPE (t)))) { if (!ctx->quiet) non_const_var_error (loc, r, /*fundef_p*/false); @@ -7844,9 +7888,9 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, r = build_constructor (TREE_TYPE (t), NULL); TREE_CONSTANT (r) = true; } - else if (TYPE_REF_P (TREE_TYPE (t))) + else if (p2280_active_p (ctx) && TYPE_REF_P (TREE_TYPE (t))) /* P2280 allows references to unknown... */; - else if (is_this_parameter (t)) + else if (p2280_active_p (ctx) && is_this_parameter (t)) /* ...as well as the this pointer. */; else { @@ -8434,7 +8478,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, if (TREE_CODE (t) == CONVERT_EXPR && ARITHMETIC_TYPE_P (type) && INDIRECT_TYPE_P (TREE_TYPE (op)) - && ctx->manifestly_const_eval == mce_true) + && ctx->strict) { if (!ctx->quiet) error_at (loc, @@ -9100,6 +9144,15 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, tree fndecl = cp_get_callee_fndecl_nofold (x); if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl)) is_consteval = true; + /* Don't try to evaluate a std::vector constructor taking an integer, it + will fail in the 'if (heap_var)' block below after doing all the work + (c++/113835). This will need adjustment if P3554 is accepted. Note + that evaluation of e.g. the vector default constructor can succeed, so + we don't shortcut all vector constructors. */ + if (fndecl && DECL_CONSTRUCTOR_P (fndecl) && allow_non_constant + && is_std_class (type, "vector") && call_expr_nargs (x) > 1 + && TREE_CODE (TREE_TYPE (get_nth_callarg (x, 1))) == INTEGER_TYPE) + return t; } if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)) { @@ -9174,11 +9227,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (r == void_node && !constexpr_dtor && ctx.ctor) r = ctx.ctor; - if (!constexpr_dtor) - verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); - else - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; - unsigned int i; tree cleanup; /* Evaluate the cleanups. */ @@ -9197,15 +9245,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } - if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) - { - if (!allow_non_constant) - error ("%qE is not a constant expression because it refers to " - "an incompletely initialized variable", t); - TREE_CONSTANT (r) = false; - non_constant_p = true; - } - if (!non_constant_p && cxx_dialect >= cxx20 && !global_ctx.heap_vars.is_empty ()) { @@ -9215,9 +9254,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (heap_var) { if (!allow_non_constant && !non_constant_p) - error_at (DECL_SOURCE_LOCATION (heap_var), - "%qE is not a constant expression because it refers to " - "a result of %<operator new%>", t); + { + error ("%qE is not a constant expression because it refers to " + "a result of %<operator new%>", t); + inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); + } r = t; non_constant_p = true; } @@ -9226,9 +9267,11 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (DECL_NAME (heap_var) != heap_deleted_identifier) { if (!allow_non_constant && !non_constant_p) - error_at (DECL_SOURCE_LOCATION (heap_var), - "%qE is not a constant expression because allocated " - "storage has not been deallocated", t); + { + error ("%qE is not a constant expression because allocated " + "storage has not been deallocated", t); + inform (DECL_SOURCE_LOCATION (heap_var), "allocated here"); + } r = t; non_constant_p = true; } @@ -9258,6 +9301,21 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, non_constant_p = true; } + if (!non_constant_p && !constexpr_dtor) + verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); + + /* After verify_constant because reduced_constant_expression_p can unset + CONSTRUCTOR_NO_CLEARING. */ + if (!non_constant_p + && TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) + { + if (!allow_non_constant) + error ("%qE is not a constant expression because it refers to " + "an incompletely initialized variable", t); + TREE_CONSTANT (r) = false; + non_constant_p = true; + } + if (non_constant_p) /* If we saw something bad, go back to our argument. The wrapping below is only for the cases of TREE_CONSTANT argument or overflow. */ @@ -9274,13 +9332,17 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (non_constant_p && !allow_non_constant) return error_mark_node; - else if (constexpr_dtor) - return r; else if (non_constant_p && TREE_CONSTANT (r)) r = mark_non_constant (r); else if (non_constant_p) return t; + if (constexpr_dtor) + { + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; + return r; + } + /* Check we are not trying to return the wrong type. */ if (!same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (r))) { @@ -9300,7 +9362,8 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, if (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_INITIAL (t) == r) return t; - else if (TREE_CODE (t) == CONSTRUCTOR || TREE_CODE (t) == CALL_EXPR) + else if (TREE_CODE (t) == CONSTRUCTOR || TREE_CODE (t) == CALL_EXPR + || TREE_CODE (t) == AGGR_INIT_EXPR) /* Don't add a TARGET_EXPR if our argument didn't have one. */; else if (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_CLEANUP (t)) r = get_target_expr (r); @@ -9431,6 +9494,9 @@ fold_simple (tree t) tree fold_to_constant (tree t) { + if (processing_template_decl) + return t; + tree r = fold (t); if (CONSTANT_CLASS_P (r) && !TREE_OVERFLOW (r)) return r; @@ -9662,7 +9728,7 @@ fold_non_dependent_init (tree t, static tree maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, - bool manifestly_const_eval) + mce_value manifestly_const_eval) { if (!t) return t; @@ -9688,17 +9754,27 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, { /* [basic.start.static] allows constant-initialization of variables with static or thread storage duration even if it isn't required, but we - shouldn't bend the rules the same way for automatic variables. */ + shouldn't bend the rules the same way for automatic variables. + + But still enforce the requirements of constexpr/constinit. + [dcl.constinit] "If a variable declared with the constinit specifier + has dynamic initialization, the program is ill-formed, even if the + implementation would perform that initialization as a static + initialization." */ bool is_static = (decl && DECL_P (decl) && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))); + bool strict = (!is_static + || (decl && DECL_P (decl) + && (DECL_DECLARED_CONSTEXPR_P (decl) + || DECL_DECLARED_CONSTINIT_P (decl)))); if (is_static) - manifestly_const_eval = true; + manifestly_const_eval = mce_true; - if (cp_unevaluated_operand && !manifestly_const_eval) + if (cp_unevaluated_operand && manifestly_const_eval != mce_true) return fold_to_constant (t); - t = cxx_eval_outermost_constant_expr (t, allow_non_constant, !is_static, - mce_value (manifestly_const_eval), + t = cxx_eval_outermost_constant_expr (t, allow_non_constant, strict, + manifestly_const_eval, false, decl); } if (TREE_CODE (t) == TARGET_EXPR) @@ -9715,6 +9791,12 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, tree maybe_constant_init (tree t, tree decl, bool manifestly_const_eval) { + return maybe_constant_init_1 (t, decl, true, mce_value (manifestly_const_eval)); +} + +tree +maybe_constant_init (tree t, tree decl, mce_value manifestly_const_eval) +{ return maybe_constant_init_1 (t, decl, true, manifestly_const_eval); } @@ -9723,7 +9805,7 @@ maybe_constant_init (tree t, tree decl, bool manifestly_const_eval) tree cxx_constant_init (tree t, tree decl) { - return maybe_constant_init_1 (t, decl, false, true); + return maybe_constant_init_1 (t, decl, false, mce_true); } #if 0 @@ -10263,22 +10345,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, return true; case INDIRECT_REF: - { - tree x = TREE_OPERAND (t, 0); - STRIP_NOPS (x); - if (is_this_parameter (x) && !is_capture_proxy (x)) - { - if (now || !var_in_maybe_constexpr_fn (x)) - { - if (flags & tf_error) - constexpr_error (loc, fundef_p, "use of %<this%> in a " - "constant expression"); - return false; - } - return true; - } - return RECUR (x, rval); - } + return RECUR (TREE_OPERAND (t, 0), rval); case STATEMENT_LIST: for (tree stmt : tsi_range (t)) diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index a9caba8..44fb086 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -354,7 +354,7 @@ struct norm_info : subst_info /* Construct a top-level context for DECL. */ norm_info (tree in_decl, bool diag) - : subst_info (tf_warning_or_error, in_decl), + : subst_info (tf_warning_or_error|tf_partial, in_decl), generate_diagnostics (diag) { if (in_decl) @@ -2704,6 +2704,8 @@ satisfy_declaration_constraints (tree t, sat_info info) static tree satisfy_declaration_constraints (tree t, tree args, sat_info info) { + tree orig_args = args; + /* Update the declaration for diagnostics. */ info.in_decl = t; @@ -2732,7 +2734,7 @@ satisfy_declaration_constraints (tree t, tree args, sat_info info) tree result = boolean_true_node; if (tree norm = get_normalized_constraints_from_decl (t, info.noisy ())) { - if (!push_tinst_level (t, args)) + if (!push_tinst_level (t, orig_args)) return result; tree pattern = DECL_TEMPLATE_RESULT (t); push_to_top_level (); diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index f2b126c..d0cfd2e 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -860,10 +860,17 @@ cp_contract_assertion_p (const_tree attr) void remove_contract_attributes (tree fndecl) { + if (!flag_contracts) + return; + tree list = NULL_TREE; for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p)) if (!cxx_contract_attribute_p (p)) - list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list); + { + tree nl = copy_node (p); + TREE_CHAIN (nl) = list; + list = nl; + } DECL_ATTRIBUTES (fndecl) = nreverse (list); } diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index b92d09f..743da06 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1852,21 +1852,6 @@ coro_build_frame_access_expr (tree coro_ref, tree member_id, bool preserve_ref, return expr; } -/* Helpers to build EXPR_STMT and void-cast EXPR_STMT, common ops. */ - -static tree -coro_build_expr_stmt (tree expr, location_t loc) -{ - return maybe_cleanup_point_expr_void (build_stmt (loc, EXPR_STMT, expr)); -} - -static tree -coro_build_cvt_void_expr_stmt (tree expr, location_t loc) -{ - tree t = build1 (CONVERT_EXPR, void_type_node, expr); - return coro_build_expr_stmt (t, loc); -} - /* Helpers to build an artificial var, with location LOC, NAME and TYPE, in CTX, and with initializer INIT. */ @@ -2582,8 +2567,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, tree hfa = build_new_method_call (ash, hfa_m, &args, NULL_TREE, LOOKUP_NORMAL, NULL, tf_warning_or_error); r = cp_build_init_expr (ash, hfa); - r = coro_build_cvt_void_expr_stmt (r, loc); - add_stmt (r); + finish_expr_stmt (r); release_tree_vector (args); /* Now we know the real promise, and enough about the frame layout to @@ -2678,8 +2662,7 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody, we must tail call them. However, some targets do not support indirect tail calls to arbitrary callees. See PR94359. */ CALL_EXPR_TAILCALL (resume) = true; - resume = coro_build_cvt_void_expr_stmt (resume, loc); - add_stmt (resume); + finish_expr_stmt (resume); r = build_stmt (loc, RETURN_EXPR, NULL); gcc_checking_assert (maybe_cleanup_point_expr_void (r) == r); diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 550cea29..d2423fd 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1199,8 +1199,11 @@ cp_build_init_expr_for_ctor (tree call, tree init) tree s = build_fold_indirect_ref_loc (loc, a); init = cp_build_init_expr (s, init); if (return_this) - init = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (call), init, - fold_convert_loc (loc, TREE_TYPE (call), a)); + { + init = build2_loc (loc, COMPOUND_EXPR, TREE_TYPE (call), init, + fold_convert_loc (loc, TREE_TYPE (call), a)); + suppress_warning (init); + } return init; } @@ -1480,7 +1483,9 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) *walk_subtrees = 0; if (!flag_no_inline) { - tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt)); + tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt), + (data->flags & ff_mce_false + ? mce_false : mce_unknown)); if (folded != init && TREE_CONSTANT (folded)) init = folded; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 927f51b..7798efb 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2206,6 +2206,8 @@ struct GTY(()) language_function { BOOL_BITFIELD invalid_constexpr : 1; BOOL_BITFIELD throwing_cleanup : 1; + /* True if we gave any errors in this function. */ + BOOL_BITFIELD erroneous : 1; hash_table<named_label_hash> *x_named_labels; @@ -8837,6 +8839,7 @@ extern void cxx_constant_dtor (tree, tree); extern tree cxx_constant_init (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE, mce_value = mce_unknown); extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false); +extern tree maybe_constant_init (tree, tree, mce_value); extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error, bool = false, tree = NULL_TREE); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 2ed94fd..84398e5 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -5339,6 +5339,8 @@ cp_make_fname_decl (location_t loc, tree id, int type_dep) decl = pushdecl_outermost_localscope (decl); if (decl != error_mark_node) add_decl_expr (decl); + else + gcc_assert (seen_error ()); } else { @@ -19834,14 +19836,14 @@ cp_tree_node_structure (union lang_tree_node * t) { switch (TREE_CODE (&t->generic)) { - case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT; + case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT; case BASELINK: return TS_CP_BASELINK; - case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO; + case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO; case DEFERRED_NOEXCEPT: return TS_CP_DEFERRED_NOEXCEPT; case DEFERRED_PARSE: return TS_CP_DEFERRED_PARSE; case IDENTIFIER_NODE: return TS_CP_IDENTIFIER; case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; - case BINDING_VECTOR: return TS_CP_BINDING_VECTOR; + case BINDING_VECTOR: return TS_CP_BINDING_VECTOR; case OVERLOAD: return TS_CP_OVERLOAD; case PTRMEM_CST: return TS_CP_PTRMEM; case STATIC_ASSERT: return TS_CP_STATIC_ASSERT; @@ -19849,6 +19851,7 @@ cp_tree_node_structure (union lang_tree_node * t) case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO; case TEMPLATE_PARM_INDEX: return TS_CP_TPI; case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; + case TU_LOCAL_ENTITY: return TS_CP_TU_LOCAL_ENTITY; case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL; default: return TS_CP_GENERIC; } diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index ec7527e..499eb1b 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -3788,18 +3788,18 @@ cp_print_error_function (diagnostic_text_output_format &text_output, { if (text_output.show_column_p () && s.column != 0) pp_printf (pp, - _(" inlined from %qD at %r%s:%d:%d%R"), + G_(" inlined from %qD at %r%s:%d:%d%R"), fndecl, "locus", s.file, s.line, s.column); else pp_printf (pp, - _(" inlined from %qD at %r%s:%d%R"), + G_(" inlined from %qD at %r%s:%d%R"), fndecl, "locus", s.file, s.line); } else - pp_printf (pp, _(" inlined from %qD"), + pp_printf (pp, G_(" inlined from %qD"), fndecl); } } @@ -3825,22 +3825,22 @@ function_category (tree fn) && DECL_FUNCTION_MEMBER_P (fn)) { if (DECL_STATIC_FUNCTION_P (fn)) - return _("In static member function %qD"); + return G_("In static member function %qD"); else if (DECL_COPY_CONSTRUCTOR_P (fn)) - return _("In copy constructor %qD"); + return G_("In copy constructor %qD"); else if (DECL_CONSTRUCTOR_P (fn)) - return _("In constructor %qD"); + return G_("In constructor %qD"); else if (DECL_DESTRUCTOR_P (fn)) - return _("In destructor %qD"); + return G_("In destructor %qD"); else if (LAMBDA_FUNCTION_P (fn)) - return _("In lambda function"); + return G_("In lambda function"); else if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)) - return _("In explicit object member function %qD"); + return G_("In explicit object member function %qD"); else - return _("In member function %qD"); + return G_("In member function %qD"); } else - return _("In function %qD"); + return G_("In function %qD"); } /* Disable warnings about missing quoting in GCC diagnostics for @@ -3867,8 +3867,8 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output) char *indent = text_output.build_indent_prefix (true); pp_verbatim (text_output.get_printer (), p->list_p () - ? _("%s%s%sIn substitution of %qS:\n") - : _("%s%s%sIn instantiation of %q#D:\n"), + ? G_("%s%s%sIn substitution of %qS:\n") + : G_("%s%s%sIn instantiation of %q#D:\n"), indent, show_file ? LOCATION_FILE (location) : "", show_file ? ": " : "", @@ -3888,10 +3888,10 @@ print_location (diagnostic_text_output_format &text_output, expanded_location xloc = expand_location (loc); pretty_printer *const pp = text_output.get_printer (); if (text_output.show_column_p ()) - pp_verbatim (pp, _("%r%s:%d:%d:%R "), + pp_verbatim (pp, G_("%r%s:%d:%d:%R "), "locus", xloc.file, xloc.line, xloc.column); else - pp_verbatim (pp, _("%r%s:%d:%R "), + pp_verbatim (pp, G_("%r%s:%d:%R "), "locus", xloc.file, xloc.line); } @@ -3984,22 +3984,22 @@ print_instantiation_partial_context_line (diagnostic_text_output_format &text_ou if (t->list_p ()) pp_verbatim (pp, recursive_p - ? _("recursively required by substitution of %qS\n") - : _("required by substitution of %qS\n"), + ? G_("recursively required by substitution of %qS\n") + : G_("required by substitution of %qS\n"), t->get_node ()); else pp_verbatim (pp, recursive_p - ? _("recursively required from %q#D\n") - : _("required from %q#D\n"), + ? G_("recursively required from %q#D\n") + : G_("required from %q#D\n"), t->get_node ()); } else { pp_verbatim (pp, recursive_p - ? _("recursively required from here\n") - : _("required from here\n")); + ? G_("recursively required from here\n") + : G_("required from here\n")); } } @@ -4049,8 +4049,8 @@ print_instantiation_partial_context (diagnostic_text_output_format &text_output, { auto_context_line sentinel (text_output, loc); pp_verbatim (text_output.get_printer (), - _("[ skipping %d instantiation contexts," - " use -ftemplate-backtrace-limit=0 to disable ]\n"), + G_("[ skipping %d instantiation contexts," + " use -ftemplate-backtrace-limit=0 to disable ]\n"), skip); do { loc = t->locus; @@ -4101,7 +4101,7 @@ maybe_print_constexpr_context (diagnostic_text_output_format &text_output) pretty_printer *const pp = text_output.get_printer (); auto_context_line sentinel (text_output, EXPR_LOCATION (t)); pp_verbatim (pp, - _("in %<constexpr%> expansion of %qs"), + G_("in %<constexpr%> expansion of %qs"), s); pp_newline (pp); } @@ -4114,7 +4114,7 @@ print_constrained_decl_info (diagnostic_text_output_format &text_output, { auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl)); pretty_printer *const pp = text_output.get_printer (); - pp_verbatim (pp, "required by the constraints of %q#D\n", decl); + pp_verbatim (pp, G_("required by the constraints of %q#D\n"), decl); } static void @@ -4129,7 +4129,7 @@ print_concept_check_info (diagnostic_text_output_format &text_output, cxx_pretty_printer *const pp = (cxx_pretty_printer *)text_output.get_printer (); - pp_verbatim (pp, "required for the satisfaction of %qE", expr); + pp_verbatim (pp, G_("required for the satisfaction of %qE"), expr); if (map && map != error_mark_node) { tree subst_map = tsubst_parameter_mapping (map, args, tf_none, NULL_TREE); @@ -4151,7 +4151,7 @@ print_constraint_context_head (diagnostic_text_output_format &text_output, { auto_context_line sentinel (text_output, input_location); pretty_printer *const pp = text_output.get_printer (); - pp_verbatim (pp, "required for constraint satisfaction\n"); + pp_verbatim (pp, G_("required for constraint satisfaction\n")); return NULL_TREE; } if (DECL_P (src)) @@ -4180,11 +4180,10 @@ print_requires_expression_info (diagnostic_text_output_format &text_output, auto_context_line sentinel (text_output, cp_expr_loc_or_input_loc (expr)); cxx_pretty_printer *const pp = static_cast <cxx_pretty_printer *> (text_output.get_printer ()); - pp_verbatim (pp, "in requirements "); tree parms = TREE_OPERAND (expr, 0); - if (parms) - pp_verbatim (pp, "with "); + pp_verbatim (pp, parms ? G_("in requirements with ") + : G_("in requirements ")); while (parms) { pp_verbatim (pp, "%q#D", parms); diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index e589e45..062a493 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -3405,7 +3405,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, errval = throw_bad_array_new_length (); if (outer_nelts_check != NULL_TREE) size = build3 (COND_EXPR, sizetype, outer_nelts_check, size, errval); - size = cp_fully_fold (size); + size = fold_to_constant (size); /* Create the argument list. */ vec_safe_insert (*placement, 0, size); /* Do name-lookup to find the appropriate operator. */ @@ -3462,7 +3462,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, outer_nelts_check = NULL_TREE; } - size = cp_fully_fold (size); + size = fold_to_constant (size); /* If size is zero e.g. due to type having zero size, try to preserve outer_nelts for constant expression evaluation purposes. */ diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc index ed70bb0..b2e0ecd 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -59,7 +59,13 @@ build_lambda_object (tree lambda_expr) vec<constructor_elt, va_gc> *elts = NULL; tree node, expr, type; - if (processing_template_decl || lambda_expr == error_mark_node) + if (processing_template_decl && !in_template_context + && current_binding_level->requires_expression) + /* As in cp_parser_lambda_expression, don't get confused by + cp_parser_requires_expression setting processing_template_decl. In that + case we want to return the result of finish_compound_literal, to avoid + tsubst_lambda_expr. */; + else if (processing_template_decl || lambda_expr == error_mark_node) return lambda_expr; /* Make sure any error messages refer to the lambda-introducer. */ @@ -1852,6 +1858,13 @@ prune_lambda_captures (tree body) cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars); + tree bind_expr = expr_single (DECL_SAVED_TREE (lambda_function (lam))); + if (bind_expr && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR) + bind_expr = expr_single (TREE_OPERAND (bind_expr, 0)); + /* FIXME: We don't currently handle noexcept lambda captures correctly, + so bind_expr may not be set; see PR c++/119764. */ + gcc_assert (!bind_expr || TREE_CODE (bind_expr) == BIND_EXPR); + tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam)); for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; ) { @@ -1873,6 +1886,23 @@ prune_lambda_captures (tree body) fieldp = &DECL_CHAIN (*fieldp); *fieldp = DECL_CHAIN (*fieldp); + /* And out of the bindings for the function. */ + tree *blockp = &BLOCK_VARS (current_binding_level->blocks); + while (*blockp != DECL_EXPR_DECL (**use)) + blockp = &DECL_CHAIN (*blockp); + *blockp = DECL_CHAIN (*blockp); + + /* And maybe out of the vars declared in the containing + BIND_EXPR, if it's listed there. */ + if (bind_expr) + { + tree *bindp = &BIND_EXPR_VARS (bind_expr); + while (*bindp && *bindp != DECL_EXPR_DECL (**use)) + bindp = &DECL_CHAIN (*bindp); + if (*bindp) + *bindp = DECL_CHAIN (*bindp); + } + /* And remove the capture proxy declaration. */ **use = void_node; continue; diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc index c12b084..12af81e 100644 --- a/gcc/cp/lex.cc +++ b/gcc/cp/lex.cc @@ -749,6 +749,9 @@ unqualified_name_lookup_error (tree name, location_t loc) if (IDENTIFIER_ANY_OP_P (name)) error_at (loc, "%qD not defined", name); + else if (!flag_concepts && name == ridpointers[(int)RID_REQUIRES]) + error_at (loc, "%<requires%> only available with %<-std=c++20%> or " + "%<-fconcepts%>"); else { if (!objc_diagnose_private_ivar (name)) diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 02129c6..3d5e96b 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -1048,6 +1048,12 @@ decl_mangling_context (tree decl) tree extra = LAMBDA_TYPE_EXTRA_SCOPE (TREE_TYPE (decl)); if (extra) return extra; + tcontext = CP_DECL_CONTEXT (decl); + if (LAMBDA_TYPE_P (tcontext)) + /* Lambda type context means this lambda appears between the + lambda-introducer and the open brace of another lambda (c++/119175). + That isn't a real scope; look further into the enclosing scope. */ + return decl_mangling_context (TYPE_NAME (tcontext)); } else if (template_type_parameter_p (decl)) /* template type parms have no mangling context. */ diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index ce22b2e..5ff5c46 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -9004,25 +9004,28 @@ trees_out::decl_node (tree decl, walk_kind ref) if (streaming_p ()) i (tt_parm); tree_node (DECL_CONTEXT (decl)); - if (streaming_p ()) - { - /* That must have put this in the map. */ - walk_kind ref = ref_node (decl); - if (ref != WK_none) - // FIXME:OPTIMIZATION We can wander into bits of the - // template this was instantiated from. For instance - // deferred noexcept and default parms. Currently we'll - // end up cloning those bits of tree. It would be nice - // to reference those specific nodes. I think putting - // those things in the map when we reference their - // template by name. See the note in add_indirects. - return true; - dump (dumper::TREE) - && dump ("Wrote %s reference %N", - TREE_CODE (decl) == PARM_DECL ? "parameter" : "result", - decl); - } + /* That must have put this in the map. */ + walk_kind ref = ref_node (decl); + if (ref != WK_none) + // FIXME:OPTIMIZATION We can wander into bits of the + // template this was instantiated from, for instance + // deferred noexcept and default parms, or references + // to parms from earlier forward-decls (PR c++/119608). + // + // Currently we'll end up cloning those bits of tree. + // It would be nice to reference those specific nodes. + // I think putting those things in the map when we + // reference their template by name. + // + // See the note in add_indirects. + return true; + + if (streaming_p ()) + dump (dumper::TREE) + && dump ("Wrote %s reference %N", + TREE_CODE (decl) == PARM_DECL ? "parameter" : "result", + decl); } return false; @@ -12087,6 +12090,8 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) gcc_checking_assert (TREE_CODE (e_inner) == TREE_CODE (d_inner)); } + // FIXME: do more precise errors at point of mismatch + const char *mismatch_msg = nullptr; if (TREE_CODE (d_inner) == FUNCTION_DECL) { tree e_ret = fndecl_declared_return_type (existing); @@ -12096,13 +12101,20 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) && LAMBDA_TYPE_P (DECL_CONTEXT (d_inner))) /* This has a recursive type that will compare different. */; else if (!same_type_p (d_ret, e_ret)) - goto mismatch; + { + mismatch_msg = G_("conflicting type for imported declaration %#qD"); + goto mismatch; + } tree e_type = TREE_TYPE (e_inner); tree d_type = TREE_TYPE (d_inner); if (DECL_EXTERN_C_P (d_inner) != DECL_EXTERN_C_P (e_inner)) - goto mismatch; + { + mismatch_msg = G_("conflicting language linkage for imported " + "declaration %#qD"); + goto mismatch; + } for (tree e_args = TYPE_ARG_TYPES (e_type), d_args = TYPE_ARG_TYPES (d_type); @@ -12110,10 +12122,18 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) e_args = TREE_CHAIN (e_args), d_args = TREE_CHAIN (d_args)) { if (!(e_args && d_args)) - goto mismatch; + { + mismatch_msg = G_("conflicting argument list for imported " + "declaration %#qD"); + goto mismatch; + } if (!same_type_p (TREE_VALUE (d_args), TREE_VALUE (e_args))) - goto mismatch; + { + mismatch_msg = G_("conflicting argument types for imported " + "declaration %#qD"); + goto mismatch; + } } /* If EXISTING has an undeduced or uninstantiated exception @@ -12122,7 +12142,7 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) instantiate it in the middle of loading. */ tree e_spec = TYPE_RAISES_EXCEPTIONS (e_type); tree d_spec = TYPE_RAISES_EXCEPTIONS (d_type); - if (DEFERRED_NOEXCEPT_SPEC_P (e_spec)) + if (DECL_MAYBE_DELETED (e_inner) || DEFERRED_NOEXCEPT_SPEC_P (e_spec)) { if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec) || (UNEVALUATED_NOEXCEPT_SPEC_P (e_spec) @@ -12144,9 +12164,14 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) } } } - else if (!DEFERRED_NOEXCEPT_SPEC_P (d_spec) + else if (!DECL_MAYBE_DELETED (d_inner) + && !DEFERRED_NOEXCEPT_SPEC_P (d_spec) && !comp_except_specs (d_spec, e_spec, ce_type)) - goto mismatch; + { + mismatch_msg = G_("conflicting %<noexcept%> specifier for " + "imported declaration %#qD"); + goto mismatch; + } /* Similarly if EXISTING has an undeduced return type, but DECL's is already deduced. */ @@ -12160,20 +12185,48 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) } else if (type_uses_auto (d_ret) && !same_type_p (TREE_TYPE (d_type), TREE_TYPE (e_type))) - goto mismatch; + { + mismatch_msg = G_("conflicting deduced return type for " + "imported declaration %#qD"); + goto mismatch; + } + + /* Similarly if EXISTING has undeduced constexpr, but DECL's + is already deduced. */ + if (DECL_MAYBE_DELETED (e_inner) && !DECL_MAYBE_DELETED (d_inner) + && DECL_DECLARED_CONSTEXPR_P (d_inner)) + DECL_DECLARED_CONSTEXPR_P (e_inner) = true; + else if (!DECL_MAYBE_DELETED (e_inner) && DECL_MAYBE_DELETED (d_inner)) + /* Nothing to do. */; + else if (DECL_DECLARED_CONSTEXPR_P (e_inner) + != DECL_DECLARED_CONSTEXPR_P (d_inner)) + { + mismatch_msg = G_("conflicting %<constexpr%> for imported " + "declaration %#qD"); + goto mismatch; + } + + /* Don't synthesize a defaulted function if we're importing one + we've already determined. */ + if (!DECL_MAYBE_DELETED (d_inner)) + DECL_MAYBE_DELETED (e_inner) = false; } else if (is_typedef) { if (!DECL_ORIGINAL_TYPE (e_inner) || !same_type_p (DECL_ORIGINAL_TYPE (d_inner), DECL_ORIGINAL_TYPE (e_inner))) - goto mismatch; + { + mismatch_msg = G_("conflicting imported declaration %q#D"); + goto mismatch; + } } /* Using cp_tree_equal because we can meet TYPE_ARGUMENT_PACKs here. I suspect the entities that directly do that are things that shouldn't go to duplicate_decls (FIELD_DECLs etc). */ else if (!cp_tree_equal (TREE_TYPE (decl), TREE_TYPE (existing))) { + mismatch_msg = G_("conflicting type for imported declaration %#qD"); mismatch: if (DECL_IS_UNDECLARED_BUILTIN (existing)) /* Just like duplicate_decls, presum the user knows what @@ -12186,11 +12239,9 @@ trees_in::is_matching_decl (tree existing, tree decl, bool is_typedef) equality isn't feasible in general for local entities. */; else { - // FIXME:QOI Might be template specialization from a module, - // not necessarily global module + gcc_checking_assert (mismatch_msg); auto_diagnostic_group d; - error_at (DECL_SOURCE_LOCATION (decl), - "conflicting global module declaration %#qD", decl); + error_at (DECL_SOURCE_LOCATION (decl), mismatch_msg, decl); inform (DECL_SOURCE_LOCATION (existing), "existing declaration %#qD", existing); return false; @@ -16679,6 +16730,15 @@ module_state::read_cluster (unsigned snum) #endif cfun->returns_struct = aggr; expand_or_defer_fn (decl); + + /* If we first see this function after at_eof, it doesn't get + note_vague_linkage_fn from tentative_decl_linkage, so the loop in + c_parse_final_cleanups won't consider it. But with DECL_COMDAT we + can just clear DECL_EXTERNAL and let cgraph decide. + FIXME handle this outside module.cc after GCC 15. */ + if (at_eof && DECL_COMDAT (decl) && DECL_EXTERNAL (decl) + && DECL_NOT_REALLY_EXTERN (decl)) + DECL_EXTERNAL (decl) = false; } } @@ -19159,6 +19219,10 @@ post_load_processing () gcc_checking_assert (DECL_MAYBE_IN_CHARGE_CDTOR_P (decl)); expand_or_defer_fn (decl); + /* As in module_state::read_cluster. */ + if (at_eof && DECL_COMDAT (decl) && DECL_EXTERNAL (decl) + && DECL_NOT_REALLY_EXTERN (decl)) + DECL_EXTERNAL (decl) = false; } cfun = old_cfun; diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 7fadbcc..aa2dc0e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -583,7 +583,7 @@ name_lookup::preserve_state () if (previous) { unsigned length = vec_safe_length (previous->scopes); - vec_safe_reserve (previous->scopes, length * 2); + vec_safe_reserve (previous->scopes, length); for (unsigned ix = length; ix--;) { tree decl = (*previous->scopes)[ix]; @@ -4178,22 +4178,6 @@ mergeable_namespace_slots (tree ns, tree name, bool is_attached, tree *vec) return vslot; } -/* Retrieve the bindings for an existing mergeable entity in namespace - NS slot NAME. Returns NULL if no such bindings exists. */ - -static tree -get_mergeable_namespace_binding (tree ns, tree name, bool is_attached) -{ - tree *mslot = find_namespace_slot (ns, name, false); - if (!mslot || !*mslot || TREE_CODE (*mslot) != BINDING_VECTOR) - return NULL_TREE; - - tree *vslot = get_fixed_binding_slot - (mslot, name, is_attached ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, - false); - return vslot ? *vslot : NULL_TREE; -} - /* DECL is a new mergeable namespace-scope decl. Add it to the mergeable entities on GSLOT. */ @@ -4572,11 +4556,9 @@ lookup_imported_hidden_friend (tree friend_tmpl) || !DECL_MODULE_ENTITY_P (inner)) return NULL_TREE; - lazy_load_pendings (friend_tmpl); - - tree bind = get_mergeable_namespace_binding - (current_namespace, DECL_NAME (inner), DECL_MODULE_ATTACH_P (inner)); - if (!bind) + tree name = DECL_NAME (inner); + tree *slot = find_namespace_slot (current_namespace, name, false); + if (!slot || !*slot || TREE_CODE (*slot) != BINDING_VECTOR) return NULL_TREE; /* We're only interested in declarations attached to the same module @@ -4584,9 +4566,28 @@ lookup_imported_hidden_friend (tree friend_tmpl) int m = get_originating_module (friend_tmpl, /*global=-1*/true); gcc_assert (m != 0); + /* First check whether there's a reachable declaration attached to the module + we're looking for. */ + if (m > 0) + if (binding_slot *mslot = search_imported_binding_slot (slot, m)) + { + if (mslot->is_lazy ()) + lazy_load_binding (m, current_namespace, name, mslot); + for (ovl_iterator iter (*mslot); iter; ++iter) + if (DECL_CLASS_TEMPLATE_P (*iter)) + return *iter; + } + + /* Otherwise, look in the mergeable slots for this name, in case an importer + has already instantiated this declaration. */ + tree *vslot = get_fixed_binding_slot + (slot, name, m > 0 ? BINDING_SLOT_PARTITION : BINDING_SLOT_GLOBAL, false); + if (!vslot || !*vslot) + return NULL_TREE; + /* There should be at most one class template from the module we're looking for, return it. */ - for (ovl_iterator iter (bind); iter; ++iter) + for (ovl_iterator iter (*vslot); iter; ++iter) if (DECL_CLASS_TEMPLATE_P (*iter) && get_originating_module (*iter, true) == m) return *iter; @@ -5204,9 +5205,11 @@ pushdecl_outermost_localscope (tree x) cp_binding_level *b = NULL; auto_cond_timevar tv (TV_NAME_LOOKUP); - /* Find the scope just inside the function parms. */ - for (cp_binding_level *n = current_binding_level; - n->kind != sk_function_parms; n = b->level_chain) + /* Find the block scope just inside the function parms. */ + cp_binding_level *n = current_binding_level; + while (n && n->kind != sk_block) + n = n->level_chain; + for (; n && n->kind != sk_function_parms; n = b->level_chain) b = n; return b ? do_pushdecl_with_scope (x, b) : error_mark_node; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index f2eea4c..3628cfe 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -11736,21 +11736,34 @@ cp_parser_lambda_expression (cp_parser* parser) if (cp_parser_error_occurred (parser)) return error_mark_node; - type = begin_lambda_type (lambda_expr); - if (type == error_mark_node) - return error_mark_node; + { + /* OK, this is a bit tricksy. cp_parser_requires_expression sets + processing_template_decl to make checking more normal, but that confuses + lambda parsing terribly. In non-template context, we want to parse the + lambda once and not tsubst_lambda_expr. So in that case, clear + processing_template_decl now, and restore it before the call to + build_lambda_object; that way we end up with what looks like a templatey + functional cast to the closure type, which is suitable for the + requires-expression tsubst_expr. This is PR99546 and friends. */ + processing_template_decl_sentinel ptds (/*reset*/false); + if (processing_template_decl && !in_template_context + && current_binding_level->requires_expression) + processing_template_decl = 0; + + type = begin_lambda_type (lambda_expr); + if (type == error_mark_node) + return error_mark_node; - record_lambda_scope (lambda_expr); - record_lambda_scope_discriminator (lambda_expr); + record_lambda_scope (lambda_expr); + record_lambda_scope_discriminator (lambda_expr); - /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */ - determine_visibility (TYPE_NAME (type)); + /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */ + determine_visibility (TYPE_NAME (type)); - /* Now that we've started the type, add the capture fields for any - explicit captures. */ - register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr)); + /* Now that we've started the type, add the capture fields for any + explicit captures. */ + register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr)); - { /* Inside the class, surrounding template-parameter-lists do not apply. */ unsigned int saved_num_template_parameter_lists = parser->num_template_parameter_lists; @@ -33621,6 +33634,8 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, = parser->num_template_parameter_lists; parser->num_template_parameter_lists = 0; + int errs = errorcount + sorrycount; + /* If the next token is `try', `__transaction_atomic', or `__transaction_relaxed`, then we are looking at either function-try-block or function-transaction-block. Note that all of these include the @@ -33640,6 +33655,9 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, fn = finish_function (inline_p); check_module_decl_linkage (fn); + if ((errorcount + sorrycount) > errs) + DECL_STRUCT_FUNCTION (fn)->language->erroneous = true; + if (modules_p () && !inline_p && TYPE_P (DECL_CONTEXT (fn)) @@ -43121,8 +43139,8 @@ cp_parser_omp_clause_init_modifiers (cp_parser *parser, bool *target, while (true); fail: - cp_parser_error (parser, "%<init%> clause with modifier other than " - "%<prefer_type%>, %<target%> or %<targetsync%>"); + cp_parser_error (parser, + "expected %<prefer_type%>, %<target%>, or %<targetsync%>"); return false; } @@ -43140,39 +43158,14 @@ cp_parser_omp_clause_init (cp_parser *parser, tree list) if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return list; - unsigned raw_pos = 1; - while (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type == CPP_NAME) - { - raw_pos++; - if (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type - == CPP_OPEN_PAREN) - { - unsigned n = cp_parser_skip_balanced_tokens (parser, raw_pos); - if (n == raw_pos) - { - raw_pos = 0; - break; - } - raw_pos = n; - } - if (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type == CPP_COLON) - break; - if (cp_lexer_peek_nth_token (parser->lexer, raw_pos)->type != CPP_COMMA) - { - raw_pos = 0; - break; - } - raw_pos++; - } - bool target = false; bool targetsync = false; tree prefer_type_tree = NULL_TREE; + location_t loc = cp_lexer_peek_token (parser->lexer)->location; - if (raw_pos > 1 - && (!cp_parser_omp_clause_init_modifiers (parser, &target, &targetsync, - &prefer_type_tree) - || !cp_parser_require (parser, CPP_COLON, RT_COLON))) + if (!cp_parser_omp_clause_init_modifiers (parser, &target, &targetsync, + &prefer_type_tree) + || !cp_parser_require (parser, CPP_COLON, RT_COLON)) { if (prefer_type_tree == error_mark_node) return error_mark_node; @@ -43182,6 +43175,10 @@ cp_parser_omp_clause_init (cp_parser *parser, tree list) return list; } + if (!target && !targetsync) + error_at (loc, + "missing required %<target%> and/or %<targetsync%> modifier"); + tree nl = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_INIT, list, NULL, false); for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) @@ -50581,6 +50578,10 @@ cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok, &targetsync, &prefer_type_tree)) goto fail; + if (!target && !targetsync) + error_at (loc, + "missing required %<target%> and/or " + "%<targetsync%> modifier"); tree t = build_tree_list (target ? boolean_true_node : boolean_false_node, targetsync ? boolean_true_node diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index f7c56a1..a71705f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11117,6 +11117,18 @@ any_template_parm_r (tree t, void *data) case LAMBDA_EXPR: { + /* TREE_STATIC on LAMBDA_EXPR_EXTRA_ARGS means a full set of + arguments, so we can just look there; they will replace + any template parms in the rest of the LAMBDA_EXPR. */ + if (tree args = LAMBDA_EXPR_EXTRA_ARGS (t)) + { + WALK_SUBTREE (args); + /* Without TREE_STATIC the args are just outer levels, so we'd + still need to look through the lambda for just inner + parameters. Hopefully that's not necessary. */ + gcc_checking_assert (TREE_STATIC (args)); + return 0; + } /* Look in the parms and body. */ tree fn = lambda_function (t); WALK_SUBTREE (TREE_TYPE (fn)); @@ -11760,6 +11772,10 @@ tsubst_friend_function (tree decl, tree args) elt.args = DECL_TI_ARGS (spec); elt.spec = NULL_TREE; + if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (DECL_TI_ARGS (spec)) + && !is_specialization_of_friend (spec, new_template)) + continue; + decl_specializations->remove_elt (&elt); tree& spec_args = DECL_TI_ARGS (spec); @@ -12413,6 +12429,8 @@ apply_late_template_attributes (tree *decl_p, tree attributes, int attr_flags, auto o4 = make_temp_override (scope_chain->omp_declare_target_attribute, NULL); auto o5 = make_temp_override (scope_chain->omp_begin_assumes, NULL); + auto o6 = make_temp_override (target_option_current_node, + target_option_default_node); cplus_decl_attributes (decl_p, late_attrs, attr_flags); @@ -13736,11 +13754,12 @@ add_extra_args (tree extra, tree args, tsubst_flags_t complain, tree in_decl) inst = local; /* else inst is already a full instantiation of the pack. */ register_local_specialization (inst, gen); + if (is_normal_capture_proxy (gen)) + register_local_specialization (inst, DECL_CAPTURED_VARIABLE (gen)); } gcc_assert (!TREE_PURPOSE (extra)); extra = TREE_VALUE (extra); } - gcc_checking_assert (TREE_STATIC (extra) == uses_template_parms (extra)); if (TREE_STATIC (extra)) /* This is a partial substitution into e.g. a requires-expr or lambda-expr inside a default template argument; we expect 'extra' to be a full set @@ -17741,13 +17760,37 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain, if (TYPE_P (t)) { + bool stripped = false; if (typedef_variant_p (t)) - t = strip_typedefs (t); - tree decl = TYPE_NAME (t); + { + /* Since this transformation may undesirably turn a deduced context + into a non-deduced one, we'd rather strip typedefs than perform + the transformation. */ + tree u = strip_typedefs (t); + if (u != t) + { + stripped = true; + t = u; + } + } + decl = TYPE_NAME (t); if (decl) decl = maybe_dependent_member_ref (decl, args, complain, in_decl); if (!decl) - return NULL_TREE; + { + if (stripped) + /* The original type was an alias from the current instantiation + which we stripped to something outside it. At this point we + need to commit to using the stripped type rather than deferring + to the caller (which would use the original type), to ensure + eligible bits of the stripped type get transformed. */ + return tsubst (t, args, complain, in_decl); + else + /* The original type wasn't a typedef, and we decided it doesn't + need rewriting, so just let the caller (tsubst) substitute it + normally. */ + return NULL_TREE; + } return cp_build_qualified_type (TREE_TYPE (decl), cp_type_quals (t), complain); } @@ -17765,7 +17808,8 @@ maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain, if (TREE_CODE (t) == TYPE_DECL) { - if (TREE_CODE (TREE_TYPE (t)) == TYPENAME_TYPE + if (!is_typedef_decl (t) + && TREE_CODE (TREE_TYPE (t)) == TYPENAME_TYPE && TYPE_NAME (TREE_TYPE (t)) == t) /* The TYPE_DECL for a typename has DECL_CONTEXT of the typename scope, but it doesn't need to be rewritten again. */ @@ -22650,7 +22694,7 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) FUNCTION_DECL which is the desired context for access checking is not built yet. We solve this chicken-and-egg problem by deferring all checks until we have the FUNCTION_DECL. */ - push_deferring_access_checks (dk_deferred); + deferring_access_check_sentinel dacs (dk_deferred); /* Instantiation of the function happens in the context of the function template, not the context of the overload resolution we're doing. */ @@ -22708,10 +22752,13 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) pop_from_top_level (); if (fndecl == error_mark_node) - { - pop_deferring_access_checks (); - return error_mark_node; - } + return error_mark_node; + + /* Substituting the type might have recursively instantiated this + same alias (c++/117530). */ + if (DECL_ALIAS_TEMPLATE_P (gen_tmpl) + && (spec = retrieve_specialization (gen_tmpl, targ_ptr, hash))) + return spec; /* The DECL_TI_TEMPLATE should always be the immediate parent template, not the most general template. */ @@ -22746,7 +22793,6 @@ instantiate_template (tree tmpl, tree orig_args, tsubst_flags_t complain) access_ok = false; pop_access_scope (fndecl); } - pop_deferring_access_checks (); /* If we've just instantiated the main entry point for a function, instantiate all the alternate entry points as well. We do this @@ -27712,6 +27758,11 @@ instantiate_body (tree pattern, tree args, tree d, bool nested_p) if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)) cp_check_omp_declare_reduction (d); + + if (int errs = errorcount + sorrycount) + if (errs > current_tinst_level->errors) + if (function *f = DECL_STRUCT_FUNCTION (d)) + f->language->erroneous = true; } /* We're not deferring instantiation any more. */ @@ -30898,9 +30949,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides) tree aguides = NULL_TREE; tree atparms = INNERMOST_TEMPLATE_PARMS (fullatparms); unsigned natparms = TREE_VEC_LENGTH (atparms); - for (ovl_iterator iter (uguides); iter; ++iter) + for (tree f : lkp_range (uguides)) { - tree f = *iter; tree in_decl = f; location_t loc = DECL_SOURCE_LOCATION (f); tree ret = TREE_TYPE (TREE_TYPE (f)); diff --git a/gcc/cp/rtti.cc b/gcc/cp/rtti.cc index 3539962..18bc479 100644 --- a/gcc/cp/rtti.cc +++ b/gcc/cp/rtti.cc @@ -1318,18 +1318,9 @@ get_pseudo_ti_index (tree type) static tinfo_s * get_tinfo_desc (unsigned ix) { - unsigned len = tinfo_descs->length (); - - if (len <= ix) - { - /* too short, extend. */ - len = ix + 1 - len; - vec_safe_reserve (tinfo_descs, len); - tinfo_s elt; - elt.type = elt.vtable = elt.name = NULL_TREE; - while (len--) - tinfo_descs->quick_push (elt); - } + if (tinfo_descs->length () <= ix) + /* too short, extend. */ + vec_safe_grow_cleared (tinfo_descs, ix + 1); tinfo_s *res = &(*tinfo_descs)[ix]; diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 7d8beb8..1aa35d3 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1180,10 +1180,13 @@ finish_expr_stmt (tree expr) expr = error_mark_node; /* Simplification of inner statement expressions, compound exprs, - etc can result in us already having an EXPR_STMT. */ + etc can result in us already having an EXPR_STMT or other statement + tree. Don't wrap them in EXPR_STMT. */ if (TREE_CODE (expr) != CLEANUP_POINT_EXPR) { - if (TREE_CODE (expr) != EXPR_STMT) + if (TREE_CODE (expr) != EXPR_STMT + && !STATEMENT_CLASS_P (expr) + && TREE_CODE (expr) != STATEMENT_LIST) expr = build_stmt (loc, EXPR_STMT, expr); expr = maybe_cleanup_point_expr_void (expr); } @@ -3082,6 +3085,7 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr) } else if (processing_template_decl) { + /* Not finish_expr_stmt because we don't want convert_to_void. */ expr = build_stmt (input_location, EXPR_STMT, expr); expr = add_stmt (expr); /* Mark the last statement so that we can recognize it as such at @@ -4755,6 +4759,7 @@ finish_id_expression_1 (tree id_expression, body, except inside an unevaluated context (i.e. decltype). */ if (TREE_CODE (decl) == PARM_DECL && DECL_CONTEXT (decl) == NULL_TREE + && !CONSTRAINT_VAR_P (decl) && !cp_unevaluated_operand && !processing_contract_condition && !processing_omp_trait_property_expr) @@ -5087,22 +5092,32 @@ static tree finish_type_pack_element (tree idx, tree types, tsubst_flags_t complain) { idx = maybe_constant_value (idx, NULL_TREE, mce_true); - if (TREE_CODE (idx) != INTEGER_CST || !INTEGRAL_TYPE_P (TREE_TYPE (idx))) + if (!INTEGRAL_TYPE_P (TREE_TYPE (idx))) { if (complain & tf_error) - error ("pack index is not an integral constant"); + error ("pack index has non-integral type %qT", TREE_TYPE (idx)); + return error_mark_node; + } + if (TREE_CODE (idx) != INTEGER_CST) + { + if (complain & tf_error) + { + error ("pack index is not an integral constant"); + cxx_constant_value (idx); + } return error_mark_node; } if (tree_int_cst_sgn (idx) < 0) { if (complain & tf_error) - error ("pack index is negative"); + error ("pack index %qE is negative", idx); return error_mark_node; } if (wi::to_widest (idx) >= TREE_VEC_LENGTH (types)) { if (complain & tf_error) - error ("pack index is out of range"); + error ("pack index %qE is out of range for pack of length %qd", + idx, TREE_VEC_LENGTH (types)); return error_mark_node; } return TREE_VEC_ELT (types, tree_to_shwi (idx)); |