Skip to content

avoid error 'placement new would change type of storage' #162589

@cppljevans

Description

@cppljevans

With the following code:

template < unsigned I >
struct type {
  constexpr type() {}
};

#include <cstddef>   //std::byte
#include <algorithm> //for std::max

template < typename... T >
union uninitialized_T0
/**<@brief
 *  A buffer for stoarge of a 
 *  variant of types T...
 */
{
  constexpr uninitialized_T0() noexcept {}
  uninitialized_T0(const uninitialized_T0&)            = delete;
  uninitialized_T0& operator=(const uninitialized_T0&) = delete;
  constexpr ~uninitialized_T0() noexcept {}

  static constexpr size_t Size = std::max({sizeof(T)...});

  alignas(T...) std::byte buffer[Size]{}

  /**<@brief
   *   Storage for any of T... with proper alignment for all.
   */
  ;
  constexpr void* voidify() { return buffer; }
//#define EXPLICIT_TYPE0
#ifdef EXPLICIT_TYPE0
  type<0> t0
      /**<@brief
       *  The only reason for this is to show the
       *  absurdity, in one sense, of the error when
       *  defined(USE_BUFFER) && defined(USE_CONSTEXPR). 
       *
       *  The error is not absurd in another sense because
       *  it conforms to the <A HREF="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2747r2.html">standard</A>:
       *  saying(at "(5.14)"):
       *    "unless P points to an object whose type is similar to T;"
       *  and std::byte[Size] is NOT similar to type<0>.
       *
       *  OTOH, it is absurd because the purpose of this union is to provide
       *  an uninitialized buffer in which to placement new a type, T, whose 
       *  "alignment and size requirements" are "compatible"
       *  with that of the buffer's.
       *
       *  Note, "alignment and size requirements" means alignas(T) and sizeof(T). 
       *
       *  The constraint, "similar to" should be irrelevant, in this case.
       */
      ;
#endif //EXPLICIT_TYPE0
};

#include <new>

template < typename... T >
struct variant {
private:
  uninitialized_T0< T... > storage;

public:
  constexpr variant() {
    new
#ifdef EXPLICIT_TYPE0
        (&storage.t0
    //with clang++20, WHEN defined(USE_CONSTEXPR),
    //this compiles without error.
#else
        (storage.voidify()
    //with clang++20, WHEN defined(USE_CONSTEXPR),
    //this causes error:
    //  error: constexpr variable 'v' must be initialized by a constant expression
    //  note: placement new would change type of storage from 'std::byte' to 'type<0>'
#endif //EXPLICIT_TYPE0
         ) type<0>;
  }
};

int main() {
  variant<type<0>, type<1>, type<2>>
#define USE_CONSTEXPR
#ifdef USE_CONSTEXPR
      constexpr
#endif //USE_CONSTEXPR
      v;
  return 0;
}

When:

defined(USE_CONSTEXPR) and !defined(EXPLICIT_T0)

as explained in the comments, clang++-20 -std=c++26 produces the error shown in the comments.

However, when:

defined(USE_CONSTEXPR) and defined(EXPLICIT_T0)

No error is produced.

Is there someway to disable the error about:

placement new would change type of storage

? If not, is there some code modification to disable that error message in
this particular case? If so, where is that code?

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang:frontendLanguage frontend issues, e.g. anything involving "Sema"constexprAnything related to constant evaluationquestionA question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions