3

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)?

Jason
  • 36,170
  • 5
  • 26
  • 60
Alex
  • 318
  • 1
  • 14

1 Answers1

2

The program is ill-formed and msvc is wrong in accepting the code. 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 addres 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

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 2
    Before reporting a new msvc bug, it should be confirmed by compiling with the flag `/permissive-`. – 273K Oct 15 '22 at 15:35
  • 1
    Yes, it's not a compiler bug but extension, and the bug report will likely be closed. – 273K Oct 15 '22 at 15:38
  • 1
    @273K The program doesn't give diagnostic with `/permissive-`. [Demo](https://godbolt.org/z/cf9xKsGMe). So, it seems to be a bug. – Jason Oct 15 '22 at 15:47
  • @273K Even with the flag you suggested, we don't get any diagnostic. So this looks like a bug as said in this answer. – Alex Oct 15 '22 at 15:51
  • 2
    It's an interesting case because `main` is not the usual function. It can't be called by another function and a side effect is that the address of local objects never differ. Still, a technical bug. – doug Oct 15 '22 at 16:12