Bug 88174 - Make __real__ += __val usable in constexpr context.
Summary: Make __real__ += __val usable in constexpr context.
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 9.0
: P3 normal
Target Milestone: 13.0
Assignee: Jakub Jelinek
URL:
Keywords: rejects-valid
: 105882 (view as bug list)
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2018-11-23 18:37 UTC by Ed Smith-Rowland
Modified: 2025-08-26 16:54 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2018-11-26 00:00:00


Attachments
Special case REALPART_EXPR, IMAGPART_EXPR in cxx_eval_store_expression. (490 bytes, patch)
2018-12-03 22:11 UTC, Ed Smith-Rowland
Details | Diff
gcc13-pr88174.patch (1.56 KB, patch)
2022-06-08 15:37 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ed Smith-Rowland 2018-11-23 18:37:38 UTC
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.
Comment 1 Marc Glisse 2018-11-23 19:06:34 UTC
(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.
Comment 2 Richard Biener 2018-11-26 09:48:43 UTC
It needs {REAL,IMAG}_PART_EXRP as well I guess.
Comment 3 Ed Smith-Rowland 2018-12-03 22:11:41 UTC
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?
Comment 4 Ed Smith-Rowland 2018-12-04 00:23:26 UTC
Never mind.
Comment 5 Drea Pinski 2022-06-08 07:16:02 UTC
*** Bug 105882 has been marked as a duplicate of this bug. ***
Comment 6 Jakub Jelinek 2022-06-08 15:37:48 UTC
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.
Comment 7 GCC Commits 2022-08-07 08:09:50 UTC
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.
Comment 8 Jakub Jelinek 2022-08-10 10:58:44 UTC
Backport doesn't work in 12 for multiple reasons and it isn't a regression anyway, so fixed for 13+.