public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
@ 2024-07-12 20:22 valentin at tolmer dot fr
  2024-07-12 20:29 ` [Bug c++/115900] [14/15 " mpolacek at gcc dot gnu.org
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: valentin at tolmer dot fr @ 2024-07-12 20:22 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

            Bug ID: 115900
           Summary: [14 Regression] constexpr object modification during
                    construction gives "Modifying a const object is not
                    allowed in a constant expression"
           Product: gcc
           Version: 14.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: valentin at tolmer dot fr
  Target Milestone: ---

The smallest example I could make is:

```cpp
struct A {
    char data;
    constexpr explicit A() {
        data = 0;
    }
};

struct C {
  constexpr C(int) {}
  constexpr C() = default;
};

struct B : public C {
  A a;
  explicit constexpr B() : C(0) {}
};

struct D : public B {};

static constexpr A a;
static constexpr B b;
static constexpr D d;
```


Building `a` and `b` succeed, but `d` fails with:
```
$ g++ -std=c++20 <source>
<source>:22:20:   in 'constexpr' expansion of 'D()'
<source>:18:8:   in 'constexpr' expansion of '((D*)this)->D::B.B::B()'
<source>:15:31:   in 'constexpr' expansion of '((B*)this)->B::a.A::A()'
<source>:4:14: error: modifying a const object '((A*)this)->A::data' is not
allowed in a constant expression
    4 |         data = 0;
      |         ~~~~~^~~
<source>:22:20: note: originally declared 'const' here
   22 | static constexpr D d;
      |                    ^
