diff options
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 38 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 12 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 50 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 47 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 3 | ||||
-rw-r--r-- | test/SemaTemplate/ms-if-exists.cpp | 11 |
9 files changed, 161 insertions, 28 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index a47f7008a2..2a97d3c565 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -187,6 +187,11 @@ public: /// \returns false if the visitation was terminated early, true otherwise. bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); + /// \brief Recursively visit a name with its location information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo); + /// \brief Recursively visit a template name and dispatch to the /// appropriate method. /// @@ -546,6 +551,31 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc( } template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo( + DeclarationNameInfo NameInfo) { + switch (NameInfo.getName().getNameKind()) { + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo()) + TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc())); + + break; + + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + break; + } + + return true; +} + +template<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) { if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier())); @@ -1216,6 +1246,7 @@ DEF_TRAVERSE_DECL(ObjCPropertyDecl, { DEF_TRAVERSE_DECL(UsingDecl, { TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); }) DEF_TRAVERSE_DECL(UsingDirectiveDecl, { @@ -1511,6 +1542,7 @@ DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, { // Like UnresolvedUsingTypenameDecl, but without the 'typename': // template <class T> Class A : public Base<T> { using Base<T>::foo; }; TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); }) DEF_TRAVERSE_DECL(IndirectFieldDecl, {}) @@ -1548,6 +1580,7 @@ DEF_TRAVERSE_DECL(ObjCIvarDecl, { template<typename Derived> bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) { TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); // If we're an explicit template specialization, iterate over the // template args that were explicitly specified. If we were doing @@ -1737,6 +1770,7 @@ DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { }) DEF_TRAVERSE_STMT(CXXForRangeStmt, { }) DEF_TRAVERSE_STMT(MSDependentExistsStmt, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); }) DEF_TRAVERSE_STMT(ReturnStmt, { }) DEF_TRAVERSE_STMT(SwitchStmt, { }) @@ -1745,6 +1779,7 @@ DEF_TRAVERSE_STMT(WhileStmt, { }) DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); if (S->hasExplicitTemplateArgs()) { TRY_TO(TraverseTemplateArgumentLocsHelper( S->getTemplateArgs(), S->getNumTemplateArgs())); @@ -1753,12 +1788,14 @@ DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { DEF_TRAVERSE_STMT(DeclRefExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); TRY_TO(TraverseTemplateArgumentLocsHelper( S->getTemplateArgs(), S->getNumTemplateArgs())); }) DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); if (S->hasExplicitTemplateArgs()) { TRY_TO(TraverseTemplateArgumentLocsHelper( S->getExplicitTemplateArgs().getTemplateArgs(), @@ -1768,6 +1805,7 @@ DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, { DEF_TRAVERSE_STMT(MemberExpr, { TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); TRY_TO(TraverseTemplateArgumentLocsHelper( S->getTemplateArgs(), S->getNumTemplateArgs())); }) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 28d5c97ec3..61a182e81b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2573,25 +2573,29 @@ def err_unexpanded_parameter_pack_0 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" - "non-type template parameter type|exception type|partial specialization}0 " + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " "contains an unexpanded parameter pack">; def err_unexpanded_parameter_pack_1 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" - "non-type template parameter type|exception type|partial specialization}0 " + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " "contains unexpanded parameter pack %1">; def err_unexpanded_parameter_pack_2 : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" - "non-type template parameter type|exception type|partial specialization}0 " + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " "contains unexpanded parameter packs %1 and %2">; def err_unexpanded_parameter_pack_3_or_more : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" - "non-type template parameter type|exception type|partial specialization}0 " + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " "contains unexpanded parameter packs %1, %2, ...">; def err_pack_expansion_without_parameter_packs : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f3634f1c11..b55fdea6b9 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2599,8 +2599,12 @@ public: /// \brief The symbol does not exist. IER_DoesNotExist, - /// \brief The name is a dependent name, so it - IER_Dependent + /// \brief The name is a dependent name, so the results will differ + /// from one instantiation to the next. + IER_Dependent, + + /// \brief An error occurred. + IER_Error }; IfExistsResult @@ -2608,7 +2612,9 @@ public: const DeclarationNameInfo &TargetNameInfo); IfExistsResult - CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name); + CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, + bool IsIfExists, CXXScopeSpec &SS, + UnqualifiedId &Name); StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, @@ -4235,8 +4241,26 @@ public: UPPC_ExceptionType, /// \brief Partial specialization. - UPPC_PartialSpecialization - }; + UPPC_PartialSpecialization, + + /// \brief Microsoft __if_exists. + UPPC_IfExists, + + /// \brief Microsoft __if_not_exists. + UPPC_IfNotExists +}; + + /// \brief Diagnose unexpanded parameter packs. + /// + /// \param Loc The location at which we should emit the diagnostic. + /// + /// \param UPPC The context in which we are diagnosing unexpanded + /// parameter packs. + /// + /// \param Unexpanded the set of unexpanded parameter packs. + void DiagnoseUnexpandedParameterPacks(SourceLocation Loc, + UnexpandedParameterPackContext UPPC, + const SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); /// \brief If the given type contains an unexpanded parameter pack, /// diagnose the error. @@ -4335,6 +4359,22 @@ public: void collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// \brief Collect the set of unexpanded parameter packs within the given + /// nested-name-specifier. + /// + /// \param SS The nested-name-specifier that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(CXXScopeSpec &SS, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// name. + /// + /// \param NameInfo The name that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// \brief Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 90bed04e75..fabb8e2a59 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1503,7 +1503,8 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { return true; // Check if the symbol exists. - switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.SS, + switch (Actions.CheckMicrosoftIfExistsSymbol(getCurScope(), Result.KeywordLoc, + Result.IsIfExists, Result.SS, Result.Name)) { case Sema::IER_Exists: Result.Behavior = Result.IsIfExists ? IEB_Parse : IEB_Skip; @@ -1516,6 +1517,9 @@ bool Parser::ParseMicrosoftIfExistsCondition(IfExistsCondition& Result) { case Sema::IER_Dependent: Result.Behavior = IEB_Dependent; break; + + case Sema::IER_Error: + return true; } return false; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 2726906c1b..9267860d15 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4700,10 +4700,24 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, return IER_DoesNotExist; } -Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, - CXXScopeSpec &SS, - UnqualifiedId &Name) { +Sema::IfExistsResult +Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, + bool IsIfExists, CXXScopeSpec &SS, + UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); + + // Check for unexpanded parameter packs. + SmallVector<UnexpandedParameterPack, 4> Unexpanded; + collectUnexpandedParameterPacks(SS, Unexpanded); + collectUnexpandedParameterPacks(TargetNameInfo, Unexpanded); + if (!Unexpanded.empty()) { + DiagnoseUnexpandedParameterPacks(KeywordLoc, + IsIfExists? UPPC_IfExists + : UPPC_IfNotExists, + Unexpanded); + return IER_Error; + } + return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d39731b90c..d2641888bd 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1307,7 +1307,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, = cast<TemplateTemplateParmDecl>(*NewParam); // Check for unexpanded parameter packs, recursively. - if (DiagnoseUnexpandedParameterPacks(*this, NewTemplateParm)) { + if (::DiagnoseUnexpandedParameterPacks(*this, NewTemplateParm)) { Invalid = true; continue; } diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index e383db9350..b219c20459 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -155,10 +155,13 @@ namespace { /// \brief Diagnose all of the unexpanded parameter packs in the given /// vector. -static void -DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc, - Sema::UnexpandedParameterPackContext UPPC, +void +Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, + UnexpandedParameterPackContext UPPC, const SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + if (Unexpanded.empty()) + return; + SmallVector<SourceLocation, 4> Locations; SmallVector<IdentifierInfo *, 4> Names; llvm::SmallPtrSet<IdentifierInfo *, 4> NamesKnown; @@ -179,13 +182,13 @@ DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc, } DiagnosticBuilder DB - = Names.size() == 0? S.Diag(Loc, diag::err_unexpanded_parameter_pack_0) + = Names.size() == 0? Diag(Loc, diag::err_unexpanded_parameter_pack_0) << (int)UPPC - : Names.size() == 1? S.Diag(Loc, diag::err_unexpanded_parameter_pack_1) + : Names.size() == 1? Diag(Loc, diag::err_unexpanded_parameter_pack_1) << (int)UPPC << Names[0] - : Names.size() == 2? S.Diag(Loc, diag::err_unexpanded_parameter_pack_2) + : Names.size() == 2? Diag(Loc, diag::err_unexpanded_parameter_pack_2) << (int)UPPC << Names[0] << Names[1] - : S.Diag(Loc, diag::err_unexpanded_parameter_pack_3_or_more) + : Diag(Loc, diag::err_unexpanded_parameter_pack_3_or_more) << (int)UPPC << Names[0] << Names[1]; for (unsigned I = 0, N = Locations.size(); I != N; ++I) @@ -205,7 +208,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc( T->getTypeLoc()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); - DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded); + DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded); return true; } @@ -220,7 +223,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); - DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded); + DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded); return true; } @@ -237,7 +240,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseNestedNameSpecifier(SS.getScopeRep()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); - DiagnoseUnexpandedParameterPacks(*this, SS.getRange().getBegin(), + DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(), UPPC, Unexpanded); return true; } @@ -274,7 +277,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseType(NameInfo.getName().getCXXNameType()); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); - DiagnoseUnexpandedParameterPacks(*this, NameInfo.getLoc(), UPPC, Unexpanded); + DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded); return true; } @@ -289,7 +292,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateName(Template); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); - DiagnoseUnexpandedParameterPacks(*this, Loc, UPPC, Unexpanded); + DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded); return true; } @@ -303,7 +306,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseTemplateArgumentLoc(Arg); assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); - DiagnoseUnexpandedParameterPacks(*this, Arg.getLocation(), UPPC, Unexpanded); + DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded); return true; } @@ -329,6 +332,24 @@ void Sema::collectUnexpandedParameterPacks(TypeLoc TL, CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); } +void Sema::collectUnexpandedParameterPacks(CXXScopeSpec &SS, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + NestedNameSpecifier *Qualifier = SS.getScopeRep(); + if (!Qualifier) + return; + + NestedNameSpecifierLoc QualifierLoc(Qualifier, SS.location_data()); + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseNestedNameSpecifierLoc(QualifierLoc); +} + +void Sema::collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseDeclarationNameInfo(NameInfo); +} + + ParsedTemplateArgument Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc) { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index dde8a974c9..46bd05b14b 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -5805,6 +5805,9 @@ TreeTransform<Derived>::TransformMSDependentExistsStmt( case Sema::IER_Dependent: Dependent = true; break; + + case Sema::IER_Error: + return StmtError(); } // We need to continue with the instantiation, so do so now. diff --git a/test/SemaTemplate/ms-if-exists.cpp b/test/SemaTemplate/ms-if-exists.cpp index 129dfa7fef..8ac4e2418c 100644 --- a/test/SemaTemplate/ms-if-exists.cpp +++ b/test/SemaTemplate/ms-if-exists.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fms-extensions %s -verify +// RUN: %clang_cc1 -fms-extensions -std=c++11 %s -verify struct Nontemplate { typedef int type; @@ -51,3 +51,12 @@ void f(T t) { template void f(HasFoo); // expected-note{{in instantiation of function template specialization 'f<HasFoo>' requested here}} template void f(HasBar); + +template<typename T, typename ...Ts> +void g(T, Ts...) { + __if_exists(T::operator Ts) { // expected-error{{__if_exists name contains unexpanded parameter pack 'Ts'}} + } + + __if_not_exists(Ts::operator T) { // expected-error{{__if_not_exists name contains unexpanded parameter pack 'Ts'}} + } +} |