diff --git a/llvm/include/llvm/ADT/FunctionExtras.h b/llvm/include/llvm/ADT/FunctionExtras.h --- a/llvm/include/llvm/ADT/FunctionExtras.h +++ b/llvm/include/llvm/ADT/FunctionExtras.h @@ -89,13 +89,24 @@ // The heuristic used is related to common ABI register passing conventions. // It doesn't have to be exact though, and in one way it is more strict // because we want to still be able to observe either moves *or* copies. + template struct AdjustedParamTBase { + static_assert(!std::is_reference::value, + "references should be handled by template specialization"); + using type = typename std::conditional< + llvm::is_trivially_copy_constructible::value && + llvm::is_trivially_move_constructible::value && + IsSizeLessThanThresholdT::value, + T, T &>::type; + }; + + // This specialization ensures that 'AdjustedParam&>' or + // 'AdjustedParam&&>' does not trigger a compile-time error when 'T' is + // an incomplete type and V a templated type. + template struct AdjustedParamTBase { using type = T &; }; + template struct AdjustedParamTBase { using type = T &; }; + template - using AdjustedParamT = typename std::conditional< - !std::is_reference::value && - llvm::is_trivially_copy_constructible::value && - llvm::is_trivially_move_constructible::value && - IsSizeLessThanThresholdT::value, - T, T &>::type; + using AdjustedParamT = typename AdjustedParamTBase::type; // The type of the erased function pointer we use as a callback to dispatch to // the stored callable when it is trivial to move and destroy. diff --git a/llvm/unittests/ADT/FunctionExtrasTest.cpp b/llvm/unittests/ADT/FunctionExtrasTest.cpp --- a/llvm/unittests/ADT/FunctionExtrasTest.cpp +++ b/llvm/unittests/ADT/FunctionExtrasTest.cpp @@ -273,4 +273,22 @@ EXPECT_EQ("string", returns([] { return "hello"; })); } +// A forward declared type, and a templated type. +class Incomplete; +template class Templated { T A; }; + +// Check that we can define unique_function that have references to +// incomplete types, even if those types are templated over an +// incomplete type. +TEST(UniqueFunctionTest, IncompleteTypes) { + unique_function &&)> + IncompleteArgumentRValueReference; + unique_function &)> + IncompleteArgumentLValueReference; + unique_function *)> IncompleteArgumentPointer; + unique_function &()> IncompleteResultLValueReference; + unique_function && ()> IncompleteResultRValueReference2; + unique_function *()> IncompleteResultPointer; +} + } // anonymous namespace