Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is comparing addresses of dynamically allocated objects allowed in C++20 constant expression?

C++20 allows heap allocation in constexpr functions as long as the memory does not leak. However GCC and Clang disagree on whether comparing the addresses of two dynamically allocated objects is a constant expression or not.

The following snippet can be compiled with Clang but not gcc.

constexpr bool foo() {
    int* a = new int(4);
    int* b = new int(4);
    bool result = a == b;
    delete a;
    delete b;
    return result;
}

constexpr bool x = foo(); // GCC:  error: '(((int*)(& heap deleted)) == ((int*)(& heap deleted)))' is not a constant expression

The following works fine on both compilers

constexpr bool foo2() {
    int a = 4;
    int b = 5;
    bool result = &a ==  &b;

    return result;
}

constexpr bool x = foo2();

I'd assume that in order to delete the dynamic objects correctly the compiler must know whether the pointers point to the same objects or not, so I'd assume this is a GCC bug (or not yet fully implemented). Can anyone confirm this assumption? Or am I wrong?

Live example here.

Edit: Strangely, when I open the live example through the link provided, it suddenly compiles on gcc, too. But if I copy-paste it to a new compiler explorer instance, it fails again. Or if I reload it multiple times it fails every second time and compiles every other second time...

like image 917
florestan Avatar asked Jan 31 '21 16:01

florestan


1 Answers

This is a gcc bug (#85428).

There's nothing in [expr.const]/5 that would cause evaluation of a == b to fail to be a constant expression. The only one there in which there is any question would be the one about undefined behavior. So we could go look at [expr.eq] to see what that says about pointer comparison:

If at least one of the operands is a pointer, pointer conversions, function pointer conversions, and qualification conversions are performed on both operands to bring them to their composite pointer type. Comparing pointers is defined as follows:

  • If one pointer represents the address of a complete object, and another pointer represents the address one past the last element of a different complete object, the result of the comparison is unspecified.
  • Otherwise, if the pointers are both null, both point to the same function, or both represent the same address, they compare equal.
  • Otherwise, the pointers compare unequal.

Both pointers represent the address of different complete objects, with neither being null, so so we fall into the third bullet point and the pointers just compare unequal. No undefined or unspecified behavior here.

a == b should just yield false.

like image 176
Barry Avatar answered Nov 04 '22 23:11

Barry