diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Parse/MinimalAction.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 46 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 30 | ||||
| -rw-r--r-- | clang/lib/Parse/Parser.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 20 |
8 files changed, 100 insertions, 18 deletions
diff --git a/clang/lib/Parse/MinimalAction.cpp b/clang/lib/Parse/MinimalAction.cpp index 5a037678117..b7205160c17 100644 --- a/clang/lib/Parse/MinimalAction.cpp +++ b/clang/lib/Parse/MinimalAction.cpp @@ -194,7 +194,9 @@ MinimalAction::isTemplateName(Scope *S, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringScope, - TemplateTy &TemplateDecl) { + TemplateTy &TemplateDecl, + bool &MemberOfUnknownSpecialization) { + MemberOfUnknownSpecialization = false; return TNK_Non_template; } diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index b7ccea53d59..1588b69bdaa 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -289,11 +289,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, EnteringContext, - Template)) { + Template, + MemberOfUnknownSpecialization)) { // We have found a template name, so annotate this this token // with a template-id annotation. We do not permit the // template-id to be translated into a type annotation, @@ -990,21 +992,54 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TNK = TNK_Dependent_template_name; if (!Template.get()) return true; - } else + } else { + bool MemberOfUnknownSpecialization; TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); + + if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && + ObjectType && IsTemplateArgumentList()) { + // We have something like t->getAs<T>(), where getAs is a + // member of an unknown specialization. However, this will only + // parse correctly as a template, so suggest the keyword 'template' + // before 'getAs' and treat this as a dependent template name. + std::string Name; + if (Id.getKind() == UnqualifiedId::IK_Identifier) + Name = Id.Identifier->getName(); + else { + Name = "operator "; + if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) + Name += getOperatorSpelling(Id.OperatorFunctionId.Operator); + else + Name += Id.Identifier->getName(); + } + Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword) + << Name + << FixItHint::CreateInsertion(Id.StartLocation, "template "); + Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, + Id, ObjectType, + EnteringContext); + TNK = TNK_Dependent_template_name; + if (!Template.get()) + return true; + } + } break; case UnqualifiedId::IK_ConstructorName: { UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); break; } case UnqualifiedId::IK_DestructorName: { UnqualifiedId TemplateName; + bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, @@ -1015,7 +1050,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, return true; } else { TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && Id.DestructorName == 0) { Diag(NameLoc, diag::err_destructor_template_id) diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 93197816ced..8b9142ce9bd 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -902,10 +902,12 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { ConsumeToken(); // the identifier if (isEndOfTemplateArgument(Tok)) { + bool MemberOfUnknownSpecialization; TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, Name, /*ObjectType=*/0, /*EnteringContext=*/false, - Template); + Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { // We have an id-expression that refers to a class template or // (C++0x) template alias. @@ -966,6 +968,32 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { ExprArg.release(), Loc); } +/// \brief Determine whether the current tokens can only be parsed as a +/// template argument list (starting with the '<') and never as a '<' +/// expression. +bool Parser::IsTemplateArgumentList() { + struct AlwaysRevertAction : TentativeParsingAction { + AlwaysRevertAction(Parser &P) : TentativeParsingAction(P) { } + ~AlwaysRevertAction() { Revert(); } + } Tentative(*this); + + // '<' + if (!Tok.is(tok::less)) + return false; + ConsumeToken(); + + // An empty template argument list. + if (Tok.is(tok::greater)) + return true; + + // See whether we have declaration specifiers, which indicate a type. + while (isCXXDeclarationSpecifier() == TPResult::True()) + ConsumeToken(); + + // If we have a '>' or a ',' then this is a template argument list. + return Tok.is(tok::greater) || Tok.is(tok::comma); +} + /// ParseTemplateArgumentList - Parse a C++ template-argument-list /// (C++ [temp.names]). Returns true if there was an error. /// diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index bfcb6e7ee76..37475d23fe0 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -980,10 +980,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, TemplateName, /*ObjectType=*/0, EnteringContext, - Template)) { + Template, MemberOfUnknownSpecialization)) { // Consume the identifier. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 0870431a0de..1b61800c2a5 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2800,14 +2800,16 @@ public: // C++ Templates [C++ 14] // void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, - QualType ObjectType, bool EnteringContext); + QualType ObjectType, bool EnteringContext, + bool &MemberOfUnknownSpecialization); virtual TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext, - TemplateTy &Template); + TemplateTy &Template, + bool &MemberOfUnknownSpecialization); virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index b94f3d75400..19e31da6ca4 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -287,8 +287,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, Name.setIdentifier(&II, IILoc); CXXScopeSpec EmptySS; TemplateTy TemplateResult; - if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult) - == TNK_Type_template) { + bool MemberOfUnknownSpecialization; + if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult, + MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.getAsVal<TemplateName>(); Diag(IILoc, diag::err_template_missing_args) << TplName; if (TemplateDecl *TplDecl = TplName.getAsTemplateDecl()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 933a696bdcc..8c854ab77a8 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1055,7 +1055,9 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // lookup to determine that it was a template name in the first place. If // this becomes a performance hit, we can work harder to preserve those // results until we get here but it's likely not worth it. - LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false); + bool MemberOfUnknownSpecialization; + LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, + MemberOfUnknownSpecialization); } else { bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 6a4f34731ea..b4f9c3df8b4 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -100,10 +100,12 @@ TemplateNameKind Sema::isTemplateName(Scope *S, UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, - TemplateTy &TemplateResult) { + TemplateTy &TemplateResult, + bool &MemberOfUnknownSpecialization) { assert(getLangOptions().CPlusPlus && "No template names in C!"); DeclarationName TName; + MemberOfUnknownSpecialization = false; switch (Name.getKind()) { case UnqualifiedId::IK_Identifier: @@ -128,7 +130,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupResult R(*this, TName, Name.getSourceRange().getBegin(), LookupOrdinaryName); R.suppressDiagnostics(); - LookupTemplateName(R, S, SS, ObjectType, EnteringContext); + LookupTemplateName(R, S, SS, ObjectType, EnteringContext, + MemberOfUnknownSpecialization); if (R.empty() || R.isAmbiguous()) return TNK_Non_template; @@ -191,8 +194,10 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, void Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, - bool EnteringContext) { + bool EnteringContext, + bool &MemberOfUnknownSpecialization) { // Determine where to perform name lookup + MemberOfUnknownSpecialization = false; DeclContext *LookupCtx = 0; bool isDependent = false; if (!ObjectType.isNull()) { @@ -241,6 +246,7 @@ void Sema::LookupTemplateName(LookupResult &Found, } else if (isDependent) { // We cannot look into a dependent object type or nested nme // specifier. + MemberOfUnknownSpecialization = true; return; } else { // Perform unqualified name lookup in the current scope. @@ -1641,8 +1647,10 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs); + bool MemberOfUnknownSpecialization; LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); - LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false); + LookupTemplateName(R, (Scope*) 0, SS, QualType(), /*Entering*/ false, + MemberOfUnknownSpecialization); if (R.isAmbiguous()) return ExprError(); @@ -1699,8 +1707,10 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // "template" keyword is now permitted). We follow the C++0x // rules, even in C++03 mode, retroactively applying the DR. TemplateTy Template; + bool MemberOfUnknownSpecialization; TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType, - EnteringContext, Template); + EnteringContext, Template, + MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && isa<CXXRecordDecl>(LookupCtx) && cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { |

