Bug 121965 - IMHO valid C++20 rejected by g++
Summary: IMHO valid C++20 rejected by g++
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 16.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2025-09-16 15:34 UTC by Jakub Jelinek
Modified: 2025-09-17 10:47 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2025-09-16 15:34:34 UTC
struct S { int a, b; };

constexpr int
foo (int x)
{
  switch (x)
    {
      int i;
    case 1:
      int j;
    case 2:
      i = 1;
      j = 2;
      return i + j;
    case 3:
      S s;
      return 2;
    case 4:
      s.a = 3;
      s.b = 4;
      [[fallthrough]];
    default:
      return s.a + s.b;
    }
}

static_assert (foo (1) == 3);
static_assert (foo (2) == 3);
static_assert (foo (3) == 2);
static_assert (foo (4) == 7);
static_assert (foo (42) == 7);

IMHO this is valid for C++20 and above, in C++17 variables with vacuous initialization aren't valid in constant expressions, in C++20 I think they should be valid if one doesn't actually use the uninitialized values.
Still, g++ rejects it with
<source>:29:24: error: non-constant condition for static assertion
   29 | static_assert (foo (1) == 3);
      |                ~~~~~~~~^~~~
in 'constexpr' expansion of 'foo(1)'
<source>:29:20:   
   29 | static_assert (foo (1) == 3);
      |                ~~~~^~~
<source>:12:9: error: modification of 'i' from outside current evaluation is not a constant expression
   12 |       i = 1;
      |       ~~^~~
<source>:30:24: error: non-constant condition for static assertion
   30 | static_assert (foo (2) == 3);
      |                ~~~~~~~~^~~~
in 'constexpr' expansion of 'foo(2)'
<source>:30:20:   
   30 | static_assert (foo (2) == 3);
      |                ~~~~^~~
<source>:12:9: error: modification of 'i' from outside current evaluation is not a constant expression
   12 |       i = 1;
      |       ~~^~~
<source>:32:24: error: non-constant condition for static assertion
   32 | static_assert (foo (4) == 11);
      |                ~~~~~~~~^~~~~
in 'constexpr' expansion of 'foo(4)'
<source>:32:20:   
   32 | static_assert (foo (4) == 11);
      |                ~~~~^~~
<source>:19:11: error: modification of 's' from outside current evaluation is not a constant expression
   19 |       s.a = 3;
      |       ~~~~^~~
<source>:33:25: error: non-constant condition for static assertion
   33 | static_assert (foo (42) == 11);
      |                ~~~~~~~~~^~~~~
in 'constexpr' expansion of 'foo(42)'
<source>:33:20:   
   33 | static_assert (foo (42) == 11);
      |                ~~~~^~~~
<source>:23:11: error: modification of 's' from outside current evaluation is not a constant expression
   23 |       s.a = 5;
      |       ~~~~^~~
and clang++ with even weirder
<source>:32:16: error: static assertion expression is not an integral constant expression
   32 | static_assert (foo (4) == 11);
      |                ^~~~~~~~~~~~~
<source>:19:7: note: unimplemented constexpr lambda feature: captures not currently allowed (coming soon!)
   19 |       s.a = 3;
      |       ^
<source>:32:16: note: in call to 'foo(4)'
   32 | static_assert (foo (4) == 11);
      |                ^~~~~~~
<source>:33:16: error: static assertion expression is not an integral constant expression
   33 | static_assert (foo (42) == 11);
      |                ^~~~~~~~~~~~~~
<source>:23:7: note: unimplemented constexpr lambda feature: captures not currently allowed (coming soon!)
   23 |       s.a = 5;
      |       ^
<source>:33:16: note: in call to 'foo(42)'
   33 | static_assert (foo (42) == 11);
      |                ^~~~~~~~
2 errors generated.
(though that shows that when using
    case 4:
    default:
      return 0;
instead of the case 4/default in the source), clang++ accepts it.
Comment 1 Jakub Jelinek 2025-09-16 15:37:40 UTC
Though, we do accept e.g.
struct S { int a, b; };

constexpr int
foo (int x)
{
  if (x == 6)
    goto l1;
  {
    int i;
    i = 6;
    l1:
    i = 4;
    return i;
  }
}

static_assert (foo (1) == 4);
for -std=c++23.