diff options
Diffstat (limited to 'clang')
33 files changed, 540 insertions, 72 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 8b52891af2f..cc59acbca99 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1931,6 +1931,12 @@ public: bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; } void setDeletedAsWritten(bool D = true) { IsDeleted = D; } + /// \brief Determines whether this function is a deduction guide. + bool isDeductionGuide() const { + return getDeclName().getNameKind() == + DeclarationName::CXXDeductionGuideName; + } + /// \brief Determines whether this function is "main", which is the /// entry point into an executable program. bool isMain() const; diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h index 2d3cfe27a16..5e773c96838 100644 --- a/clang/include/clang/AST/DeclarationName.h +++ b/clang/include/clang/AST/DeclarationName.h @@ -23,6 +23,7 @@ namespace llvm { namespace clang { class ASTContext; + class CXXDeductionGuideNameExtra; class CXXLiteralOperatorIdName; class CXXOperatorIdName; class CXXSpecialName; @@ -32,6 +33,7 @@ namespace clang { enum OverloadedOperatorKind : int; struct PrintingPolicy; class QualType; + class TemplateDecl; class Type; class TypeSourceInfo; class UsingDirectiveDecl; @@ -56,6 +58,7 @@ public: CXXConstructorName, CXXDestructorName, CXXConversionFunctionName, + CXXDeductionGuideName, CXXOperatorName, CXXLiteralOperatorName, CXXUsingDirective @@ -118,42 +121,36 @@ private: CXXSpecialName *getAsCXXSpecialName() const { NameKind Kind = getNameKind(); if (Kind >= CXXConstructorName && Kind <= CXXConversionFunctionName) - return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask); + return reinterpret_cast<CXXSpecialName *>(getExtra()); + return nullptr; + } + + /// If the stored pointer is actually a CXXDeductionGuideNameExtra, returns a + /// pointer to it. Otherwise, returns a NULL pointer. + CXXDeductionGuideNameExtra *getAsCXXDeductionGuideNameExtra() const { + if (getNameKind() == CXXDeductionGuideName) + return reinterpret_cast<CXXDeductionGuideNameExtra *>(getExtra()); return nullptr; } /// getAsCXXOperatorIdName CXXOperatorIdName *getAsCXXOperatorIdName() const { if (getNameKind() == CXXOperatorName) - return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask); + return reinterpret_cast<CXXOperatorIdName *>(getExtra()); return nullptr; } CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const { if (getNameKind() == CXXLiteralOperatorName) - return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask); + return reinterpret_cast<CXXLiteralOperatorIdName *>(getExtra()); return nullptr; } // Construct a declaration name from the name of a C++ constructor, // destructor, or conversion function. - DeclarationName(CXXSpecialName *Name) - : Ptr(reinterpret_cast<uintptr_t>(Name)) { - assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName"); - Ptr |= StoredDeclarationNameExtra; - } - - // Construct a declaration name from the name of a C++ overloaded - // operator. - DeclarationName(CXXOperatorIdName *Name) + DeclarationName(DeclarationNameExtra *Name) : Ptr(reinterpret_cast<uintptr_t>(Name)) { - assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId"); - Ptr |= StoredDeclarationNameExtra; - } - - DeclarationName(CXXLiteralOperatorIdName *Name) - : Ptr(reinterpret_cast<uintptr_t>(Name)) { - assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId"); + assert((Ptr & PtrMask) == 0 && "Improperly aligned DeclarationNameExtra"); Ptr |= StoredDeclarationNameExtra; } @@ -252,6 +249,10 @@ public: /// type associated with that name. QualType getCXXNameType() const; + /// If this name is the name of a C++ deduction guide, return the + /// template associated with that name. + TemplateDecl *getCXXDeductionGuideTemplate() const; + /// getCXXOverloadedOperator - If this name is the name of an /// overloadable operator in C++ (e.g., @c operator+), retrieve the /// kind of overloaded operator. @@ -346,6 +347,7 @@ class DeclarationNameTable { void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> * CXXOperatorIdName *CXXOperatorNames; // Operator names void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName* + void *CXXDeductionGuideNames; // FoldingSet<CXXDeductionGuideNameExtra> * DeclarationNameTable(const DeclarationNameTable&) = delete; void operator=(const DeclarationNameTable&) = delete; @@ -368,6 +370,9 @@ public: /// for the given Type. DeclarationName getCXXDestructorName(CanQualType Ty); + /// Returns the name of a C++ deduction guide for the given template. + DeclarationName getCXXDeductionGuideName(TemplateDecl *TD); + /// getCXXConversionFunctionName - Returns the name of a C++ /// conversion function for the given Type. DeclarationName getCXXConversionFunctionName(CanQualType Ty); diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 1cd71d299e0..f41f8416267 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -774,6 +774,11 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo( TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc())); break; + case DeclarationName::CXXDeductionGuideName: + TRY_TO(TraverseTemplateName( + TemplateName(NameInfo.getName().getCXXDeductionGuideTemplate()))); + break; + case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 29eedc1e682..1e1ee3d5e90 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1207,8 +1207,9 @@ def warn_cxx98_compat_unelaborated_friend_type : Warning< def err_qualified_friend_not_found : Error< "no function named %0 with type %1 was found in the specified scope">; def err_introducing_special_friend : Error< - "must use a qualified name when declaring a %select{constructor|" - "destructor|conversion operator}0 as a friend">; + "%plural{[0,2]:must use a qualified name when declaring|3:cannot declare}0" + " a %select{constructor|destructor|conversion operator|deduction guide}0 " + "as a friend">; def err_tagless_friend_type_template : Error< "friend type templates must use an elaborated type">; def err_no_matching_local_friend : Error< @@ -1960,6 +1961,15 @@ def err_deduced_class_template_compound_type : Error< "deduced class template specialization type">; def err_deduced_class_template_not_supported : Error< "deduction of template arguments for class templates is not yet supported">; +def err_deduction_guide_no_trailing_return_type : Error< + "deduction guide declaration without trailing return type">; +def err_deduction_guide_with_complex_decl : Error< + "cannot specify any part of a return type in the " + "declaration of a deduction guide">; +def err_deduction_guide_name_not_class_template : Error< + "cannot specify deduction guide for " + "%select{<error>|function template|variable template|alias template|" + "template template parameter|dependent template name}0 %1">; // C++1y deduced return types def err_auto_fn_deduction_failure : Error< diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 3001d0b1b0c..aaed4819062 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -818,6 +818,7 @@ public: #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ CXXOperator##Name, #include "clang/Basic/OperatorKinds.def" + CXXDeductionGuide, CXXLiteralOperator, CXXUsingDirective, NUM_EXTRA_KINDS diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 01ee93fb267..f39c176b58a 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1967,7 +1967,7 @@ private: /// \brief Starting with a scope specifier, identifier, or /// template-id that refers to the current class, determine whether /// this is a constructor declarator. - bool isConstructorDeclarator(bool Unqualified); + bool isConstructorDeclarator(bool Unqualified, bool DeductionGuide = false); /// \brief Specifies the context in which type-id/expression /// disambiguation will occur. @@ -2634,6 +2634,7 @@ public: bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, + bool AllowDeductionGuide, ParsedType ObjectType, SourceLocation& TemplateKWLoc, UnqualifiedId &Result); diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 7505c741a58..c489186d764 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -908,7 +908,9 @@ public: /// \brief A template-id, e.g., f<int>. IK_TemplateId, /// \brief An implicit 'self' parameter - IK_ImplicitSelfParam + IK_ImplicitSelfParam, + /// \brief A deduction-guide name (a template-name) + IK_DeductionGuideName } Kind; struct OFI { @@ -928,8 +930,8 @@ public: /// \brief Anonymous union that holds extra data associated with the /// parsed unqualified-id. union { - /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind - /// == IK_UserLiteralId, the identifier suffix. + /// \brief When Kind == IK_Identifier, the parsed identifier, or when + /// Kind == IK_UserLiteralId, the identifier suffix. IdentifierInfo *Identifier; /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator @@ -947,6 +949,9 @@ public: /// \brief When Kind == IK_DestructorName, the type referred to by the /// class-name. UnionParsedType DestructorName; + + /// \brief When Kind == IK_DeductionGuideName, the parsed template-name. + UnionParsedTemplateTy TemplateName; /// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId, /// the template-id annotation that contains the template name and @@ -1085,6 +1090,18 @@ public: /// \p TemplateId and will free it on destruction. void setTemplateId(TemplateIdAnnotation *TemplateId); + /// \brief Specify that this unqualified-id was parsed as a template-name for + /// a deduction-guide. + /// + /// \param Template The parsed template-name. + /// \param TemplateLoc The location of the parsed template-name. + void setDeductionGuideName(ParsedTemplateTy Template, + SourceLocation TemplateLoc) { + Kind = IK_DeductionGuideName; + TemplateName = Template; + StartLocation = EndLocation = TemplateLoc; + } + /// \brief Return the source range that covers this unqualified-id. SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(StartLocation, EndLocation); @@ -2319,6 +2336,16 @@ public: return true; } + /// \brief Determine whether a trailing return type was written (at any + /// level) within this declarator. + bool hasTrailingReturnType() const { + for (const auto &Chunk : type_objects()) + if (Chunk.Kind == DeclaratorChunk::Function && + Chunk.Fun.hasTrailingReturnType()) + return true; + return false; + } + /// takeAttributes - Takes attributes from the given parsed-attributes /// set and add them to this declarator. /// diff --git a/clang/include/clang/Sema/Ownership.h b/clang/include/clang/Sema/Ownership.h index fd46de870fb..848837a1dec 100644 --- a/clang/include/clang/Sema/Ownership.h +++ b/clang/include/clang/Sema/Ownership.h @@ -257,6 +257,7 @@ namespace clang { typedef ActionResult<Decl*> DeclResult; typedef OpaquePtr<TemplateName> ParsedTemplateTy; + typedef UnionOpaquePtr<TemplateName> UnionParsedTemplateTy; typedef MutableArrayRef<Expr*> MultiExprArg; typedef MutableArrayRef<Stmt*> MultiStmtArg; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index dc2947f587e..8a285847376 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5619,6 +5619,8 @@ public: void CheckConversionDeclarator(Declarator &D, QualType &R, StorageClass& SC); Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); + void CheckDeductionGuideDeclarator(Declarator &D, QualType &R, + StorageClass &SC); void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD, @@ -5822,6 +5824,22 @@ public: TemplateTy &Template, bool &MemberOfUnknownSpecialization); + /// Determine whether a particular identifier might be the name in a C++1z + /// deduction-guide declaration. + bool isDeductionGuideName(Scope *S, const IdentifierInfo &Name, + SourceLocation NameLoc, + ParsedTemplateTy *Template = nullptr) { + CXXScopeSpec SS; + UnqualifiedId Id; + Id.setIdentifier(&Name, NameLoc); + TemplateTy TemplateFallback; + bool MemberOfUnknownSpecialization; + // FIXME: Use redeclaration lookup! + return isTemplateName(S, SS, false, Id, ParsedType(), false, + Template ? *Template : TemplateFallback, + MemberOfUnknownSpecialization) == TNK_Type_template; + } + bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 32322b59baf..24fefc74edb 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1628,7 +1628,8 @@ namespace clang { IdentifierInfo *getIdentifier() const { assert(Kind == DeclarationName::Identifier || - Kind == DeclarationName::CXXLiteralOperatorName); + Kind == DeclarationName::CXXLiteralOperatorName || + Kind == DeclarationName::CXXDeductionGuideName); return (IdentifierInfo *)Data; } Selector getSelector() const { diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index f80ce35df2b..9ded89413e8 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2264,6 +2264,7 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From, case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: return; case DeclarationName::CXXOperatorName: { @@ -7448,6 +7449,14 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) { ToContext.getCanonicalType(T)); } + case DeclarationName::CXXDeductionGuideName: { + TemplateDecl *Template = cast_or_null<TemplateDecl>( + Import(FromName.getCXXDeductionGuideTemplate())); + if (!Template) + return DeclarationName(); + return ToContext.DeclarationNames.getCXXDeductionGuideName(Template); + } + case DeclarationName::CXXConversionFunctionName: { QualType T = Import(FromName.getCXXNameType()); if (T.isNull()) diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index 52791e51d2d..5f09b2701a1 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" @@ -43,6 +44,22 @@ public: } }; +/// Contains extra information for the name of a C++ deduction guide. +class CXXDeductionGuideNameExtra : public DeclarationNameExtra, + public llvm::FoldingSetNode { +public: + /// The template named by the deduction guide. + TemplateDecl *Template; + + /// FETokenInfo - Extra information associated with this operator + /// name that can be used by the front end. + void *FETokenInfo; + + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddPointer(Template); + } +}; + /// CXXOperatorIdName - Contains extra information for the name of an /// overloaded operator in C++, such as "operator+. class CXXOperatorIdName : public DeclarationNameExtra { @@ -122,7 +139,13 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType())) return 1; return 0; - + + case DeclarationName::CXXDeductionGuideName: + // We never want to compare deduction guide names for templates from + // different scopes, so just compare the template-name. + return compare(LHS.getCXXDeductionGuideTemplate()->getDeclName(), + RHS.getCXXDeductionGuideTemplate()->getDeclName()); + case DeclarationName::CXXOperatorName: return compareInt(LHS.getCXXOverloadedOperator(), RHS.getCXXOverloadedOperator()); @@ -179,6 +202,9 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { return printCXXConstructorDestructorName(N.getCXXNameType(), OS, Policy); } + case DeclarationName::CXXDeductionGuideName: + return getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy); + case DeclarationName::CXXOperatorName: { static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = { nullptr, @@ -243,6 +269,9 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { case DeclarationNameExtra::CXXDestructor: return CXXDestructorName; + case DeclarationNameExtra::CXXDeductionGuide: + return CXXDeductionGuideName; + case DeclarationNameExtra::CXXConversionFunction: return CXXConversionFunctionName; @@ -268,7 +297,15 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { bool DeclarationName::isDependentName() const { QualType T = getCXXNameType(); - return !T.isNull() && T->isDependentType(); + if (!T.isNull() && T->isDependentType()) + return true; + + // A class-scope deduction guide in a dependent context has a dependent name. + auto *TD = getCXXDeductionGuideTemplate(); + if (TD && TD->getDeclContext()->isDependentContext()) + return true; + + return false; } std::string DeclarationName::getAsString() const { @@ -285,6 +322,12 @@ QualType DeclarationName::getCXXNameType() const { return QualType(); } +TemplateDecl *DeclarationName::getCXXDeductionGuideTemplate() const { + if (auto *Guide = getAsCXXDeductionGuideNameExtra()) + return Guide->Template; + return nullptr; +} + OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const { if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) { unsigned value @@ -312,6 +355,9 @@ void *DeclarationName::getFETokenInfoAsVoidSlow() const { case CXXConversionFunctionName: return getAsCXXSpecialName()->FETokenInfo; + case CXXDeductionGuideName: + return getAsCXXDeductionGuideNameExtra()->FETokenInfo; + case CXXOperatorName: return getAsCXXOperatorIdName()->FETokenInfo; @@ -335,6 +381,10 @@ void DeclarationName::setFETokenInfo(void *T) { getAsCXXSpecialName()->FETokenInfo = T; break; + case CXXDeductionGuideName: + getAsCXXDeductionGuideNameExtra()->FETokenInfo = T; + break; + case CXXOperatorName: getAsCXXOperatorIdName()->FETokenInfo = T; break; @@ -366,6 +416,7 @@ LLVM_DUMP_METHOD void DeclarationName::dump() const { DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>; + CXXDeductionGuideNames = new llvm::FoldingSet<CXXDeductionGuideNameExtra>; // Initialize the overloaded operator names. CXXOperatorNames = new (Ctx) CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; @@ -377,14 +428,18 @@ DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { } DeclarationNameTable::~DeclarationNameTable() { - llvm::FoldingSet<CXXSpecialName> *SpecialNames = - static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); - llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames - = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> - (CXXLiteralOperatorNames); + auto *SpecialNames = + static_cast<llvm::FoldingSet<CXXSpecialName> *>(CXXSpecialNamesImpl); + auto *LiteralNames = + static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName> *>( + CXXLiteralOperatorNames); + auto *DeductionGuideNames = + static_cast<llvm::FoldingSet<CXXDeductionGuideNameExtra> *>( + CXXDeductionGuideNames); delete SpecialNames; delete LiteralNames; + delete DeductionGuideNames; } DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) { @@ -398,6 +453,30 @@ DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) { } DeclarationName +DeclarationNameTable::getCXXDeductionGuideName(TemplateDecl *Template) { + Template = cast<TemplateDecl>(Template->getCanonicalDecl()); + + auto *DeductionGuideNames = + static_cast<llvm::FoldingSet<CXXDeductionGuideNameExtra> *>( + CXXDeductionGuideNames); + + llvm::FoldingSetNodeID ID; + ID.AddPointer(Template); + + void *InsertPos = nullptr; + if (auto *Name = DeductionGuideNames->FindNodeOrInsertPos(ID, InsertPos)) + return DeclarationName(Name); + + auto *Name = new (Ctx) CXXDeductionGuideNameExtra; + Name->ExtraKindOrNumArgs = DeclarationNameExtra::CXXDeductionGuide; + Name->Template = Template; + Name->FETokenInfo = nullptr; + + DeductionGuideNames->InsertNode(Name, InsertPos); + return DeclarationName(Name); +} + +DeclarationName DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) { return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty); } @@ -477,6 +556,7 @@ DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) { switch (Name.getNameKind()) { case DeclarationName::Identifier: + case DeclarationName::CXXDeductionGuideName: break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: @@ -509,6 +589,7 @@ bool DeclarationNameInfo::containsUnexpandedParameterPack() const { case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: return false; case DeclarationName::CXXConstructorName: @@ -531,6 +612,7 @@ bool DeclarationNameInfo::isInstantiationDependent() const { case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: return false; case DeclarationName::CXXConstructorName: @@ -560,6 +642,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: OS << Name; return; @@ -585,6 +668,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { SourceLocation DeclarationNameInfo::getEndLoc() const { switch (Name.getNameKind()) { case DeclarationName::Identifier: + case DeclarationName::CXXDeductionGuideName: return NameLoc; case DeclarationName::CXXOperatorName: { diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 4c1beaab10b..1aa9ad26e9c 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1190,6 +1190,8 @@ void CXXNameMangler::mangleUnresolvedName( llvm_unreachable("Can't mangle a constructor name!"); case DeclarationName::CXXUsingDirective: llvm_unreachable("Can't mangle a using directive name!"); + case DeclarationName::CXXDeductionGuideName: + llvm_unreachable("Can't mangle a deduction guide name!"); case DeclarationName::ObjCMultiArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCZeroArgSelector: @@ -1419,6 +1421,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, writeAbiTags(ND, AdditionalAbiTags); break; + case DeclarationName::CXXDeductionGuideName: + llvm_unreachable("Can't mangle a deduction guide name!"); + case DeclarationName::CXXUsingDirective: llvm_unreachable("Can't mangle a using directive name!"); } @@ -1997,6 +2002,7 @@ void CXXNameMangler::mangleOperatorName(DeclarationName Name, unsigned Arity) { switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: + case DeclarationName::CXXDeductionGuideName: case DeclarationName::CXXUsingDirective: case DeclarationName::Identifier: case DeclarationName::ObjCMultiArgSelector: diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index a76d186747e..07e38eb7bba 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -942,6 +942,9 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, break; } + case DeclarationName::CXXDeductionGuideName: + llvm_unreachable("Can't mangle a deduction guide name!"); + case DeclarationName::CXXUsingDirective: llvm_unreachable("Can't mangle a using directive name!"); } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 6da61c689eb..9e8823fb4d1 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3025,6 +3025,16 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isConstructorDeclarator(/*Unqualified*/true)) goto DoneWithDeclSpec; + // Likewise, if this is a context where the identifier could be a template + // name, check whether this is a deduction guide declaration. + if (getLangOpts().CPlusPlus1z && + (DSContext == DSC_class || DSContext == DSC_top_level) && + Actions.isDeductionGuideName(getCurScope(), *Tok.getIdentifierInfo(), + Tok.getLocation()) && + isConstructorDeclarator(/*Unqualified*/ true, + /*DeductionGuide*/ true)) + goto DoneWithDeclSpec; + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, TypeRep, Policy); if (isInvalid) @@ -4644,7 +4654,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { } } -bool Parser::isConstructorDeclarator(bool IsUnqualified) { +bool Parser::isConstructorDeclarator(bool IsUnqualified, bool DeductionGuide) { TentativeParsingAction TPA(*this); // Parse the C++ scope specifier. @@ -4732,6 +4742,11 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { case tok::r_paren: // C(X ) + if (DeductionGuide) { + // C(X) -> ... is a deduction guide. + IsConstructor = NextToken().is(tok::arrow); + break; + } if (NextToken().is(tok::colon) || NextToken().is(tok::kw_try)) { // Assume these were meant to be constructors: // C(X) : (the name of a bit-field cannot be parenthesized). @@ -4749,7 +4764,7 @@ bool Parser::isConstructorDeclarator(bool IsUnqualified) { // // FIXME: We can actually do this whether or not the name is qualified, // because if it is qualified in this context it must be being used as - // a constructor name. However, we do not implement that rule correctly + // a constructor name. // currently, so we're somewhat conservative here. IsConstructor = IsUnqualified; } @@ -5280,21 +5295,29 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. bool AllowConstructorName; - if (D.getDeclSpec().hasTypeSpecifier()) + bool AllowDeductionGuide; + if (D.getDeclSpec().hasTypeSpecifier()) { AllowConstructorName = false; - else if (D.getCXXScopeSpec().isSet()) + AllowDeductionGuide = false; + } else if (D.getCXXScopeSpec().isSet()) { AllowConstructorName = (D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext); - else + AllowDeductionGuide = false; + } else { AllowConstructorName = (D.getContext() == Declarator::MemberContext); + AllowDeductionGuide = + (D.getContext() == Declarator::FileContext || + D.getContext() == Declarator::MemberContext); + } SourceLocation TemplateKWLoc; bool HadScope = D.getCXXScopeSpec().isValid(); if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, - nullptr, TemplateKWLoc, D.getName()) || + AllowDeductionGuide, nullptr, TemplateKWLoc, + D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. D.getCXXScopeSpec().isInvalid()) { diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 6403caa27b3..d5589096033 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -576,6 +576,7 @@ bool Parser::ParseUsingDeclarator(unsigned Context, UsingDeclarator &D) { /*AllowDestructorName=*/true, /*AllowConstructorName=*/!(Tok.is(tok::identifier) && NextToken().is(tok::equal)), + /*AllowDeductionGuide=*/false, nullptr, D.TemplateKWLoc, D.Name)) return true; } @@ -2426,8 +2427,8 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Try to parse an unqualified-id. SourceLocation TemplateKWLoc; UnqualifiedId Name; - if (ParseUnqualifiedId(SS, false, true, true, nullptr, TemplateKWLoc, - Name)) { + if (ParseUnqualifiedId(SS, false, true, true, false, nullptr, + TemplateKWLoc, Name)) { SkipUntil(tok::semi); return nullptr; } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index ee06c76f602..0c09614547c 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1693,6 +1693,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /*AllowDestructorName=*/true, /*AllowConstructorName=*/ getLangOpts().MicrosoftExt, + /*AllowDeductionGuide=*/false, ObjectType, TemplateKWLoc, Name)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index cfda2cddec8..1ba1695800f 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -546,6 +546,7 @@ ExprResult Parser::tryParseCXXIdExpression(CXXScopeSpec &SS, bool isAddressOfOpe /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, /*ObjectType=*/nullptr, TemplateKWLoc, Name)) return ExprError(); @@ -2429,6 +2430,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, /// /// \param AllowConstructorName whether we allow parsing a constructor name. /// +/// \param AllowDeductionGuide whether we allow parsing a deduction guide name. +/// /// \param ObjectType if this unqualified-id occurs within a member access /// expression, the type of the base object whose member is being accessed. /// @@ -2438,6 +2441,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, + bool AllowDeductionGuide, ParsedType ObjectType, SourceLocation& TemplateKWLoc, UnqualifiedId &Result) { @@ -2466,6 +2470,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, return false; } + ParsedTemplateTy TemplateName; if (AllowConstructorName && Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. @@ -2474,6 +2479,12 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, /*IsCtorOrDtorName=*/true, /*NonTrivialTypeSourceInfo=*/true); Result.setConstructorName(Ty, IdLoc, IdLoc); + } else if (getLangOpts().CPlusPlus1z && + AllowDeductionGuide && SS.isEmpty() && + Actions.isDeductionGuideName(getCurScope(), *Id, IdLoc, + &TemplateName)) { + // We have parsed a template-name naming a deduction guide. + Result.setDeductionGuideName(TemplateName, IdLoc); } else { // We have parsed an identifier. Result.setIdentifier(Id, IdLoc); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index cab7d3432db..574ed6ee598 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -1053,7 +1053,7 @@ bool Parser::ParseOpenMPSimpleVarList( IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); - } else if (ParseUnqualifiedId(SS, false, false, false, nullptr, + } else if (ParseUnqualifiedId(SS, false, false, false, false, nullptr, TemplateKWLoc, Name)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, @@ -1557,8 +1557,9 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec, } return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false, /*AllowDestructorName*/ false, - /*AllowConstructorName*/ false, nullptr, - TemplateKWLoc, ReductionId); + /*AllowConstructorName*/ false, + /*AllowDeductionGuide*/ false, + nullptr, TemplateKWLoc, ReductionId); } /// Parses clauses with list. diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index 7fd9fa21462..59e96d982a0 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -224,6 +224,7 @@ ExprResult Parser::ParseMSAsmIdentifier(llvm::SmallVectorImpl<Token> &LineToks, /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, /*ObjectType=*/nullptr, TemplateKWLoc, Id); // Perform the lookup. Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 8713bb2c23f..9030ebff0f6 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1966,8 +1966,10 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { // Parse the unqualified-id. SourceLocation TemplateKWLoc; // FIXME: parsed, but unused. - if (ParseUnqualifiedId(Result.SS, false, true, true, nullptr, TemplateKWLoc, - Result.Name)) { + if (ParseUnqualifiedId( + Result.SS, /*EnteringContext*/false, /*AllowDestructorName*/true, + /*AllowConstructorName*/true, /*AllowDeductionGuide*/false, nullptr, + TemplateKWLoc, Result.Name)) { T.skipToEnd(); return true; } diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 85343cde2ba..5f65df2ef37 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -2585,6 +2585,7 @@ static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy, Result.getAllocator().CopyString(ND->getNameAsString())); break; + case DeclarationName::CXXDeductionGuideName: case DeclarationName::CXXUsingDirective: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 32663121f88..41d977fa9c6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -4675,6 +4675,34 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { NameInfo.setLoc(Name.StartLocation); return NameInfo; + case UnqualifiedId::IK_DeductionGuideName: { + // C++ [temp.deduct.guide]p3: + // The simple-template-id shall name a class template specialization. + // The template-name shall be the same identifier as the template-name + // of the simple-template-id. + // These together intend to imply that the template-name shall name a + // class template. + // FIXME: template<typename T> struct X {}; + // template<typename T> using Y = X<T>; + // Y(int) -> Y<int>; + // satisfies these rules but does not name a class template. + TemplateName TN = Name.TemplateName.get().get(); + auto *Template = TN.getAsTemplateDecl(); + if (!Template || !isa<ClassTemplateDecl>(Template)) { + Diag(Name.StartLocation, + diag::err_deduction_guide_name_not_class_template) + << (int)getTemplateNameKindForDiagnostics(TN) << TN; + if (Template) + Diag(Template->getLocation(), diag::note_template_decl_here); + return DeclarationNameInfo(); + } + + NameInfo.setName( + Context.DeclarationNames.getCXXDeductionGuideName(Template)); + NameInfo.setLoc(Name.StartLocation); + return NameInfo; + } + case UnqualifiedId::IK_OperatorFunctionId: NameInfo.setName(Context.DeclarationNames.getCXXOperatorName( Name.OperatorFunctionId.Operator)); @@ -7621,6 +7649,15 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, R, TInfo, isInline, isExplicit, isConstexpr, SourceLocation()); + } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) { + SemaRef.CheckDeductionGuideDeclarator(D, R, SC); + + // We don't need to store any extra information for a deduction guide, so + // just model it as a plain FunctionDecl. + return FunctionDecl::Create(SemaRef.Context, DC, + D.getLocStart(), + NameInfo, R, TInfo, SC, isInline, + true/*HasPrototype*/, isConstexpr); } else if (DC->isRecord()) { // If the name of the function is the same as the name of the record, // then this must be an invalid constructor that has a return type. @@ -8109,7 +8146,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // The explicit specifier shall be used only in the declaration of a // constructor or conversion function within its class definition; // see 12.3.1 and 12.3.2. - if (isExplicit && !NewFD->isInvalidDecl()) { + if (isExplicit && !NewFD->isInvalidDecl() && !NewFD->isDeductionGuide()) { if (!CurContext->isRecord()) { // 'explicit' was specified outside of the class. Diag(D.getDeclSpec().getExplicitSpecLoc(), diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 671d3251a54..49cf8e15ed5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -8033,6 +8033,15 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { return Conversion; } +/// Check the validity of a declarator that we parsed for a deduction-guide. +/// These aren't actually declarators in the grammar, so we need to check that +/// the user didn't specify any pieces that are not part of the deduction-guide +/// grammar. +void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, + StorageClass &SC) { + // FIXME: Implement +} + //===----------------------------------------------------------------------===// // Namespace Handling //===----------------------------------------------------------------------===// @@ -8613,6 +8622,9 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, Diag(Name.getLocStart(), diag::err_using_decl_template_id) << SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc); return nullptr; + + case UnqualifiedId::IK_DeductionGuideName: + llvm_unreachable("cannot parse qualified deduction guide name"); } DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); @@ -13747,6 +13759,9 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, case UnqualifiedId::IK_ConversionFunctionId: DiagArg = 2; break; + case UnqualifiedId::IK_DeductionGuideName: + DiagArg = 3; + break; case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_LiteralOperatorId: diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 54556b505ee..4ea04ac143a 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -321,6 +321,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: return false; case DeclarationName::CXXConstructorName: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a59511ca77e..250f6f99464 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2733,6 +2733,17 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, D.getDeclSpec().getAttributes().getList()); break; + case UnqualifiedId::IK_DeductionGuideName: + // Deduction guides have a trailing return type and no type in their + // decl-specifier sequence. + T = SemaRef.Context.getAutoDeductType(); + if (!D.hasTrailingReturnType()) { + SemaRef.Diag(D.getName().getLocStart(), + diag::err_deduction_guide_no_trailing_return_type); + D.setInvalidType(true); + } + break; + case UnqualifiedId::IK_ConversionFunctionId: // The result type of a conversion function is the type that it // converts to. @@ -2884,20 +2895,10 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, // better diagnostics. // We don't support '__auto_type' with trailing return types. // FIXME: Should we only do this for 'auto' and not 'decltype(auto)'? - if (SemaRef.getLangOpts().CPlusPlus11 && IsCXXAutoType) { - for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { - unsigned chunkIndex = e - i - 1; - state.setCurrentChunkIndex(chunkIndex); - DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); - if (DeclType.Kind == DeclaratorChunk::Function) { - const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - if (FTI.hasTrailingReturnType()) { - HaveTrailing = true; - Error = -1; - break; - } - } - } + if (SemaRef.getLangOpts().CPlusPlus11 && IsCXXAutoType && + D.hasTrailingReturnType()) { + HaveTrailing = true; + Error = -1; } SourceRange AutoRange = D.getDeclSpec().getTypeSpecTypeLoc(); @@ -4176,16 +4177,22 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } else if (FTI.hasTrailingReturnType()) { // T must be exactly 'auto' at this point. See CWG issue 681. if (isa<ParenType>(T)) { - S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + S.Diag(D.getLocStart(), diag::err_trailing_return_in_parens) - << T << D.getDeclSpec().getSourceRange(); + << T << D.getSourceRange(); D.setInvalidType(true); } else if (D.getContext() != Declarator::LambdaExprContext && (T.hasQualifiers() || !isa<AutoType>(T) || - cast<AutoType>(T)->getKeyword() != AutoTypeKeyword::Auto)) { - S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), - diag::err_trailing_return_without_auto) - << T << D.getDeclSpec().getSourceRange(); + cast<AutoType>(T)->getKeyword() != + AutoTypeKeyword::Auto)) { + if (D.getName().getKind() == UnqualifiedId::IK_DeductionGuideName) + S.Diag(D.getDeclSpec().getLocStart(), + diag::err_deduction_guide_with_complex_decl) + << D.getSourceRange(); + else + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_trailing_return_without_auto) + << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 7019f15849a..ef349c395f8 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3617,6 +3617,19 @@ TreeTransform<Derived> case DeclarationName::CXXUsingDirective: return NameInfo; + case DeclarationName::CXXDeductionGuideName: { + TemplateDecl *OldTemplate = Name.getCXXDeductionGuideTemplate(); + TemplateDecl *NewTemplate = cast_or_null<TemplateDecl>( + getDerived().TransformDecl(NameInfo.getLoc(), OldTemplate)); + if (!NewTemplate) + return DeclarationNameInfo(); + + DeclarationNameInfo NewNameInfo(NameInfo); + NewNameInfo.setName( + SemaRef.Context.DeclarationNames.getCXXDeductionGuideName(NewTemplate)); + return NewNameInfo; + } + case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index da8e5ff6b90..67c7e460997 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -944,6 +944,10 @@ DeclarationNameKey::DeclarationNameKey(DeclarationName Name) case DeclarationName::CXXLiteralOperatorName: Data = (uint64_t)Name.getCXXLiteralIdentifier(); break; + case DeclarationName::CXXDeductionGuideName: + Data = (uint64_t)Name.getCXXDeductionGuideTemplate() + ->getDeclName().getAsIdentifierInfo(); + break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: @@ -960,6 +964,7 @@ unsigned DeclarationNameKey::getHash() const { switch (Kind) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: ID.AddString(((IdentifierInfo*)Data)->getName()); break; case DeclarationName::ObjCZeroArgSelector: @@ -1003,6 +1008,8 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) { uint64_t Data; switch (Kind) { case DeclarationName::Identifier: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: Data = (uint64_t)Reader.getLocalIdentifier( F, endian::readNext<uint32_t, little, unaligned>(d)); break; @@ -1017,10 +1024,6 @@ ASTDeclContextNameLookupTrait::ReadKey(const unsigned char *d, unsigned) { case DeclarationName::CXXOperatorName: Data = *d++; // OverloadedOperatorKind break; - case DeclarationName::CXXLiteralOperatorName: - Data = (uint64_t)Reader.getLocalIdentifier( - F, endian::readNext<uint32_t, little, unaligned>(d)); - break; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: @@ -7992,6 +7995,10 @@ ASTReader::ReadDeclarationName(ModuleFile &F, return Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(readType(F, Record, Idx))); + case DeclarationName::CXXDeductionGuideName: + return Context.DeclarationNames.getCXXDeductionGuideName( + ReadDeclAs<TemplateDecl>(F, Record, Idx)); + case DeclarationName::CXXConversionFunctionName: return Context.DeclarationNames.getCXXConversionFunctionName( Context.getCanonicalType(readType(F, Record, Idx))); @@ -8039,6 +8046,7 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: break; } } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 1f5ef422c5e..69136015f48 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3600,6 +3600,7 @@ public: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: KeyLen += 4; break; case DeclarationName::CXXOperatorName: @@ -3629,6 +3630,7 @@ public: switch (Name.getKind()) { case DeclarationName::Identifier: case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXDeductionGuideName: LE.write<uint32_t>(Writer.getIdentifierRef(Name.getIdentifier())); return; case DeclarationName::ObjCZeroArgSelector: @@ -5273,6 +5275,10 @@ void ASTRecordWriter::AddDeclarationName(DeclarationName Name) { AddTypeRef(Name.getCXXNameType()); break; + case DeclarationName::CXXDeductionGuideName: + AddDeclRef(Name.getCXXDeductionGuideTemplate()); + break; + case DeclarationName::CXXOperatorName: Record->push_back(Name.getCXXOverloadedOperator()); break; @@ -5334,6 +5340,7 @@ void ASTRecordWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: break; } } diff --git a/clang/test/CXX/temp/temp.deduct.guide/p1.cpp b/clang/test/CXX/temp/temp.deduct.guide/p1.cpp new file mode 100644 index 00000000000..08c4c936191 --- /dev/null +++ b/clang/test/CXX/temp/temp.deduct.guide/p1.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s +// RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s -DCLASS + +#ifdef CLASS +struct Outer { +#endif + +template<typename> struct A {}; + +// Valid forms. +A(int(&)[1]) -> A<int>; +explicit A(int(&)[2]) -> A<int>; + +// Declarator pieces are not OK. +*A(int(&)[3]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}} +&A(int(&)[4]) -> A<int>; // expected-error {{cannot specify any part of a return type in the declaration of a deduction guide}} +A(int(&)[5])[3] -> A<int>; +#ifdef CLASS // FIXME: These diagnostics are both pretty bad. +// expected-error@-2 {{deduction guide declaration without trailing return type}} expected-error@-2 {{array of 'auto'}} expected-error@-2 {{';'}} +#else +// expected-error@-4 {{expected function body after function declarator}} +#endif + +// (Pending DR) attributes and parens around the declarator-id are OK. +[[deprecated]] A(int(&)[6]) [[]] -> A<int> [[]]; +A [[]] (int(&)[7]) -> A<int>; // FIXME: expected-error 2{{expected}} expected-note {{to match}} +(A)(int(&)[8]) -> A<int>; + +// ... but the trailing-return-type is part of the function-declarator as normal +(A(int(&)[9])) -> A<int>; +#ifdef CLASS // FIXME: These diagnostics are both pretty bad. +// expected-error@-2 {{deduction guide declaration without trailing return type}} expected-error@-2 {{';'}} +#else +// expected-error@-4 {{expected function body after function declarator}} +#endif +(A(int(&)[10]) -> A<int>); // expected-error {{trailing return type may not be nested within parentheses}} + +// A trailing-return-type is mandatory. +A(int(&)[11]); // expected-error {{deduction guide declaration without trailing return type}} + +// No type specifier is permitted; we don't even parse such cases as a deduction-guide. +int A(int) -> A<int>; // expected-error {{function with trailing return type must specify return type 'auto', not 'int'}} +template<typename T> struct B {}; // expected-note {{here}} +auto B(int) -> B<int>; // expected-error {{redefinition of 'B' as different kind of symbol}} + +// FIXME: No storage class specifier, function specifier, ... +friend A(int(&)[20]) -> A<int>; +#ifdef CLASS +// expected-error@-2 {{cannot declare a deduction guide as a friend}} +#else +// expected-error@-4 {{'friend' used outside of class}} +#endif +typedef A(int(&)[21]) -> A<int>; // FIXME: Bad diagnostic: expected-error {{typedef name must be an identifier}} +constexpr A(int(&)[22]) -> A<int>; +inline A(int(&)[23]) -> A<int>; +static A(int(&)[24]) -> A<int>; +thread_local A(int(&)[25]) -> A<int>; // expected-error {{'thread_local' is only allowed on variable declarations}} +extern A(int(&)[26]) -> A<int>; +#ifdef CLASS +// expected-error@-2 {{storage class specified for a member}} +#endif +mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}} +virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}} + +// FIXME: No definition is allowed. +A(int(&)[30]) -> A<int> {} +A(int(&)[31]) -> A<int> = default; // expected-error {{only special member functions may be defaulted}} +A(int(&)[32]) -> A<int> = delete; +A(int(&)[33]) -> A<int> try {} catch (...) {} + +#ifdef CLASS +}; +#endif diff --git a/clang/test/CXX/temp/temp.deduct.guide/p2.cpp b/clang/test/CXX/temp/temp.deduct.guide/p2.cpp new file mode 100644 index 00000000000..ef45429b1a7 --- /dev/null +++ b/clang/test/CXX/temp/temp.deduct.guide/p2.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +namespace std_example { + template<typename T, typename U = int> struct S { + T data; + }; + template<typename U> S(U) -> S<typename U::type>; + + struct A { + using type = short; + operator type(); + }; + S x{A()}; // expected-error {{not yet supported}} +} diff --git a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp new file mode 100644 index 00000000000..3db40e31a95 --- /dev/null +++ b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -std=c++1z %s -verify + +// The same restrictions apply to the parameter-declaration-clause of a +// deduction guide as in a function declaration. +template<typename T> struct A {}; +A(void) -> A<int>; // ok +A(void, int) -> A<int>; // expected-error {{'void' must be the first and only parameter if specified}} + +// We interpret this as also extending to the validity of redeclarations. It's +// a bit of a stretch (OK, a lot of a stretch) but it gives desirable answers. +A() -> A<int>; // ok, redeclaration + +A() -> A<int>; // expected-note {{previous}} +A() -> A<float>; // FIXME: "functions" is a poor term. expected-error {{functions that differ only in their return type cannot be overloaded}} + +template<typename T> A(T) -> A<typename T::foo>; +template<typename T> A(T) -> A<typename T::bar>; // ok, can overload on return type (SFINAE applies) + +A(long) -> A<int>; +template<typename T = int> A(long) -> A<char>; // ok, non-template beats template as usual + +// (Pending DR) The template-name shall name a class template. +template<typename T> using B = A<T>; // expected-note {{template}} +B() -> B<int>; // expected-error {{cannot specify deduction guide for alias template 'B'}} +// FIXME: expected-error@-1 {{declarator requires an identifier}} +template<typename T> int C; +C() -> int; // expected-error {{requires a type specifier}} +template<typename T> void D(); +D() -> int; // expected-error {{requires a type specifier}} +template<template<typename> typename TT> struct E { // expected-note 2{{template}} + // FIXME: Should only diagnose this once! + TT(int) -> TT<int>; // expected-error 2{{cannot specify deduction guide for template template parameter 'TT'}} expected-error {{requires an identifier}} +}; + +// FIXME: Even if the DR is applied as we hope, we should still warn if the +// trailing-return-type can obviously never produce a specialization of the +// named template. +A(int) -> int; +template<typename T> A(T) -> T*; + +// A deduction-guide shall be declared in the same scope as the corresponding +// class template. +namespace WrongScope { + namespace { + template<typename T> struct AnonNS1 {}; + AnonNS1(float) -> AnonNS1<float>; // ok + } + AnonNS1(int) -> AnonNS1<int>; // FIXME + template<typename T> struct AnonNS2 {}; + namespace { + AnonNS1(char) -> AnonNS1<char>; // ok + AnonNS2(int) -> AnonNS2<int>; // FIXME + } + namespace N { + template<typename T> struct NamedNS1 {}; + template<typename T> struct NamedNS2 {}; + } + using N::NamedNS1; + NamedNS1(int) -> NamedNS1<int>; // FIXME + using namespace N; + NamedNS2(int) -> NamedNS2<int>; // FIXME + struct ClassMemberA { + template<typename T> struct X {}; + }; + struct ClassMemberB : ClassMemberA { + X(int) -> X<int>; // FIXME + }; + template<typename T> struct Local {}; + void f() { + Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}} + using WrongScope::Local; + Local(int) -> Local<int>; // expected-error 2{{expected}} expected-note {{to match}} + } +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 6f4868d4b6f..f4661ca2066 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1265,10 +1265,11 @@ bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { switch (Name.getName().getNameKind()) { case clang::DeclarationName::Identifier: case clang::DeclarationName::CXXLiteralOperatorName: + case clang::DeclarationName::CXXDeductionGuideName: case clang::DeclarationName::CXXOperatorName: case clang::DeclarationName::CXXUsingDirective: return false; - + case clang::DeclarationName::CXXConstructorName: case clang::DeclarationName::CXXDestructorName: case clang::DeclarationName::CXXConversionFunctionName: |