See: https://godbolt.org/z/9jvYTfYE4 ``` struct QQQ { consteval QQQ(std::string_view d): data(d) {} std::string_view data; }; void sink(const QQQ&); void f() { QQQ q("dogsdogsdogs"); sink(q); } ``` This code is accepted with warnings ``` <source>: In function 'void f()': <source>:13:25: warning: statement with no effect [-Wunused-value] 13 | QQQ q("dogsdogsdogs"); | ^ <source>:14:9: warning: 'q' may be used uninitialized [-Wmaybe-uninitialized] 14 | sink(q); | ~~~~^~~ <source>:10:6: note: by argument 1 of type 'const QQQ&' to 'void sink(const QQQ&)' declared here 10 | void sink(const QQQ&); | ^~~~ <source>:13:9: note: 'q' declared here 13 | QQQ q("dogsdogsdogs"); | ``` And no code is generated for the initialization fo variable `q` GCC 13 and Clang 19 accept this code with no warnings and the correct initialization code is generated.
Since r14-4140 commit 6851e3423c2b5ec6516efa0677745d25c905e079 Author: Marek Polacek <polacek@redhat.com> Date: Thu Aug 31 20:11:50 2023 -0400 c++: Move consteval folding to cp_fold_r I see: 117501.C: In function ‘void f()’: 117501.C:10:25: in ‘constexpr’ expansion of ‘q.QQQ::QQQ(std::basic_string_view<char>(((const char*)"dogsdogsdogs")))’ 117501.C:3:40: error: modification of ‘q’ is not a constant expression so that probably has something to do with this.
I got the same bisect result (I'd started before seeing your comment).
Mine then.
``` constexpr unsigned length () { bool __trans_tmp_1 = __builtin_is_constant_evaluated(); if (__trans_tmp_1) return 42; return 1; } struct basic_string_view { constexpr basic_string_view(const char *) : _M_len{length()}, _M_str{} {} long _M_len; char _M_str; }; struct QQQ { consteval QQQ(basic_string_view d) : data(d) {} basic_string_view data; }; int main () { QQQ q(""); if (q.data._M_len != 42) __builtin_abort (); } ```
I think the problem is that we evaluate struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt QQQ::QQQ (&q, TARGET_EXPR <D.2687, <<< Unknown tree: aggr_init_expr 5 __ct_comp D.2687 (struct basic_string_view *) <<< Unknown tree: void_cst >>> (const char *) "" >>>>) >>>>>; into struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt {.data={._M_len=42, ._M_str=0}} >>>>>; and then the useless expr_stmt is dropped on the floor. So q isn't initialized.
And we want this instead: struct QQQ q = {.data={._M_len=0, ._M_str=0}}; <<cleanup_point struct QQQ q = {.data={._M_len=0, ._M_str=0}};>>;
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>: https://gcc.gnu.org/g:0d97700443b45b947eda40dac7cf4d0397770b87 commit r15-7306-g0d97700443b45b947eda40dac7cf4d0397770b87 Author: Marek Polacek <polacek@redhat.com> Date: Mon Jan 27 14:23:22 2025 -0500 c++: wrong-code with consteval constructor [PR117501] We've had a wrong-code problem since r14-4140, due to which we forget to initialize a variable. In consteval39.C, we evaluate struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt QQQ::QQQ (&q, TARGET_EXPR <D.2687, <<< Unknown tree: aggr_init_expr 5 __ct_comp D.2687 (struct basic_string_view *) <<< Unknown tree: void_cst >>> (const char *) "" >>>>) >>>>>; into struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt {.data={._M_len=42, ._M_str=0}} >>>>>; and then the useless expr_stmt is dropped on the floor, so q isn't initialized. As pre-r14-4140, we need to handle constructors specially. With this patch, we generate: struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt q = {.data={._M_len=42, ._M_str=0}} >>>>>; initializing q properly. PR c++/117501 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_build_init_expr_for_ctor): New. (cp_fold_immediate_r): Call it. (cp_fold): Break out code into cp_build_init_expr_for_ctor. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/consteval39.C: New test. * g++.dg/cpp2a/consteval40.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
Fixed on trunk so far.
Safe enough to backport?
The releases/gcc-14 branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>: https://gcc.gnu.org/g:1dc1c1e7f0bb3a295eff1bc8c5d4f4d4b2898d50 commit r14-11779-g1dc1c1e7f0bb3a295eff1bc8c5d4f4d4b2898d50 Author: Marek Polacek <polacek@redhat.com> Date: Wed May 14 10:38:47 2025 -0400 c++: wrong-code with consteval constructor [PR117501] We've had a wrong-code problem since r14-4140, due to which we forget to initialize a variable. In consteval39.C, we evaluate struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt QQQ::QQQ (&q, TARGET_EXPR <D.2687, <<< Unknown tree: aggr_init_expr 5 __ct_comp D.2687 (struct basic_string_view *) <<< Unknown tree: void_cst >>> (const char *) "" >>>>) >>>>>; into struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt {.data={._M_len=42, ._M_str=0}} >>>>>; and then the useless expr_stmt is dropped on the floor, so q isn't initialized. As pre-r14-4140, we need to handle constructors specially. With this patch, we generate: struct QQQ q; <<cleanup_point <<< Unknown tree: expr_stmt q = {.data={._M_len=42, ._M_str=0}} >>>>>; initializing q properly. PR c++/117501 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_build_init_expr_for_ctor): New. (cp_fold_immediate_r): Call it. (cp_fold): Break out code into cp_build_init_expr_for_ctor. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/consteval39.C: New test. * g++.dg/cpp2a/consteval40.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
Fixed.