Bug 92505 - Using mutable in constexpr
Summary: Using mutable in constexpr
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: 13.0
Assignee: Patrick Palka
URL:
Keywords: rejects-valid
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2019-11-14 03:22 UTC by Casey Carter
Modified: 2023-07-06 07:38 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-11-14 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Casey Carter 2019-11-14 03:22:19 UTC
GCC trunk does not accept this well-formed program in -std=c++2a mode:

    constexpr int f() {
        struct {
            mutable int i = 41;
        } s;
        auto const& cs = s;
        return ++cs.i;
    }

    int main() {
        constexpr int i = f();
        return 42 - i;
    }

Diagnosing (https://godbolt.org/z/n259tb):

    <source>: In function 'int main()':
    <source>:10:24:   in 'constexpr' expansion of 'f()'
    <source>:10:25: error: mutable 'f()::<unnamed struct>::i' is not usable in a constant expression
       10 |     constexpr int i = f();
          |                         ^
    Compiler returned: 1

AFAICS this is well-formed back to C++14 since it applies lvalue-to-rvalue conversion to "a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;".
Comment 1 Marek Polacek 2019-11-14 14:53:20 UTC
Looks like this never worked.
Comment 2 Marek Polacek 2019-11-14 14:57:30 UTC
cxx_eval_component_reference has:
2967   if (DECL_MUTABLE_P (part))
2968     {
2969       if (!ctx->quiet)
2970         error ("mutable %qD is not usable in a constant expression", part);
2971       *non_constant_p = true;
2972     }

Added in https://gcc.gnu.org/ml/gcc-patches/2011-10/msg02593.html

I will need to do a bit of archeology on the isocpp mailing list to see the discussions.
Comment 3 Christopher Di Bella 2021-07-13 04:53:19 UTC
Gentle ping, this has started to cause issues in the libc++ GCC CI for ranges.
Comment 4 Arthur O'Dwyer 2021-09-06 16:28:14 UTC
Confirmed; the test case can be as simple as

// https://godbolt.org/z/M9rf31qqq
struct S { mutable int m; };
static_assert(S{42}.m == 42);

(Removing the "mutable" keyword makes GCC happy.)
Comment 5 GCC Commits 2022-09-16 15:11:32 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:7107ea6fb933f1e928593c7e92edfd64ccf0df63

commit r13-2701-g7107ea6fb933f1e928593c7e92edfd64ccf0df63
Author: Patrick Palka <ppalka@redhat.com>
Date:   Fri Sep 16 11:10:43 2022 -0400

    c++: 'mutable' member within constexpr [PR92505]
    
    This patch permits accessing 'mutable' members of local objects during
    constexpr evaluation, while continuing to reject it for global objects
    (as in the last line of cpp0x/constexpr-mutable1.C).  To distinguish
    between the two cases, it looks like it suffices to just check
    CONSTRUCTOR_MUTABLE_POSION in cxx_eval_component_reference before
    deciding to reject a DECL_MUTABLE_P member access.
    
            PR c++/92505
    
    gcc/cp/ChangeLog:
    
            * constexpr.cc (cxx_eval_component_reference): Check non_constant_p
            sooner.  In C++14 or later, reject a DECL_MUTABLE_P member access
            only if CONSTRUCTOR_MUTABLE_POISION is also set.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp0x/constexpr-mutable3.C: New test.
            * g++.dg/cpp1y/constexpr-mutable1.C: New test.
Comment 6 Patrick Palka 2022-09-18 16:58:05 UTC
Fixed for GCC 13.