| // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=c++17 -Wno-vla-cxx-extension %s |
| // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=c++20 -Wno-vla-cxx-extension %s |
| |
| #if !__has_builtin(__builtin_common_type) |
| # error |
| #endif |
| |
| // expected-note@*:* {{template declaration from hidden source: template <template <class ...> class, template <class> class, class, class ...>}} |
| |
| void test() { |
| __builtin_common_type<> a; // expected-error {{too few template arguments for template '__builtin_common_type'}} |
| __builtin_common_type<1> b; // expected-error {{template argument for template template parameter must be a class template or type alias template}} |
| __builtin_common_type<int, 1> c; // expected-error {{template argument for template template parameter must be a class template or type alias template}} |
| } |
| |
| struct empty_type {}; |
| |
| template <class T> |
| struct type_identity { |
| using type = T; |
| }; |
| |
| template <class...> |
| struct common_type; |
| |
| template <class... Args> |
| using common_type_t = typename common_type<Args...>::type; |
| |
| void test_vla() { |
| int i = 4; |
| int VLA[i]; |
| __builtin_common_type<common_type_t, type_identity, empty_type, decltype(VLA)> d; // expected-error {{variably modified type 'decltype(VLA)' (aka 'int[i]') cannot be used as a template argument}} |
| } |
| |
| template <class... Args> |
| using common_type_base = __builtin_common_type<common_type_t, type_identity, empty_type, Args...>; |
| // expected-note@-1 {{in instantiation of default function argument expression for 'InvalidConversion<void>' required here}} |
| |
| template <class... Args> |
| struct common_type : common_type_base<Args...> {}; |
| |
| struct Incomplete; |
| |
| template<> |
| struct common_type<Incomplete, Incomplete>; |
| |
| static_assert(__is_same(common_type_base<>, empty_type)); |
| static_assert(__is_same(common_type_base<Incomplete>, empty_type)); |
| static_assert(__is_same(common_type_base<char>, type_identity<char>)); |
| static_assert(__is_same(common_type_base<int>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<const int>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<volatile int>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<const volatile int>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<int[]>, type_identity<int*>)); |
| static_assert(__is_same(common_type_base<const int[]>, type_identity<const int*>)); |
| static_assert(__is_same(common_type_base<void(&)()>, type_identity<void(*)()>)); |
| static_assert(__is_same(common_type_base<int[], int[]>, type_identity<int*>)); |
| |
| static_assert(__is_same(common_type_base<int, int>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<int, long>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<long, int>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<long, long>, type_identity<long>)); |
| |
| static_assert(__is_same(common_type_base<const int, long>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<const volatile int, long>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<int, const long>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<int, const volatile long>, type_identity<long>)); |
| |
| static_assert(__is_same(common_type_base<int*, long*>, empty_type)); |
| |
| static_assert(__is_same(common_type_base<int, long, float>, type_identity<float>)); |
| static_assert(__is_same(common_type_base<unsigned, char, long>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<long long, long long, long>, type_identity<long long>)); |
| |
| static_assert(__is_same(common_type_base<int [[clang::address_space(1)]]>, type_identity<int [[clang::address_space(1)]]>)); |
| static_assert(__is_same(common_type_base<int [[clang::address_space(1)]], int>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], int>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], int [[clang::address_space(1)]]>, type_identity<long>)); |
| static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], long [[clang::address_space(1)]]>, type_identity<long [[clang::address_space(1)]]>)); |
| static_assert(__is_same(common_type_base<long [[clang::address_space(1)]], long [[clang::address_space(2)]]>, type_identity<long>)); |
| |
| struct S {}; |
| struct T : S {}; |
| |
| static_assert(__is_same(common_type_base<int S::*, int S::*>, type_identity<int S::*>)); |
| static_assert(__is_same(common_type_base<int S::*, int T::*>, type_identity<int T::*>)); |
| static_assert(__is_same(common_type_base<int S::*, long S::*>, empty_type)); |
| |
| static_assert(__is_same(common_type_base<int (S::*)(), int (S::*)()>, type_identity<int (S::*)()>)); |
| static_assert(__is_same(common_type_base<int (S::*)(), int (T::*)()>, type_identity<int (T::*)()>)); |
| static_assert(__is_same(common_type_base<int (S::*)(), long (S::*)()>, empty_type)); |
| |
| struct NoCommonType {}; |
| |
| template <> |
| struct common_type<NoCommonType, NoCommonType> {}; |
| |
| struct CommonTypeInt {}; |
| |
| template <> |
| struct common_type<CommonTypeInt, CommonTypeInt> { |
| using type = int; |
| }; |
| |
| template <> |
| struct common_type<CommonTypeInt, int> { |
| using type = int; |
| }; |
| |
| template <> |
| struct common_type<int, CommonTypeInt> { |
| using type = int; |
| }; |
| |
| static_assert(__is_same(common_type_base<NoCommonType>, empty_type)); |
| static_assert(__is_same(common_type_base<CommonTypeInt>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<NoCommonType, NoCommonType, NoCommonType>, empty_type)); |
| static_assert(__is_same(common_type_base<CommonTypeInt, CommonTypeInt, CommonTypeInt>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<CommonTypeInt&, CommonTypeInt&&>, type_identity<int>)); |
| |
| static_assert(__is_same(common_type_base<void, int>, empty_type)); |
| static_assert(__is_same(common_type_base<void, void>, type_identity<void>)); |
| static_assert(__is_same(common_type_base<const void, void>, type_identity<void>)); |
| static_assert(__is_same(common_type_base<void, const void>, type_identity<void>)); |
| |
| template <class T> |
| struct ConvertibleTo { |
| operator T(); |
| }; |
| |
| static_assert(__is_same(common_type_base<ConvertibleTo<int>>, type_identity<ConvertibleTo<int>>)); |
| static_assert(__is_same(common_type_base<ConvertibleTo<int>, int>, type_identity<int>)); |
| static_assert(__is_same(common_type_base<ConvertibleTo<int&>, ConvertibleTo<long&>>, type_identity<long>)); |
| |
| struct ConvertibleToB; |
| |
| struct ConvertibleToA { |
| operator ConvertibleToB(); |
| }; |
| |
| struct ConvertibleToB { |
| operator ConvertibleToA(); |
| }; |
| |
| static_assert(__is_same(common_type_base<ConvertibleToA, ConvertibleToB>, empty_type)); |
| |
| struct const_ref_convertible { |
| operator int&() const &; |
| operator int&() && = delete; |
| }; |
| |
| #if __cplusplus >= 202002L |
| static_assert(__is_same(common_type_base<const_ref_convertible, int &>, type_identity<int>)); |
| #else |
| static_assert(__is_same(common_type_base<const_ref_convertible, int &>, empty_type)); |
| #endif |
| |
| struct WeirdConvertible_1p2_p3 {}; |
| |
| struct WeirdConvertible3 { |
| operator WeirdConvertible_1p2_p3(); |
| }; |
| |
| struct WeirdConvertible1p2 { |
| operator WeirdConvertible_1p2_p3(); |
| }; |
| |
| template <> |
| struct common_type<WeirdConvertible3, WeirdConvertible1p2> { |
| using type = WeirdConvertible_1p2_p3; |
| }; |
| |
| template <> |
| struct common_type<WeirdConvertible1p2, WeirdConvertible3> { |
| using type = WeirdConvertible_1p2_p3; |
| }; |
| |
| struct WeirdConvertible1 { |
| operator WeirdConvertible1p2(); |
| }; |
| |
| struct WeirdConvertible2 { |
| operator WeirdConvertible1p2(); |
| }; |
| |
| template <> |
| struct common_type<WeirdConvertible1, WeirdConvertible2> { |
| using type = WeirdConvertible1p2; |
| }; |
| |
| template <> |
| struct common_type<WeirdConvertible2, WeirdConvertible1> { |
| using type = WeirdConvertible1p2; |
| }; |
| |
| static_assert(__is_same(common_type_base<WeirdConvertible1, WeirdConvertible2, WeirdConvertible3>, |
| type_identity<WeirdConvertible_1p2_p3>)); |
| |
| struct PrivateTypeMember |
| { |
| operator int(); |
| }; |
| |
| template<> |
| struct common_type<PrivateTypeMember, PrivateTypeMember> |
| { |
| private: |
| using type = int; |
| }; |
| |
| static_assert(__is_same(common_type_base<PrivateTypeMember, PrivateTypeMember, PrivateTypeMember>, empty_type)); |
| |
| class PrivateConstructor { |
| private: |
| PrivateConstructor(int); |
| }; |
| |
| static_assert(__is_same(common_type_base<int, PrivateConstructor>, empty_type)); |
| |
| // expected-note@+1 {{in instantiation of template type alias 'common_type_base' requested here}} |
| template<typename A, typename B, typename Res = common_type_base<A, B>> |
| static Res common_type_sfinae(); |
| // expected-note@-1 {{in instantiation of default argument for 'common_type_sfinae<int, InvalidConversion>' required here}} |
| |
| // Make sure we don't emit "calling a private constructor" in SFINAE context ... |
| static_assert(__is_same(decltype(common_type_sfinae<int, PrivateConstructor>()), empty_type)); |
| |
| // ... but we still emit errors outside of the immediate context. |
| template<typename T> |
| struct Member { |
| T t; // expected-error {{field has incomplete type 'void'}} |
| }; |
| |
| // The conversion from int has a non-SFINAE error. |
| class InvalidConversion { |
| private: |
| template<typename T = void> |
| InvalidConversion(int, Member<T> = {}); |
| // expected-note@-1 {{in instantiation of template class 'Member<void>' requested here}} |
| // expected-note@-2 {{passing argument to parameter here}} |
| }; |
| |
| // expected-note@+1 {{while substituting deduced template arguments into function template 'common_type_sfinae'}} |
| static_assert(__is_same(decltype(common_type_sfinae<int, InvalidConversion>()), empty_type)); |