//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H #define TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H #include #include #include #include #include #include #include #include #include "test_macros.h" #if TEST_STD_VER >= 23 #include "almost_satisfies_types.h" #endif #if TEST_STD_VER >= 23 template struct RangeT { T* begin(); T* end(); }; static_assert(std::ranges::input_range>); template using BadRangeT = InputRangeNotDerivedFromGeneric; static_assert(std::ranges::range>); static_assert(!std::ranges::input_range>); #endif // `SFINAEs_away` template variable checks whether the template arguments for // a given template class `Instantiated` can be deduced from the given // constructor parameter types `CtrArgs` using CTAD. template class Instantiated, class ...CtrArgs, class = decltype(Instantiated(std::declval()...))> std::false_type SFINAEs_away_impl(int); template class Instantiated, class ...CtrArgs> std::true_type SFINAEs_away_impl(...); template class Instantiated, class ...CtrArgs> constexpr bool SFINAEs_away = decltype(SFINAEs_away_impl(0))::value; struct Empty {}; // For sequence containers the deduction guides should be SFINAE'd away when // given: // - "bad" input iterators (that is, a type not qualifying as an input // iterator); // - a bad allocator; // - a range not satisfying the `input_range` concept. template class Container, typename InstantiatedContainer, typename BadAlloc = Empty> constexpr void SequenceContainerDeductionGuidesSfinaeAway() { using T = typename InstantiatedContainer::value_type; using Alloc = std::allocator; using Iter = T*; // Note: the only requirement in the Standard is that integral types cannot be // considered input iterators; however, this doesn't work for sequence // containers because they have constructors of the form `(size_type count, // const value_type& value)`. These constructors would be used when passing // two integral types and would deduce `value_type` to be an integral type. #ifdef _LIBCPP_VERSION using OutputIter = std::insert_iterator; #endif // _LIBCPP_VERSION // (iter, iter) // // Cannot deduce from (BAD_iter, BAD_iter) LIBCPP_STATIC_ASSERT(SFINAEs_away); // (iter, iter, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, alloc) LIBCPP_STATIC_ASSERT(SFINAEs_away); // Cannot deduce from (iter, iter, BAD_alloc) static_assert(SFINAEs_away); // (alloc) // // Cannot deduce from (alloc) static_assert(SFINAEs_away); #if TEST_STD_VER >= 23 using BadRange = BadRangeT; // (from_range, range) // // Cannot deduce from (BAD_range) static_assert(SFINAEs_away); // (from_range, range, alloc) // // Cannot deduce from (range, BAD_alloc) static_assert(SFINAEs_away, BadAlloc>); #endif } // Deduction guides should be SFINAE'd away when given: // - a "bad" allocator (that is, a type not qualifying as an allocator); // - an allocator instead of a container; // - an allocator and a container that uses a different allocator; // - a range not satisfying the `input_range` concept. template class Container, typename InstantiatedContainer> constexpr void ContainerAdaptorDeductionGuidesSfinaeAway() { using T = typename InstantiatedContainer::value_type; using Alloc [[maybe_unused]] = std::allocator; using Iter = T*; using BadIter [[maybe_unused]] = int; using BadAlloc = Empty; // (container) -- no constraints. // (container, alloc) // // Cannot deduce from (container, BAD_alloc) static_assert(SFINAEs_away, BadAlloc>); // (iter, iter) // // Cannot deduce from (BAD_iter, BAD_iter) LIBCPP_STATIC_ASSERT(SFINAEs_away); #if TEST_STD_VER >= 23 using BadRange = BadRangeT; // (iter, iter, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, alloc) LIBCPP_STATIC_ASSERT(SFINAEs_away); // Cannot deduce from (iter, iter, BAD_alloc) static_assert(SFINAEs_away); // (from_range, range) // // Cannot deduce from (BAD_range) static_assert(SFINAEs_away); // (from_range, range, alloc) // // Cannot deduce from (range, BAD_alloc) static_assert(SFINAEs_away, BadAlloc>); #endif } // For associative containers the deduction guides should be SFINAE'd away when // given: // - "bad" input iterators (that is, a type not qualifying as an input // iterator); // - a bad allocator; // - an allocator in place of a comparator; // - a range not satisfying the `input_range` concept. template class Container, typename InstantiatedContainer> constexpr void AssociativeContainerDeductionGuidesSfinaeAway() { using ValueType = typename InstantiatedContainer::value_type; using Comp = std::less; using Alloc = std::allocator; using Iter = ValueType*; using InitList = std::initializer_list; struct BadAlloc {}; // The only requirement in the Standard is that integral types cannot be // considered input iterators, beyond that it is unspecified. using BadIter = int; #ifdef _LIBCPP_VERSION using OutputIter = std::insert_iterator; #endif // _LIBCPP_VERSION using AllocAsComp = Alloc; // (iter, iter) // // Cannot deduce from (BAD_iter, BAD_iter) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT(SFINAEs_away); // (iter, iter, comp) // // Cannot deduce from (BAD_iter, BAD_iter, comp) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT(SFINAEs_away); // (iter, iter, comp, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, comp, alloc) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT( SFINAEs_away); // Cannot deduce from (iter, iter, ALLOC_as_comp, alloc) static_assert(SFINAEs_away); // Cannot deduce from (iter, iter, comp, BAD_alloc) static_assert(SFINAEs_away); // (iter, iter, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, alloc) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT(SFINAEs_away); // Note: (iter, iter, BAD_alloc) is interpreted as (iter, iter, comp) // instead and fails upon instantiation. There is no requirement to SFINAE // away bad comparators. // (init_list, comp, alloc) // // Cannot deduce from (init_list, ALLOC_as_comp, alloc) static_assert(SFINAEs_away); // Cannot deduce from (init_list, comp, BAD_alloc) static_assert(SFINAEs_away); // (init_list, alloc) // // Note: (init_list, BAD_alloc) is interpreted as (init_list, comp) instead // and fails upon instantiation. There is no requirement to SFINAE away bad // comparators. #if TEST_STD_VER >= 23 using Range = RangeT; using BadRange = BadRangeT; // (from_range, range) // // Can deduce from (from_range, range) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range) static_assert(SFINAEs_away); // (from_range, range, comp) // // Can deduce from (from_range, _range, comp) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, comp) static_assert(SFINAEs_away); // (from_range, range, comp, alloc) // // Can deduce from (from_range, range, comp, alloc) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, comp, alloc) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, comp, BAD_alloc) static_assert(SFINAEs_away); // (from_range, range, alloc) // // Can deduce from (from_range, range, alloc) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, alloc) static_assert(SFINAEs_away); // Note: (from_range, range, BAD_alloc) is interpreted as (from_range, range, comp) instead. #endif } // For unordered containers the deduction guides should be SFINAE'd away when // given: // - "bad" input iterators (that is, a type not qualifying as an input // iterator); // - a bad allocator; // - a bad hash functor (an integral type in place of a hash); // - an allocator in place of a hash functor; // - an allocator in place of a predicate; // - a range not satisfying the `input_range` concept. template class Container, typename InstantiatedContainer> constexpr void UnorderedContainerDeductionGuidesSfinaeAway() { using ValueType = typename InstantiatedContainer::value_type; using Pred = std::equal_to; using Hash = std::hash; using Alloc = std::allocator; using Iter = ValueType*; using InitList = std::initializer_list; using BadHash = short; struct BadAlloc {}; // The only requirement in the Standard is that integral types cannot be // considered input iterators, beyond that it is unspecified. using BadIter = int; #ifdef _LIBCPP_VERSION using OutputIter = std::insert_iterator; #endif // _LIBCPP_VERSION using AllocAsHash = Alloc; using AllocAsPred = Alloc; // (iter, iter) // // Cannot deduce from (BAD_iter, BAD_iter) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT(SFINAEs_away); // (iter, iter, buckets) // // Cannot deduce from (BAD_iter, BAD_iter, buckets) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT(SFINAEs_away); // (iter, iter, buckets, hash) // // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT( SFINAEs_away); // Cannot deduce from (iter, iter, buckets, BAD_hash) static_assert(SFINAEs_away); // Note: (iter, iter, buckets, ALLOC_as_hash) is allowed -- it just calls // (iter, iter, buckets, alloc) // (iter, iter, buckets, hash, pred) // // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, pred) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT( SFINAEs_away); // Cannot deduce from (iter, iter, buckets, BAD_hash, pred) static_assert(SFINAEs_away); // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred) static_assert(SFINAEs_away); // Note: (iter, iter, buckets, hash, ALLOC_as_pred) is allowed -- it just // calls (iter, iter, buckets, hash, alloc) // (iter, iter, buckets, hash, pred, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, pred, alloc) static_assert( SFINAEs_away); LIBCPP_STATIC_ASSERT(SFINAEs_away); // Cannot deduce from (iter, iter, buckets, BAD_hash, pred, alloc) static_assert(SFINAEs_away); // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, pred, alloc) static_assert( SFINAEs_away); // Cannot deduce from (iter, iter, buckets, hash, ALLOC_as_pred, alloc) static_assert( SFINAEs_away); // Cannot deduce from (iter, iter, buckets, hash, pred, BAD_alloc) static_assert( SFINAEs_away); // (iter, iter, buckets, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, buckets, alloc) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT( SFINAEs_away); // Note: (iter, iter, buckets, BAD_alloc) is interpreted as (iter, iter, // buckets, hash), which is valid because the only requirement for the hash // parameter is that it's not integral. // (iter, iter, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, alloc) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT(SFINAEs_away); // Cannot deduce from (iter, iter, BAD_alloc) static_assert(SFINAEs_away); // (iter, iter, buckets, hash, alloc) // // Cannot deduce from (BAD_iter, BAD_iter, buckets, hash, alloc) static_assert(SFINAEs_away); LIBCPP_STATIC_ASSERT( SFINAEs_away); // Cannot deduce from (iter, iter, buckets, BAD_hash, alloc) static_assert(SFINAEs_away); // Cannot deduce from (iter, iter, buckets, ALLOC_as_hash, alloc) static_assert(SFINAEs_away); // Note: (iter, iter, buckets, hash, BAD_alloc) is interpreted as (iter, iter, // buckets, hash, pred), which is valid because there are no requirements for // the predicate. // (init_list, buckets, hash) // // Cannot deduce from (init_list, buckets, BAD_hash) static_assert(SFINAEs_away); // Note: (init_list, buckets, ALLOC_as_hash) is interpreted as (init_list, // buckets, alloc), which is valid. // (init_list, buckets, hash, pred) // // Cannot deduce from (init_list, buckets, BAD_hash, pred) static_assert(SFINAEs_away); // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred) static_assert(SFINAEs_away); // Note: (init_list, buckets, hash, ALLOC_as_pred) is interpreted as // (init_list, buckets, hash, alloc), which is valid. // (init_list, buckets, hash, pred, alloc) // // Cannot deduce from (init_list, buckets, BAD_hash, pred, alloc) static_assert( SFINAEs_away); // Cannot deduce from (init_list, buckets, ALLOC_as_hash, pred, alloc) static_assert( SFINAEs_away); // Cannot deduce from (init_list, buckets, hash, ALLOC_as_pred, alloc) static_assert( SFINAEs_away); // Cannot deduce from (init_list, buckets, hash, pred, BAD_alloc) static_assert( SFINAEs_away); // (init_list, buckets, alloc) // // Note: (init_list, buckets, BAD_alloc) is interpreted as (init_list, // buckets, hash), which is valid because the only requirement for the hash // parameter is that it's not integral. // (init_list, buckets, hash, alloc) // // Cannot deduce from (init_list, buckets, BAD_hash, alloc) static_assert(SFINAEs_away); // Cannot deduce from (init_list, buckets, ALLOC_as_hash, alloc) static_assert(SFINAEs_away); // (init_list, alloc) // // Cannot deduce from (init_list, BAD_alloc) static_assert(SFINAEs_away); #if TEST_STD_VER >= 23 using Range = RangeT; using BadRange = BadRangeT; // (from_range, range) // // Can deduce from (from_range, range) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range) static_assert(SFINAEs_away); // (from_range, range, buckets) // // Can deduce from (from_range, range, buckets) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, buckets) static_assert(SFINAEs_away); // (from_range, range, buckets, hash) // // Can deduce from (from_range, range, buckets, hash) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, buckets, hash) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, buckets, BAD_hash) static_assert(SFINAEs_away); // (from_range, range, buckets, hash, pred) // // Can deduce from (from_range, range, buckets, hash, pred) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, buckets, hash, pred) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, buckets, BAD_hash, pred) static_assert(SFINAEs_away); // (from_range, range, buckets, hash, pred, alloc) // // Can deduce from (from_range, range, buckets, hash, pred, alloc) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, buckets, hash, pred, alloc) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, buckets, BAD_hash, pred, alloc) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, buckets, hash, pred, BAD_alloc) static_assert(SFINAEs_away); // (from_range, range, buckets, alloc) // // Can deduce from (from_range, range, buckets, alloc) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, buckets, alloc) static_assert(SFINAEs_away); // Note: (from_range, range, buckets, BAD_alloc) is interpreted as (from_range, range, buckets, hash), which is valid // because the only requirement for the hash parameter is that it's not integral. // (from_range, range, alloc) // // Can deduce from (from_range, range, alloc) // TODO(LWG 2713): uncomment this test once the constructor is added. // static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, alloc) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, BAD_alloc) static_assert(SFINAEs_away); // (from_range, range, buckets, hash, alloc) // // Can deduce from (from_range, range, buckets, hash, alloc) static_assert(!SFINAEs_away); // Cannot deduce from (from_range, BAD_range, buckets, hash, alloc) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, buckets, BAD_hash, alloc) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, buckets, ALLOC_as_hash, alloc) static_assert(SFINAEs_away); // Cannot deduce from (from_range, range, buckets, hash, BAD_alloc) // Note: (from_range, range, buckets, hash, BAD_alloc) is interpreted as (from_range, range, buckets, hash, pred), // which is valid because the only requirement for the predicate parameter is that it does not resemble an allocator. #endif } #endif // TEST_SUPPORT_DEDUCTION_GUIDES_SFINAE_CHECKS_H