Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the compiler allowed leeway in what it considers undefined behavior in a constant expression?

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.

like image 499
Shafik Yaghmour Avatar asked Feb 01 '14 18:02

Shafik Yaghmour


People also ask

What is undefined behavior in programming?

In computer programming, undefined behavior (UB) is the result of executing a program whose behavior is prescribed to be unpredictable, in the language specification to which the computer code adheres.

What does undefined behavior mean in C?

Undefined Behavior in C and C++ So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended.

Why does C have undefined behavior?

C and C++ have undefined behaviors because it allows compilers to avoid lots of checks. Suppose a set of code with greater performing array need not keep a look at the bounds, which avoid the needs for complex optimization pass to check such conditions outside loops.

Does Python have undefined behavior?

Python has undefined behavior because it's implementations are written in languages that do.


1 Answers

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.

like image 75
Shafik Yaghmour Avatar answered Oct 19 '22 22:10

Shafik Yaghmour