summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2017-02-07 01:37:30 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2017-02-07 01:37:30 +0000
commitb95354dce3f19fb3406bee636bcca9ab7f2f8737 (patch)
treeae8c2276b9b2f14b6fc169032920a57f87da3c83 /lib
parentb51cd02fb216a64a3a7dc1602eeed3e1d657e8e7 (diff)
downloadclang-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.cpp9
-rw-r--r--lib/AST/DeclarationName.cpp98
-rw-r--r--lib/AST/ItaniumMangle.cpp6
-rw-r--r--lib/AST/MicrosoftMangle.cpp3
-rw-r--r--lib/Parse/ParseDecl.cpp35
-rw-r--r--lib/Parse/ParseDeclCXX.cpp5
-rw-r--r--lib/Parse/ParseExpr.cpp1
-rw-r--r--lib/Parse/ParseExprCXX.cpp11
-rw-r--r--lib/Parse/ParseOpenMP.cpp7
-rw-r--r--lib/Parse/ParseStmtAsm.cpp1
-rw-r--r--lib/Parse/Parser.cpp6
-rw-r--r--lib/Sema/SemaCodeComplete.cpp1
-rw-r--r--lib/Sema/SemaDecl.cpp39
-rw-r--r--lib/Sema/SemaDeclCXX.cpp15
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp1
-rw-r--r--lib/Sema/SemaType.cpp47
-rw-r--r--lib/Sema/TreeTransform.h13
-rw-r--r--lib/Serialization/ASTReader.cpp16
-rw-r--r--lib/Serialization/ASTWriter.cpp7
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;
}
}