aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog41
-rw-r--r--gcc/cp/constexpr.cc63
-rw-r--r--gcc/cp/contracts.cc3
-rw-r--r--gcc/cp/coroutines.cc21
-rw-r--r--gcc/cp/init.cc4
-rw-r--r--gcc/cp/name-lookup.cc45
-rw-r--r--gcc/cp/semantics.cc8
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