Author: rsmith Date: Mon Feb 6 19:37:30 2017 New Revision: 294266 URL: http://llvm.org/viewvc/llvm-project?rev=294266&view=rev Log: P0091R3: Implement basic parsing support for C++17 deduction-guides.
We model deduction-guides as functions with a new kind of name that identifies the template whose deduction they guide; the bulk of this patch is adding the new name kind. This gives us a clean way to attach an extensible list of guides to a class template in a way that doesn't require any special handling in AST files etc (and we're going to need these functions we come to performing deduction). Added: cfe/trunk/test/CXX/temp/temp.deduct.guide/ cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp Modified: cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/DeclarationName.h cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Basic/IdentifierTable.h cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/include/clang/Sema/DeclSpec.h cfe/trunk/include/clang/Sema/Ownership.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Serialization/ASTBitCodes.h cfe/trunk/lib/AST/ASTImporter.cpp cfe/trunk/lib/AST/DeclarationName.cpp cfe/trunk/lib/AST/ItaniumMangle.cpp cfe/trunk/lib/AST/MicrosoftMangle.cpp cfe/trunk/lib/Parse/ParseDecl.cpp cfe/trunk/lib/Parse/ParseDeclCXX.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Parse/ParseExprCXX.cpp cfe/trunk/lib/Parse/ParseOpenMP.cpp cfe/trunk/lib/Parse/ParseStmtAsm.cpp cfe/trunk/lib/Parse/Parser.cpp cfe/trunk/lib/Sema/SemaCodeComplete.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/lib/Sema/TreeTransform.h cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/tools/libclang/CIndex.cpp Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Mon Feb 6 19:37:30 2017 @@ -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; Modified: cfe/trunk/include/clang/AST/DeclarationName.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclarationName.h (original) +++ cfe/trunk/include/clang/AST/DeclarationName.h Mon Feb 6 19:37:30 2017 @@ -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); Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Mon Feb 6 19:37:30 2017 @@ -774,6 +774,11 @@ bool RecursiveASTVisitor<Derived>::Trave 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: Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Feb 6 19:37:30 2017 @@ -1207,8 +1207,9 @@ def warn_cxx98_compat_unelaborated_frien 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_ "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< Modified: cfe/trunk/include/clang/Basic/IdentifierTable.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/IdentifierTable.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/IdentifierTable.h (original) +++ cfe/trunk/include/clang/Basic/IdentifierTable.h Mon Feb 6 19:37:30 2017 @@ -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 Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Mon Feb 6 19:37:30 2017 @@ -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); Modified: cfe/trunk/include/clang/Sema/DeclSpec.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/DeclSpec.h (original) +++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Feb 6 19:37:30 2017 @@ -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. /// Modified: cfe/trunk/include/clang/Sema/Ownership.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Ownership.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Ownership.h (original) +++ cfe/trunk/include/clang/Sema/Ownership.h Mon Feb 6 19:37:30 2017 @@ -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; Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Mon Feb 6 19:37:30 2017 @@ -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, Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original) +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Mon Feb 6 19:37:30 2017 @@ -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 { Modified: cfe/trunk/lib/AST/ASTImporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTImporter.cpp (original) +++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Feb 6 19:37:30 2017 @@ -2264,6 +2264,7 @@ ASTNodeImporter::ImportDeclarationNameLo case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: return; case DeclarationName::CXXOperatorName: { @@ -7448,6 +7449,14 @@ DeclarationName ASTImporter::Import(Decl 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()) Modified: cfe/trunk/lib/AST/DeclarationName.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclarationName.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclarationName.cpp (original) +++ cfe/trunk/lib/AST/DeclarationName.cpp Mon Feb 6 19:37:30 2017 @@ -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(Declaration 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 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 DeclarationNam case DeclarationNameExtra::CXXDestructor: return CXXDestructorName; + case DeclarationNameExtra::CXXDeductionGuide: + return CXXDeductionGuideName; + case DeclarationNameExtra::CXXConversionFunction: return CXXConversionFunctionName; @@ -268,7 +297,15 @@ DeclarationName::NameKind DeclarationNam 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 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::getFETokenInfoAsV case CXXConversionFunctionName: return getAsCXXSpecialName()->FETokenInfo; + case CXXDeductionGuideName: + return getAsCXXDeductionGuideNameExtra()->FETokenInfo; + case CXXOperatorName: return getAsCXXOperatorIdName()->FETokenInfo; @@ -335,6 +381,10 @@ void DeclarationName::setFETokenInfo(voi 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::d 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::DeclarationNameTab } 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::ge } 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::getCXXLiteralOpera 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::containsUnexpa case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: return false; case DeclarationName::CXXConstructorName: @@ -531,6 +612,7 @@ bool DeclarationNameInfo::isInstantiatio 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_ case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: OS << Name; return; @@ -585,6 +668,7 @@ void DeclarationNameInfo::printName(raw_ SourceLocation DeclarationNameInfo::getEndLoc() const { switch (Name.getNameKind()) { case DeclarationName::Identifier: + case DeclarationName::CXXDeductionGuideName: return NameLoc; case DeclarationName::CXXOperatorName: { Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original) +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Mon Feb 6 19:37:30 2017 @@ -1190,6 +1190,8 @@ void CXXNameMangler::mangleUnresolvedNam 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::mangleUnqualifiedNa 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( switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: + case DeclarationName::CXXDeductionGuideName: case DeclarationName::CXXUsingDirective: case DeclarationName::Identifier: case DeclarationName::ObjCMultiArgSelector: Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original) +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Mon Feb 6 19:37:30 2017 @@ -942,6 +942,9 @@ void MicrosoftCXXNameMangler::mangleUnqu 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!"); } Modified: cfe/trunk/lib/Parse/ParseDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp (original) +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Feb 6 19:37:30 2017 @@ -3025,6 +3025,16 @@ void Parser::ParseDeclarationSpecifiers( 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 } } -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(boo 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(boo // // 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(Decla // 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()) { Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Feb 6 19:37:30 2017 @@ -576,6 +576,7 @@ bool Parser::ParseUsingDeclarator(unsign /*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(A // 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; } Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Mon Feb 6 19:37:30 2017 @@ -1693,6 +1693,7 @@ Parser::ParsePostfixExpressionSuffix(Exp /*AllowDestructorName=*/true, /*AllowConstructorName=*/ getLangOpts().MicrosoftExt, + /*AllowDeductionGuide=*/false, ObjectType, TemplateKWLoc, Name)) { (void)Actions.CorrectDelayedTyposInExpr(LHS); LHS = ExprError(); Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original) +++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Feb 6 19:37:30 2017 @@ -546,6 +546,7 @@ ExprResult Parser::tryParseCXXIdExpressi /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, /*ObjectType=*/nullptr, TemplateKWLoc, Name)) return ExprError(); @@ -2429,6 +2430,8 @@ bool Parser::ParseUnqualifiedIdOperator( /// /// \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( 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(CXXScope return false; } + ParsedTemplateTy TemplateName; if (AllowConstructorName && Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. @@ -2474,6 +2479,12 @@ bool Parser::ParseUnqualifiedId(CXXScope /*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); Modified: cfe/trunk/lib/Parse/ParseOpenMP.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseOpenMP.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseOpenMP.cpp (original) +++ cfe/trunk/lib/Parse/ParseOpenMP.cpp Mon Feb 6 19:37:30 2017 @@ -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, } return P.ParseUnqualifiedId(ReductionIdScopeSpec, /*EnteringContext*/ false, /*AllowDestructorName*/ false, - /*AllowConstructorName*/ false, nullptr, - TemplateKWLoc, ReductionId); + /*AllowConstructorName*/ false, + /*AllowDeductionGuide*/ false, + nullptr, TemplateKWLoc, ReductionId); } /// Parses clauses with list. Modified: cfe/trunk/lib/Parse/ParseStmtAsm.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmtAsm.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseStmtAsm.cpp (original) +++ cfe/trunk/lib/Parse/ParseStmtAsm.cpp Mon Feb 6 19:37:30 2017 @@ -224,6 +224,7 @@ ExprResult Parser::ParseMSAsmIdentifier( /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, /*ObjectType=*/nullptr, TemplateKWLoc, Id); // Perform the lookup. Result = Actions.LookupInlineAsmIdentifier(SS, TemplateKWLoc, Id, Info, Modified: cfe/trunk/lib/Parse/Parser.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Parse/Parser.cpp (original) +++ cfe/trunk/lib/Parse/Parser.cpp Mon Feb 6 19:37:30 2017 @@ -1966,8 +1966,10 @@ bool Parser::ParseMicrosoftIfExistsCondi // 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; } Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original) +++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Mon Feb 6 19:37:30 2017 @@ -2585,6 +2585,7 @@ static void AddTypedNameChunk(ASTContext Result.getAllocator().CopyString(ND->getNameAsString())); break; + case DeclarationName::CXXDeductionGuideName: case DeclarationName::CXXUsingDirective: case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Feb 6 19:37:30 2017 @@ -4675,6 +4675,34 @@ Sema::GetNameFromUnqualifiedId(const Unq 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* CreateNewFunctionDe 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, // 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(), Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Feb 6 19:37:30 2017 @@ -8033,6 +8033,15 @@ Decl *Sema::ActOnConversionDeclarator(CX 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 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 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: Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Mon Feb 6 19:37:30 2017 @@ -321,6 +321,7 @@ bool Sema::DiagnoseUnexpandedParameterPa case DeclarationName::CXXOperatorName: case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: return false; case DeclarationName::CXXConstructorName: Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Mon Feb 6 19:37:30 2017 @@ -2733,6 +2733,17 @@ static QualType GetDeclSpecTypeForDeclar 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 GetDeclSpecTypeForDeclar // 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 *GetFullTypeForDec } 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); Modified: cfe/trunk/lib/Sema/TreeTransform.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Sema/TreeTransform.h (original) +++ cfe/trunk/lib/Sema/TreeTransform.h Mon Feb 6 19:37:30 2017 @@ -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: { Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Feb 6 19:37:30 2017 @@ -944,6 +944,10 @@ DeclarationNameKey::DeclarationNameKey(D 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() c 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(c 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(c 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(ModuleFil 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(M case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: break; } } Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Mon Feb 6 19:37:30 2017 @@ -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 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::AddDeclarationName case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: case DeclarationName::CXXUsingDirective: + case DeclarationName::CXXDeductionGuideName: break; } } Added: cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp?rev=294266&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp Mon Feb 6 19:37:30 2017 @@ -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 Added: cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp?rev=294266&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p2.cpp Mon Feb 6 19:37:30 2017 @@ -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}} +} Added: cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp?rev=294266&view=auto ============================================================================== --- cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp (added) +++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp Mon Feb 6 19:37:30 2017 @@ -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}} + } +} Modified: cfe/trunk/tools/libclang/CIndex.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=294266&r1=294265&r2=294266&view=diff ============================================================================== --- cfe/trunk/tools/libclang/CIndex.cpp (original) +++ cfe/trunk/tools/libclang/CIndex.cpp Mon Feb 6 19:37:30 2017 @@ -1265,10 +1265,11 @@ bool CursorVisitor::VisitDeclarationName 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: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits