diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 53 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 63 | ||||
-rw-r--r-- | gcc/cp/contracts.cc | 3 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 10 | ||||
-rw-r--r-- | gcc/cp/init.cc | 4 | ||||
-rw-r--r-- | gcc/cp/lambda.cc | 41 | ||||
-rw-r--r-- | gcc/cp/name-lookup.cc | 45 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 10 |
8 files changed, 164 insertions, 65 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 6975efb..d092553 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,56 @@ +2025-04-25 Jason Merrill <jason@redhat.com> + + PR c++/119764 + PR c++/87185 + * lambda.cc (insert_capture_proxy): Handle noexcept lambda. + (prune_lambda_captures): Likewise, in ABI v21. + +2025-04-25 Jason Merrill <jason@redhat.com> + + * cp-tree.h (struct tinst_level): Add had_errors bit. + * pt.cc (push_tinst_level_loc): Clear it. + (pop_tinst_level): Set it. + (reopen_tinst_level): Check it. + (instantiate_pending_templates): Call limit_bad_template_recursion. + +2025-04-24 Jason Merrill <jason@redhat.com> + + PR c++/116954 + * contracts.cc (remove_contract_attributes): Return early if + not enabled. + +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) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index f56c5c4..8a11e62 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -2956,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; @@ -8479,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, @@ -9228,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. */ @@ -9251,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 ()) { @@ -9316,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. */ @@ -9332,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))) { @@ -9490,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; @@ -9747,16 +9754,26 @@ 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 = mce_true; 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, + t = cxx_eval_outermost_constant_expr (t, allow_non_constant, strict, manifestly_const_eval, false, decl); } diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc index 3ca2102..d0cfd2e 100644 --- a/gcc/cp/contracts.cc +++ b/gcc/cp/contracts.cc @@ -860,6 +860,9 @@ 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)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 7798efb..856202c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6755,8 +6755,14 @@ struct GTY((chain_next ("%h.next"))) tinst_level { /* The location where the template is instantiated. */ location_t locus; - /* errorcount + sorrycount when we pushed this level. */ - unsigned short errors; + /* errorcount + sorrycount when we pushed this level. If the value + overflows, it will always seem like we currently have more errors, so we + will limit template recursion even from non-erroneous templates. In a TU + with over 32k errors, that's fine. */ + unsigned short errors : 15; + + /* set in pop_tinst_level if there have been errors since we pushed. */ + bool had_errors : 1; /* Count references to this object. If refcount reaches refcount_infinity value, we don't increment or decrement the 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 b2e0ecd..a2bed9f 100644 --- a/gcc/cp/lambda.cc +++ b/gcc/cp/lambda.cc @@ -348,7 +348,11 @@ insert_capture_proxy (tree var) /* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */ var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var); - tree stmt_list = (*stmt_list_stack)[1]; + /* The first stmt_list is from start_preparsed_function. Then there's a + possible stmt_list from begin_eh_spec_block, then the one from the + lambda's outer {}. */ + unsigned index = 1 + use_eh_spec_block (current_function_decl); + tree stmt_list = (*stmt_list_stack)[index]; gcc_assert (stmt_list); append_to_statement_list_force (var, &stmt_list); } @@ -1859,11 +1863,10 @@ 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) + bool noexcept_p = (bind_expr + && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR); + if (noexcept_p) 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; ) @@ -1872,11 +1875,23 @@ prune_lambda_captures (tree body) if (tree var = var_to_maybe_prune (cap)) { tree **use = const_vars.get (var); - if (use && TREE_CODE (**use) == DECL_EXPR) + if (TREE_CODE (**use) == DECL_EXPR) { /* All uses of this capture were folded away, leaving only the proxy declaration. */ + if (noexcept_p) + { + /* We didn't handle noexcept lambda captures correctly before + the fix for PR c++/119764. */ + if (abi_version_crosses (21)) + warning_at (location_of (lam), OPT_Wabi, "%qD is no longer" + " captured in noexcept lambda in ABI v21 " + "(GCC 16)", var); + if (!abi_version_at_least (21)) + goto next; + } + /* Splice the capture out of LAMBDA_EXPR_CAPTURE_LIST. */ *capp = TREE_CHAIN (cap); @@ -1894,14 +1909,11 @@ prune_lambda_captures (tree body) /* 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); - } + 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; @@ -1909,6 +1921,7 @@ prune_lambda_captures (tree body) } } + next: capp = &TREE_CHAIN (cap); } } diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 498126a..aa2dc0e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -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; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index a71705f..e8d342f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -11418,6 +11418,7 @@ push_tinst_level_loc (tree tldcl, tree targs, location_t loc) new_level->targs = targs; new_level->locus = loc; new_level->errors = errorcount + sorrycount; + new_level->had_errors = false; new_level->next = NULL; new_level->refcount = 0; new_level->path = new_level->visible = nullptr; @@ -11468,6 +11469,9 @@ pop_tinst_level (void) /* Restore the filename and line number stashed away when we started this instantiation. */ input_location = current_tinst_level->locus; + if (unsigned errs = errorcount + sorrycount) + if (errs > current_tinst_level->errors) + current_tinst_level->had_errors = true; set_refcount_ptr (current_tinst_level, current_tinst_level->next); --tinst_depth; } @@ -11487,7 +11491,7 @@ reopen_tinst_level (struct tinst_level *level) set_refcount_ptr (current_tinst_level, level); pop_tinst_level (); - if (current_tinst_level) + if (current_tinst_level && !current_tinst_level->had_errors) current_tinst_level->errors = errorcount+sorrycount; tree decl = level->maybe_get_node (); @@ -28072,7 +28076,9 @@ instantiate_pending_templates (int retries) tree instantiation = reopen_tinst_level ((*t)->tinst); bool complete = false; - if (TYPE_P (instantiation)) + if (limit_bad_template_recursion (instantiation)) + /* Do nothing. */; + else if (TYPE_P (instantiation)) { if (!COMPLETE_TYPE_P (instantiation)) { |