Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

constexpr undefined behaviour

I've been experimenting with constexpr. On my test compiler (g++ 4.6) this fails to compile with an error about out of bounds access. Is a compiler required to spot this at compile time?

#include <iostream>

constexpr const char *str = "hi";

constexpr int fail() {
  return str[1000]; // Way past the end!
}

template <int N>
struct foo {
  static void print() { std::cout << N << std::endl; }
};

int main() {  
  foo<fail()>::print();
}
like image 325
Flexo Avatar asked Sep 14 '11 18:09

Flexo


2 Answers

§5.19/2 (on the second page; it really should be split into many paragraphs) forbids constant expressions containing

— an lvalue-to-rvalue conversion (4.1) unless it is applied to

— a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or

— a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object

str[1000] translates to * ( str + 1000 ), which does not refer to a subobject of str, in contrast with an in-bounds array access. So this is a diagnosable rule, and the compiler is required to complain.

EDIT: It seems there's some confusion about how this diagnosis comes about. The compiler checks an expression against §5.19 when it needs to be constant. If the expression doesn't satisfy the requirements, the compiler is required to complain. In effect, it is required to validate constant expressions against anything that might otherwise cause undefined behavior.* This may or may not involve attempting to evaluate the expression.

 * In C++11, "a result that is not mathematically defined." In C++14, "an operation that would have undefined behavior," which by definition (§1.3.24) ignores behavior that the implementation might define as a fallback.

like image 136
Potatoswatter Avatar answered Oct 08 '22 10:10

Potatoswatter


Yes, the compiler is supposed to catch this at compile time, if we look at section 5.19 Constant expressions paragraph 2 of the draft C++ standard it lists this as an exclusion for constant expressions:

an operation that would have undefined behavior [ Note: including, for example, signed integer overflow (Clause 5), certain pointer arithmetic (5.7), division by zero (5.6), or certain shift operations (5.8) —end note ];

and issue 695 as far as I can tell says that undefined behavior is non-const and should issue a diagnostic:

The consensus of the CWG was that an expression like 1/0 should simply be considered non-constant; any diagnostic would result from the use of the expression in a context requiring a constant expression.

You can find more details at my self answered question here which also goes into the uses of this feature.

like image 45
Shafik Yaghmour Avatar answered Oct 08 '22 12:10

Shafik Yaghmour