aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r--lib/Sema/SemaTemplate.cpp113
1 files changed, 102 insertions, 11 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index e3538e8a4c..db582edba2 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1520,6 +1520,77 @@ Sema::CheckTemplateDeclScope(Scope *S,
<< TemplateRange;
}
+/// \brief Check whether a class template specialization in the
+/// current context is well-formed.
+///
+/// This routine determines whether a class template specialization
+/// can be declared in the current context (C++ [temp.expl.spec]p2)
+/// and emits appropriate diagnostics if there was an error. It
+/// returns true if there was an error that we cannot recover from,
+/// and false otherwise.
+bool
+Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
+ ClassTemplateSpecializationDecl *PrevDecl,
+ SourceLocation TemplateNameLoc,
+ SourceRange ScopeSpecifierRange) {
+ // C++ [temp.expl.spec]p2:
+ // An explicit specialization shall be declared in the namespace
+ // of which the template is a member, or, for member templates, in
+ // the namespace of which the enclosing class or enclosing class
+ // template is a member. An explicit specialization of a member
+ // function, member class or static data member of a class
+ // template shall be declared in the namespace of which the class
+ // template is a member. Such a declaration may also be a
+ // definition. If the declaration is not a definition, the
+ // specialization may be defined later in the name- space in which
+ // the explicit specialization was declared, or in a namespace
+ // that encloses the one in which the explicit specialization was
+ // declared.
+ if (CurContext->getLookupContext()->isFunctionOrMethod()) {
+ Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
+ << ClassTemplate;
+ return true;
+ }
+
+ DeclContext *DC = CurContext->getEnclosingNamespaceContext();
+ DeclContext *TemplateContext
+ = ClassTemplate->getDeclContext()->getEnclosingNamespaceContext();
+ if (!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) {
+ // There is no prior declaration of this entity, so this
+ // specialization must be in the same context as the template
+ // itself.
+ if (DC != TemplateContext) {
+ if (isa<TranslationUnitDecl>(TemplateContext))
+ Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global)
+ << ClassTemplate << ScopeSpecifierRange;
+ else if (isa<NamespaceDecl>(TemplateContext))
+ Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope)
+ << ClassTemplate << cast<NamedDecl>(TemplateContext)
+ << ScopeSpecifierRange;
+
+ Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
+ }
+
+ return false;
+ }
+
+ // We have a previous declaration of this entity. Make sure that
+ // this redeclaration (or definition) occurs in an enclosing namespace.
+ if (!CurContext->Encloses(TemplateContext)) {
+ if (isa<TranslationUnitDecl>(TemplateContext))
+ Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
+ << ClassTemplate << ScopeSpecifierRange;
+ else if (isa<NamespaceDecl>(TemplateContext))
+ Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
+ << ClassTemplate << cast<NamedDecl>(TemplateContext)
+ << ScopeSpecifierRange;
+
+ Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
+ }
+
+ return false;
+}
+
Sema::DeclTy *
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc,
@@ -1532,23 +1603,36 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation RAngleLoc,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists) {
- // FIXME: We need to match up the scope-specifier with the template
- // parameter lists, and will eventually end up with a single
- // template parameter list remaining (which applies to
- // TemplateIdType).
- assert(TemplateParameterLists.size() == 1 &&
- "Clang doesn't handle with ill-formed specializations yet.");
-
- assert(static_cast<TemplateParameterList*>(*TemplateParameterLists.get())
- ->size() == 0 &&
- "Clang doesn't handle class template partial specializations yet");
-
// Find the class template we're specializing
ClassTemplateDecl *ClassTemplate
= dyn_cast_or_null<ClassTemplateDecl>(static_cast<Decl *>(TemplateD));
if (!ClassTemplate)
return 0;
+ // Check the validity of the template headers that introduce this
+ // template.
+ if (TemplateParameterLists.size() == 0) {
+ // FIXME: It would be very nifty if we could introduce some kind
+ // of "code insertion hint" that could show the code that needs to
+ // be added.
+ Diag(KWLoc, diag::err_template_spec_needs_header);
+ } else {
+ TemplateParameterList *TemplateParams
+ = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
+ if (TemplateParameterLists.size() > 1) {
+ Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_spec_extra_headers);
+ return 0;
+ }
+
+ if (TemplateParams->size() > 0) {
+ // FIXME: No support for class template partial specialization.
+ Diag(TemplateParams->getTemplateLoc(),
+ diag::unsup_template_partial_spec);
+ return 0;
+ }
+ }
+
// Check that the specialization uses the same tag kind as the
// original template.
TagDecl::TagKind Kind;
@@ -1588,6 +1672,13 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
ClassTemplateSpecializationDecl *Specialization = 0;
+ // Check whether we can declare a class template specialization in
+ // the current scope.
+ if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
+ TemplateNameLoc,
+ SS.getRange()))
+ return 0;
+
if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) {
// Since the only prior class template specialization with these
// arguments was referenced but not declared, reuse that