11

The following code attempts to use array indexing on a string literal in two different constant contexts:

static char x = "abcx"[3];

_Static_assert ("abcx"[3] == 'x', "...");

Judging by Compiler Explorer, there's clear consensus among tool vendors that doing this in the second context, which explicitly requires an integer constant expression, is not allowed. However, they seem to differ about the first context, which is only an arithmetic constant expression used in an initializer. GCC and Clang stand out as implementations which permit this.

By itself this isn't interesting because in paragraph 10 of 6.6, C11/C18 does say that "an implementation may accept other forms of constant expressions." However, it stands out in this case because:

  • GCC and Clang are both accepting this silently with -pedantic (true, signoff by a compiler doesn't mean code is conforming). Building the code makes sense as its meaning is straightforward, but I would expect a warning if they thought this wasn't conforming, and they can recognize whether (they think) it is or not, because...

  • for both compilers, the behaviour has changed recently - Clang used to raise an error over this up until 3.8, while GCC used to raise an error up until 8.0. These versions came out in 2016 and 2018 respectively. This suggests the change was intentional, but I haven't yet found release notes for either compiler that go into this level of detail.

The timing of the change in behaviour makes it look like this was something to do with C18, but the wording of 6.6 doesn't seem to have changed. The restrictions on integer constant expressions remain strict (as shown by the second line continuing to error), and the wording of paragraph 9 seems the same as it was in C11, in particular continuing to say that "the value of an object shall not be accessed by use of these operators" (w.r.t [] and friends).

Is the first context a valid initializer constant by any reading of the standard, not counting paragraph 10? Is there anywhere I would be likely to find a rationale for the GCC/Clang changes?

curiousguy
  • 7,344
  • 2
  • 37
  • 52
Leushenko
  • 11,633
  • 9
  • 44
  • 84
  • I happen to think this *should* be allowed as a true ICE, but that's just personal opinion. – Leushenko Jun 15 '19 at 15:38
  • If you don't count 6.10 (An implementation may accept other forms of constant expressions.), it's pretty clear that by 6.6 alone it's not an integer constant expression. With that, failure to report it under `-pedantic` should be considered a bug, IMO. (I think compilers should not take 6.10 into account as far as -pedantic is concerned.) – PSkocik Jun 15 '19 at 15:45
  • 1
    From [the answer to my question](https://stackoverflow.com/questions/54135942/why-initializer-element-is-not-a-constant-is-not-working-anymore) that looks similar I asked some time ago: "GCC's `-pedantic` option ensures diagnostics only where required by the standard, which does not include these cases." The standard does not require a diagnostic when accepting implementation form of a constant expression, so `-pedantic` does not issue any. A flag like like `-Wimplementation-constant-expression` would be cool. (is this a duplicate?) – KamilCuk Jun 15 '19 at 16:02
  • Possible duplicate of [Why "initializer element is not a constant" is... not working anymore?](https://stackoverflow.com/questions/54135942/why-initializer-element-is-not-a-constant-is-not-working-anymore) – Leushenko Jun 16 '19 at 08:51
  • What makes you think the change was intentional? Seems like a gcc bug to me. Though apparently clang and icc always allowed this code. – Lundin Jun 17 '19 at 07:01

1 Answers1

2

6.6 Constant expressions, ¶8:

An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer constants, floating constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and _Alignof expressions. Cast operators in an arithmetic constant expression shall only convert arithmetic types to arithmetic types, except as part of an operand to a sizeof or _Alignof operator.

A string literal is not any of the above 6 operand types permitted, so the expression is not an arithmetic constant expression unless it's accepted as an extension.

R.. GitHub STOP HELPING ICE
  • 195,354
  • 31
  • 331
  • 669
  • Paragraph 10 says "An implementation may accept other forms of constant expressions." Since an implementation would need no special permission from the Standard to accept other forms of constant expression *as an extension*, I think one could reasonably interpret paragraph 10 as saying that the acceptance of additional forms of constant expression need not be considered an extension. – supercat Mar 17 '20 at 15:59