```

This compiles fine with GCC 13.3.0, but fails with GCC 14.1.0 or trunk (on
godbolt as of this writing, g++
(Compiler-Explorer-Build-gcc-88ff0504ab3286df57e27514065494a30c365ec5-binutils-2.42)
15.0.0 20240712 (experimental) ).

https://godbolt.org/z/TvjM4qjb6

AFAIK, a constexpr object only becomes const after the construction ended (the
constructor returns). Moreover, there's no reason why B works but not D.
Interestingly, calling C's default constructor instead of the one that takes an
`int` (inside B) makes the code compile.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
@ 2024-07-12 20:29 ` mpolacek at gcc dot gnu.org
  2024-07-12 20:31 ` pinskia at gcc dot gnu.org
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: mpolacek at gcc dot gnu.org @ 2024-07-12 20:29 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

Marek Polacek <mpolacek at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|[14 Regression] constexpr   |[14/15 Regression]
                   |object modification during  |constexpr object
                   |construction gives          |modification during
                   |"Modifying a const object   |construction gives
                   |is not allowed in a         |"Modifying a const object
                   |constant expression"        |is not allowed in a
                   |                            |constant expression"
             Status|UNCONFIRMED                 |NEW
     Ever confirmed|0                           |1
                 CC|                            |mpolacek at gcc dot gnu.org
           Priority|P3                          |P2
   Last reconfirmed|                            |2024-07-12
   Target Milestone|---                         |14.2
           Keywords|                            |rejects-valid

--- Comment #1 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
Started with r14-409:

commit 4b8d0d4d7fd245ef85c7801e7838845502a5a61d
Author: Jason Merrill <jason@redhat.com>
Date:   Mon May 1 17:41:44 2023 -0400

    c++: std::variant slow to compile [PR109678]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
  2024-07-12 20:29 ` [Bug c++/115900] [14/15 " mpolacek at gcc dot gnu.org
@ 2024-07-12 20:31 ` pinskia at gcc dot gnu.org
  2024-07-12 20:34 ` pinskia at gcc dot gnu.org
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: pinskia at gcc dot gnu.org @ 2024-07-12 20:31 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #2 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
Reduced slightly more:
```
struct A {
    char m;
    constexpr A() { m = 0; }
};

struct C {
  constexpr C(){ };
};

struct B : C {
  A a;
  constexpr B() {}
};

struct D : B { };

static constexpr A a;
static constexpr B b;
static constexpr D d;
```

Confirmed.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
  2024-07-12 20:29 ` [Bug c++/115900] [14/15 " mpolacek at gcc dot gnu.org
  2024-07-12 20:31 ` pinskia at gcc dot gnu.org
@ 2024-07-12 20:34 ` pinskia at gcc dot gnu.org
  2024-07-12 20:39 ` mpolacek at gcc dot gnu.org
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: pinskia at gcc dot gnu.org @ 2024-07-12 20:34 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #3 from Andrew Pinski <pinskia at gcc dot gnu.org> ---
(In reply to Marek Polacek from comment #1)
> Started with r14-409:
> 
> commit 4b8d0d4d7fd245ef85c7801e7838845502a5a61d
> Author: Jason Merrill <jason@redhat.com>
> Date:   Mon May 1 17:41:44 2023 -0400
> 
>     c++: std::variant slow to compile [PR109678]

Hmm, that was backported for GCC 13.3.0 but the test works there. Maybe it was
r14-410 which is related but not backported.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (2 preceding siblings ...)
  2024-07-12 20:34 ` pinskia at gcc dot gnu.org
@ 2024-07-12 20:39 ` mpolacek at gcc dot gnu.org
  2024-07-15 21:53 ` mpolacek at gcc dot gnu.org
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: mpolacek at gcc dot gnu.org @ 2024-07-12 20:39 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #4 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
Reverting r14-409 fixes the problem on trunk, so that change must mean
something.

I added the modifying-const-objects constexpr checking, so maybe I should poke
more at this.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (3 preceding siblings ...)
  2024-07-12 20:39 ` mpolacek at gcc dot gnu.org
@ 2024-07-15 21:53 ` mpolacek at gcc dot gnu.org
  2024-07-16 20:06 ` mpolacek at gcc dot gnu.org
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: mpolacek at gcc dot gnu.org @ 2024-07-15 21:53 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #5 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
What changed is the initializer we generate for 'd'.  It used to be:

  d = {.D.2656={.a={.data=0}}}

but now it is:

  D::D ((struct D *) &d)

The second one causes trouble because we evaluate

  ((struct A *) this)->data = NON_LVALUE_EXPR <0>

(where the LHS evaluates to d.D.256.a) *after* 'd' was marked READONLY in
build_aggr_init, which causes the error.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (4 preceding siblings ...)
  2024-07-15 21:53 ` mpolacek at gcc dot gnu.org
@ 2024-07-16 20:06 ` mpolacek at gcc dot gnu.org
  2024-07-16 20:53 ` mpolacek at gcc dot gnu.org
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: mpolacek at gcc dot gnu.org @ 2024-07-16 20:06 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #6 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
This is beginning to make sense to me now.

Pre-r14-409: we're evaluating the call to C::C(), which is in the body of
B::B(), which is the body of D::D(&d):

  C::C ((struct C *) this, NON_LVALUE_EXPR <0>)

It's a ctor so we get here:

 3118   /* Remember the object we are constructing or destructing.  */
 3119   tree new_obj = NULL_TREE;
 3120   if (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun))
 3121     {
 3122       /* In a cdtor, it should be the first `this' argument.
 3123          At this point it has already been evaluated in the call
 3124          to cxx_bind_parameters_in_call.  */
 3125       new_obj = TREE_VEC_ELT (new_call.bindings, 0);

new_obj=(struct C *) &d.D.2656

 3126       new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun),
new_obj);

new_obj=d.D.2656.D.2597

We proceed to evaluate the call, then we get here:

 3317           /* At this point, the object's constructor will have run, so
 3318              the object is no longer under construction, and its possible
 3319              'const' semantics now apply.  Make a note of this fact by
 3320              marking the CONSTRUCTOR TREE_READONLY.  */
 3321           if (new_obj && DECL_CONSTRUCTOR_P (fun))
 3322             cxx_set_object_constness (ctx, new_obj, /*readonly_p=*/true,
 3323                                       non_constant_p, overflow_p);

new_obj is still d.D.2656.D.2597, its type is "C", cxx_set_object_constness
doesn't set anything as const.  This is fine.

