On 1/31/26 7:18 AM, Nathaniel Shead wrote:
On Mon, Jan 26, 2026 at 10:49:46AM +0800, Jason Merrill wrote:
On 1/24/26 8:00 PM, Nathaniel Shead wrote:
On Sat, Jan 24, 2026 at 10:49:17PM +1100, Nathaniel Shead wrote:
On Sat, Jan 24, 2026 at 09:41:51PM +1100, Nathaniel Shead wrote:
On Sat, Jan 24, 2026 at 04:57:44PM +0800, Jason Merrill wrote:
On 1/24/26 4:41 PM, Nathaniel Shead wrote:
Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
-- >8 --
This fixes two issues with cp_fold_non_odr_use_1:
- When called to fold away a reference, it considers the use to not be
an lvalue and so 'maybe_constant_value' folds all the way through the
nested INDIRECT_REF to a prvalue. Fixed by forcing the expression
to be an ADDR_EXPR before calling 'maybe_constant_value', and then
folding it away afterwards.
For the REFERENCE_REF case it would make sense to pass its op0 to
fold_non_odr rather than the ref itself; we already convert_from_reference
the result.
Right, makes sense; thanks. Here's an updated patch that does this
which passes bootstrap and regtest on x86_64-pc-linux-gnu, OK for trunk?
Actually, ignore this: I just noticed that this fails with modules in
some cases with wrong-looking GIMPLE; for cases like
export module M;
static const int& ref = 123;
constexpr int foo() { return ref; }
we no longer fold 'ref' to 123 but instead return
'(int)*(const int&)&_ZGRL3ref_'
which then can fail calls because the local symbol is not defined in
importers. Even my original patch will break on this case; I'll need to
think more about what to do here.
Sorry, again misread: my original patch does actually work here. I'll
need to sleep soon but I'll take another look at why that one worked and
this one didn't; it seems to be that the issue does come down to whether
cxx_eval_outermost_constant_eval considers us to be in an lvalue or
rvalue context, changing the way that it folds constant values.
I think _outermost_ is fine. The problem is that with this patch we first
_fold_non_odr_ in cp_fold, which returns the above, so when we then call
_fold_non_odr_ again in cp_fold_maybe_rvalue the argument no longer looks
like a use of a variable.
So we want to avoid the double _fold_non_odr_. Maybe move the rval &&
non_odr handliing above the cp_fold in _maybe_rvalue_?
Ah I see, thanks. Here's an updated patch that does this and seems to
work. Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?
OK.
-- >8 --
This fixes two issues with cp_fold_non_odr_use_1:
- When called to fold away a reference, it considers the use to not be
an lvalue and so 'maybe_constant_value' folds all the way through the
nested INDIRECT_REF to a prvalue. Fixed by folding the op0 of the
INDIRECT_REF rather than the ref itself and avoiding a double
cp_fold_non_odr_use_1.
- When used to fold away the initializing expression for an INIT_EXPR,
it doesn't mark any new TARGET_EXPRs as eliding. Fixed by reapplying
'set_target_expr_eliding' for the initializer of an INIT_EXPR if it
got modified during ff_only_non_odr walk.
PR c++/123557
PR c++/123738
gcc/cp/ChangeLog:
* cp-gimplify.cc (cp_fold_maybe_rvalue): Call
cp_fold_non_odr_use_1 before recursing cp_fold.
(cp_fold): Pass op0 to cp_fold_non_odr_use_1 when folding a
reference. Reapply set_target_expr_eliding on the initializing
expression of an INIT_EXPR.
gcc/testsuite/ChangeLog:
* g++.dg/cpp0x/constexpr-ice22.C: New test.
* g++.dg/cpp2a/constexpr-ref2.C: New test.
Signed-off-by: Nathaniel Shead <[email protected]>
Reviewed-by: Jason Merrill <[email protected]>
---
gcc/cp/cp-gimplify.cc | 39 ++++++++++----------
gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C | 14 +++++++
gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C | 19 ++++++++++
3 files changed, 52 insertions(+), 20 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C
create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 59e01c103fd..bf4804cfdc1 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -3139,26 +3139,21 @@ cp_fold_maybe_rvalue (tree x, bool rval, fold_flags_t
flags)
{
while (true)
{
+ if (rval && (flags & ff_only_non_odr))
+ x = cp_fold_non_odr_use_1 (x);
x = cp_fold (x, flags);
if (rval)
- x = mark_rvalue_use (x);
- if (rval && (flags & ff_only_non_odr))
- {
- tree v = cp_fold_non_odr_use_1 (x);
- if (v != x)
- {
- x = v;
- continue;
- }
- }
- else if (rval && DECL_P (x)
- && !TYPE_REF_P (TREE_TYPE (x)))
{
- tree v = decl_constant_value (x);
- if (v != x && v != error_mark_node)
+ x = mark_rvalue_use (x);
+ if (!(flags & ff_only_non_odr)
+ && DECL_P (x) && !TYPE_REF_P (TREE_TYPE (x)))
{
- x = v;
- continue;
+ tree v = decl_constant_value (x);
+ if (v != x && v != error_mark_node)
+ {
+ x = v;
+ continue;
+ }
}
}
break;
@@ -3422,9 +3417,9 @@ cp_fold (tree x, fold_flags_t flags)
used as lvalues. */
if ((flags & ff_only_non_odr) && REFERENCE_REF_P (x))
{
- tree r = cp_fold_non_odr_use_1 (x);
- if (r != x)
- return convert_from_reference (cp_fold (r, flags));
+ op0 = cp_fold_non_odr_use_1 (TREE_OPERAND (x, 0));
+ if (op0 != TREE_OPERAND (x, 0))
+ return convert_from_reference (cp_fold (op0, flags));
}
goto unary;
@@ -3571,7 +3566,11 @@ cp_fold (tree x, fold_flags_t flags)
if (op0 == error_mark_node || op1 == error_mark_node)
x = error_mark_node;
else if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1))
- x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+ {
+ if (code == INIT_EXPR && op1 != TREE_OPERAND (x, 1))
+ set_target_expr_eliding (op1);
+ x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+ }
break;
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C
new file mode 100644
index 00000000000..900c8053a92
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C
@@ -0,0 +1,14 @@
+// PR c++/123557
+// { dg-do compile { target c++11 } }
+
+struct a {
+ a() = default;
+ a(a const &) = default;
+ a(a &&);
+};
+struct c {
+ c();
+ a e;
+};
+constexpr a b;
+c::c() : e(b) {}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C
b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C
new file mode 100644
index 00000000000..659beed3a25
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C
@@ -0,0 +1,19 @@
+// PR c++/123738
+// { dg-do compile { target c++20 } }
+
+struct OStringLiteral {
+ int str = 0;
+};
+
+template<auto L> struct OStringHolder {
+ static constexpr auto & literal = L;
+};
+
+struct OString {
+ template<auto L> constexpr OString(OStringHolder<L> const &):
+ p(&OStringHolder<L>::literal.str) {}
+ int const * p;
+};
+
+
+constexpr OString s = OStringHolder<OStringLiteral{}>{};