c++language-lawyerc++17constexpr

Modifying a global variable in a constexpr function in C++17


In C++17, are you allowed to modify global variables in a constexpr function?

#include <iostream>

int global = 0;

constexpr int Foo(bool arg) {
    if (arg) {
        return 1;
    }
    return global++;
}

int main() {
    std::cout << global;
    Foo(true);
    std::cout << global;
    Foo(false);
    std::cout << global;
}

I wouldn't expect you to be able to, but clang 6 allows it: https://godbolt.org/g/UB8iK2

GCC, however, doesn't: https://godbolt.org/g/ykAJMA

Which compiler is correct?


Solution

  • Which compiler is correct?

    Clang is right.

    The definition of a constexpr function as per dcl.constexpr/3

    The definition of a constexpr function shall satisfy the following requirements:

    (3.1) its return type shall be a literal type;
    (3.2) each of its parameter types shall be a literal type;
    (3.3) its function-body shall be = delete, = default, or a compound-statement that does not contain:

    (3.3.1) an asm-definition,
    (3.3.2) a goto statement,
    (3.3.3) an identifier label,
    (3.3.4) a try-block, or
    (3.3.5) a definition of a variable of non-literal type or of static or thread storage duration or for which no initialization is performed.

    Also as per dcl.constexpr/5:

    For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required.

    Foo(true) could be evaluated to a core constant expression (i.e 1).

    Also, Foo(false) could be but is not required to be constant evaluated.

    CONCLUSION

    Thus, a bug in GCC.


    Many thanks to @Barry, @aschepler and @BenVoigt for helping me with this answer.