After r14-409: on line 3125, new_obj is (struct C *) &d.D.2656 as before, but
we go to
cxx_fold_indirect_ref_1:

 5739       if (is_empty_class (type)
 5740           && CLASS_TYPE_P (optype)
 5741           && lookup_base (optype, type, ba_any, NULL, tf_none, off))
 5742         { 
 5743           if (empty_base) 
 5744             *empty_base = true;
 5745           return op;

type is C, which is an empty class; optype is "const D", and C is a base of D. 
So we return the VAR_DECL 'd'.  Then we get to cxx_set_object_constness with
object=d, which is const, so we mark the constructor READONLY.

Then we're evaluating A::A() which has

  ((A*)this)->data = 0;

we evaluate the LHS to d.D.2656.a, for which the initializer is
{.D.2656={.a={.data=}}} which is TREE_READONLY and 'd' is const, so we think
we're modifying a const object and fail the constexpr evaluation.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (5 preceding siblings ...)
  2024-07-16 20:06 ` mpolacek at gcc dot gnu.org
@ 2024-07-16 20:53 ` mpolacek at gcc dot gnu.org
  2024-07-17 17:55 ` cvs-commit at gcc dot gnu.org
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: mpolacek at gcc dot gnu.org @ 2024-07-16 20:53 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

Marek Polacek <mpolacek at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Assignee|unassigned at gcc dot gnu.org      |mpolacek at gcc dot gnu.org
             Status|NEW                         |ASSIGNED

--- Comment #7 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
Thus:

--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3123,10 +3123,14 @@ cxx_eval_call_expression (const constexpr_ctx *ctx,
tree t,
     At this point it has already been evaluated in the call
     to cxx_bind_parameters_in_call.  */
       new_obj = TREE_VEC_ELT (new_call.bindings, 0);
-      new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj);
-
-      if (ctx->call && ctx->call->fundef
-     && DECL_CONSTRUCTOR_P (ctx->call->fundef->decl))
+      bool empty_base = false;
+      new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun), new_obj,
+                      &empty_base);
+
+      if (empty_base)
+   new_obj = NULL_TREE;
+      else if (ctx->call && ctx->call->fundef
+          && DECL_CONSTRUCTOR_P (ctx->call->fundef->decl))
    {
      tree cur_obj = TREE_VEC_ELT (ctx->call->bindings, 0);
      STRIP_NOPS (cur_obj);

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14/15 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (6 preceding siblings ...)
  2024-07-16 20:53 ` mpolacek at gcc dot gnu.org
@ 2024-07-17 17:55 ` cvs-commit at gcc dot gnu.org
  2024-07-17 17:57 ` [Bug c++/115900] [14 " mpolacek at gcc dot gnu.org
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2024-07-17 17:55 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #8 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:d890b04197fb0ddba4fbfb32f88e266fa27e02f3

commit r15-2108-gd890b04197fb0ddba4fbfb32f88e266fa27e02f3
Author: Marek Polacek <polacek@redhat.com>
Date:   Wed Jul 17 11:19:32 2024 -0400

    c++: wrong error initializing empty class [PR115900]

    In r14-409, we started handling empty bases first in
cxx_fold_indirect_ref_1
    so that we don't need to recurse and waste time.

    This caused a bogus "modifying a const object" error.  I'm appending my
    analysis from the PR, but basically, cxx_fold_indirect_ref now returns
    a different object than before, and we mark the wrong thing as const,
    but since we're initializing an empty object, we should avoid setting
    the object constness.

    ~~
    Pre-r14-409: we're evaluating the call to C::C(), which is in the body of
    B::B(), which is the body of D::D(&d):

      C::C ((struct C *) this, NON_LVALUE_EXPR <0>)

    It's a ctor so we get here:

     3118   /* Remember the object we are constructing or destructing.  */
     3119   tree new_obj = NULL_TREE;
     3120   if (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun))
     3121     {
     3122       /* In a cdtor, it should be the first `this' argument.
     3123          At this point it has already been evaluated in the call
     3124          to cxx_bind_parameters_in_call.  */
     3125       new_obj = TREE_VEC_ELT (new_call.bindings, 0);

    new_obj=(struct C *) &d.D.2656

     3126       new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun),
new_obj);

    new_obj=d.D.2656.D.2597

    We proceed to evaluate the call, then we get here:

     3317           /* At this point, the object's constructor will have run,
so
     3318              the object is no longer under construction, and its
possible
     3319              'const' semantics now apply.  Make a note of this fact
by
     3320              marking the CONSTRUCTOR TREE_READONLY.  */
     3321           if (new_obj && DECL_CONSTRUCTOR_P (fun))
     3322             cxx_set_object_constness (ctx, new_obj,
/*readonly_p=*/true,
     3323                                       non_constant_p, overflow_p);

    new_obj is still d.D.2656.D.2597, its type is "C", cxx_set_object_constness
    doesn't set anything as const.  This is fine.

    After r14-409: on line 3125, new_obj is (struct C *) &d.D.2656 as before,
    but we go to cxx_fold_indirect_ref_1:

     5739       if (is_empty_class (type)
     5740           && CLASS_TYPE_P (optype)
     5741           && lookup_base (optype, type, ba_any, NULL, tf_none, off))
     5742         {
     5743           if (empty_base)
     5744             *empty_base = true;
     5745           return op;

    type is C, which is an empty class; optype is "const D", and C is a base of
D.
    So we return the VAR_DECL 'd'.  Then we get to cxx_set_object_constness
with
    object=d, which is const, so we mark the constructor READONLY.

    Then we're evaluating A::A() which has

      ((A*)this)->data = 0;

    we evaluate the LHS to d.D.2656.a, for which the initializer is
    {.D.2656={.a={.data=}}} which is TREE_READONLY and 'd' is const, so we
think
    we're modifying a const object and fail the constexpr evaluation.

            PR c++/115900

    gcc/cp/ChangeLog:

            * constexpr.cc (cxx_eval_call_expression): Set new_obj to NULL_TREE
            if cxx_fold_indirect_ref set empty_base to true.

    gcc/testsuite/ChangeLog:

            * g++.dg/cpp2a/constexpr-init23.C: New test.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (7 preceding siblings ...)
  2024-07-17 17:55 ` cvs-commit at gcc dot gnu.org
@ 2024-07-17 17:57 ` mpolacek at gcc dot gnu.org
  2024-07-17 20:02 ` valentin at tolmer dot fr
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: mpolacek at gcc dot gnu.org @ 2024-07-17 17:57 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

Marek Polacek <mpolacek at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|[14/15 Regression]          |[14 Regression] constexpr
                   |constexpr object            |object modification during
                   |modification during         |construction gives
                   |construction gives          |"Modifying a const object
                   |"Modifying a const object   |is not allowed in a
                   |is not allowed in a         |constant expression"
                   |constant expression"        |

--- Comment #9 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
Should be fixed on trunk.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (8 preceding siblings ...)
  2024-07-17 17:57 ` [Bug c++/115900] [14 " mpolacek at gcc dot gnu.org
@ 2024-07-17 20:02 ` valentin at tolmer dot fr
  2024-07-29 13:44 ` cvs-commit at gcc dot gnu.org
  2024-07-29 13:54 ` jason at gcc dot gnu.org
  11 siblings, 0 replies; 13+ messages in thread
From: valentin at tolmer dot fr @ 2024-07-17 20:02 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #10 from Valentin Tolmer <valentin at tolmer dot fr> ---
Thanks a lot, that was fast!

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (9 preceding siblings ...)
  2024-07-17 20:02 ` valentin at tolmer dot fr
@ 2024-07-29 13:44 ` cvs-commit at gcc dot gnu.org
  2024-07-29 13:54 ` jason at gcc dot gnu.org
  11 siblings, 0 replies; 13+ messages in thread
From: cvs-commit at gcc dot gnu.org @ 2024-07-29 13:44 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

--- Comment #11 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The releases/gcc-14 branch has been updated by Jason Merrill
<jason@gcc.gnu.org>:

https://gcc.gnu.org/g:da7f0be91e2ae15342541546152a7a27a601c4b4

commit r14-10521-gda7f0be91e2ae15342541546152a7a27a601c4b4
Author: Marek Polacek <polacek@redhat.com>
Date:   Wed Jul 17 11:19:32 2024 -0400

    c++: wrong error initializing empty class [PR115900]

    In r14-409, we started handling empty bases first in
cxx_fold_indirect_ref_1
    so that we don't need to recurse and waste time.

    This caused a bogus "modifying a const object" error.  I'm appending my
    analysis from the PR, but basically, cxx_fold_indirect_ref now returns
    a different object than before, and we mark the wrong thing as const,
    but since we're initializing an empty object, we should avoid setting
    the object constness.

    ~~
    Pre-r14-409: we're evaluating the call to C::C(), which is in the body of
    B::B(), which is the body of D::D(&d):

      C::C ((struct C *) this, NON_LVALUE_EXPR <0>)

    It's a ctor so we get here:

     3118   /* Remember the object we are constructing or destructing.  */
     3119   tree new_obj = NULL_TREE;
     3120   if (DECL_CONSTRUCTOR_P (fun) || DECL_DESTRUCTOR_P (fun))
     3121     {
     3122       /* In a cdtor, it should be the first `this' argument.
     3123          At this point it has already been evaluated in the call
     3124          to cxx_bind_parameters_in_call.  */
     3125       new_obj = TREE_VEC_ELT (new_call.bindings, 0);

    new_obj=(struct C *) &d.D.2656

     3126       new_obj = cxx_fold_indirect_ref (ctx, loc, DECL_CONTEXT (fun),
new_obj);

    new_obj=d.D.2656.D.2597

    We proceed to evaluate the call, then we get here:

     3317           /* At this point, the object's constructor will have run,
so
     3318              the object is no longer under construction, and its
possible
     3319              'const' semantics now apply.  Make a note of this fact
by
     3320              marking the CONSTRUCTOR TREE_READONLY.  */
     3321           if (new_obj && DECL_CONSTRUCTOR_P (fun))
     3322             cxx_set_object_constness (ctx, new_obj,
/*readonly_p=*/true,
     3323                                       non_constant_p, overflow_p);

    new_obj is still d.D.2656.D.2597, its type is "C", cxx_set_object_constness
    doesn't set anything as const.  This is fine.

    After r14-409: on line 3125, new_obj is (struct C *) &d.D.2656 as before,
    but we go to cxx_fold_indirect_ref_1:

     5739       if (is_empty_class (type)
     5740           && CLASS_TYPE_P (optype)
     5741           && lookup_base (optype, type, ba_any, NULL, tf_none, off))
     5742         {
     5743           if (empty_base)
     5744             *empty_base = true;
     5745           return op;

    type is C, which is an empty class; optype is "const D", and C is a base of
D.
    So we return the VAR_DECL 'd'.  Then we get to cxx_set_object_constness
with
    object=d, which is const, so we mark the constructor READONLY.

    Then we're evaluating A::A() which has

      ((A*)this)->data = 0;

    we evaluate the LHS to d.D.2656.a, for which the initializer is
    {.D.2656={.a={.data=}}} which is TREE_READONLY and 'd' is const, so we
think
    we're modifying a const object and fail the constexpr evaluation.

            PR c++/115900

    gcc/cp/ChangeLog:

            * constexpr.cc (cxx_eval_call_expression): Set new_obj to NULL_TREE
            if cxx_fold_indirect_ref set empty_base to true.

    gcc/testsuite/ChangeLog:

            * g++.dg/cpp2a/constexpr-init23.C: New test.

    (cherry picked from commit d890b04197fb0ddba4fbfb32f88e266fa27e02f3)

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Bug c++/115900] [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression"
  2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
                   ` (10 preceding siblings ...)
  2024-07-29 13:44 ` cvs-commit at gcc dot gnu.org
@ 2024-07-29 13:54 ` jason at gcc dot gnu.org
  11 siblings, 0 replies; 13+ messages in thread
From: jason at gcc dot gnu.org @ 2024-07-29 13:54 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115900

Jason Merrill <jason at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|ASSIGNED                    |RESOLVED
         Resolution|---                         |FIXED
                 CC|                            |jason at gcc dot gnu.org

--- Comment #12 from Jason Merrill <jason at gcc dot gnu.org> ---
Fixed for 14.2/15.

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-07-29 13:54 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-07-12 20:22 [Bug c++/115900] New: [14 Regression] constexpr object modification during construction gives "Modifying a const object is not allowed in a constant expression" valentin at tolmer dot fr
2024-07-12 20:29 ` [Bug c++/115900] [14/15 " mpolacek at gcc dot gnu.org
2024-07-12 20:31 ` pinskia at gcc dot gnu.org
2024-07-12 20:34 ` pinskia at gcc dot gnu.org
2024-07-12 20:39 ` mpolacek at gcc dot gnu.org
2024-07-15 21:53 ` mpolacek at gcc dot gnu.org
2024-07-16 20:06 ` mpolacek at gcc dot gnu.org
2024-07-16 20:53 ` mpolacek at gcc dot gnu.org
2024-07-17 17:55 ` cvs-commit at gcc dot gnu.org
2024-07-17 17:57 ` [Bug c++/115900] [14 " mpolacek at gcc dot gnu.org
2024-07-17 20:02 ` valentin at tolmer dot fr
2024-07-29 13:44 ` cvs-commit at gcc dot gnu.org
2024-07-29 13:54 ` jason at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).