diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 8f9774d78bd1..5b926864f0cc 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -2476,6 +2476,16 @@ bool hasNItemsOrLess(ContainerTy &&C, unsigned N) { template auto to_address(const Ptr &P) { return P.operator->(); } template constexpr T *to_address(T *P) { return P; } +// Detect incomplete types, relying on the fact that their size is unknown. +namespace detail { +template using has_sizeof = decltype(sizeof(T)); +} // namespace detail + +/// Detects when type `T` is incomplete. This is true for forward declarations +/// and false for types with a full definition. +template +constexpr bool is_incomplete_v = !is_detected::value; + } // end namespace llvm namespace std { diff --git a/llvm/unittests/ADT/STLExtrasTest.cpp b/llvm/unittests/ADT/STLExtrasTest.cpp index 278447166fc5..c34760d83874 100644 --- a/llvm/unittests/ADT/STLExtrasTest.cpp +++ b/llvm/unittests/ADT/STLExtrasTest.cpp @@ -1300,4 +1300,10 @@ TEST(STLExtrasTest, LessSecond) { } } +struct Foo; +struct Bar {}; + +static_assert(is_incomplete_v, "Foo is incomplete"); +static_assert(!is_incomplete_v, "Bar is defined"); + } // namespace