Title
constexpr launder makes pointers to inactive members of unions usable
Status
c++23
Section
[ptr.launder]
Submitter
Hubert Tong

Created on 2020-11-10.00:00:00 last changed 5 months ago

Messages

Date: 2021-02-26.17:31:29

Proposed resolution:

This wording is relative to N4868.

  1. Modify [ptr.launder] as indicated:

    template<class T> [[nodiscard]] constexpr T* launder(T* p) noexcept;
    

    […]

    -4- Remarks: An invocation of this function may be used in a core constant expression whenever theif and only if the (converted) value of its argument may be used in a core constant expressionplace of the function invocation. A byte of storage b is reachable through a pointer value that points to an object Y if there is an object Z, pointer-interconvertible with Y, such that b is within the storage occupied by Z, or the immediately-enclosing array object if Z is an array element.

    […]

Date: 2021-02-26.00:00:00

[ 2021-02-26 Approved at February 2021 virtual plenary. Status changed: Tentatively Ready → WP. ]

Date: 2021-02-15.00:00:00

[ 2021-02-08; Reflector poll ]

Set status to Tentatively Ready after five votes in favour during reflector poll.

Date: 2020-12-15.00:00:00

[ 2020-12-07; Davis Herring comments ]

This issue is related to CWG 2464.

Date: 2020-11-15.00:00:00

[ 2020-11-21; Reflector prioritization ]

Set priority to 3 during reflector discussions.

Date: 2020-11-10.00:00:00

The wording in [ptr.launder] paragraph 4:

An invocation of this function may be used in a core constant expression whenever the value of its argument may be used in a core constant expression.

can be taken to mean that the invocation may be used only when the value of its argument can be used in place of the invocation itself.

That interpretation is not particularly obvious, but based on comments on the CWG reflector (see here), that is the interpretation that matches the design intent.

Consider:

#include <new>

struct A { int x; int y; };
struct B { float x; int y; };

union U {
  A a;
  B b;
};

constexpr A foo() {
  U u;
  int* byp = &u.b.y;
  static_assert(&u.b.y == static_cast<void*>(&u.a.y));
  u.a.y = 42;
  *std::launder(byp) = 13;
  return u.a;
}

extern constexpr A globA = foo();

If the static_assert succeeds, then a possible interpretation is that the source file above compiles because the call to std::launder produces a pointer to u.a.y. That interpretation is apparently not desirable.

History
Date User Action Args
2023-11-22 15:47:43adminsetstatus: wp -> c++23
2021-02-26 17:31:29adminsetmessages: + msg11704
2021-02-26 17:31:29adminsetstatus: ready -> wp
2021-02-08 13:01:11adminsetmessages: + msg11682
2021-02-08 13:01:11adminsetstatus: new -> ready
2020-12-13 17:23:42adminsetmessages: + msg11641
2020-11-21 14:06:16adminsetmessages: + msg11623
2020-11-15 14:16:16adminsetmessages: + msg11608
2020-11-10 00:00:00admincreate