[cfe-commits] r131138 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
Douglas Gregor
dgregor at apple.com
Tue May 10 11:27:06 PDT 2011
Author: dgregor
Date: Tue May 10 13:27:06 2011
New Revision: 131138
URL: http://llvm.org/viewvc/llvm-project?rev=131138&view=rev
Log:
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>.
Added:
cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=131138&r1=131137&r2=131138&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue May 10 13:27:06 2011
@@ -3491,6 +3491,7 @@
TemplateParamListContext TPC);
TemplateParameterList *
MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ SourceLocation DeclLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=131138&r1=131137&r2=131138&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue May 10 13:27:06 2011
@@ -3557,7 +3557,8 @@
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 @@
<< II
<< SourceRange(TemplateParams->getTemplateLoc(),
TemplateParams->getRAngleLoc());
- isExplicitSpecialization = true;
}
}
@@ -4252,6 +4252,7 @@
if (TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getSourceRange().getBegin(),
+ D.getIdentifierLoc(),
D.getCXXScopeSpec(),
TemplateParamLists.get(),
TemplateParamLists.size(),
@@ -6650,7 +6651,7 @@
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,
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=131138&r1=131137&r2=131138&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue May 10 13:27:06 2011
@@ -7259,7 +7259,7 @@
bool Invalid = false;
if (TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TagLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS,
TempParamLists.get(),
TempParamLists.size(),
/*friend*/ true,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=131138&r1=131137&r2=131138&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue May 10 13:27:06 2011
@@ -1433,16 +1433,34 @@
};
}
-/// 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 @@
/// \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 @@
/// itself a template).
TemplateParameterList *
Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
+ SourceLocation DeclLoc,
const CXXScopeSpec &SS,
TemplateParameterList **ParamLists,
unsigned NumParamLists,
@@ -1481,138 +1502,236 @@
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;
}
+ } else if (Record->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization) {
+ ExplicitSpecLoc = Record->getLocation();
+ break;
+ }
+
+ 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;
}
-
- 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;
+
+ // 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;
}
- if (ParamIdx >= NumParamLists) {
- // We have a template-id without a corresponding template parameter
- // list.
+ 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());
+
+ // 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;
- // ...which is fine if this is a friend declaration.
- if (IsFriend) {
- IsExplicitSpecialization = true;
- break;
+ // 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();
+ 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;
}
-
- 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<> ");
+ } 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<> ");
}
- return 0;
+
+ continue;
}
-
- // Check the template parameter list against its corresponding template-id.
- if (DependentTemplateId) {
- TemplateParameterList *ExpectedTemplateParams = 0;
-
- // 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
- ExpectedTemplateParams = Record->getDescribedClassTemplate()
- ->getTemplateParameters();
+
+ 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 @@
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
+ 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[ParamIdx]->getRAngleLoc());
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[NumParamLists - 2]->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 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 @@
// friend declarations.
bool Invalid = false;
TemplateParameterList *TemplateParams
- = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
+ = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc,
+ TemplateNameLoc,
+ SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size(),
TUK == TUK_Friend,
Added: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp?rev=131138&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp Tue May 10 13:27:06 2011
@@ -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'}}
+}
Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp?rev=131138&r1=131137&r2=131138&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p17.cpp Tue May 10 13:27:06 2011
@@ -24,12 +24,11 @@
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;
}
More information about the cfe-commits
mailing list