Check for unexpanded parameter packs in the name that guards a

Microsoft __if_exists/__if_not_exists statement. Also note that we
weren't traversing DeclarationNameInfo *at all* within the
RecursiveASTVisitor, which would be rather fatal for variadic
templates.

llvm-svn: 142906
This commit is contained in:
Douglas Gregor 2011-10-25 03:44:56 +00:00
parent 016055fa69
commit 4a2a8f7fb8
9 changed files with 161 additions and 28 deletions

View File

@ -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.
///
@ -545,6 +550,31 @@ bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
return true;
}
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())
@ -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()));
})

View File

@ -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<

View File

@ -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.
///

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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) {

View File

@ -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.

View File

@ -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'}}
}
}