From: Jason Merrill Date: Wed, 22 Apr 2026 18:53:14 +0000 (-0400) Subject: c++: consteval, array, modules [PR124973] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b6e40cf38c60d11c4e105f9179a6d5cfb502bd9b;p=thirdparty%2Fgcc.git c++: consteval, array, modules [PR124973] Here the consteval holder constructor calls the defaulted element_array constructor, which uses a VEC_INIT_EXPR to call the defaulted element constructor. When we read in the holder constructor, we need to clone it, so we call finish_function, which calls cp_fold_function_non_odr_use, which tries to constant-evaluate the call to the element_array constructor. This eventually wants to evaluate the VEC_INIT_EXPR, which wants to call the element constructor (complete object clone). But we haven't cloned the element constructor yet, so mark_used tries to synthesize it again, which breaks because the constructor is already defined, just not cloned yet. We should have cloned the element constructor first, but we didn't know that the element_array constructor depends on it because VEC_INIT_EXPR doesn't express that; build_vec_init_expr calls build_vec_init_elt and then throws it away. Perhaps we want to add the elt_init as an additional operand that is used to express dependencies, but ignored in expansion? It would also be nice not to repeat all the finish_function passes when loading a function from a module; we already did cp_fold_function_non_odr_use and such for this function before writing out the module, doing it again is a waste of time. But also, trying to constant-evaluate the element_array constructor is wrong for _non_odr_use, it shouldn't be doing any optimization folding. Furthermore, since the TARGET_EXPR is wrapped in an INIT_EXPR, we should never have tried to fold it by itself, before cp_genericize_init_expr has a chance to elide it. So let's only do that folding when ff_genericize, like the other TARGET_EXPR transformations. This is a much simpler fix for this testcase. While we're at it, let's also suppress the other flag_no_inline-conditional folding when ff_only_non_odr. PR c++/124973 PR c++/120502 PR c++/120005 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_fold_r) : Only do optimization folding when ff_genericize. (cp_fold) : Don't do optimization folding when ff_only_non_odr. gcc/testsuite/ChangeLog: * g++.dg/modules/consteval-1_a.C: New test. * g++.dg/modules/consteval-1_b.C: New test. --- diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 5bcf5168970..8ae66405817 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1717,7 +1717,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) break; case TARGET_EXPR: - if (!flag_no_inline) + if (!flag_no_inline + && (data->flags && ff_genericize)) if (tree &init = TARGET_EXPR_INITIAL (stmt)) { tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt), @@ -3769,6 +3770,7 @@ cp_fold (tree x, fold_flags_t flags) if ((OPTION_SET_P (flag_fold_simple_inlines) ? flag_fold_simple_inlines : !flag_no_inline) + && !(flags & ff_only_non_odr) && call_expr_nargs (x) == 1 && decl_in_std_namespace_p (callee) && DECL_NAME (callee) != NULL_TREE @@ -3881,6 +3883,7 @@ cp_fold (tree x, fold_flags_t flags) Do constexpr expansion of expressions where the call itself is not constant, but the call followed by an INDIRECT_REF is. */ if (callee && DECL_DECLARED_CONSTEXPR_P (callee) + && !(flags & ff_only_non_odr) && (!flag_no_inline || lookup_attribute ("always_inline", DECL_ATTRIBUTES (callee)))) diff --git a/gcc/testsuite/g++.dg/modules/consteval-1_a.C b/gcc/testsuite/g++.dg/modules/consteval-1_a.C new file mode 100644 index 00000000000..dac678c32b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/consteval-1_a.C @@ -0,0 +1,36 @@ +// PR c++/124973 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-fmodules" } + +export module right; // { dg-module-cmi right } + +struct constexpr_move { + constexpr_move() = default; + constexpr_move(const constexpr_move&) = default; + constexpr constexpr_move(constexpr_move&&) {} +}; + +struct element { + constexpr_move a; + int b; +}; + +template +struct element_array { + element data[ N ]; +}; + +template +struct holder { + consteval holder(element_array values) : + values_{static_cast&&>(values)} {} + element_array values_; +}; + +template +constexpr auto holder_of = holder{element_array{}}; + +export class environment { + decltype(holder_of<1>) s1_{holder_of<1>}; + decltype(holder_of<2>) s2_{holder_of<2>}; +}; diff --git a/gcc/testsuite/g++.dg/modules/consteval-1_b.C b/gcc/testsuite/g++.dg/modules/consteval-1_b.C new file mode 100644 index 00000000000..14676e5dcea --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/consteval-1_b.C @@ -0,0 +1,8 @@ +// PR c++/124973 +// { dg-do compile { target c++20 } } +// { dg-additional-options "-fmodules" } + +export module left; // { dg-module-cmi left } +import right; + +export auto xx(environment&) -> void;