aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclTemplate.h81
-rw-r--r--lib/AST/Decl.cpp4
-rw-r--r--lib/Sema/Sema.h1
-rw-r--r--lib/Sema/SemaDecl.cpp24
-rw-r--r--lib/Sema/SemaTemplate.cpp6
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp32
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp14
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp6
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp30
9 files changed, 172 insertions, 26 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index e21849c453..8d44676124 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -621,7 +621,7 @@ protected:
/// \brief Data that is common to all of the declarations of a given
/// function template.
struct Common {
- Common() : InstantiatedFromMember(0) { }
+ Common() : InstantiatedFromMember(0, false) { }
/// \brief The function template specializations for this function
/// template, including explicit specializations and instantiations.
@@ -629,7 +629,10 @@ protected:
/// \brief The member function template from which this was most
/// directly instantiated (or null).
- FunctionTemplateDecl *InstantiatedFromMember;
+ ///
+ /// The boolean value indicates whether this member function template
+ /// was explicitly specialized.
+ llvm::PointerIntPair<FunctionTemplateDecl*, 1, bool> InstantiatedFromMember;
};
/// \brief A pointer to the previous declaration (if this is a redeclaration)
@@ -704,14 +707,40 @@ public:
/// \returns NULL if this is not an instantiation of a member function
/// template.
FunctionTemplateDecl *getInstantiatedFromMemberTemplate() {
- return getCommonPtr()->InstantiatedFromMember;
+ return getCommonPtr()->InstantiatedFromMember.getPointer();
}
void setInstantiatedFromMemberTemplate(FunctionTemplateDecl *FTD) {
- assert(!getCommonPtr()->InstantiatedFromMember);
- getCommonPtr()->InstantiatedFromMember = FTD;
+ assert(!getCommonPtr()->InstantiatedFromMember.getPointer());
+ getCommonPtr()->InstantiatedFromMember.setPointer(FTD);
}
+ /// \brief Determines whether this template was a specialization of a
+ /// member template.
+ ///
+ /// In the following example, the function template \c X<int>::f is a
+ /// member specialization.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<typename U> void f(T, U);
+ /// };
+ ///
+ /// template<> template<typename T>
+ /// void X<int>::f(int, T);
+ /// \endcode
+ bool isMemberSpecialization() {
+ return getCommonPtr()->InstantiatedFromMember.getInt();
+ }
+
+ /// \brief Note that this member template is a specialization.
+ void setMemberSpecialization() {
+ assert(getCommonPtr()->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ getCommonPtr()->InstantiatedFromMember.setInt(true);
+ }
+
/// Create a template function node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
@@ -1163,7 +1192,7 @@ protected:
/// \brief Data that is common to all of the declarations of a given
/// class template.
struct Common {
- Common() : InstantiatedFromMember(0) {}
+ Common() : InstantiatedFromMember(0, 0) {}
/// \brief The class template specializations for this class
/// template, including explicit specializations and instantiations.
@@ -1179,9 +1208,15 @@ protected:
/// \brief The templated member class from which this was most
/// directly instantiated (or null).
- ClassTemplateDecl *InstantiatedFromMember;
+ ///
+ /// The boolean value indicates whether this member class template
+ /// was explicitly specialized.
+ llvm::PointerIntPair<ClassTemplateDecl *, 1, bool> InstantiatedFromMember;
};
+ // FIXME: Combine PreviousDeclaration with CommonPtr, as in
+ // FunctionTemplateDecl.
+
/// \brief Previous declaration of this class template.
ClassTemplateDecl *PreviousDeclaration;
@@ -1280,14 +1315,40 @@ public:
///
/// \returns null if this is not an instantiation of a member class template.
ClassTemplateDecl *getInstantiatedFromMemberTemplate() const {
- return CommonPtr->InstantiatedFromMember;
+ return CommonPtr->InstantiatedFromMember.getPointer();
}
void setInstantiatedFromMemberTemplate(ClassTemplateDecl *CTD) {
- assert(!CommonPtr->InstantiatedFromMember);
- CommonPtr->InstantiatedFromMember = CTD;
+ assert(!CommonPtr->InstantiatedFromMember.getPointer());
+ CommonPtr->InstantiatedFromMember.setPointer(CTD);
}
+ /// \brief Determines whether this template was a specialization of a
+ /// member template.
+ ///
+ /// In the following example, the member template \c X<int>::Inner is a
+ /// member specialization.
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// template<typename U> struct Inner;
+ /// };
+ ///
+ /// template<> template<typename T>
+ /// struct X<int>::Inner { /* ... */ };
+ /// \endcode
+ bool isMemberSpecialization() {
+ return CommonPtr->InstantiatedFromMember.getInt();
+ }
+
+ /// \brief Note that this member template is a specialization.
+ void setMemberSpecialization() {
+ assert(CommonPtr->InstantiatedFromMember.getPointer() &&
+ "Only member templates can be member template specializations");
+ CommonPtr->InstantiatedFromMember.setInt(true);
+ }
+
// Implement isa/cast/dyncast support
static bool classof(const Decl *D)
{ return D->getKind() == ClassTemplate; }
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 638d1cfd46..429729ea3b 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -737,8 +737,8 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
const TemplateArgumentList *
FunctionDecl::getTemplateSpecializationArgs() const {
if (FunctionTemplateSpecializationInfo *Info
- = TemplateOrSpecialization
- .dyn_cast<FunctionTemplateSpecializationInfo*>()) {
+ = TemplateOrSpecialization
+ .dyn_cast<FunctionTemplateSpecializationInfo*>()) {
return Info->TemplateArguments;
}
return 0;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 40e7426e97..fed2fbc081 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -551,6 +551,7 @@ public:
bool IsFunctionDefinition,
bool &Redeclaration);
void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool IsExplicitSpecialization,
bool &Redeclaration,
bool &OverloadableAttrRequired);
void CheckMain(FunctionDecl *FD);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 69426ee755..a1582a900f 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1735,6 +1735,10 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
return DeclPtrTy();
}
+ if (!DC->isDependentContext() &&
+ RequireCompleteDeclContext(D.getCXXScopeSpec()))
+ return DeclPtrTy();
+
LookupResult Res;
LookupQualifiedName(Res, DC, Name, LookupOrdinaryName, true);
PrevDecl = Res.getAsSingleDecl(Context);
@@ -2807,11 +2811,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) &&
CheckMemberSpecialization(NewFD, PrevDecl))
NewFD->setInvalidDecl();
-
+
// Perform semantic checking on the function declaration.
bool OverloadableAttrRequired = false; // FIXME: HACK!
- CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
- /*FIXME:*/OverloadableAttrRequired);
+ CheckFunctionDeclaration(NewFD, PrevDecl, isExplicitSpecialization,
+ Redeclaration, /*FIXME:*/OverloadableAttrRequired);
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
// An out-of-line member function declaration must also be a
@@ -2914,8 +2918,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
/// that have been instantiated via C++ template instantiation (called
/// via InstantiateDecl).
///
+/// \param IsExplicitSpecialiation whether this new function declaration is
+/// an explicit specialization of the previous declaration.
+///
/// This sets NewFD->isInvalidDecl() to true if there was an error.
void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+ bool IsExplicitSpecialization,
bool &Redeclaration,
bool &OverloadableAttrRequired) {
// If NewFD is already known erroneous, don't do any of this checking.
@@ -2990,7 +2998,7 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
if (FunctionTemplateDecl *OldTemplateDecl
= dyn_cast<FunctionTemplateDecl>(OldDecl)) {
- NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
FunctionTemplateDecl *NewTemplateDecl
= NewFD->getDescribedFunctionTemplate();
assert(NewTemplateDecl && "Template/non-template mismatch");
@@ -2999,6 +3007,14 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
Method->setAccess(OldTemplateDecl->getAccess());
NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
}
+
+ // If this is an explicit specialization of a member that is a function
+ // template, mark it as a member specialization.
+ if (IsExplicitSpecialization &&
+ NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+ NewTemplateDecl->setMemberSpecialization();
+ assert(OldTemplateDecl->isMemberSpecialization());
+ }
} else {
if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
NewFD->setAccess(OldDecl->getAccess());
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 7412049857..3ee15a5b4d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -716,6 +716,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
assert(T->isDependentType() && "Class template type is not dependent?");
(void)T;
+ // If we are providing an explicit specialization of a member that is a
+ // class template, make a note of that.
+ if (PrevClassTemplate &&
+ PrevClassTemplate->getInstantiatedFromMemberTemplate())
+ PrevClassTemplate->setMemberSpecialization();
+
// Set the access specifier.
if (!Invalid && TUK != TUK_Friend)
SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index ec00d9805c..65260c8e1e 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -46,15 +46,31 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) {
break;
Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs());
+
+ // If this class template specialization was instantiated from a
+ // specialized member that is a class template, we're done.
+ assert(Spec->getSpecializedTemplate() && "No class template?");
+ if (Spec->getSpecializedTemplate()->isMemberSpecialization())
+ break;
}
-
// Add template arguments from a function template specialization.
else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
- // FIXME: Check whether this is an explicit specialization.
+ if (Function->getTemplateSpecializationKind()
+ == TSK_ExplicitSpecialization)
+ break;
+
if (const TemplateArgumentList *TemplateArgs
- = Function->getTemplateSpecializationArgs())
+ = Function->getTemplateSpecializationArgs()) {
+ // Add the template arguments for this specialization.
Result.addOuterTemplateArguments(TemplateArgs);
+ // If this function was instantiated from a specialized member that is
+ // a function template, we're done.
+ assert(Function->getPrimaryTemplate() && "No function template?");
+ if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ break;
+ }
+
// If this is a friend declaration and it declares an entity at
// namespace scope, take arguments from its lexical parent
// instead of its semantic parent.
@@ -940,9 +956,15 @@ Sema::InstantiateClassTemplateSpecialization(
// -- If no matches are found, the instantiation is generated
// from the primary template.
ClassTemplateDecl *OrigTemplate = Template;
- while (OrigTemplate->getInstantiatedFromMemberTemplate())
+ while (OrigTemplate->getInstantiatedFromMemberTemplate()) {
+ // If we've found an explicit specialization of this class template,
+ // stop here and use that as the pattern.
+ if (OrigTemplate->isMemberSpecialization())
+ break;
+
OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate();
-
+ }
+
Pattern = OrigTemplate->getTemplatedDecl();
}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index b03734346c..33fa28866e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -581,7 +581,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
PrevDecl = 0;
}
- SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
+ SemaRef.CheckFunctionDeclaration(Function, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
// If the original function was part of a friend declaration,
@@ -748,7 +748,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
- SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+ SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) &&
@@ -1057,9 +1057,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = 0;
if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) {
- while (Primary->getInstantiatedFromMemberTemplate())
+ while (Primary->getInstantiatedFromMemberTemplate()) {
+ // If we have hit a point where the user provided a specialization of
+ // this template, we're done looking.
+ if (Primary->isMemberSpecialization())
+ break;
+
Primary = Primary->getInstantiatedFromMemberTemplate();
-
+ }
+
PatternDecl = Primary->getTemplatedDecl();
} else
PatternDecl = Function->getInstantiatedFromMemberFunction();
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
index 112444af95..04129f8091 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp
@@ -7,10 +7,14 @@ template<class T1> class A {
};
template<> template<class X>
-class A<int>::B { };
+class A<long>::B { };
+// FIXME: If we make the explicit specialization of A<long>::B, above, into
+// a specialization of A<int>::B, our diagnostic is correct but not very
+// helpful.
template<> template<> template<class T>
void A<int>::B<double>::mf1(T t) { }
+// FIXME: This diagnostic could probably be better.
template<class Y> template<>
void A<Y>::B<double>::mf2() { } // expected-error{{does not refer}}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp
new file mode 100644
index 0000000000..1f38e5a2c1
--- /dev/null
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp
@@ -0,0 +1,30 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X {
+ template<typename U> struct Inner { };
+
+ template<typename U> void f(T, U) { }
+};
+
+template<> template<typename U>
+struct X<int>::Inner {
+ U member;
+};
+
+template<> template<typename U>
+void X<int>::f(int x, U y) {
+ x = y; // expected-error{{incompatible type}}
+}
+
+void test(X<int> xi, X<long> xl, float *fp) {
+ X<int>::Inner<float*> xii;
+ xii.member = fp;
+ xi.f(17, 25);
+ xi.f(17, 3.14159);
+ xi.f(17, fp); // expected-note{{instantiation}}
+ X<long>::Inner<float*> xli;
+
+ xli.member = fp; // expected-error{{no member}}
+ xl.f(17, fp); // okay
+}