forked from OSchip/llvm-project
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:
parent
016055fa69
commit
4a2a8f7fb8
|
@ -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()));
|
||||
})
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue