https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/121199
None >From e0db7316b2705398a2ac7e69cd1e3e83ece52613 Mon Sep 17 00:00:00 2001 From: Nikolas Klauser <nikolasklau...@berlin.de> Date: Fri, 27 Sep 2024 22:11:14 +0200 Subject: [PATCH] [Clang] Add __builtin_common_reference --- clang/docs/LanguageExtensions.rst | 17 ++ clang/include/clang/AST/ASTContext.h | 13 + clang/include/clang/AST/ASTNodeTraverser.h | 4 + clang/include/clang/AST/DeclID.h | 3 + clang/include/clang/AST/DeclTemplate.h | 37 +++ clang/include/clang/AST/RecursiveASTVisitor.h | 4 + clang/include/clang/Basic/Builtins.h | 3 + clang/include/clang/Basic/DeclNodes.td | 1 + clang/include/clang/Sema/Sema.h | 19 ++ clang/lib/AST/ASTContext.cpp | 31 ++ clang/lib/AST/ASTImporter.cpp | 3 + clang/lib/AST/DeclBase.cpp | 1 + clang/lib/AST/DeclTemplate.cpp | 102 +++++++ clang/lib/CodeGen/CGDecl.cpp | 1 + clang/lib/Lex/PPMacroExpansion.cpp | 1 + clang/lib/Sema/SemaExprCXX.cpp | 92 +----- clang/lib/Sema/SemaLookup.cpp | 4 + clang/lib/Sema/SemaTemplate.cpp | 275 ++++++++++++++++-- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 + clang/lib/Sema/SemaType.cpp | 73 +++++ clang/lib/Serialization/ASTCommon.cpp | 1 + clang/lib/Serialization/ASTReader.cpp | 6 + clang/lib/Serialization/ASTWriter.cpp | 2 + .../SemaCXX/type-trait-common-reference.cpp | 120 ++++++++ clang/tools/libclang/CIndex.cpp | 1 + .../include/__type_traits/common_reference.h | 36 ++- 26 files changed, 738 insertions(+), 117 deletions(-) create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 3d4f68b818bce7..09311f3e1233d9 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1546,6 +1546,23 @@ Builtin type aliases Clang provides a few builtin aliases to improve the throughput of certain metaprogramming facilities. +__builtin_common_reference +-------------------------- + +.. code-block:: c++ + + template <template <class, class, template <class> class, template <class> class> class BasicCommonReferenceT, + template <class... Args> CommonTypeT, + template <class> HasTypeMember, + class HasNoTypeMember, + class... Ts> + using __builtin_common_reference = ...; + +This alias is used for implementing ``std::common_refernce``. If ``std::common_reference`` should contain a ``type`` +member, it is an alias to ``HasTypeMember<TheCommonReference>``. Otherwse it is an alias to ``HasNoTypeMember``. The +``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` is usually an alias template to +``basic_common_reference<T, U, TX, UX>::type``. + __builtin_common_type --------------------- diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 1e89a6805ce9c6..3c18e73cdc391a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -419,6 +419,9 @@ class ASTContext : public RefCountedBase<ASTContext> { /// The identifier '__builtin_common_type'. mutable IdentifierInfo *BuiltinCommonTypeName = nullptr; + /// The identifier '__builtin_common_reference'. + mutable IdentifierInfo *BuiltinCommonReferenceName = nullptr; + QualType ObjCConstantStringType; mutable RecordDecl *CFConstantStringTagDecl = nullptr; mutable TypedefDecl *CFConstantStringTypeDecl = nullptr; @@ -627,6 +630,8 @@ class ASTContext : public RefCountedBase<ASTContext> { mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr; mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr; mutable BuiltinTemplateDecl *BuiltinCommonTypeDecl = nullptr; + mutable BuiltinTemplateDecl *BuiltinCommonReferenceDecl = nullptr; + mutable CVRefQualifyingTemplateDecl *CVRefQualifyingDecls[12] = {}; /// The associated SourceManager object. SourceManager &SourceMgr; @@ -1155,6 +1160,8 @@ class ASTContext : public RefCountedBase<ASTContext> { BuiltinTemplateDecl *getMakeIntegerSeqDecl() const; BuiltinTemplateDecl *getTypePackElementDecl() const; BuiltinTemplateDecl *getBuiltinCommonTypeDecl() const; + BuiltinTemplateDecl *getBuiltinCommonReferenceDecl() const; + CVRefQualifyingTemplateDecl *getCVRefQualifyingAliasDecl(QualType From) const; // Builtin Types. CanQualType VoidTy; @@ -2072,6 +2079,12 @@ class ASTContext : public RefCountedBase<ASTContext> { return BuiltinCommonTypeName; } + IdentifierInfo *getBuiltinCommonReferenceName() const { + if (!BuiltinCommonReferenceName) + BuiltinCommonReferenceName = &Idents.get("__builtin_common_reference"); + return BuiltinCommonReferenceName; + } + /// Retrieve the Objective-C "instancetype" type, if already known; /// otherwise, returns a NULL type; QualType getObjCInstanceType() { diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index f5652b295de168..993821b43b683c 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -684,6 +684,10 @@ class ASTNodeTraverser dumpTemplateParameters(D->getTemplateParameters()); } + void VisitCVRefQualifyingTemplateDecl(const CVRefQualifyingTemplateDecl *D) { + dumpTemplateParameters(D->getTemplateParameters()); + } + void VisitVarTemplateSpecializationDecl(const VarTemplateSpecializationDecl *D) { dumpTemplateArgumentList(D->getTemplateArgs()); diff --git a/clang/include/clang/AST/DeclID.h b/clang/include/clang/AST/DeclID.h index 49964b43c7d1d8..b1b1d18d762fdc 100644 --- a/clang/include/clang/AST/DeclID.h +++ b/clang/include/clang/AST/DeclID.h @@ -86,6 +86,9 @@ enum PredefinedDeclIDs { /// The internal '__builtin_common_type' template. PREDEF_DECL_COMMON_TYPE_ID, + /// The internal '__builtin_common_reference' template. + PREDEF_DECL_COMMON_REFERENCE_ID, + /// The number of declaration IDs that are predefined. NUM_PREDEF_DECL_IDS }; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index d3a466a8617bb1..b765e0d17c7119 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1777,6 +1777,43 @@ class BuiltinTemplateDecl : public TemplateDecl { BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; } }; +class CVRefQualifyingTemplateDecl : public TemplateDecl { +public: + // LValueRef and RValueRef are mutually exclusive + enum CVRefQuals { + None = 0x0, + Const = 0x1, + Volatile = 0x2, + LValueRef = 0x4, + RValueRef = 0x8, + LLVM_BITMASK_LARGEST_ENUMERATOR, + }; + +private: + CVRefQuals Quals; + + CVRefQualifyingTemplateDecl(const ASTContext &C, DeclContext *DC, + CVRefQuals Quals); + + void anchor() override; + +public: + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == CVRefQualifyingTemplate; } + + static CVRefQualifyingTemplateDecl *Create(const ASTContext &C, + DeclContext *DC, CVRefQuals Ref) { + return new (C, DC) CVRefQualifyingTemplateDecl(C, DC, Ref); + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return {}; + } + + CVRefQuals getQuals() { return Quals; } +}; + /// Provides information about an explicit instantiation of a variable or class /// template. struct ExplicitInstantiationInfo { diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index d9a87b30062df8..5a2131b51cb0a7 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1960,6 +1960,10 @@ DEF_TRAVERSE_DECL(BuiltinTemplateDecl, { TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); }) +DEF_TRAVERSE_DECL(CVRefQualifyingTemplateDecl, { + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); +}) + template <typename Derived> bool RecursiveASTVisitor<Derived>::TraverseTemplateTypeParamDeclConstraints( const TemplateTypeParmDecl *D) { diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h index e27d8ccce73664..17e616825f74b7 100644 --- a/clang/include/clang/Basic/Builtins.h +++ b/clang/include/clang/Basic/Builtins.h @@ -311,6 +311,9 @@ enum BuiltinTemplateKind : int { /// This names the __builtin_common_type BuiltinTemplateDecl. BTK__builtin_common_type, + + /// This names the __builtin_common_reference BuiltinTemplateDecl. + BTK__builtin_common_reference, }; } // end namespace clang diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 48396e85c5adac..3905504f0dfa7b 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -71,6 +71,7 @@ def Named : DeclNode<Decl, "named declarations", 1>; def TypeAliasTemplate : DeclNode<RedeclarableTemplate>; def TemplateTemplateParm : DeclNode<Template>; def BuiltinTemplate : DeclNode<Template>; + def CVRefQualifyingTemplate : DeclNode<Template>; def Concept : DeclNode<Template>; def BaseUsing : DeclNode<Named, "", 1>; def Using : DeclNode<BaseUsing>; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5ee7ea48cc983c..6dbec5a4b69447 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14897,15 +14897,34 @@ class Sema final : public SemaBase { QualType BuiltinDecay(QualType BaseType, SourceLocation Loc); QualType BuiltinAddReference(QualType BaseType, UTTKind UKind, SourceLocation Loc); + + QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) { + return BuiltinAddReference(BaseType, UnaryTransformType::AddRvalueReference, + Loc); + } + + QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) { + return BuiltinAddReference(BaseType, UnaryTransformType::AddLvalueReference, + Loc); + } + QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind, SourceLocation Loc); QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind, SourceLocation Loc); + + QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) { + return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc); + } + QualType BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind, SourceLocation Loc); QualType BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, SourceLocation Loc); + bool BuiltinIsConvertible(QualType From, QualType To, SourceLocation Loc, + bool CheckNothrow = false); + /// Ensure that the type T is a literal type. /// /// This routine checks whether the type @p T is a literal type. If @p T is an diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 6ec927e13a7552..5bd5cecf475052 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1218,6 +1218,37 @@ BuiltinTemplateDecl *ASTContext::getBuiltinCommonTypeDecl() const { return BuiltinCommonTypeDecl; } +BuiltinTemplateDecl *ASTContext::getBuiltinCommonReferenceDecl() const { + if (!BuiltinCommonReferenceDecl) + BuiltinCommonReferenceDecl = buildBuiltinTemplateDecl( + BTK__builtin_common_reference, getBuiltinCommonReferenceName()); + return BuiltinCommonReferenceDecl; +} + +CVRefQualifyingTemplateDecl * +ASTContext::getCVRefQualifyingAliasDecl(QualType From) const { + using CVRefQuals = CVRefQualifyingTemplateDecl::CVRefQuals; + + CVRefQuals Q = CVRefQuals::None; + if (From->isReferenceType()) { + Q |= From->isLValueReferenceType() ? CVRefQuals::LValueRef + : CVRefQuals::RValueRef; + From = From.getNonReferenceType(); + } + + if (From.isConstQualified()) + Q |= CVRefQuals::Const; + if (From.isVolatileQualified()) + Q |= CVRefQuals::Volatile; + auto *Decl = CVRefQualifyingDecls[Q]; + if (!Decl) + Decl = + CVRefQualifyingTemplateDecl::Create(*this, getTranslationUnitDecl(), Q); + Decl->setImplicit(); + getTranslationUnitDecl()->addDecl(Decl); + return Decl; +} + 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 26d33b0d94795f..e06194ecd1a852 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -5469,6 +5469,9 @@ ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) { case BuiltinTemplateKind::BTK__builtin_common_type: ToD = Importer.getToContext().getBuiltinCommonTypeDecl(); break; + case BuiltinTemplateKind::BTK__builtin_common_reference: + ToD = Importer.getToContext().getBuiltinCommonReferenceDecl(); + break; } assert(ToD && "BuiltinTemplateDecl of unsupported kind!"); Importer.MapImported(D, ToD); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index fb701f76231bcd..a5f99d5325f091 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -967,6 +967,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case UsingDirective: case BuiltinTemplate: + case CVRefQualifyingTemplate: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: case VarTemplateSpecialization: diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 40ee3753c24227..635e2eb3480cd2 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -306,6 +306,7 @@ bool TemplateDecl::isTypeAlias() const { switch (getKind()) { case TemplateDecl::TypeAliasTemplate: case TemplateDecl::BuiltinTemplate: + case TemplateDecl::CVRefQualifyingTemplate: return true; default: return false; @@ -1696,6 +1697,83 @@ static TemplateParameterList *createBuiltinCommonTypeList(const ASTContext &C, nullptr); } +static TemplateTypeParmDecl *BICreateTemplateParm(const ASTContext &C, + DeclContext *DC, + unsigned Depth, + unsigned Position, + bool ParameterPack = false) { + return TemplateTypeParmDecl::Create( + C, DC, SourceLocation(), SourceLocation(), Depth, Position, + /*Id=*/nullptr, /*Typename=*/false, ParameterPack); +} + +static TemplateTemplateParmDecl * +BICreateTemplateTemplateParm(const ASTContext &C, DeclContext *DC, + ArrayRef<NamedDecl *> Parms, unsigned Depth, + unsigned Position, bool ParameterPack = false) { + auto *List = TemplateParameterList::Create( + C, SourceLocation(), SourceLocation(), Parms, SourceLocation(), nullptr); + return TemplateTemplateParmDecl::Create(C, DC, SourceLocation(), Depth, + Position, ParameterPack, + /*Id=*/nullptr, false, List); +} + +static TemplateTemplateParmDecl * +createBuiltinCommonReferenceBasicCommonReferenceT(const ASTContext &C, + DeclContext *DC) { + auto *T = BICreateTemplateParm(C, DC, /*Depth=*/1, /*Position=*/0); + auto *U = BICreateTemplateParm(C, DC, /*Depth=*/1, /*Position=*/1); + auto *TXArg = BICreateTemplateParm(C, DC, /*Depth=*/2, /*Position=*/0); + auto *TX = + BICreateTemplateTemplateParm(C, DC, {TXArg}, /*Depth=*/1, /*Position=*/2); + auto *UXArg = BICreateTemplateParm(C, DC, /*Depth=*/2, /*Position=*/0); + auto *UX = + BICreateTemplateTemplateParm(C, DC, {UXArg}, /*Depth=*/1, /*Position=*/2); + return BICreateTemplateTemplateParm(C, DC, {T, U, TX, UX}, /*Depth=*/0, + /*Position=*/0); +} + +static TemplateParameterList *createBuiltinCommonReferenceList(const ASTContext &C, + DeclContext *DC) { + // template <class, class, template <class> class, template <class> class> + // class + auto *BasicCommonReference = + createBuiltinCommonReferenceBasicCommonReferenceT(C, DC); + // class... Args + auto *Args = BICreateTemplateParm(C, DC, /*Depth=*/1, /*Position=*/0, + /*ParameterPack=*/true); + + // template <class... Args> + auto *BaseTemplate = + BICreateTemplateTemplateParm(C, DC, Args, /*Depth=*/0, /*Position=*/1); + + // class TypeMember + auto *TypeMember = BICreateTemplateParm(C, DC, /*Depth=*/1, /*Position=*/0); + + // template <class TypeMember> + auto *HasTypeMember = BICreateTemplateTemplateParm( + C, DC, TypeMember, /*Depth=*/0, /*Position=*/2); + + // class HasNoTypeMember + auto *HasNoTypeMember = + BICreateTemplateParm(C, DC, /*Depth=*/0, /*Position=*/3); + + // class... Ts + auto *Ts = BICreateTemplateParm(C, DC, /*Depth=*/0, /*Position=*/4, + /*ParameterPack=*/true); + + // template <template <class, class, template <class> class, template <class> + // class BasicCommonReference, + // template <class... Args> class CommonType, + // template <class TypeMember> class HasTypeMember, + // class HasNoTypeMember, + // class... Ts> + return TemplateParameterList::Create( + C, SourceLocation(), SourceLocation(), + {BasicCommonReference, BaseTemplate, HasTypeMember, HasNoTypeMember, Ts}, + SourceLocation(), nullptr); +} + static TemplateParameterList *createBuiltinTemplateParameterList( const ASTContext &C, DeclContext *DC, BuiltinTemplateKind BTK) { switch (BTK) { @@ -1705,6 +1783,8 @@ static TemplateParameterList *createBuiltinTemplateParameterList( return createTypePackElementParameterList(C, DC); case BTK__builtin_common_type: return createBuiltinCommonTypeList(C, DC); + case BTK__builtin_common_reference: + return createBuiltinCommonReferenceList(C, DC); } llvm_unreachable("unhandled BuiltinTemplateKind!"); @@ -1719,6 +1799,26 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC, createBuiltinTemplateParameterList(C, DC, BTK)), BTK(BTK) {} +void CVRefQualifyingTemplateDecl::anchor() {} + +static TemplateParameterList * +createCVRefQualifyingTemplateParameterList(const ASTContext &C, + DeclContext *DC) { + auto *T = TemplateTypeParmDecl::Create( + C, DC, SourceLocation(), SourceLocation(), + /*Depth=*/0, /*Position=*/0, /*Id=*/nullptr, false, false); + return TemplateParameterList::Create(C, SourceLocation(), SourceLocation(), + {T}, SourceLocation(), nullptr); +} + +CVRefQualifyingTemplateDecl::CVRefQualifyingTemplateDecl(const ASTContext &C, + DeclContext *DC, + CVRefQuals Quals) + : TemplateDecl(CVRefQualifyingTemplate, DC, SourceLocation(), + DeclarationName(), + createCVRefQualifyingTemplateParameterList(C, DC)), + Quals(Quals) {} + TemplateParamObjectDecl *TemplateParamObjectDecl::Create(const ASTContext &C, QualType T, const APValue &V) { @@ -1784,6 +1884,8 @@ TemplateParameterList *clang::getReplacedTemplateParameterList(Decl *D) { return cast<TypeAliasTemplateDecl>(D)->getTemplateParameters(); case Decl::Kind::BuiltinTemplate: return cast<BuiltinTemplateDecl>(D)->getTemplateParameters(); + case Decl::Kind::CVRefQualifyingTemplate: + return cast<CVRefQualifyingTemplateDecl>(D)->getTemplateParameters(); case Decl::Kind::CXXDeductionGuide: case Decl::Kind::CXXConversion: case Decl::Kind::CXXConstructor: diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 47b21bc9f63f04..f7f9d553ad3a96 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -50,6 +50,7 @@ static_assert(clang::Sema::MaximumAlignment <= llvm::Value::MaximumAlignment, void CodeGenFunction::EmitDecl(const Decl &D) { switch (D.getKind()) { case Decl::BuiltinTemplate: + case Decl::CVRefQualifyingTemplate: case Decl::TranslationUnit: case Decl::ExternCContext: case Decl::Namespace: diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 347c13da0ad215..28db246c160fea 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1834,6 +1834,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { .Case("__make_integer_seq", getLangOpts().CPlusPlus) .Case("__type_pack_element", getLangOpts().CPlusPlus) .Case("__builtin_common_type", getLangOpts().CPlusPlus) + .Case("__builtin_common_reference", 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/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index e04ece0bda82eb..da2f9129a89e09 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5742,76 +5742,6 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs, SourceLocation KeyLoc); -static ExprResult CheckConvertibilityForTypeTraits( - Sema &Self, const TypeSourceInfo *Lhs, const TypeSourceInfo *Rhs, - SourceLocation KeyLoc, llvm::BumpPtrAllocator &OpaqueExprAllocator) { - - QualType LhsT = Lhs->getType(); - QualType RhsT = Rhs->getType(); - - // C++0x [meta.rel]p4: - // Given the following function prototype: - // - // template <class T> - // typename add_rvalue_reference<T>::type create(); - // - // the predicate condition for a template specialization - // is_convertible<From, To> shall be satisfied if and only if - // the return expression in the following code would be - // well-formed, including any implicit conversions to the return - // type of the function: - // - // To test() { - // return create<From>(); - // } - // - // Access checking is performed as if in a context unrelated to To and - // From. Only the validity of the immediate context of the expression - // of the return-statement (including conversions to the return type) - // is considered. - // - // We model the initialization as a copy-initialization of a temporary - // of the appropriate type, which for this expression is identical to the - // return statement (since NRVO doesn't apply). - - // Functions aren't allowed to return function or array types. - if (RhsT->isFunctionType() || RhsT->isArrayType()) - return ExprError(); - - // A function definition requires a complete, non-abstract return type. - if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) || - Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT)) - return ExprError(); - - // Compute the result of add_rvalue_reference. - if (LhsT->isObjectType() || LhsT->isFunctionType()) - LhsT = Self.Context.getRValueReferenceType(LhsT); - - // Build a fake source and destination for initialization. - InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); - Expr *From = new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>()) - OpaqueValueExpr(KeyLoc, LhsT.getNonLValueExprType(Self.Context), - Expr::getValueKindForType(LhsT)); - InitializationKind Kind = - InitializationKind::CreateCopy(KeyLoc, SourceLocation()); - - // Perform the initialization in an unevaluated context within a SFINAE - // trap at translation unit scope. - EnterExpressionEvaluationContext Unevaluated( - Self, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); - Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); - InitializationSequence Init(Self, To, Kind, From); - if (Init.Failed()) - return ExprError(); - - ExprResult Result = Init.Perform(Self, To, Kind, From); - if (Result.isInvalid() || SFINAE.hasErrorOccurred()) - return ExprError(); - - return Result; -} - static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, ArrayRef<TypeSourceInfo *> Args, @@ -5933,9 +5863,8 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, S.Context.getPointerType(T.getNonReferenceType())); TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo( S.Context.getPointerType(U.getNonReferenceType())); - return !CheckConvertibilityForTypeTraits(S, UPtr, TPtr, RParenLoc, - OpaqueExprAllocator) - .isInvalid(); + return S.BuiltinIsConvertible(UPtr->getType(), TPtr->getType(), + RParenLoc); } if (Kind == clang::TT_IsNothrowConstructible) @@ -6166,20 +6095,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI } case BTT_IsConvertible: case BTT_IsConvertibleTo: - case BTT_IsNothrowConvertible: { - if (RhsT->isVoidType()) - return LhsT->isVoidType(); - llvm::BumpPtrAllocator OpaqueExprAllocator; - ExprResult Result = CheckConvertibilityForTypeTraits(Self, Lhs, Rhs, KeyLoc, - OpaqueExprAllocator); - if (Result.isInvalid()) - return false; - - if (BTT != BTT_IsNothrowConvertible) - return true; - - return Self.canThrow(Result.get()) == CT_Cannot; - } + case BTT_IsNothrowConvertible: + return Self.BuiltinIsConvertible(LhsT, RhsT, KeyLoc, + BTT == BTT_IsNothrowConvertible); case BTT_IsAssignable: case BTT_IsNothrowAssignable: diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e1171d4284c763..2028793d897067 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -936,6 +936,10 @@ bool Sema::LookupBuiltin(LookupResult &R) { R.addDecl(getASTContext().getBuiltinCommonTypeDecl()); return true; } + if (II == getASTContext().getBuiltinCommonReferenceName()) { + R.addDecl(getASTContext().getBuiltinCommonReferenceDecl()); + 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 5e7a3c8484c88f..4706013ff79225 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3072,6 +3072,33 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { } } +static QualType InstantiateTemplate(Sema &S, TemplateName Template, + ArrayRef<TemplateArgument> Args, + SourceLocation Loc) { + TemplateArgumentListInfo ArgList; + for (auto Arg : Args) { + if (Arg.getKind() == TemplateArgument::Type) { + ArgList.addArgument(TemplateArgumentLoc( + Arg, S.Context.getTrivialTypeSourceInfo(Arg.getAsType()))); + } else { + ArgList.addArgument( + S.getTrivialTemplateArgumentLoc(Arg, QualType(), Loc)); + } + } + + EnterExpressionEvaluationContext UnevaluatedContext( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); + + QualType Instantiation = S.CheckTemplateIdType(Template, Loc, ArgList); + + if (SFINAE.hasErrorOccurred()) + return QualType(); + + return Instantiation; +} + static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate, SourceLocation TemplateLoc, ArrayRef<TemplateArgument> Ts) { @@ -3082,24 +3109,7 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate, if (T1.getAsType()->isBuiltinType() && T2.getAsType()->isBuiltinType()) return builtinCommonTypeImpl(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()))); - - EnterExpressionEvaluationContext UnevaluatedContext( - S, Sema::ExpressionEvaluationContext::Unevaluated); - Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); - Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); - - QualType BaseTemplateInst = - S.CheckTemplateIdType(BaseTemplate, TemplateLoc, Args); - - if (SFINAE.hasErrorOccurred()) - return QualType(); - - return BaseTemplateInst; + return InstantiateTemplate(S, BaseTemplate, {T1, T2}, TemplateLoc); }; // Note A: For the common_type trait applied to a template parameter pack T of @@ -3206,6 +3216,195 @@ static QualType builtinCommonTypeImpl(Sema &S, TemplateName BaseTemplate, } } +static QualType CopyCV(QualType From, QualType To) { + if (From.isConstQualified()) + To.addConst(); + if (From.isVolatileQualified()) + To.addVolatile(); + return To; +} + +// COND-RES(X, Y) be decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()()) +static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) { + EnterExpressionEvaluationContext UnevaluatedContext( + S, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); + + // false + OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, + VK_PRValue); + ExprResult Cond = &CondExpr; + + // declval<X(&)()>()() + OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context), + Expr::getValueKindForType(X)); + ExprResult LHS = &LHSExpr; + + // declval<Y(&)()>()() + OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context), + Expr::getValueKindForType(Y)); + ExprResult RHS = &RHSExpr; + + ExprValueKind VK = VK_PRValue; + ExprObjectKind OK = OK_Ordinary; + + // decltype(false ? declval<X(&)()>()() : declval<Y(&)()>()()) + QualType Result = + S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc); + + if (SFINAE.hasErrorOccurred()) + return QualType(); + if (VK == VK_LValue) + return S.BuiltinAddLValueReference(Result, Loc); + return Result; +} + +static QualType CommonRef(Sema &S, QualType A, QualType B, + SourceLocation Loc) { + // Given types A and B, let X be remove_reference_t<A>, let Y be + // remove_reference_t<B>, and let COMMON-REF(A, B) be: + assert(A->isReferenceType() && B->isReferenceType() && + "A and B have to be ref qualified for a COMMON-REF"); + auto X = A.getNonReferenceType(); + auto Y = B.getNonReferenceType(); + + // If A and B are both lvalue reference types, COMMON-REF(A, B) is + // COND-RES(COPYCV(X, Y) &, COPYCV(Y, X) &) if that type exists and is a + // reference type. + if (A->isLValueReferenceType() && B->isLValueReferenceType()) { + auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc), + S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc); + if (CR.isNull() || !CR->isReferenceType()) + return QualType(); + return CR; + } + + // Otherwise, let C be remove_reference_t<COMMON-REF(X&, Y&)>&&. If A and B + // are both rvalue reference types, C is well-formed, and + // is_convertible_v<A, C> && is_convertible_v<B, C> is true, then + // COMMON-REF(A, B) is C. + if (A->isRValueReferenceType() && B->isRValueReferenceType()) { + auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc), + S.BuiltinAddRValueReference(Y, Loc), Loc) + .getNonReferenceType(); + if (!C.isNull() && S.BuiltinIsConvertible(A, C, Loc) && + S.BuiltinIsConvertible(B, C, Loc)) + return C; + return QualType(); + } + + // Otherwise, if A is an lvalue reference and B is an rvalue reference, then + // COMMON-REF(A, B) is COMMON-REF(B, A). + if (A->isLValueReferenceType() && B->isRValueReferenceType()) + std::swap(A, B); + + // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference + // and B is an lvalue reference and D is well-formed and + // is_convertible_v<A, D> is true, then COMMON-REF(A, B) is D. + if (A->isRValueReferenceType() && B->isLValueReferenceType()) { + auto X2 = X; + X2.addConst(); + auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc), + S.BuiltinAddLValueReference(Y, Loc), Loc); + if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc)) + return D; + return QualType(); + } + + // Otherwise, COMMON-REF(A, B) is ill-formed. + // This is implemented by returning from the individual branches above. + + llvm_unreachable("The above cases should be exhaustive"); +} + +static QualType builtinCommonReferenceImpl(Sema &S, + TemplateName CommonReference, + TemplateName CommonType, + SourceLocation TemplateLoc, + ArrayRef<TemplateArgument> Ts) { + switch (Ts.size()) { + // If sizeof...(T) is zero, there shall be no member type. + case 0: + return QualType(); + + // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the + // pack T. The member typedef type shall denote the same type as T0. + case 1: + return Ts[0].getAsType(); + + // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in + // the pack T. Then + case 2: { + auto T1 = Ts[0].getAsType(); + auto T2 = Ts[1].getAsType(); + + // Let R be COMMON-REF(T1, T2). If T1 and T2 are reference types, R is + // well-formed, and is_convertible_v<add_pointer_t<T1>, add_pointer_t<R>> && + // is_convertible_v<add_pointer_t<T2>, add_pointer_t<R>> is true, then the + // member typedef type denotes R. + if (T1->isReferenceType() && T2->isReferenceType()) { + QualType R = CommonRef(S, T1, T2, TemplateLoc); + if (!R.isNull()) { + if (S.BuiltinIsConvertible(S.BuiltinAddPointer(T1, TemplateLoc), + S.BuiltinAddPointer(R, TemplateLoc), + TemplateLoc) && + S.BuiltinIsConvertible(S.BuiltinAddPointer(T2, TemplateLoc), + S.BuiltinAddPointer(R, TemplateLoc), + TemplateLoc)) { + return R; + } + } + } + + // Otherwise, if basic_common_reference<remove_cvref_t<T1>, + // remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type is well-formed, + // then the member typedef type denotes that type. + { + auto BCR = InstantiateTemplate( + S, CommonReference, + {S.BuiltinRemoveCVRef(T1, TemplateLoc), + S.BuiltinRemoveCVRef(T2, TemplateLoc), + TemplateName{S.Context.getCVRefQualifyingAliasDecl(T1)}, + TemplateName{S.Context.getCVRefQualifyingAliasDecl(T2)}}, + TemplateLoc); + if (!BCR.isNull()) + return BCR; + } + + // Otherwise, if COND-RES(T1, T2) is well-formed, then the member typedef + // type denotes that type. + if (auto CR = CondRes(S, T1, T2, TemplateLoc); !CR.isNull()) + return CR; + + // Otherwise, if common_type_t<T1, T2> is well-formed, then the member + // typedef type denotes that type. + if (auto CT = InstantiateTemplate(S, CommonType, {T1, T2}, TemplateLoc); + !CT.isNull()) + return CT; + + // Otherwise, there shall be no member type. + return QualType(); + } + + // Otherwise, if sizeof...(T) is greater than two, let T1, T2, and Rest, + // respectively, denote the first, second, and (pack of) remaining types + // comprising T. Let C be the type common_reference_t<T1, T2>. Then: + default: { + auto T1 = Ts[0]; + auto T2 = Ts[1]; + auto Rest = Ts.drop_front(2); + auto C = builtinCommonReferenceImpl(S, CommonReference, CommonType, TemplateLoc, {T1, T2}); + if (C.isNull()) + return QualType(); + llvm::SmallVector<TemplateArgument, 4> Args; + Args.emplace_back(C); + Args.append(Rest.begin(), Rest.end()); + return builtinCommonReferenceImpl(S, CommonReference, CommonType, TemplateLoc, Args); + } + } +} + static QualType checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, ArrayRef<TemplateArgument> Converted, @@ -3310,6 +3509,29 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, } return HasNoTypeMember; } + + case BTK__builtin_common_reference: { + assert(Converted.size() == 5); + if (llvm::any_of(Converted, [](auto &C) { return C.isDependent(); })) + return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), + Converted); + + TemplateName BasicCommonReference = Converted[0].getAsTemplate(); + TemplateName CommonType = Converted[1].getAsTemplate(); + TemplateName HasTypeMember = Converted[2].getAsTemplate(); + QualType HasNoTypeMember = Converted[3].getAsType(); + ArrayRef<TemplateArgument> Ts = Converted[4].getPackAsArray(); + if (auto CR = builtinCommonReferenceImpl(SemaRef, BasicCommonReference, + CommonType, TemplateLoc, Ts); + !CR.isNull()) { + TemplateArgumentListInfo TAs; + TAs.addArgument(TemplateArgumentLoc( + TemplateArgument(CR), SemaRef.Context.getTrivialTypeSourceInfo( + CR, TemplateArgs[1].getLocation()))); + return SemaRef.CheckTemplateIdType(HasTypeMember, TemplateLoc, TAs); + } + return HasNoTypeMember; + } } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -3575,6 +3797,20 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) { CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted, TemplateLoc, TemplateArgs); + } else if (auto *QTD = dyn_cast<CVRefQualifyingTemplateDecl>(Template)) { + assert(SugaredConverted.size() == 1); + CanonType = SugaredConverted[0].getAsType(); + + using CVRefQuals = CVRefQualifyingTemplateDecl::CVRefQuals; + auto Quals = QTD->getQuals(); + if (Quals & CVRefQuals::Const) + CanonType.addConst(); + if (Quals & CVRefQuals::Volatile) + CanonType.addVolatile(); + if (Quals & CVRefQuals::LValueRef) + CanonType = BuiltinAddLValueReference(CanonType, TemplateLoc); + else if (Quals & CVRefQuals::RValueRef) + CanonType = BuiltinAddRValueReference(CanonType, TemplateLoc); } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, CanonicalConverted)) { @@ -7339,7 +7575,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, if (!isa<ClassTemplateDecl>(Template) && !isa<TemplateTemplateParmDecl>(Template) && !isa<TypeAliasTemplateDecl>(Template) && - !isa<BuiltinTemplateDecl>(Template)) { + !isa<BuiltinTemplateDecl>(Template) && + !isa<CVRefQualifyingTemplateDecl>(Template)) { assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template); diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index e058afe81da589..6b296e8676be85 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1694,6 +1694,11 @@ TemplateDeclInstantiator::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) { llvm_unreachable("BuiltinTemplateDecls cannot be instantiated."); } +Decl *TemplateDeclInstantiator::VisitCVRefQualifyingTemplateDecl( + CVRefQualifyingTemplateDecl *D) { + llvm_unreachable("CVRefQualifyingTemplateDecls cannot be instantiated."); +} + Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 83464c50b4b238..f912e4a4eba14c 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -32,6 +32,8 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/EnterExpressionEvaluationContext.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/ParsedTemplate.h" @@ -9909,6 +9911,77 @@ QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, return Context.getQualifiedType(Underlying, BaseType.getQualifiers()); } +bool Sema::BuiltinIsConvertible(QualType From, QualType To, SourceLocation Loc, + bool CheckNothrow) { + if (To->isVoidType()) + return From->isVoidType(); + + if (RequireCompleteType(Loc, From, + diag::err_incomplete_type_used_in_type_trait_expr) || + RequireCompleteType(Loc, To, + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + + // C++11 [meta.rel]p4: + // Given the following function prototype: + // + // template <class T> + // typename add_rvalue_reference<T>::type create(); + // + // the predicate condition for a template specialization + // is_convertible<From, To> shall be satisfied if and only if + // the return expression in the following code would be + // well-formed, including any implicit conversions to the return + // type of the function: + // + // To test() { + // return create<From>(); + // } + // + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression + // of the return-statement (including conversions to the return type) + // is considered. + // + // We model the initialization as a copy-initialization of a temporary + // of the appropriate type, which for this expression is identical to the + // return statement (since NRVO doesn't apply). + + // Functions aren't allowed to return function or array types. + if (From->isFunctionType() || To->isArrayType()) + return false; + + // A function definition requires a non-abstract return type. + if (isAbstractType(Loc, To)) + return false; + + From = BuiltinAddRValueReference(From, Loc); + + // Build a fake source and destination for initialization. + InitializedEntity ToEntity(InitializedEntity::InitializeTemporary(To)); + OpaqueValueExpr FromExpr(Loc, From.getNonLValueExprType(Context), + Expr::getValueKindForType(From)); + InitializationKind Kind = + InitializationKind::CreateCopy(Loc, SourceLocation()); + + // Perform the initialization in an unevaluated context within a SFINAE + // trap at translation unit scope. + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(*this, /*AccessCheckingSFINAE=*/true); + Sema::ContextRAII TUContext(*this, Context.getTranslationUnitDecl()); + Expr *FromExprPtr = &FromExpr; + InitializationSequence Init(*this, ToEntity, Kind, FromExprPtr); + if (Init.Failed()) + return false; + + ExprResult Result = Init.Perform(*this, ToEntity, Kind, FromExprPtr); + if (Result.isInvalid() || SFINAE.hasErrorOccurred()) + return false; + + return !CheckNothrow || canThrow(Result.get()) == CT_Cannot; +} + QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind, SourceLocation Loc) { if (BaseType->isDependentType()) diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index ec18e84255ca8e..178739aa071c70 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -448,6 +448,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::OMPDeclareReduction: case Decl::OMPDeclareMapper: case Decl::BuiltinTemplate: + case Decl::CVRefQualifyingTemplate: case Decl::Decomposition: case Decl::Binding: case Decl::Concept: diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 21f6b2ecc58c4f..7d0c92e18967f1 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8035,6 +8035,12 @@ Decl *ASTReader::getPredefinedDecl(PredefinedDeclIDs ID) { NewLoaded = Context.getBuiltinCommonTypeDecl(); break; + case PREDEF_DECL_COMMON_REFERENCE_ID: + if (Context.BuiltinCommonReferenceDecl) + return Context.BuiltinCommonReferenceDecl; + NewLoaded = Context.getBuiltinCommonReferenceDecl(); + break; + case NUM_PREDEF_DECL_IDS: llvm_unreachable("Invalid decl ID"); break; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 6db2262a7952ec..072cf6ac1863b2 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5299,6 +5299,8 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) { RegisterPredefDecl(Context.TypePackElementDecl, PREDEF_DECL_TYPE_PACK_ELEMENT_ID); RegisterPredefDecl(Context.BuiltinCommonTypeDecl, PREDEF_DECL_COMMON_TYPE_ID); + RegisterPredefDecl(Context.BuiltinCommonReferenceDecl, + PREDEF_DECL_COMMON_REFERENCE_ID); const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); diff --git a/clang/test/SemaCXX/type-trait-common-reference.cpp b/clang/test/SemaCXX/type-trait-common-reference.cpp new file mode 100644 index 00000000000000..bb475821fbc9b7 --- /dev/null +++ b/clang/test/SemaCXX/type-trait-common-reference.cpp @@ -0,0 +1,120 @@ +// 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_reference) +# error +#endif + +// expected-note@*:* {{template <template <class, class, template <class> class, template <class> class> class, template <class ...> class, template <class> class, class, class ...>}} + +void test() { + __builtin_common_reference<> a; // expected-error {{too few template arguments for template '__builtin_common_reference'}} + __builtin_common_reference<1> b; // expected-error {{template argument for template template parameter must be a class template or type alias template}} + __builtin_common_reference<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; + +template <class, class, template <class> class, template <class> class> +struct basic_common_reference {}; + +template <class T, class U, template <class> class TX, template <class> class UX> +using basic_common_reference_t = typename basic_common_reference<T, U, TX, UX>::type; + +void test_vla() { + int i = 4; + int VLA[i]; + __builtin_common_reference<basic_common_reference_t, 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_reference_base = __builtin_common_reference<basic_common_reference_t, common_type_t, type_identity, empty_type, Args...>; + +template <class... Args> +struct common_reference : common_reference_base<Args...> {}; + +template <class... Args> +using common_reference_t = typename __builtin_common_reference<basic_common_reference_t, common_type_t, type_identity, empty_type, Args...>::type; + +struct Incomplete; + +template<> +struct common_type<Incomplete, Incomplete>; + +static_assert(__is_same(common_reference_base<>, empty_type)); + +static_assert(__is_same(common_reference_base<Incomplete>, type_identity<Incomplete>)); +static_assert(__is_same(common_reference_base<char>, type_identity<char>)); +static_assert(__is_same(common_reference_base<int>, type_identity<int>)); +static_assert(__is_same(common_reference_base<const int>, type_identity<const int>)); +static_assert(__is_same(common_reference_base<volatile int>, type_identity<volatile int>)); +static_assert(__is_same(common_reference_base<const volatile int>, type_identity<const volatile int>)); +static_assert(__is_same(common_reference_base<int[]>, type_identity<int[]>)); +static_assert(__is_same(common_reference_base<const int[]>, type_identity<const int[]>)); +static_assert(__is_same(common_reference_base<void(&)()>, type_identity<void(&)()>)); + +static_assert(__is_same(common_reference_base<int[], int[]>, type_identity<int*>)); +static_assert(__is_same(common_reference_base<int, int>, type_identity<int>)); +static_assert(__is_same(common_reference_base<int, long>, type_identity<long>)); +static_assert(__is_same(common_reference_base<long, int>, type_identity<long>)); +static_assert(__is_same(common_reference_base<long, long>, type_identity<long>)); + +static_assert(__is_same(common_reference_base<const int, long>, type_identity<long>)); +static_assert(__is_same(common_reference_base<const volatile int, long>, type_identity<long>)); +static_assert(__is_same(common_reference_base<int, const long>, type_identity<long>)); +static_assert(__is_same(common_reference_base<int, const volatile long>, type_identity<long>)); + +static_assert(__is_same(common_reference_base<int*, long*>, empty_type)); +static_assert(__is_same(common_reference_base<const unsigned int *const &, const unsigned int *const &>, type_identity<const unsigned int *const &>)); + +static_assert(__is_same(common_reference_base<int, long, float>, type_identity<float>)); +static_assert(__is_same(common_reference_base<unsigned, char, long>, type_identity<long>)); +static_assert(__is_same(common_reference_base<long long, long long, long>, type_identity<long long>)); + +static_assert(__is_same(common_reference_base<int [[clang::address_space(1)]]>, type_identity<int [[clang::address_space(1)]]>)); +static_assert(__is_same(common_reference_base<int [[clang::address_space(1)]], int>, type_identity<int>)); +static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], int>, type_identity<long>)); +static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], int [[clang::address_space(1)]]>, type_identity<long>)); +static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], long [[clang::address_space(1)]]>, type_identity<long>)); +static_assert(__is_same(common_reference_base<long [[clang::address_space(1)]], long [[clang::address_space(2)]]>, type_identity<long>)); + +struct S {}; +struct T : S {}; +struct U {}; + +static_assert(__is_same(common_reference_base<int S::*, int S::*>, type_identity<int S::*>)); +static_assert(__is_same(common_reference_base<int S::*, int T::*>, type_identity<int T::*>)); +static_assert(__is_same(common_reference_base<int S::*, long S::*>, empty_type)); + +static_assert(__is_same(common_reference_base<int (S::*)(), int (S::*)()>, type_identity<int (S::*)()>)); +static_assert(__is_same(common_reference_base<int (S::*)(), int (T::*)()>, type_identity<int (T::*)()>)); +static_assert(__is_same(common_reference_base<int (S::*)(), long (S::*)()>, empty_type)); + +static_assert(__is_same(common_reference_base<int&, int&>, type_identity<int&>)); +static_assert(__is_same(common_reference_base<int&, const int&>, type_identity<const int&>)); +static_assert(__is_same(common_reference_base<volatile int&, const int&>, type_identity<const volatile int&>)); + +template <class T, class U> +struct my_pair; + +template <class T1, class U1, class T2, class U2, template <class> class TX, template <class> class UX> +struct basic_common_reference<my_pair<T1, U1>, my_pair<T2, U2>, TX, UX> { + using type = my_pair<common_reference_t<TX<T1>, UX<T2>>, common_reference_t<TX<U1>, UX<U2>>>; +}; + +static_assert(__is_same(common_reference_base<my_pair<const int&, int&>, my_pair<int&, volatile int&>>, type_identity<my_pair<const int&, volatile int&>>)); +static_assert(__is_same(common_reference_base<const my_pair<int, int>&, my_pair<int&, volatile int&>>, type_identity<my_pair<const int&, const volatile int&>>)); +static_assert(__is_same(common_reference_base<const int&, const volatile int&>, type_identity<const volatile int&>)); +static_assert(__is_same(common_reference_base<int&&, const volatile int&>, type_identity<int>)); +static_assert(__is_same(common_reference_base<my_pair<int, int>&&, my_pair<int&, volatile int&>>, type_identity<my_pair<const int&, int>>)); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 9bdc4c9f8ce238..e2a1af61f2c1c7 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -7163,6 +7163,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::OMPRequires: case Decl::ObjCTypeParam: case Decl::BuiltinTemplate: + case Decl::CVRefQualifyingTemplate: case Decl::PragmaComment: case Decl::PragmaDetectMismatch: case Decl::UsingPack: diff --git a/libcxx/include/__type_traits/common_reference.h b/libcxx/include/__type_traits/common_reference.h index c802902eb19fc3..a41143670bc6e6 100644 --- a/libcxx/include/__type_traits/common_reference.h +++ b/libcxx/include/__type_traits/common_reference.h @@ -18,16 +18,36 @@ #include <__type_traits/remove_cv.h> #include <__type_traits/remove_cvref.h> #include <__type_traits/remove_reference.h> +#include <__type_traits/type_identity.h> #include <__utility/declval.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_BEGIN_NAMESPACE_STD -// common_reference -#if _LIBCPP_STD_VER >= 20 +template <class...> +struct common_reference; + +template <class... _Types> +using common_reference_t = typename common_reference<_Types...>::type; + +template <class, class, template <class> class, template <class> class> +struct basic_common_reference {}; + +#if __has_builtin(__builtin_common_reference) + +template <class _Tp, class _Up, template <class> class _Tx, template <class> class _Ux> +using __basic_common_reference_t = basic_common_reference<_Tp, _Up, _Tx, _Ux>::type; + +template <class... _Args> +struct common_reference : __builtin_common_reference<__basic_common_reference_t, common_type_t, type_identity, __empty, _Args...> {}; + +#else + // Let COND_RES(X, Y) be: template <class _Xp, class _Yp> using __cond_res = decltype(false ? std::declval<_Xp (&)()>()() : std::declval<_Yp (&)()>()()); @@ -109,12 +129,6 @@ struct __common_ref {}; // Note C: For the common_reference trait applied to a parameter pack [...] -template <class...> -struct common_reference; - -template <class... _Types> -using common_reference_t = typename common_reference<_Types...>::type; - // bullet 1 - sizeof...(T) == 0 template <> struct common_reference<> {}; @@ -146,8 +160,6 @@ struct __common_reference_sub_bullet1<_Tp, _Up> { // sub-bullet 2 - Otherwise, if basic_common_reference<remove_cvref_t<T1>, remove_cvref_t<T2>, XREF(T1), XREF(T2)>::type // is well-formed, then the member typedef `type` denotes that type. -template <class, class, template <class> class, template <class> class> -struct basic_common_reference {}; template <class _Tp, class _Up> using __basic_common_reference_t = @@ -186,8 +198,10 @@ struct common_reference<_Tp, _Up, _Vp, _Rest...> : common_reference<common_refer template <class...> struct common_reference {}; -#endif // _LIBCPP_STD_VER >= 20 +#endif // __has_builtin(__builtin_common_reference) _LIBCPP_END_NAMESPACE_STD +#endif // _LIBCPP_STD_VER >= 20 + #endif // _LIBCPP___TYPE_TRAITS_COMMON_REFERENCE_H _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits