6

We know that operations that would cause undefined behavior are not core constant expressions(section 5.19 paragraph 2 from the draft C++ standard)

In the tests I have done both clang and gcc treat undefined behavior in a constexpr as an error but they are inconsistent in the case of left an right shift. For example, in all of these cases which are considered undefined behavior according to section 5.8 Shift operators paragraph 1 to 3:

constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
constexpr int x2 =  1 << -1 ;
constexpr int x3 =  -1 << 1 ;
constexpr int x4 =  1 >> 33 ; //Assuming 32-bit int
constexpr int x5 =  1 >> -1 ;

clang will produce an error (see it live):

error: constexpr variable 'x1' must be initialized by a constant expression
    constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
                  ^     ~~~~~~~
note: shift count 33 >= width of type 'int' (32 bits)
    constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
....

while gcc will produce a warning but it will still consider each variable to be constant expression (see it live):

warning: left shift count >= width of type [enabled by default]
 constexpr int x1 =  1 << 33 ; //Assuming 32-bit int
                          ^
warning: left shift count is negative [enabled by default]
 constexpr int x2 =  1 << -1 ;
...

This looks like a gcc bug but I know a compiler can make stronger guarantees for behavior the standard says is undefined and it does look like gcc gives some stronger guarantees for shifts. This may end up being a bug but it makes me wonder if the compiler allowed that same leeway in the context of a constexpr as well or does the compiler have to strictly adhere to what the standard says is undefined behavior here?

Update

As Alan mentions, it is indeed true that the diagnostic of an ill-formed program can be either an error or a warning but in this case gcc does not seem to consider the program ill-formed. Unlike other instances such as in the case of overflow, gcc does not complain about an invalid constexpr but warns about the shifts. So then it would seem that either it is a bug or gcc does not consider these cases to be undefined and hence my question.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • As far as I know, it is not. Any kind of undefined behavior in a `constexpr` **must** lead to an error; though it may be that this error can be SFINAE'd. – Matthieu M. Feb 01 '14 at 19:21
  • 7
    The standard requires a diagnostic (which may be an error, or a warning, or pretty much anything) if the input program is ill-formed. It allows the implementation to produce a program anyway (and places no restrictions on what that program does). So I would think both behaviours are conforming. – Alan Stokes Feb 01 '14 at 20:12
  • 3
    In addition, the Standard requires *at least one diagnostic*. It does not require a diagnostic for each case of ill-formedness (And I don't think that would work. The spec would have to define the "recover"-behavior for each ill-formed construct then. What size should `int a[-1]` have in the code following it?). So if GCC gives the warning, it satisfies that requirement and doesn't need to complain about the constexprness later. – Johannes Schaub - litb Feb 03 '14 at 18:01
  • Have you tried what happens if you put that into SFINAE? – dyp Feb 03 '14 at 20:42
  • @dyp SFINAE does not work in `gcc` with the shifts. My guess is that this was not intended behavior. – Shafik Yaghmour Feb 04 '14 at 02:36
  • @JohannesSchaub-litb you might as well make that an answer, I see it now. I don't think it was intended behavior so I filled a bug report but I understand it is compliant behavior. – Shafik Yaghmour Feb 11 '14 at 18:35
  • @ShafikYaghmour: Implementations are free to do whatever they want with undefined behavior. _Including to define it_. I know there's many cases of undefined behavior that MSVC and Intel specially define as "will work in such-and-such manner". Intel (IIRC) specifies that a `v<32` will be treated as `v<<(s%32)` in their documentation. That's totally allowed. – Mooing Duck Feb 12 '14 at 17:43
  • 1
    @MooingDuck I am aware of that I even linked to `gcc`s docs that say they give stronger guarantees for shifts. I just want not sure how it applied in the context of *constexpr* since there was a specific exception for *undefined behavior* and Howard in [another thread has specifically said that constexpr allow us to catch UB at compile time](http://stackoverflow.com/questions/19593938/is-left-shifting-a-negative-integer-undefined-behavior-in-c11#comment29091986_19593938). This implied something stronger to me but I understand it better now. – Shafik Yaghmour Feb 12 '14 at 17:51
  • @MooingDuck if you were one of the downvoters, in that context I don't think the answer was that obvious. – Shafik Yaghmour Feb 12 '14 at 18:03
  • @dyp update, the consensus is that this is conforming. It is inconsistent behavior so I filed a bug report. My hope is that this will be fixed and become consistent. – Shafik Yaghmour Feb 14 '14 at 16:38
  • @ShafikYaghmour Thanks for the update. I agree that accepting the ill-formed program (UB in a constant expression) is conforming (an extension), but is breaking the SFINAE trick conforming? In case of SFINAE, the compiler isn't just accepting an ill-formed program, it changes the semantics of a well-formed program. – dyp Feb 14 '14 at 16:46
  • @dyp not sure, hopefully the bug report will eventually clear that up. I linked it in my answer so you can add a comment if you wish. – Shafik Yaghmour Feb 14 '14 at 17:29
  • @dyp considering that the committee found it undesirable to break SFINAE in the case of [implementations adding constexpr to standard library functions](http://stackoverflow.com/a/27744080/1708801) I would guess this is not conforming but I have not found a general statement saying that but it would be consistent. – Shafik Yaghmour May 19 '15 at 14:08
  • Although one could make a reasonable argument that it breaks the *as-if rule*. – Shafik Yaghmour May 19 '15 at 14:23

1 Answers1

3

Since Johannes does not seem to want to convert his comment into an answer then I will self-answer. I had an offline conversation with Howard Hinnant and he confirmed the consensus in the comments that gccs behavior in this context is indeed conforming.

The relevant section from the draft standard would be section 1.4 Implementation compliance which says in paragraph 2:

Although this International Standard states only requirements on C++ implementations, those requirements are often easier to understand if they are phrased as requirements on programs, parts of programs, or execution of programs. Such requirements have the following meaning:

and has the following bullet (emphasis mine):

If a program contains a violation of any diagnosable rule or an occurrence of a construct described in this Standard as “conditionally-supported” when the implementation does not support that construct, a conforming implementation shall issue at least one diagnostic message.

A diagnostic can either be a warning or an error. So once gcc provides a warning about the undefined behavior it does not requires a subsequent warning about the constexpr itself.

Although this is conforming behavior generating an error for the constexpr and allowing SFINAE would seem to be more robust behavior. Considering that gcc issues errors in other instances of undefined behavior in a constexpr this does not seem like the intended behavior or if it was, at least inconsistent behavior, so I filed a bug report.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • The Standard is inconsistent with its definition of Undefined Behavior, since in circumstances other than SFINAE, the Standard expressly allows implementations to process constructs that invoke UB in any fashion they see fit provided they issue a diagnostic, and implementations would often process constructs usefully even when not required to do so. SFINAE means that some constructs which supposedly invoke UB are required to be treated as invalid. – supercat Nov 06 '18 at 03:27