https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/99473
This implements the logic of the `common_type` base template as a builtin alias. If there should be no `type` member, an empty class is returned. Otherwise a specialization of a `type_identity`-like class is returned. The base template (i.e. `std::common_type`) as well as the empty class and `type_identity`-like struct are given as arguments to the builtin. >From c893eb9db0b25eef0b1c9df8e711358c14bc8a63 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <nikolasklau...@berlin.de> Date: Tue, 16 Jul 2024 14:48:10 +0200 Subject: [PATCH] [Clang] Add __common_type builtin --- clang/include/clang/AST/ASTContext.h | 11 + clang/include/clang/AST/DeclID.h | 3 + clang/include/clang/Basic/Builtins.h | 5 +- clang/include/clang/Sema/Sema.h | 4 + clang/lib/AST/ASTContext.cpp | 8 + clang/lib/AST/ASTImporter.cpp | 3 + clang/lib/AST/DeclTemplate.cpp | 53 ++++ clang/lib/Lex/PPMacroExpansion.cpp | 1 + clang/lib/Sema/SemaChecking.cpp | 8 + clang/lib/Sema/SemaLookup.cpp | 4 + clang/lib/Sema/SemaTemplate.cpp | 154 ++++++++++- clang/test/AST/Interp/crash-GH49103-2.cpp | 4 +- clang/test/SemaCXX/crash-GH49103-2.cpp | 4 +- clang/test/SemaCXX/type-trait-common-type.cpp | 125 +++++++++ clang/test/SemaCXX/type-traits.cpp | 240 +++++++++--------- 15 files changed, 501 insertions(+), 126 deletions(-) create mode 100644 clang/test/SemaCXX/type-trait-common-type.cpp diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 57022e75073fe..867467d01f4d1 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -399,6 +399,9 @@ class ASTContext : public RefCountedBase<ASTContext> { /// The identifier '__type_pack_element'. mutable IdentifierInfo *TypePackElementName = nullptr; + /// The identifier '__common_type'. + mutable IdentifierInfo *CommonTypeName = nullptr; + QualType ObjCConstantStringType; mutable RecordDecl *CFConstantStringTagDecl = nullptr; mutable TypedefDecl *CFConstantStringTypeDecl = nullptr; @@ -606,6 +609,7 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable ExternCContextDecl *ExternCContext = nullptr; mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr; mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr; + mutable BuiltinTemplateDecl *CommonTypeDecl = nullptr; /// The associated SourceManager object. SourceManager &SourceMgr; @@ -1104,6 +1108,7 @@ class ASTContext : public RefCountedBase<ASTContext> { ExternCContextDecl *getExternCContextDecl() const; BuiltinTemplateDecl *getMakeIntegerSeqDecl() const; BuiltinTemplateDecl *getTypePackElementDecl() const; + BuiltinTemplateDecl *getCommonTypeDecl() const; // Builtin Types. CanQualType VoidTy; @@ -1981,6 +1986,12 @@ class ASTContext : public RefCountedBase<ASTContext> { return TypePackElementName; } + IdentifierInfo *getCommonTypeName() const { + if (!CommonTypeName) + CommonTypeName = &Idents.get("__common_type"); + return CommonTypeName; + } + /// Retrieve the Objective-C "instancetype" type, if already known; /// otherwise, returns a NULL type; QualType getObjCInstanceType() { diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h index e5e27389fac60..d8243773d8d98 100644 --- a/clang/include/clang/AST/DeclID.h +++ b/clang/include/clang/AST/DeclID.h @@ -84,6 +84,9 @@ enum PredefinedDeclIDs { /// The internal '__type_pack_element' template. PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17, + + /// The internal '__common_type' template. + PREDEF_DECL_COMMON_TYPE_ID = 17, }; /// The number of declaration IDs that are predefined. diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index f955d21169556..defffb334d480 100644 --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -304,7 +304,10 @@ enum BuiltinTemplateKind : int { BTK__make_integer_seq, /// This names the __type_pack_element BuiltinTemplateDecl. - BTK__type_pack_element + BTK__type_pack_element, + + /// This names the __common_type BuiltinTemplateDecl. + BTK__common_type, }; } // end namespace clang diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 48dff1b76cc57..1f9480418238a 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2282,6 +2282,10 @@ class Sema final : public SemaBase { /// Check to see if a given expression could have '.c_str()' called on it. bool hasCStrMethod(const Expr *E); + // Check whether a type member 'Type::Name' exists, and if yes, return the + // type. If there is no type, the QualType is null + QualType getTypeMember(StringRef Name, QualType Type); + /// Diagnose pointers that are always non-null. /// \param E the expression containing the pointer /// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6c89e3890ae3e..4000c2c2d6836 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1170,6 +1170,14 @@ ASTContext::getTypePackElementDecl() const { return TypePackElementDecl; } +BuiltinTemplateDecl * +ASTContext::getCommonTypeDecl() const { + if (!CommonTypeDecl) + CommonTypeDecl = + buildBuiltinTemplateDecl(BTK__common_type, getCommonTypeName()); + return CommonTypeDecl; +} + RecordDecl *ASTContext::buildImplicitRecord(StringRef Name, RecordDecl::TagKind TK) const { SourceLocation Loc; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 4e1b3a5a94de7..e9d8748d4ee37 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -5408,6 +5408,9 @@ ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) { case BuiltinTemplateKind::BTK__type_pack_element: ToD = Importer.getToContext().getTypePackElementDecl(); break; + case BuiltinTemplateKind::BTK__common_type: + ToD = Importer.getToContext().getCommonTypeDecl(); + break; } assert(ToD && "BuiltinTemplateDecl of unsupported kind!"); Importer.MapImported(D, ToD); diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 722c7fcf0b0df..d290c91fb8290 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1599,6 +1599,57 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) { nullptr); } +static TemplateParameterList *createCommonTypeList(const ASTContext &C, + DeclContext *DC) { + // class... Args + auto *Args = TemplateTypeParmDecl::Create( + C, DC, {}, {}, /*Depth=*/1, /*Position=*/0, /*Id=*/nullptr, + /*Typename=*/false, /*ParameterPack=*/true); + Args->setImplicit(); + + // <class... Args> + auto *BaseTemplateList = + TemplateParameterList::Create(C, {}, {}, Args, {}, nullptr); + + // template <class... Args> class BaseTemplate + auto *BaseTemplate = TemplateTemplateParmDecl::Create( + C, DC, {}, /*Depth=*/0, /*Position=*/0, /*ParameterPack=*/false, {}, + /*Typename=*/false, BaseTemplateList); + + // class TypeMember + auto *TypeMember = TemplateTypeParmDecl::Create( + C, DC, {}, {}, /*Depth=*/1, /*Position=*/0, /*Id=*/nullptr, + /*Typename=*/false, /*ParameterPack=*/false); + + // <class TypeMember> + auto *HasTypeMemberList = + TemplateParameterList::Create(C, {}, {}, TypeMember, {}, nullptr); + + // template <class TypeMember> class HasTypeMember + auto *HasTypeMember = + TemplateTemplateParmDecl::Create(C, DC, {}, /*Depth=*/0, /*Position=*/1, + /*ParameterPack=*/false, {}, + /*Typename=*/false, HasTypeMemberList); + + // class HasNoTypeMember + auto *HasNoTypeMember = TemplateTypeParmDecl::Create( + C, DC, {}, {}, /*Depth=*/0, /*Position=*/2, /*Id=*/nullptr, + /*Typename=*/false, /*ParameterPack=*/false); + + // class... Ts + auto *Ts = TemplateTypeParmDecl::Create( + C, DC, {}, {}, /*Depth=*/0, /*Position=*/3, + /*Id=*/nullptr, /*Typename=*/false, /*ParameterPack=*/true); + Ts->setImplicit(); + + // template <template <class... Args> class BaseTemplate, + // template <class TypeMember> class HasTypeMember, class HasNoTypeMember, + // class... Ts> + return TemplateParameterList::Create( + C, {}, {}, {BaseTemplate, HasTypeMember, HasNoTypeMember, Ts}, {}, + nullptr); +} + static TemplateParameterList *createBuiltinTemplateParameterList( const ASTContext &C, DeclContext *DC, BuiltinTemplateKind BTK) { switch (BTK) { @@ -1606,6 +1657,8 @@ static TemplateParameterList *createBuiltinTemplateParameterList( return createMakeIntegerSeqParameterList(C, DC); case BTK__type_pack_element: return createTypePackElementParameterList(C, DC); + case BTK__common_type: + return createCommonTypeList(C, DC); } llvm_unreachable("unhandled BuiltinTemplateKind!"); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 3913ff08c2eb5..4a6dd13229fe0 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1822,6 +1822,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Report builtin templates as being builtins. .Case("__make_integer_seq", getLangOpts().CPlusPlus) .Case("__type_pack_element", getLangOpts().CPlusPlus) + .Case("__common_type", getLangOpts().CPlusPlus) // Likewise for some builtin preprocessor macros. // FIXME: This is inconsistent; we usually suggest detecting // builtin macros via #ifdef. Don't add more cases here. diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 45b9bbb23dbf7..10c821fd367e7 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -6844,6 +6844,14 @@ CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { return Results; } +QualType Sema::getTypeMember(StringRef Name, QualType Type) { + auto Results = CXXRecordMembersNamed<TypeDecl>(Name, *this, Type); + assert(Results.size() <= 1); + if (Results.empty()) + return {}; + return Context.getTypeDeclType(*Results.begin()); +} + /// Check if we could call '.c_str()' on an object. /// /// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 7a6a64529f52e..96551c5106b1b 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -932,6 +932,10 @@ bool Sema::LookupBuiltin(LookupResult &R) { R.addDecl(getASTContext().getTypePackElementDecl()); return true; } + if (II == getASTContext().getCommonTypeName()) { + R.addDecl(getASTContext().getCommonTypeDecl()); + return true; + } } // Check if this is an OpenCL Builtin, and if so, insert its overloads. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9d96201625389..3f862d06af502 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3058,6 +3058,136 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { } } +static std::optional<QualType> +commonTypeImpl(Sema &S, TemplateName BaseTemplate, + SourceLocation TemplateLoc, ArrayRef<TemplateArgument> Ts) { + auto lookUpCommonType = [&](TemplateArgument T1, + TemplateArgument T2) -> std::optional<QualType> { + // Don't bother looking for other specializations if both types are + // builtins - users aren't allowed to specialize for them + if (T1.getAsType()->isBuiltinType() && T2.getAsType()->isBuiltinType()) + return commonTypeImpl(S, BaseTemplate, TemplateLoc, {T1, T2}); + + TemplateArgumentListInfo Args; + Args.addArgument(TemplateArgumentLoc( + T1, S.Context.getTrivialTypeSourceInfo(T1.getAsType()))); + Args.addArgument(TemplateArgumentLoc( + T2, S.Context.getTrivialTypeSourceInfo(T2.getAsType()))); + QualType BaseTemplateInst = + S.CheckTemplateIdType(BaseTemplate, TemplateLoc, Args); + if (S.RequireCompleteType(TemplateLoc, BaseTemplateInst, + diag::err_incomplete_type)) + return std::nullopt; + if (QualType Type = S.getTypeMember("type", BaseTemplateInst); + !Type.isNull()) { + return Type; + } + return std::nullopt; + }; + + // Note A: For the common_type trait applied to a template parameter pack T of + // types, the member type shall be either defined or not present as follows: + switch (Ts.size()) { + + // If sizeof...(T) is zero, there shall be no member type. + case 0: + return std::nullopt; + + // If sizeof...(T) is one, let T0 denote the sole type constituting the + // pack T. The member typedef-name type shall denote the same type, if any, as + // common_type_t<T0, T0>; otherwise there shall be no member type. + case 1: + return lookUpCommonType(Ts[0], Ts[0]); + + // If sizeof...(T) is two, let the first and second types constituting T be + // denoted by T1 and T2, respectively, and let D1 and D2 denote the same types + // as decay_t<T1> and decay_t<T2>, respectively. + case 2: { + QualType T1 = Ts[0].getAsType(); + QualType T2 = Ts[1].getAsType(); + QualType D1 = S.BuiltinDecay(T1, {}); + QualType D2 = S.BuiltinDecay(T2, {}); + + // If is_same_v<T1, D1> is false or is_same_v<T2, D2> is false, let C denote + // the same type, if any, as common_type_t<D1, D2>. + if (!S.Context.hasSameType(T1, D1) || !S.Context.hasSameType(T2, D2)) { + return lookUpCommonType(D1, D2); + } + + // Otherwise, if decay_t<decltype(false ? declval<D1>() : declval<D2>())> + // denotes a valid type, let C denote that type. + { + auto CheckConditionalOperands = + [&](bool ConstRefQual) -> std::optional<QualType> { + EnterExpressionEvaluationContext UnevaluatedContext( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); + + // false + OpaqueValueExpr CondExpr({}, S.Context.BoolTy, + ExprValueKind::VK_PRValue); + ExprResult Cond = &CondExpr; + + // declval<D1>() + auto EVK = ConstRefQual ? ExprValueKind::VK_LValue + : ExprValueKind::VK_PRValue; + if (ConstRefQual) { + D1.addConst(); + D2.addConst(); + } + OpaqueValueExpr LHSExpr(TemplateLoc, D1, EVK); + ExprResult LHS = &LHSExpr; + + // declval<D2>() + OpaqueValueExpr RHSExpr(TemplateLoc, D2, EVK); + ExprResult RHS = &RHSExpr; + + ExprValueKind VK = VK_PRValue; + ExprObjectKind OK = OK_Ordinary; + + QualType Result = + S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, TemplateLoc); + + if (Result.isNull() || SFINAE.hasErrorOccurred()) + return std::nullopt; + return Result; + }; + + if (auto Res = CheckConditionalOperands(false)) + return Res; + + // Let: + // CREF(A) be add_lvalue_reference_t<const remove_reference_t<A>>, + // COND-RES(X, Y) be + // decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()()). + + // C++20 only + // Otherwise, if COND-RES(CREF(D1), CREF(D2)) denotes a type, let C denote + // the type decay_t<COND-RES(CREF(D1), CREF(D2))>. + if (!S.Context.getLangOpts().CPlusPlus20) + return std::nullopt; + return CheckConditionalOperands(true); + } + } + + // If sizeof...(T) is greater than two, let T1, T2, and R, respectively, + // denote the first, second, and (pack of) remaining types constituting T. Let + // C denote the same type, if any, as common_type_t<T1, T2>. If there is such + // a type C, the member typedef-name type shall denote the same type, if any, + // as common_type_t<C, R...>. Otherwise, there shall be no member type. + default: { + std::optional<QualType> Result = Ts[Ts.size() - 1].getAsType(); + for (size_t i = Ts.size() - 1; i != 0; --i) { + Result = lookUpCommonType(Ts[i - 1].getAsType(), *Result); + if (!Result) + return std::nullopt; + } + return Result; + } + } +} + static QualType checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, ArrayRef<TemplateArgument> Converted, @@ -3114,7 +3244,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, TemplateLoc, SyntheticTemplateArgs); } - case BTK__type_pack_element: + case BTK__type_pack_element: { // Specializations of // __type_pack_element<Index, T_1, ..., T_N> // are treated like T_Index. @@ -3140,6 +3270,28 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, int64_t N = Index.getExtValue(); return Ts.getPackAsArray()[N].getAsType(); } + + case BTK__common_type: + assert(Converted.size() == 4); + if (Converted[0].isDependent() || Converted[1].isDependent() || + Converted[2].isDependent() || Converted[3].isDependent()) + return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), + Converted); + + TemplateName BaseTemplate = Converted[0].getAsTemplate(); + TemplateName HasTypeMember = Converted[1].getAsTemplate(); + QualType HasNoTypeMember = Converted[2].getAsType(); + ArrayRef<TemplateArgument> Ts = Converted[3].getPackAsArray(); + if (auto CT = commonTypeImpl(SemaRef, BaseTemplate, TemplateLoc, Ts)) { + TemplateArgumentListInfo TAs; + TAs.addArgument(TemplateArgumentLoc( + TemplateArgument(*CT), SemaRef.Context.getTrivialTypeSourceInfo( + *CT, TemplateArgs[1].getLocation()))); + + return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs); + } + return HasNoTypeMember; + } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } diff --git a/clang/test/AST/Interp/crash-GH49103-2.cpp b/clang/test/AST/Interp/crash-GH49103-2.cpp index 82d78e2aeab0c..98fb036a2a017 100644 --- a/clang/test/AST/Interp/crash-GH49103-2.cpp +++ b/clang/test/AST/Interp/crash-GH49103-2.cpp @@ -9,5 +9,5 @@ // https://github.com/llvm/llvm-project/issues/49103 template<class> struct A; // expected-note 0+ {{}} -struct S : __make_integer_seq<A, int, 42> { }; // expected-error 0+ {{}} -S s; +struct NoCommonType : __make_integer_seq<A, int, 42> { }; // expected-error 0+ {{}} +NoCommonType s; diff --git a/clang/test/SemaCXX/crash-GH49103-2.cpp b/clang/test/SemaCXX/crash-GH49103-2.cpp index 4c17a054c73af..d2a831e43b803 100644 --- a/clang/test/SemaCXX/crash-GH49103-2.cpp +++ b/clang/test/SemaCXX/crash-GH49103-2.cpp @@ -9,5 +9,5 @@ // https://github.com/llvm/llvm-project/issues/49103 template<class> struct A; // expected-note 0+ {{}} -struct S : __make_integer_seq<A, int, 42> { }; // expected-error 0+ {{}} -S s; +struct NoCommonType : __make_integer_seq<A, int, 42> { }; // expected-error 0+ {{}} +NoCommonType s; diff --git a/clang/test/SemaCXX/type-trait-common-type.cpp b/clang/test/SemaCXX/type-trait-common-type.cpp new file mode 100644 index 0000000000000..d9ce9c15dad4d --- /dev/null +++ b/clang/test/SemaCXX/type-trait-common-type.cpp @@ -0,0 +1,125 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s + +#if !__has_builtin(__common_type) +# error +#endif + +// expected-note@*:* {{template declaration from hidden source: template <class, template <class> class, class>}} + +void test() { + __common_type<> a; // expected-error {{too few template arguments for template '__common_type'}} +} + +struct empty_type {}; + +template <class T> +struct type_identity { + using type = T; +}; + +template <class...> +struct common_type; + +template <class... Args> +using common_type_base = __common_type<common_type, type_identity, empty_type, Args...>; // expected-error {{incomplete type 'common_type<Incomplete, Incomplete>' where a complete type is required}} + +template <class... Args> +struct common_type : common_type_base<Args...> {}; + +struct Incomplete; + +template<> +struct common_type<Incomplete, Incomplete>; // expected-note {{forward declaration}} + +static_assert(__is_same(common_type_base<>, empty_type)); +static_assert(__is_same(common_type_base<Incomplete>, empty_type)); // expected-note {{requested here}} +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>)); + +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 diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 7adbf4aad7afe..efcbdd18b6e75 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -4135,7 +4135,7 @@ void test_errors() { } } -struct S {}; +struct NoCommonType {}; template <class T> using remove_const_t = __remove_const(T); void check_remove_const() { @@ -4157,14 +4157,14 @@ void check_remove_const() { static_assert(__is_same(remove_const_t<int (*const)()>, int (*)())); static_assert(__is_same(remove_const_t<int (&)()>, int (&)())); - static_assert(__is_same(remove_const_t<S>, S)); - static_assert(__is_same(remove_const_t<const S>, S)); - static_assert(__is_same(remove_const_t<volatile S>, volatile S)); - static_assert(__is_same(remove_const_t<S *__restrict>, S *__restrict)); - static_assert(__is_same(remove_const_t<const volatile S>, volatile S)); - static_assert(__is_same(remove_const_t<S *const volatile __restrict>, S *volatile __restrict)); - static_assert(__is_same(remove_const_t<int S::*const>, int S::*)); - static_assert(__is_same(remove_const_t<int (S::*const)()>, int(S::*)())); + static_assert(__is_same(remove_const_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_const_t<const NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_const_t<volatile NoCommonType>, volatile NoCommonType)); + static_assert(__is_same(remove_const_t<NoCommonType *__restrict>, NoCommonType *__restrict)); + static_assert(__is_same(remove_const_t<const volatile NoCommonType>, volatile NoCommonType)); + static_assert(__is_same(remove_const_t<NoCommonType *const volatile __restrict>, NoCommonType *volatile __restrict)); + static_assert(__is_same(remove_const_t<int NoCommonType::*const>, int NoCommonType::*)); + static_assert(__is_same(remove_const_t<int (NoCommonType::*const)()>, int(NoCommonType::*)())); } template <class T> using remove_restrict_t = __remove_restrict(T); @@ -4186,13 +4186,13 @@ void check_remove_restrict() { static_assert(__is_same(remove_restrict_t<int (*const volatile)()>, int (*const volatile)())); static_assert(__is_same(remove_restrict_t<int (&)()>, int (&)())); - static_assert(__is_same(remove_restrict_t<S>, S)); - static_assert(__is_same(remove_restrict_t<const S>, const S)); - static_assert(__is_same(remove_restrict_t<volatile S>, volatile S)); - static_assert(__is_same(remove_restrict_t<S *__restrict>, S *)); - static_assert(__is_same(remove_restrict_t<S *const volatile __restrict>, S *const volatile)); - static_assert(__is_same(remove_restrict_t<int S::*__restrict>, int S::*)); - static_assert(__is_same(remove_restrict_t<int (S::*const volatile)()>, int(S::*const volatile)())); + static_assert(__is_same(remove_restrict_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_restrict_t<const NoCommonType>, const NoCommonType)); + static_assert(__is_same(remove_restrict_t<volatile NoCommonType>, volatile NoCommonType)); + static_assert(__is_same(remove_restrict_t<NoCommonType *__restrict>, NoCommonType *)); + static_assert(__is_same(remove_restrict_t<NoCommonType *const volatile __restrict>, NoCommonType *const volatile)); + static_assert(__is_same(remove_restrict_t<int NoCommonType::*__restrict>, int NoCommonType::*)); + static_assert(__is_same(remove_restrict_t<int (NoCommonType::*const volatile)()>, int(NoCommonType::*const volatile)())); } template <class T> using remove_volatile_t = __remove_volatile(T); @@ -4217,12 +4217,12 @@ void check_remove_volatile() { static_assert(__is_same(remove_volatile_t<int (*volatile)()>, int (*)())); static_assert(__is_same(remove_volatile_t<int (&)()>, int (&)())); - static_assert(__is_same(remove_volatile_t<S>, S)); - static_assert(__is_same(remove_volatile_t<const S>, const S)); - static_assert(__is_same(remove_volatile_t<volatile S>, S)); - static_assert(__is_same(remove_volatile_t<const volatile S>, const S)); - static_assert(__is_same(remove_volatile_t<int S::*volatile>, int S::*)); - static_assert(__is_same(remove_volatile_t<int (S::*volatile)()>, int(S::*)())); + static_assert(__is_same(remove_volatile_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_volatile_t<const NoCommonType>, const NoCommonType)); + static_assert(__is_same(remove_volatile_t<volatile NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_volatile_t<const volatile NoCommonType>, const NoCommonType)); + static_assert(__is_same(remove_volatile_t<int NoCommonType::*volatile>, int NoCommonType::*)); + static_assert(__is_same(remove_volatile_t<int (NoCommonType::*volatile)()>, int(NoCommonType::*)())); } template <class T> using remove_cv_t = __remove_cv(T); @@ -4247,12 +4247,12 @@ void check_remove_cv() { static_assert(__is_same(remove_cv_t<int (*const volatile)()>, int (*)())); static_assert(__is_same(remove_cv_t<int (&)()>, int (&)())); - static_assert(__is_same(remove_cv_t<S>, S)); - static_assert(__is_same(remove_cv_t<const S>, S)); - static_assert(__is_same(remove_cv_t<volatile S>, S)); - static_assert(__is_same(remove_cv_t<const volatile S>, S)); - static_assert(__is_same(remove_cv_t<int S::*const volatile>, int S::*)); - static_assert(__is_same(remove_cv_t<int (S::*const volatile)()>, int(S::*)())); + static_assert(__is_same(remove_cv_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cv_t<const NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cv_t<volatile NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cv_t<const volatile NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cv_t<int NoCommonType::*const volatile>, int NoCommonType::*)); + static_assert(__is_same(remove_cv_t<int (NoCommonType::*const volatile)()>, int(NoCommonType::*)())); } template <class T> using add_pointer_t = __add_pointer(T); @@ -4273,15 +4273,15 @@ void add_pointer() { static_assert(__is_same(add_pointer_t<int (*)()>, int (**)())); static_assert(__is_same(add_pointer_t<int (&)()>, int (*)())); - static_assert(__is_same(add_pointer_t<S>, S *)); - static_assert(__is_same(add_pointer_t<const S>, const S *)); - static_assert(__is_same(add_pointer_t<volatile S>, volatile S *)); - static_assert(__is_same(add_pointer_t<const volatile S>, const volatile S *)); - static_assert(__is_same(add_pointer_t<int S::*>, int S::**)); - static_assert(__is_same(add_pointer_t<int (S::*)()>, int(S::**)())); + static_assert(__is_same(add_pointer_t<NoCommonType>, NoCommonType *)); + static_assert(__is_same(add_pointer_t<const NoCommonType>, const NoCommonType *)); + static_assert(__is_same(add_pointer_t<volatile NoCommonType>, volatile NoCommonType *)); + static_assert(__is_same(add_pointer_t<const volatile NoCommonType>, const volatile NoCommonType *)); + static_assert(__is_same(add_pointer_t<int NoCommonType::*>, int NoCommonType::**)); + static_assert(__is_same(add_pointer_t<int (NoCommonType::*)()>, int(NoCommonType::**)())); static_assert(__is_same(add_pointer_t<int __attribute__((address_space(1)))>, int __attribute__((address_space(1))) *)); - static_assert(__is_same(add_pointer_t<S __attribute__((address_space(2)))>, S __attribute__((address_space(2))) *)); + static_assert(__is_same(add_pointer_t<NoCommonType __attribute__((address_space(2)))>, NoCommonType __attribute__((address_space(2))) *)); } template <class T> using remove_pointer_t = __remove_pointer(T); @@ -4308,15 +4308,15 @@ void remove_pointer() { static_assert(__is_same(remove_pointer_t<int (*)()>, int())); static_assert(__is_same(remove_pointer_t<int (&)()>, int (&)())); - static_assert(__is_same(remove_pointer_t<S>, S)); - static_assert(__is_same(remove_pointer_t<const S>, const S)); - static_assert(__is_same(remove_pointer_t<volatile S>, volatile S)); - static_assert(__is_same(remove_pointer_t<const volatile S>, const volatile S)); - static_assert(__is_same(remove_pointer_t<int S::*>, int S::*)); - static_assert(__is_same(remove_pointer_t<int (S::*)()>, int(S::*)())); + static_assert(__is_same(remove_pointer_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_pointer_t<const NoCommonType>, const NoCommonType)); + static_assert(__is_same(remove_pointer_t<volatile NoCommonType>, volatile NoCommonType)); + static_assert(__is_same(remove_pointer_t<const volatile NoCommonType>, const volatile NoCommonType)); + static_assert(__is_same(remove_pointer_t<int NoCommonType::*>, int NoCommonType::*)); + static_assert(__is_same(remove_pointer_t<int (NoCommonType::*)()>, int(NoCommonType::*)())); static_assert(__is_same(remove_pointer_t<int __attribute__((address_space(1))) *>, int __attribute__((address_space(1))))); - static_assert(__is_same(remove_pointer_t<S __attribute__((address_space(2))) *>, S __attribute__((address_space(2))))); + static_assert(__is_same(remove_pointer_t<NoCommonType __attribute__((address_space(2))) *>, NoCommonType __attribute__((address_space(2))))); static_assert(__is_same(remove_pointer_t<int (^)(char)>, int (^)(char))); } @@ -4339,12 +4339,12 @@ void add_lvalue_reference() { static_assert(__is_same(add_lvalue_reference_t<int (*)()>, int (*&)())); static_assert(__is_same(add_lvalue_reference_t<int (&)()>, int (&)())); - static_assert(__is_same(add_lvalue_reference_t<S>, S &)); - static_assert(__is_same(add_lvalue_reference_t<const S>, const S &)); - static_assert(__is_same(add_lvalue_reference_t<volatile S>, volatile S &)); - static_assert(__is_same(add_lvalue_reference_t<const volatile S>, const volatile S &)); - static_assert(__is_same(add_lvalue_reference_t<int S::*>, int S::*&)); - static_assert(__is_same(add_lvalue_reference_t<int (S::*)()>, int(S::*&)())); + static_assert(__is_same(add_lvalue_reference_t<NoCommonType>, NoCommonType &)); + static_assert(__is_same(add_lvalue_reference_t<const NoCommonType>, const NoCommonType &)); + static_assert(__is_same(add_lvalue_reference_t<volatile NoCommonType>, volatile NoCommonType &)); + static_assert(__is_same(add_lvalue_reference_t<const volatile NoCommonType>, const volatile NoCommonType &)); + static_assert(__is_same(add_lvalue_reference_t<int NoCommonType::*>, int NoCommonType::*&)); + static_assert(__is_same(add_lvalue_reference_t<int (NoCommonType::*)()>, int(NoCommonType::*&)())); } template <class T> using add_rvalue_reference_t = __add_rvalue_reference(T); @@ -4365,12 +4365,12 @@ void add_rvalue_reference() { static_assert(__is_same(add_rvalue_reference_t<int (*)()>, int (*&&)())); static_assert(__is_same(add_rvalue_reference_t<int (&)()>, int (&)())); // reference collapsing - static_assert(__is_same(add_rvalue_reference_t<S>, S &&)); - static_assert(__is_same(add_rvalue_reference_t<const S>, const S &&)); - static_assert(__is_same(add_rvalue_reference_t<volatile S>, volatile S &&)); - static_assert(__is_same(add_rvalue_reference_t<const volatile S>, const volatile S &&)); - static_assert(__is_same(add_rvalue_reference_t<int S::*>, int S::*&&)); - static_assert(__is_same(add_rvalue_reference_t<int (S::*)()>, int(S::* &&)())); + static_assert(__is_same(add_rvalue_reference_t<NoCommonType>, NoCommonType &&)); + static_assert(__is_same(add_rvalue_reference_t<const NoCommonType>, const NoCommonType &&)); + static_assert(__is_same(add_rvalue_reference_t<volatile NoCommonType>, volatile NoCommonType &&)); + static_assert(__is_same(add_rvalue_reference_t<const volatile NoCommonType>, const volatile NoCommonType &&)); + static_assert(__is_same(add_rvalue_reference_t<int NoCommonType::*>, int NoCommonType::*&&)); + static_assert(__is_same(add_rvalue_reference_t<int (NoCommonType::*)()>, int(NoCommonType::* &&)())); } template <class T> using remove_reference_t = __remove_reference_t(T); @@ -4393,21 +4393,21 @@ void check_remove_reference() { static_assert(__is_same(remove_reference_t<int (*const volatile)()>, int (*const volatile)())); static_assert(__is_same(remove_reference_t<int (&)()>, int())); - static_assert(__is_same(remove_reference_t<S>, S)); - static_assert(__is_same(remove_reference_t<S &>, S)); - static_assert(__is_same(remove_reference_t<S &&>, S)); - static_assert(__is_same(remove_reference_t<const S>, const S)); - static_assert(__is_same(remove_reference_t<const S &>, const S)); - static_assert(__is_same(remove_reference_t<const S &&>, const S)); - static_assert(__is_same(remove_reference_t<volatile S>, volatile S)); - static_assert(__is_same(remove_reference_t<volatile S &>, volatile S)); - static_assert(__is_same(remove_reference_t<volatile S &&>, volatile S)); - static_assert(__is_same(remove_reference_t<const volatile S>, const volatile S)); - static_assert(__is_same(remove_reference_t<const volatile S &>, const volatile S)); - static_assert(__is_same(remove_reference_t<const volatile S &&>, const volatile S)); - static_assert(__is_same(remove_reference_t<int S::*const volatile &>, int S::*const volatile)); - static_assert(__is_same(remove_reference_t<int (S::*const volatile &)()>, int(S::*const volatile)())); - static_assert(__is_same(remove_reference_t<int (S::*const volatile &&)() &>, int(S::*const volatile)() &)); + static_assert(__is_same(remove_reference_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_reference_t<NoCommonType &>, NoCommonType)); + static_assert(__is_same(remove_reference_t<NoCommonType &&>, NoCommonType)); + static_assert(__is_same(remove_reference_t<const NoCommonType>, const NoCommonType)); + static_assert(__is_same(remove_reference_t<const NoCommonType &>, const NoCommonType)); + static_assert(__is_same(remove_reference_t<const NoCommonType &&>, const NoCommonType)); + static_assert(__is_same(remove_reference_t<volatile NoCommonType>, volatile NoCommonType)); + static_assert(__is_same(remove_reference_t<volatile NoCommonType &>, volatile NoCommonType)); + static_assert(__is_same(remove_reference_t<volatile NoCommonType &&>, volatile NoCommonType)); + static_assert(__is_same(remove_reference_t<const volatile NoCommonType>, const volatile NoCommonType)); + static_assert(__is_same(remove_reference_t<const volatile NoCommonType &>, const volatile NoCommonType)); + static_assert(__is_same(remove_reference_t<const volatile NoCommonType &&>, const volatile NoCommonType)); + static_assert(__is_same(remove_reference_t<int NoCommonType::*const volatile &>, int NoCommonType::*const volatile)); + static_assert(__is_same(remove_reference_t<int (NoCommonType::*const volatile &)()>, int(NoCommonType::*const volatile)())); + static_assert(__is_same(remove_reference_t<int (NoCommonType::*const volatile &&)() &>, int(NoCommonType::*const volatile)() &)); } template <class T> using remove_cvref_t = __remove_cvref(T); @@ -4432,22 +4432,22 @@ void check_remove_cvref() { static_assert(__is_same(remove_cvref_t<int (*const volatile)()>, int (*)())); static_assert(__is_same(remove_cvref_t<int (&)()>, int())); - static_assert(__is_same(remove_cvref_t<S>, S)); - static_assert(__is_same(remove_cvref_t<S &>, S)); - static_assert(__is_same(remove_cvref_t<S &&>, S)); - static_assert(__is_same(remove_cvref_t<const S>, S)); - static_assert(__is_same(remove_cvref_t<const S &>, S)); - static_assert(__is_same(remove_cvref_t<const S &&>, S)); - static_assert(__is_same(remove_cvref_t<volatile S>, S)); - static_assert(__is_same(remove_cvref_t<volatile S &>, S)); - static_assert(__is_same(remove_cvref_t<volatile S &&>, S)); - static_assert(__is_same(remove_cvref_t<const volatile S>, S)); - static_assert(__is_same(remove_cvref_t<const volatile S &>, S)); - static_assert(__is_same(remove_cvref_t<const volatile S &&>, S)); - static_assert(__is_same(remove_cvref_t<int S::*const volatile>, int S::*)); - static_assert(__is_same(remove_cvref_t<int (S::*const volatile)()>, int(S::*)())); - static_assert(__is_same(remove_cvref_t<int (S::*const volatile)() &>, int(S::*)() &)); - static_assert(__is_same(remove_cvref_t<int (S::*const volatile)() &&>, int(S::*)() &&)); + static_assert(__is_same(remove_cvref_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<NoCommonType &>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<NoCommonType &&>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<const NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<const NoCommonType &>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<const NoCommonType &&>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<volatile NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<volatile NoCommonType &>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<volatile NoCommonType &&>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<const volatile NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<const volatile NoCommonType &>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<const volatile NoCommonType &&>, NoCommonType)); + static_assert(__is_same(remove_cvref_t<int NoCommonType::*const volatile>, int NoCommonType::*)); + static_assert(__is_same(remove_cvref_t<int (NoCommonType::*const volatile)()>, int(NoCommonType::*)())); + static_assert(__is_same(remove_cvref_t<int (NoCommonType::*const volatile)() &>, int(NoCommonType::*)() &)); + static_assert(__is_same(remove_cvref_t<int (NoCommonType::*const volatile)() &&>, int(NoCommonType::*)() &&)); } template <class T> using decay_t = __decay(T); @@ -4477,28 +4477,28 @@ void check_decay() { static_assert(__is_same(decay_t<IntAr>, int *)); static_assert(__is_same(decay_t<IntArNB>, int *)); - static_assert(__is_same(decay_t<S>, S)); - static_assert(__is_same(decay_t<S &>, S)); - static_assert(__is_same(decay_t<S &&>, S)); - static_assert(__is_same(decay_t<const S>, S)); - static_assert(__is_same(decay_t<const S &>, S)); - static_assert(__is_same(decay_t<const S &&>, S)); - static_assert(__is_same(decay_t<volatile S>, S)); - static_assert(__is_same(decay_t<volatile S &>, S)); - static_assert(__is_same(decay_t<volatile S &&>, S)); - static_assert(__is_same(decay_t<const volatile S>, S)); - static_assert(__is_same(decay_t<const volatile S &>, S)); - static_assert(__is_same(decay_t<const volatile S &&>, S)); - static_assert(__is_same(decay_t<int S::*const volatile>, int S::*)); - static_assert(__is_same(decay_t<int (S::*const volatile)()>, int(S::*)())); - static_assert(__is_same(decay_t<int S::*const volatile &>, int S::*)); - static_assert(__is_same(decay_t<int (S::*const volatile &)()>, int(S::*)())); - static_assert(__is_same(decay_t<int S::*const volatile &&>, int S::*)); + static_assert(__is_same(decay_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(decay_t<NoCommonType &>, NoCommonType)); + static_assert(__is_same(decay_t<NoCommonType &&>, NoCommonType)); + static_assert(__is_same(decay_t<const NoCommonType>, NoCommonType)); + static_assert(__is_same(decay_t<const NoCommonType &>, NoCommonType)); + static_assert(__is_same(decay_t<const NoCommonType &&>, NoCommonType)); + static_assert(__is_same(decay_t<volatile NoCommonType>, NoCommonType)); + static_assert(__is_same(decay_t<volatile NoCommonType &>, NoCommonType)); + static_assert(__is_same(decay_t<volatile NoCommonType &&>, NoCommonType)); + static_assert(__is_same(decay_t<const volatile NoCommonType>, NoCommonType)); + static_assert(__is_same(decay_t<const volatile NoCommonType &>, NoCommonType)); + static_assert(__is_same(decay_t<const volatile NoCommonType &&>, NoCommonType)); + static_assert(__is_same(decay_t<int NoCommonType::*const volatile>, int NoCommonType::*)); + static_assert(__is_same(decay_t<int (NoCommonType::*const volatile)()>, int(NoCommonType::*)())); + static_assert(__is_same(decay_t<int NoCommonType::*const volatile &>, int NoCommonType::*)); + static_assert(__is_same(decay_t<int (NoCommonType::*const volatile &)()>, int(NoCommonType::*)())); + static_assert(__is_same(decay_t<int NoCommonType::*const volatile &&>, int NoCommonType::*)); } template <class T> struct CheckAbominableFunction {}; template <class M> -struct CheckAbominableFunction<M S::*> { +struct CheckAbominableFunction<M NoCommonType::*> { static void checks() { static_assert(__is_same(add_lvalue_reference_t<M>, M)); static_assert(__is_same(add_pointer_t<M>, M)); @@ -4516,17 +4516,17 @@ struct CheckAbominableFunction<M S::*> { }; void check_abominable_function() { - { CheckAbominableFunction<int (S::*)() &> x; } - { CheckAbominableFunction<int (S::*)() &&> x; } - { CheckAbominableFunction<int (S::*)() const> x; } - { CheckAbominableFunction<int (S::*)() const &> x; } - { CheckAbominableFunction<int (S::*)() const &&> x; } - { CheckAbominableFunction<int (S::*)() volatile> x; } - { CheckAbominableFunction<int (S::*)() volatile &> x; } - { CheckAbominableFunction<int (S::*)() volatile &&> x; } - { CheckAbominableFunction<int (S::*)() const volatile> x; } - { CheckAbominableFunction<int (S::*)() const volatile &> x; } - { CheckAbominableFunction<int (S::*)() const volatile &&> x; } + { CheckAbominableFunction<int (NoCommonType::*)() &> x; } + { CheckAbominableFunction<int (NoCommonType::*)() &&> x; } + { CheckAbominableFunction<int (NoCommonType::*)() const> x; } + { CheckAbominableFunction<int (NoCommonType::*)() const &> x; } + { CheckAbominableFunction<int (NoCommonType::*)() const &&> x; } + { CheckAbominableFunction<int (NoCommonType::*)() volatile> x; } + { CheckAbominableFunction<int (NoCommonType::*)() volatile &> x; } + { CheckAbominableFunction<int (NoCommonType::*)() volatile &&> x; } + { CheckAbominableFunction<int (NoCommonType::*)() const volatile> x; } + { CheckAbominableFunction<int (NoCommonType::*)() const volatile &> x; } + { CheckAbominableFunction<int (NoCommonType::*)() const volatile &&> x; } } template <class T> using make_signed_t = __make_signed(T); @@ -4756,9 +4756,9 @@ void remove_extent() { static_assert(__is_same(remove_extent_t<int (*)()>, int (*)())); static_assert(__is_same(remove_extent_t<int (&)()>, int (&)())); - static_assert(__is_same(remove_extent_t<S>, S)); - static_assert(__is_same(remove_extent_t<int S::*>, int S::*)); - static_assert(__is_same(remove_extent_t<int (S::*)()>, int(S::*)())); + static_assert(__is_same(remove_extent_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_extent_t<int NoCommonType::*>, int NoCommonType::*)); + static_assert(__is_same(remove_extent_t<int (NoCommonType::*)()>, int(NoCommonType::*)())); using SomeArray = int[1][2]; static_assert(__is_same(remove_extent_t<const SomeArray>, const int[2])); @@ -4795,9 +4795,9 @@ void remove_all_extents() { static_assert(__is_same(remove_all_extents_t<int (*)()>, int (*)())); static_assert(__is_same(remove_all_extents_t<int (&)()>, int (&)())); - static_assert(__is_same(remove_all_extents_t<S>, S)); - static_assert(__is_same(remove_all_extents_t<int S::*>, int S::*)); - static_assert(__is_same(remove_all_extents_t<int (S::*)()>, int(S::*)())); + static_assert(__is_same(remove_all_extents_t<NoCommonType>, NoCommonType)); + static_assert(__is_same(remove_all_extents_t<int NoCommonType::*>, int NoCommonType::*)); + static_assert(__is_same(remove_all_extents_t<int (NoCommonType::*)()>, int(NoCommonType::*)())); using SomeArray = int[1][2]; static_assert(__is_same(remove_all_extents_t<const SomeArray>, const int)); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits