diff options
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/ChangeLog | 41 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 63 | ||||
-rw-r--r-- | gcc/cp/contracts.cc | 3 | ||||
-rw-r--r-- | gcc/cp/coroutines.cc | 21 | ||||
-rw-r--r-- | gcc/cp/init.cc | 4 | ||||
-rw-r--r-- | gcc/cp/name-lookup.cc | 45 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 8 |
7 files changed, 117 insertions, 68 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 644b36a..d9f0298 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,44 @@ +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. 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/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/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/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/semantics.cc b/gcc/cp/semantics.cc index 7f23efd..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 |