llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.14k stars 12.02k forks source link

c++23: constexpr std::unique_ptr::~unique_ptr()/std::default_delete<T> instantiation too strict #111185

Open jdrouhard opened 1 month ago

jdrouhard commented 1 month ago
#include <memory>

class Foo {
  inline static std::unique_ptr<Foo> instance_;
};

See: https://godbolt.org/z/MqMxs9nzr

This fails to compile due to unique_ptr<T>::~unique_ptr() (and thus default_delete<T>::operator()) being instantiated at the point of the variable declaration (when the class isn't fully defined yet). Since c++23, unique_ptr and default_delete::operator() are constexpr, but the declaration of the unique_ptr should not attempt to fully instantiate the destructor or std::default_delete::operator() yet. Or at least the above usage pattern should be allowed, as this is a valid pattern for singletons (that aren't Meyers style). Should this fall back to non-constexpr unique_ptr/default_delete?

This fails using both libc++ and libstdc++. gcc and msvc both compile it fine.

In file included from test.cpp:1:
In file included from /builds/clang-19.1.0/bin/../include/c++/v1/memory:944:
In file included from /builds/clang-19.1.0/bin/../include/c++/v1/__memory/inout_ptr.h:16:
In file included from /builds/clang-19.1.0/bin/../include/c++/v1/__memory/shared_ptr.h:32:
/builds/clang-19.1.0/bin/../include/c++/v1/__memory/unique_ptr.h:78:19: error: invalid application of 'sizeof' to an incomplete type 'Foo'
   78 |     static_assert(sizeof(_Tp) >= 0, "cannot delete an incomplete type");
      |                   ^~~~~~~~~~~
/builds/clang-19.1.0/bin/../include/c++/v1/__memory/unique_ptr.h:292:7: note: in instantiation of member function 'std::default_delete<Foo>::operator()' requested here
  292 |       __ptr_.second()(__tmp);
      |       ^
/builds/clang-19.1.0/bin/../include/c++/v1/__memory/unique_ptr.h:261:71: note: in instantiation of member function 'std::unique_ptr<Foo>::reset' requested here
  261 |   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 ~unique_ptr() { reset(); }
      |                                                                       ^
simple.cpp:4:38: note: in instantiation of member function 'std::unique_ptr<Foo>::~unique_ptr' requested here
    4 |   inline static std::unique_ptr<Foo> instance;
      |                                      ^
simple.cpp:3:7: note: definition of 'Foo' is not complete until the closing '}'
    3 | class Foo {
llvmbot commented 1 month ago

@llvm/issue-subscribers-clang-frontend

Author: None (jdrouhard)

```cpp #include <memory> class Foo { inline static std::unique_ptr<Foo> instance_; }; ``` See: https://godbolt.org/z/MqMxs9nzr This fails to compile due to `unique_ptr<T>::~unique_ptr()` (and thus `default_delete<T>::operator()`) being instantiated at the point of the variable declaration (when the class isn't fully defined yet). Since c++23, `unique_ptr` and `default_delete::operator()` are constexpr, but the declaration of the unique_ptr should not attempt to fully instantiate the destructor or std::default_delete<T>::operator() yet. Or at least the above usage pattern should be allowed, as this is a valid pattern for singletons (that aren't Meyers style). Should this fall back to non-constexpr unique_ptr/default_delete? This fails using both libc++ and libstdc++. gcc and msvc both compile it fine. ``` In file included from test.cpp:1: In file included from /builds/clang-19.1.0/bin/../include/c++/v1/memory:944: In file included from /builds/clang-19.1.0/bin/../include/c++/v1/__memory/inout_ptr.h:16: In file included from /builds/clang-19.1.0/bin/../include/c++/v1/__memory/shared_ptr.h:32: /builds/clang-19.1.0/bin/../include/c++/v1/__memory/unique_ptr.h:78:19: error: invalid application of 'sizeof' to an incomplete type 'Foo' 78 | static_assert(sizeof(_Tp) >= 0, "cannot delete an incomplete type"); | ^~~~~~~~~~~ /builds/clang-19.1.0/bin/../include/c++/v1/__memory/unique_ptr.h:292:7: note: in instantiation of member function 'std::default_delete<Foo>::operator()' requested here 292 | __ptr_.second()(__tmp); | ^ /builds/clang-19.1.0/bin/../include/c++/v1/__memory/unique_ptr.h:261:71: note: in instantiation of member function 'std::unique_ptr<Foo>::reset' requested here 261 | _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 ~unique_ptr() { reset(); } | ^ simple.cpp:4:38: note: in instantiation of member function 'std::unique_ptr<Foo>::~unique_ptr' requested here 4 | inline static std::unique_ptr<Foo> instance; | ^ simple.cpp:3:7: note: definition of 'Foo' is not complete until the closing '}' 3 | class Foo { ```
zyn0217 commented 1 month ago

See also https://github.com/llvm/llvm-project/issues/59966