While updating libstdc++ for constexpr operators I came across this: __real__ _M_value += __z.real(); is not constexpr even though __real__ _M_value = __z.real(); is. I was able to use a workaraound with complex::__rep() but having the op= JUST WORK would have made the patch less invasive. I request that for the usual arithmetic operators @ = [+-*/] __real__ _M_value @= __re; __imag__ _M_value @= __im; be available in contexpr contexts.
(In reply to emsr from comment #0) > While updating libstdc++ for constexpr operators I came across this: > __real__ _M_value += __z.real(); > is not constexpr even though > __real__ _M_value = __z.real(); > is. Is it? I get "error: modification of '__real__ x' is not a constant expression". cxx_eval_store_expression has special cases for ARRAY_REF, BIT_FIELD_REF, COMPONENT_REF, maybe it needs more.
It needs {REAL,IMAG}_PART_EXRP as well I guess.
Created attachment 45150 [details] Special case REALPART_EXPR, IMAGPART_EXPR in cxx_eval_store_expression. Obeying the smart people. ;-) I reverted the workaround in libstdc++ that I needed because of this. With this patch and reverting those changes libstdc++ works (C++20 constexpr complex). Checking everything to see if I broke anything. I shoud have a testcase somewhere too. I didn't limit this to C++20. What do you all think?
Never mind.
*** Bug 105882 has been marked as a duplicate of this bug. ***
Created attachment 53104 [details] gcc13-pr88174.patch Untested fix. Also fixes e.g.: #include <complex> constexpr bool foo () { std::complex<double> a (1.0, 2.0); a += 3.0; a.real (6.0); return a.real () == 6.0 && a.imag () == 2.0; } static_assert (foo ()); with -std=c++20 which failed before.
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>: https://gcc.gnu.org/g:190776773516955df480bfa75731c34c5aaf2306 commit r13-1983-g190776773516955df480bfa75731c34c5aaf2306 Author: Jakub Jelinek <jakub@redhat.com> Date: Sun Aug 7 10:07:38 2022 +0200 c++: Add support for __real__/__imag__ modifications in constant expressions [PR88174] We claim we support P0415R1 (constexpr complex), but e.g. #include <complex> constexpr bool foo () { std::complex<double> a (1.0, 2.0); a += 3.0; a.real (6.0); return a.real () == 6.0 && a.imag () == 2.0; } static_assert (foo ()); fails with test.C:12:20: error: non-constant condition for static assertion 12 | static_assert (foo ()); | ~~~~^~ test.C:12:20: in âconstexprâ expansion of âfoo()â test.C:8:10: in âconstexprâ expansion of âa.std::complex<double>::real(6.0e+0)â test.C:12:20: error: modification of â__real__ a.std::complex<double>::_M_valueâ is not a constant expression The problem is we don't handle REALPART_EXPR and IMAGPART_EXPR in cxx_eval_store_expression. The following patch attempts to support it (with a requirement that those are the outermost expressions, ARRAY_REF/COMPONENT_REF etc. are just not possible on the result of these, BIT_FIELD_REF would be theoretically possible if trying to extract some bits from one part of a complex int, but I don't see how it could appear in the FE trees. For these references, the code handles value being COMPLEX_CST, COMPLEX_EXPR or CONSTRUCTOR_NO_CLEARING empty CONSTRUCTOR (what we use to represent uninitialized values for C++20 and later) and the code starts by rewriting it to COMPLEX_EXPR, so that we can freely adjust the individual parts and later on possibly optimize it back to COMPLEX_CST if both halves are constant. 2022-08-07 Jakub Jelinek <jakub@redhat.com> PR c++/88174 * constexpr.cc (cxx_eval_store_expression): Handle REALPART_EXPR and IMAGPART_EXPR. Change ctors from releasing_vec to auto_vec<tree *>, adjust all uses. For !preeval, update ctors vector. * g++.dg/cpp1y/constexpr-complex1.C: New test.
Backport doesn't work in 12 for multiple reasons and it isn't a regression anyway, so fixed for 13+.