зеркало из https://github.com/microsoft/clang-1.git
Reimplement Sema::MatchTemplateParametersToScopeSpecifier() based on
the semantic context referenced by the nested-name-specifier rather than the syntactic form of the nested-name-specifier. The previous incarnation was based on my complete misunderstanding of C++ [temp.expl.spec]. The latest C++0x working draft clarifies the requirements here, and this rewrite is intended to follow that. Along the way, improve source location information in the diagnostics. For example, if we report that a specific type needs or doesn't need a 'template<>' header, we dig out that type in the nested-name-specifier and highlight its range. Fixes: PR5907, PR9421, PR8277, PR8708, PR9482, PR9668, PR9877, and <rdar://problem/9135379>. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131138 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
969f9d4733
Коммит
c840649ed5
|
@ -3491,6 +3491,7 @@ public:
|
|||
TemplateParamListContext TPC);
|
||||
TemplateParameterList *
|
||||
MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||
SourceLocation DeclLoc,
|
||||
const CXXScopeSpec &SS,
|
||||
TemplateParameterList **ParamLists,
|
||||
unsigned NumParamLists,
|
||||
|
|
|
@ -3557,7 +3557,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
bool Invalid = false;
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getSourceRange().getBegin(),
|
||||
D.getDeclSpec().getSourceRange().getBegin(),
|
||||
D.getIdentifierLoc(),
|
||||
D.getCXXScopeSpec(),
|
||||
TemplateParamLists.get(),
|
||||
TemplateParamLists.size(),
|
||||
|
@ -3579,7 +3580,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
<< II
|
||||
<< SourceRange(TemplateParams->getTemplateLoc(),
|
||||
TemplateParams->getRAngleLoc());
|
||||
isExplicitSpecialization = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4252,6 +4252,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getSourceRange().getBegin(),
|
||||
D.getIdentifierLoc(),
|
||||
D.getCXXScopeSpec(),
|
||||
TemplateParamLists.get(),
|
||||
TemplateParamLists.size(),
|
||||
|
@ -6650,7 +6651,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
if (TemplateParameterLists.size() > 0 ||
|
||||
(SS.isNotEmpty() && TUK != TUK_Reference)) {
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
|
||||
= MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS,
|
||||
TemplateParameterLists.get(),
|
||||
TemplateParameterLists.size(),
|
||||
TUK == TUK_Friend,
|
||||
|
|
|
@ -7259,7 +7259,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
|
|||
bool Invalid = false;
|
||||
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(TagLoc, SS,
|
||||
= MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS,
|
||||
TempParamLists.get(),
|
||||
TempParamLists.size(),
|
||||
/*friend*/ true,
|
||||
|
|
|
@ -1433,16 +1433,34 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
|
|||
};
|
||||
}
|
||||
|
||||
/// Determines whether a template-id depends on the given parameter
|
||||
/// Determines whether a given type depends on the given parameter
|
||||
/// list.
|
||||
static bool
|
||||
DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
|
||||
TemplateParameterList *Params) {
|
||||
DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) {
|
||||
DependencyChecker Checker(Params);
|
||||
Checker.TraverseType(QualType(TemplateId, 0));
|
||||
Checker.TraverseType(T);
|
||||
return Checker.Match;
|
||||
}
|
||||
|
||||
// Find the source range corresponding to the named type in the given
|
||||
// nested-name-specifier, if any.
|
||||
static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context,
|
||||
QualType T,
|
||||
const CXXScopeSpec &SS) {
|
||||
NestedNameSpecifierLoc NNSLoc(SS.getScopeRep(), SS.location_data());
|
||||
while (NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier()) {
|
||||
if (const Type *CurType = NNS->getAsType()) {
|
||||
if (Context.hasSameUnqualifiedType(T, QualType(CurType, 0)))
|
||||
return NNSLoc.getTypeLoc().getSourceRange();
|
||||
} else
|
||||
break;
|
||||
|
||||
NNSLoc = NNSLoc.getPrefix();
|
||||
}
|
||||
|
||||
return SourceRange();
|
||||
}
|
||||
|
||||
/// \brief Match the given template parameter lists to the given scope
|
||||
/// specifier, returning the template parameter list that applies to the
|
||||
/// name.
|
||||
|
@ -1450,6 +1468,8 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
|
|||
/// \param DeclStartLoc the start of the declaration that has a scope
|
||||
/// specifier or a template parameter list.
|
||||
///
|
||||
/// \param DeclLoc The location of the declaration itself.
|
||||
///
|
||||
/// \param SS the scope specifier that will be matched to the given template
|
||||
/// parameter lists. This scope specifier precedes a qualified name that is
|
||||
/// being declared.
|
||||
|
@ -1474,6 +1494,7 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
|
|||
/// itself a template).
|
||||
TemplateParameterList *
|
||||
Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||
SourceLocation DeclLoc,
|
||||
const CXXScopeSpec &SS,
|
||||
TemplateParameterList **ParamLists,
|
||||
unsigned NumParamLists,
|
||||
|
@ -1481,138 +1502,236 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
|||
bool &IsExplicitSpecialization,
|
||||
bool &Invalid) {
|
||||
IsExplicitSpecialization = false;
|
||||
|
||||
// Find the template-ids that occur within the nested-name-specifier. These
|
||||
// template-ids will match up with the template parameter lists.
|
||||
llvm::SmallVector<const TemplateSpecializationType *, 4>
|
||||
TemplateIdsInSpecifier;
|
||||
llvm::SmallVector<ClassTemplateSpecializationDecl *, 4>
|
||||
ExplicitSpecializationsInSpecifier;
|
||||
for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
|
||||
NNS; NNS = NNS->getPrefix()) {
|
||||
const Type *T = NNS->getAsType();
|
||||
if (!T) break;
|
||||
|
||||
// C++0x [temp.expl.spec]p17:
|
||||
// A member or a member template may be nested within many
|
||||
// enclosing class templates. In an explicit specialization for
|
||||
// such a member, the member declaration shall be preceded by a
|
||||
// template<> for each enclosing class template that is
|
||||
// explicitly specialized.
|
||||
//
|
||||
// Following the existing practice of GNU and EDG, we allow a typedef of a
|
||||
// template specialization type.
|
||||
while (const TypedefType *TT = dyn_cast<TypedefType>(T))
|
||||
T = TT->getDecl()->getUnderlyingType().getTypePtr();
|
||||
|
||||
if (const TemplateSpecializationType *SpecType
|
||||
= dyn_cast<TemplateSpecializationType>(T)) {
|
||||
TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl();
|
||||
if (!Template)
|
||||
continue; // FIXME: should this be an error? probably...
|
||||
|
||||
if (const RecordType *Record = SpecType->getAs<RecordType>()) {
|
||||
ClassTemplateSpecializationDecl *SpecDecl
|
||||
= cast<ClassTemplateSpecializationDecl>(Record->getDecl());
|
||||
// If the nested name specifier refers to an explicit specialization,
|
||||
// we don't need a template<> header.
|
||||
if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) {
|
||||
ExplicitSpecializationsInSpecifier.push_back(SpecDecl);
|
||||
continue;
|
||||
Invalid = false;
|
||||
|
||||
// The sequence of nested types to which we will match up the template
|
||||
// parameter lists. We first build this list by starting with the type named
|
||||
// by the nested-name-specifier and walking out until we run out of types.
|
||||
llvm::SmallVector<QualType, 4> NestedTypes;
|
||||
QualType T;
|
||||
if (SS.getScopeRep())
|
||||
T = QualType(SS.getScopeRep()->getAsType(), 0);
|
||||
|
||||
// If we found an explicit specialization that prevents us from needing
|
||||
// 'template<>' headers, this will be set to the location of that
|
||||
// explicit specialization.
|
||||
SourceLocation ExplicitSpecLoc;
|
||||
|
||||
while (!T.isNull()) {
|
||||
NestedTypes.push_back(T);
|
||||
|
||||
// Retrieve the parent of a record type.
|
||||
if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
|
||||
// If this type is an explicit specialization, we're done.
|
||||
if (ClassTemplateSpecializationDecl *Spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
|
||||
if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) &&
|
||||
Spec->getSpecializationKind() == TSK_ExplicitSpecialization) {
|
||||
ExplicitSpecLoc = Spec->getLocation();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TemplateIdsInSpecifier.push_back(SpecType);
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse the list of template-ids in the scope specifier, so that we can
|
||||
// more easily match up the template-ids and the template parameter lists.
|
||||
std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end());
|
||||
|
||||
SourceLocation FirstTemplateLoc = DeclStartLoc;
|
||||
if (NumParamLists)
|
||||
FirstTemplateLoc = ParamLists[0]->getTemplateLoc();
|
||||
|
||||
// Match the template-ids found in the specifier to the template parameter
|
||||
// lists.
|
||||
unsigned ParamIdx = 0, TemplateIdx = 0;
|
||||
for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
|
||||
TemplateIdx != NumTemplateIds; ++TemplateIdx) {
|
||||
const TemplateSpecializationType *TemplateId
|
||||
= TemplateIdsInSpecifier[TemplateIdx];
|
||||
bool DependentTemplateId = TemplateId->isDependentType();
|
||||
|
||||
// In friend declarations we can have template-ids which don't
|
||||
// depend on the corresponding template parameter lists. But
|
||||
// assume that empty parameter lists are supposed to match this
|
||||
// template-id.
|
||||
if (IsFriend && ParamIdx < NumParamLists && ParamLists[ParamIdx]->size()) {
|
||||
if (!DependentTemplateId ||
|
||||
!DependsOnTemplateParameters(TemplateId, ParamLists[ParamIdx]))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ParamIdx >= NumParamLists) {
|
||||
// We have a template-id without a corresponding template parameter
|
||||
// list.
|
||||
|
||||
// ...which is fine if this is a friend declaration.
|
||||
if (IsFriend) {
|
||||
IsExplicitSpecialization = true;
|
||||
} else if (Record->getTemplateSpecializationKind()
|
||||
== TSK_ExplicitSpecialization) {
|
||||
ExplicitSpecLoc = Record->getLocation();
|
||||
break;
|
||||
}
|
||||
|
||||
if (DependentTemplateId) {
|
||||
// FIXME: the location information here isn't great.
|
||||
Diag(SS.getRange().getBegin(),
|
||||
diag::err_template_spec_needs_template_parameters)
|
||||
<< QualType(TemplateId, 0)
|
||||
<< SS.getRange();
|
||||
Invalid = true;
|
||||
} else {
|
||||
Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
|
||||
<< SS.getRange()
|
||||
<< FixItHint::CreateInsertion(FirstTemplateLoc, "template<> ");
|
||||
IsExplicitSpecialization = true;
|
||||
|
||||
if (TypeDecl *Parent = dyn_cast<TypeDecl>(Record->getParent()))
|
||||
T = Context.getTypeDeclType(Parent);
|
||||
else
|
||||
T = QualType();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const TemplateSpecializationType *TST
|
||||
= T->getAs<TemplateSpecializationType>()) {
|
||||
if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
|
||||
if (TypeDecl *Parent = dyn_cast<TypeDecl>(Template->getDeclContext()))
|
||||
T = Context.getTypeDeclType(Parent);
|
||||
else
|
||||
T = QualType();
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Look one step prior in a dependent template specialization type.
|
||||
if (const DependentTemplateSpecializationType *DependentTST
|
||||
= T->getAs<DependentTemplateSpecializationType>()) {
|
||||
if (NestedNameSpecifier *NNS = DependentTST->getQualifier())
|
||||
T = QualType(NNS->getAsType(), 0);
|
||||
else
|
||||
T = QualType();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look one step prior in a dependent name type.
|
||||
if (const DependentNameType *DependentName = T->getAs<DependentNameType>()){
|
||||
if (NestedNameSpecifier *NNS = DependentName->getQualifier())
|
||||
T = QualType(NNS->getAsType(), 0);
|
||||
else
|
||||
T = QualType();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retrieve the parent of an enumeration type.
|
||||
if (const EnumType *EnumT = T->getAs<EnumType>()) {
|
||||
// FIXME: Forward-declared enums require a TSK_ExplicitSpecialization
|
||||
// check here.
|
||||
EnumDecl *Enum = EnumT->getDecl();
|
||||
|
||||
// Get to the parent type.
|
||||
if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent()))
|
||||
T = Context.getTypeDeclType(Parent);
|
||||
else
|
||||
T = QualType();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the template parameter list against its corresponding template-id.
|
||||
if (DependentTemplateId) {
|
||||
TemplateParameterList *ExpectedTemplateParams = 0;
|
||||
T = QualType();
|
||||
}
|
||||
// Reverse the nested types list, since we want to traverse from the outermost
|
||||
// to the innermost while checking template-parameter-lists.
|
||||
std::reverse(NestedTypes.begin(), NestedTypes.end());
|
||||
|
||||
// Are there cases in (e.g.) friends where this won't match?
|
||||
if (const InjectedClassNameType *Injected
|
||||
= TemplateId->getAs<InjectedClassNameType>()) {
|
||||
CXXRecordDecl *Record = Injected->getDecl();
|
||||
if (ClassTemplatePartialSpecializationDecl *Partial =
|
||||
dyn_cast<ClassTemplatePartialSpecializationDecl>(Record))
|
||||
ExpectedTemplateParams = Partial->getTemplateParameters();
|
||||
else
|
||||
// C++0x [temp.expl.spec]p17:
|
||||
// A member or a member template may be nested within many
|
||||
// enclosing class templates. In an explicit specialization for
|
||||
// such a member, the member declaration shall be preceded by a
|
||||
// template<> for each enclosing class template that is
|
||||
// explicitly specialized.
|
||||
unsigned ParamIdx = 0;
|
||||
for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes;
|
||||
++TypeIdx) {
|
||||
T = NestedTypes[TypeIdx];
|
||||
|
||||
// Whether we expect a 'template<>' header.
|
||||
bool NeedEmptyTemplateHeader = false;
|
||||
|
||||
// Whether we expect a template header with parameters.
|
||||
bool NeedNonemptyTemplateHeader = false;
|
||||
|
||||
// For a dependent type, the set of template parameters that we
|
||||
// expect to see.
|
||||
TemplateParameterList *ExpectedTemplateParams = 0;
|
||||
|
||||
if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) {
|
||||
if (ClassTemplatePartialSpecializationDecl *Partial
|
||||
= dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
|
||||
ExpectedTemplateParams = Partial->getTemplateParameters();
|
||||
NeedNonemptyTemplateHeader = true;
|
||||
} else if (Record->isDependentType()) {
|
||||
if (Record->getDescribedClassTemplate()) {
|
||||
ExpectedTemplateParams = Record->getDescribedClassTemplate()
|
||||
->getTemplateParameters();
|
||||
->getTemplateParameters();
|
||||
NeedNonemptyTemplateHeader = true;
|
||||
}
|
||||
} else if (ClassTemplateSpecializationDecl *Spec
|
||||
= dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
|
||||
// C++0x [temp.expl.spec]p4:
|
||||
// Members of an explicitly specialized class template are defined
|
||||
// in the same manner as members of normal classes, and not using
|
||||
// the template<> syntax.
|
||||
if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization)
|
||||
NeedEmptyTemplateHeader = true;
|
||||
else
|
||||
break;
|
||||
} else if (Record->getTemplateSpecializationKind()) {
|
||||
if (Record->getTemplateSpecializationKind()
|
||||
!= TSK_ExplicitSpecialization)
|
||||
NeedEmptyTemplateHeader = true;
|
||||
else
|
||||
break;
|
||||
}
|
||||
} else if (const TemplateSpecializationType *TST
|
||||
= T->getAs<TemplateSpecializationType>()) {
|
||||
if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) {
|
||||
ExpectedTemplateParams = Template->getTemplateParameters();
|
||||
NeedNonemptyTemplateHeader = true;
|
||||
}
|
||||
} else if (T->getAs<DependentTemplateSpecializationType>()) {
|
||||
// FIXME: We actually could/should check the template arguments here
|
||||
// against the corresponding template parameter list.
|
||||
NeedNonemptyTemplateHeader = false;
|
||||
}
|
||||
|
||||
if (NeedEmptyTemplateHeader) {
|
||||
// If we're on the last of the types, and we need a 'template<>' header
|
||||
// here, then it's an explicit specialization.
|
||||
if (TypeIdx == NumTypes - 1)
|
||||
IsExplicitSpecialization = true;
|
||||
|
||||
if (ParamIdx < NumParamLists) {
|
||||
if (ParamLists[ParamIdx]->size() > 0) {
|
||||
// The header has template parameters when it shouldn't. Complain.
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
diag::err_template_param_list_matches_nontemplate)
|
||||
<< T
|
||||
<< SourceRange(ParamLists[ParamIdx]->getLAngleLoc(),
|
||||
ParamLists[ParamIdx]->getRAngleLoc())
|
||||
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
|
||||
Invalid = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Consume this template header.
|
||||
++ParamIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsFriend) {
|
||||
// We don't have a template header, but we should.
|
||||
SourceLocation ExpectedTemplateLoc;
|
||||
if (NumParamLists > 0)
|
||||
ExpectedTemplateLoc = ParamLists[0]->getTemplateLoc();
|
||||
else
|
||||
ExpectedTemplateLoc = DeclStartLoc;
|
||||
|
||||
Diag(DeclLoc, diag::err_template_spec_needs_header)
|
||||
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS)
|
||||
<< FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> ");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NeedNonemptyTemplateHeader) {
|
||||
// In friend declarations we can have template-ids which don't
|
||||
// depend on the corresponding template parameter lists. But
|
||||
// assume that empty parameter lists are supposed to match this
|
||||
// template-id.
|
||||
if (IsFriend && T->isDependentType()) {
|
||||
if (ParamIdx < NumParamLists &&
|
||||
DependsOnTemplateParameters(T, ParamLists[ParamIdx]))
|
||||
ExpectedTemplateParams = 0;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ExpectedTemplateParams)
|
||||
TemplateParameterListsAreEqual(ParamLists[ParamIdx],
|
||||
ExpectedTemplateParams,
|
||||
true, TPL_TemplateMatch);
|
||||
|
||||
CheckTemplateParameterList(ParamLists[ParamIdx], 0,
|
||||
TPC_ClassTemplateMember);
|
||||
} else if (ParamLists[ParamIdx]->size() > 0)
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
diag::err_template_param_list_matches_nontemplate)
|
||||
<< TemplateId
|
||||
<< ParamLists[ParamIdx]->getSourceRange();
|
||||
else
|
||||
IsExplicitSpecialization = true;
|
||||
|
||||
++ParamIdx;
|
||||
if (ParamIdx < NumParamLists) {
|
||||
// Check the template parameter list, if we can.
|
||||
if (ExpectedTemplateParams &&
|
||||
!TemplateParameterListsAreEqual(ParamLists[ParamIdx],
|
||||
ExpectedTemplateParams,
|
||||
true, TPL_TemplateMatch))
|
||||
Invalid = true;
|
||||
|
||||
if (!Invalid &&
|
||||
CheckTemplateParameterList(ParamLists[ParamIdx], 0,
|
||||
TPC_ClassTemplateMember))
|
||||
Invalid = true;
|
||||
|
||||
++ParamIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
Diag(DeclLoc, diag::err_template_spec_needs_template_parameters)
|
||||
<< T
|
||||
<< getRangeOfTypeInNestedNameSpecifier(Context, T, SS);
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If there were at least as many template-ids as there were template
|
||||
// parameter lists, then there are no template parameter lists remaining for
|
||||
// the declaration itself.
|
||||
|
@ -1620,30 +1739,35 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
|||
return 0;
|
||||
|
||||
// If there were too many template parameter lists, complain about that now.
|
||||
if (ParamIdx != NumParamLists - 1) {
|
||||
while (ParamIdx < NumParamLists - 1) {
|
||||
bool isExplicitSpecHeader = ParamLists[ParamIdx]->size() == 0;
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
isExplicitSpecHeader? diag::warn_template_spec_extra_headers
|
||||
: diag::err_template_spec_extra_headers)
|
||||
<< SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
ParamLists[ParamIdx]->getRAngleLoc());
|
||||
|
||||
if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) {
|
||||
Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(),
|
||||
diag::note_explicit_template_spec_does_not_need_header)
|
||||
<< ExplicitSpecializationsInSpecifier.back();
|
||||
ExplicitSpecializationsInSpecifier.pop_back();
|
||||
}
|
||||
|
||||
// We have a template parameter list with no corresponding scope, which
|
||||
// means that the resulting template declaration can't be instantiated
|
||||
// properly (we'll end up with dependent nodes when we shouldn't).
|
||||
if (!isExplicitSpecHeader)
|
||||
Invalid = true;
|
||||
|
||||
++ParamIdx;
|
||||
if (ParamIdx < NumParamLists - 1) {
|
||||
bool HasAnyExplicitSpecHeader = false;
|
||||
bool AllExplicitSpecHeaders = true;
|
||||
for (unsigned I = ParamIdx; I != NumParamLists - 1; ++I) {
|
||||
if (ParamLists[I]->size() == 0)
|
||||
HasAnyExplicitSpecHeader = true;
|
||||
else
|
||||
AllExplicitSpecHeaders = false;
|
||||
}
|
||||
|
||||
Diag(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
AllExplicitSpecHeaders? diag::warn_template_spec_extra_headers
|
||||
: diag::err_template_spec_extra_headers)
|
||||
<< SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
|
||||
ParamLists[NumParamLists - 2]->getRAngleLoc());
|
||||
|
||||
// If there was a specialization somewhere, such that 'template<>' is
|
||||
// not required, and there were any 'template<>' headers, note where the
|
||||
// specialization occurred.
|
||||
if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader)
|
||||
Diag(ExplicitSpecLoc,
|
||||
diag::note_explicit_template_spec_does_not_need_header)
|
||||
<< NestedTypes.back();
|
||||
|
||||
// We have a template parameter list with no corresponding scope, which
|
||||
// means that the resulting template declaration can't be instantiated
|
||||
// properly (we'll end up with dependent nodes when we shouldn't).
|
||||
if (!AllExplicitSpecHeaders)
|
||||
Invalid = true;
|
||||
}
|
||||
|
||||
// Return the last template parameter list, which corresponds to the
|
||||
|
@ -4495,7 +4619,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
// friend declarations.
|
||||
bool Invalid = false;
|
||||
TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
|
||||
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc,
|
||||
TemplateNameLoc,
|
||||
SS,
|
||||
(TemplateParameterList**)TemplateParameterLists.get(),
|
||||
TemplateParameterLists.size(),
|
||||
TUK == TUK_Friend,
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
namespace PR5907 {
|
||||
template<typename T> struct identity { typedef T type; };
|
||||
struct A { A(); };
|
||||
identity<A>::type::A() { }
|
||||
|
||||
struct B { void f(); };
|
||||
template<typename T> struct C { typedef B type; };
|
||||
|
||||
void C<int>::type::f() { }
|
||||
}
|
||||
|
||||
namespace PR9421 {
|
||||
namespace N { template<typename T> struct S { void f(); }; }
|
||||
typedef N::S<int> T;
|
||||
namespace N { template<> void T::f() {} }
|
||||
}
|
||||
|
||||
namespace PR8277 {
|
||||
template< typename S >
|
||||
struct C
|
||||
{
|
||||
template< int >
|
||||
void F( void )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template< typename S >
|
||||
struct D
|
||||
{
|
||||
typedef C< int > A;
|
||||
};
|
||||
|
||||
typedef D< int >::A A;
|
||||
|
||||
template<>
|
||||
template<>
|
||||
void A::F< 0 >( void )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR8277b {
|
||||
template<typename S> struct C {
|
||||
void f();
|
||||
};
|
||||
template<typename S> struct D {
|
||||
typedef C<int> A;
|
||||
};
|
||||
template<> void D<int>::A::f() {
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR8708 {
|
||||
template<typename T> struct A {
|
||||
template<typename U> struct B {
|
||||
// #2
|
||||
void f();
|
||||
};
|
||||
};
|
||||
|
||||
// #A specialize the member template for
|
||||
// implicit instantiation of A<int>,
|
||||
// leaving the member template "unspecialized"
|
||||
// (14.7.3/16). Specialization uses the syntax
|
||||
// for explicit specialization (14.7.3/14)
|
||||
template<> template<typename U>
|
||||
struct A<int>::B {
|
||||
// #1
|
||||
void g();
|
||||
};
|
||||
|
||||
// #1 define its function g. There is an enclosing
|
||||
// class template, so we write template<> for each
|
||||
// specialized template (14.7.3/15).
|
||||
template<> template<typename U>
|
||||
void A<int>::B<U>::g() { }
|
||||
|
||||
// #2 define the unspecialized member template's
|
||||
// f
|
||||
template<typename T> template<typename U>
|
||||
void A<T>::B<U>::f() { }
|
||||
|
||||
|
||||
// specialize the member template again, now
|
||||
// specializing the member too. This specializes
|
||||
// #A
|
||||
template<> template<>
|
||||
struct A<int>::B<int> {
|
||||
// #3
|
||||
void h();
|
||||
};
|
||||
|
||||
// defines #3. There is no enclosing class template, so
|
||||
// we write no "template<>".
|
||||
void A<int>::B<int>::h() { }
|
||||
|
||||
void test() {
|
||||
// calls #1
|
||||
A<int>::B<float> a; a.g();
|
||||
|
||||
// calls #2
|
||||
A<float>::B<int> b; b.f();
|
||||
|
||||
// calls #3
|
||||
A<int>::B<int> c; c.h();
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR9482 {
|
||||
namespace N1 {
|
||||
template <typename T> struct S {
|
||||
void foo() {}
|
||||
};
|
||||
}
|
||||
|
||||
namespace N2 {
|
||||
typedef N1::S<int> X;
|
||||
}
|
||||
|
||||
namespace N1 {
|
||||
template<> void N2::X::foo() {}
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR9668 {
|
||||
namespace First
|
||||
{
|
||||
template<class T>
|
||||
class Bar
|
||||
{
|
||||
protected:
|
||||
|
||||
static const bool static_bool;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Second
|
||||
{
|
||||
class Foo;
|
||||
}
|
||||
|
||||
typedef First::Bar<Second::Foo> Special;
|
||||
|
||||
namespace
|
||||
First
|
||||
{
|
||||
template<>
|
||||
const bool Special::static_bool(false);
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR9877 {
|
||||
template<int>
|
||||
struct X
|
||||
{
|
||||
struct Y;
|
||||
};
|
||||
|
||||
template<> struct X<0>::Y { static const int Z = 1; };
|
||||
template<> struct X<1>::Y { static const int Z = 1; };
|
||||
|
||||
const int X<0>::Y::Z;
|
||||
template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}}
|
||||
}
|
|
@ -24,12 +24,11 @@ namespace test1 {
|
|||
|
||||
template <> class A<double> {
|
||||
public:
|
||||
static int foo; // expected-note{{attempt to specialize}}
|
||||
static int foo;
|
||||
static int bar;
|
||||
};
|
||||
|
||||
typedef A<double> AB;
|
||||
template <> int AB::foo = 0; // expected-error{{extraneous 'template<>'}} \
|
||||
// expected-error{{does not specialize}}
|
||||
template <> int AB::foo = 0; // expected-error{{extraneous 'template<>'}}
|
||||
int AB::bar = 1;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче