diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-02-07 01:37:30 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-02-07 01:37:30 +0000 |
commit | b95354dce3f19fb3406bee636bcca9ab7f2f8737 (patch) | |
tree | ae8c2276b9b2f14b6fc169032920a57f87da3c83 /lib | |
parent | b51cd02fb216a64a3a7dc1602eeed3e1d657e8e7 (diff) | |
download | clang-b95354dce3f19fb3406bee636bcca9ab7f2f8737.tar.gz |
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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294266 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTImporter.cpp | 9 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 98 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 6 | ||||
-rw-r--r-- | lib/AST/MicrosoftMangle.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 35 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 5 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 11 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 7 | ||||
-rw-r--r-- | lib/Parse/ParseStmtAsm.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 39 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 47 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 13 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 16 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 7 |
19 files changed, 276 insertions, 45 deletions
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index f80ce35df2..9ded89413e 100644 --- a/lib/AST/ASTImporter.cpp +++ b/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/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 52791e51d2..5f09b2701a 100644 --- a/lib/AST/DeclarationName.cpp +++ b/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/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 4c1beaab10..1aa9ad26e9 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/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/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index a76d186747..07e38eb7bb 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 6da61c689e..9e8823fb4d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 6403caa27b..d558909603 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/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/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index ee06c76f60..0c09614547 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/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/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index cfda2cddec..1ba1695800 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/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/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index cab7d3432d..574ed6ee59 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/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/lib/Parse/ParseStmtAsm.cpp b/lib/Parse/ParseStmtAsm.cpp index 7fd9fa2146..59e96d982a 100644 --- a/lib/Parse/ParseStmtAsm.cpp +++ b/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/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 8713bb2c23..9030ebff0f 100644 --- a/lib/Parse/Parser.cpp +++ b/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/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 85343cde2b..5f65df2ef3 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 32663121f8..41d977fa9c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 671d3251a5..49cf8e15ed 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/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/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 54556b505e..4ea04ac143 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/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/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index a59511ca77..250f6f9946 100644 --- a/lib/Sema/SemaType.cpp +++ b/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/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 7019f15849..ef349c395f 100644 --- a/lib/Sema/TreeTransform.h +++ b/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/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index da8e5ff6b9..67c7e46099 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/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/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 1f5ef422c5..69136015f4 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/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; } } |