Search code examples
c++pointersreferencelanguage-lawyerconstexpr

constexpr int* ptr =&i compiles in msvc but not with clang and gcc


I am learning about constexpr variables using the books listed here. In particular I read in C++ Primer that:

Variables declared constexpr are implicitly const and must be initialized with constant expressions.

Now, to further clear my concept and check if I understood the things correctly, I wrote the following simple program that compiles with msvc but not with gcc and clang: Demo

int main(void)
{
   int i = 0;
   constexpr int *ptr= &i; //compiles with msvc but not with clang and gcc 
}

So, my question is which compiler is right here(if any)?


Solution

  • The program is ill-formed and msvc is wrong in not giving a diagnostic(this has been fixed in latest version of msvc). This is because i is not an statically allocated object and so its address is not constant. Basically, since we can initialize a constexpr pointer only from either the nullptr literal or literal 0 or from an address of an object that has fixed address and in your example, i is not an object that has a fixed address so that &i is not a constant expression.

    This can be seen from expr.const#11 which states:

    A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

    • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a non-immediate function, or a null pointer value,

    An entity is a permitted result of a constant expression if it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.

    (emphasis mine)

    This means that there are two ways to solve the problem. First is that you can add static infront of i to make it a local static. The second is to move the definition of i to global scope outside the main function. In both cases(shown below), i will then have static storage duration so that &i will now be a constant expression according to the above quoted statement.


    Method 1

    int main()
    {
    //-vvvvvv------------->static added here so that i now has static storage duration
       static int i = 0;
       constexpr int *ptr= &i; //works now
       
    }
    

    Method 2

    int i = 0;  //make i global so that i now has static storage duration  
    int main()
    {
    
       constexpr int *ptr= &i; //works now   
    }
    

    Here is the msvc bug report:

    MSVC compiles invalid constexpr int*ptr= &i where i is a local nonstatic object