From 16df850bb73e8e2a3dece830b59785ff167428bc Mon Sep 17 00:00:00 2001
From: Douglas Gregor
Date: Fri, 12 Jun 2009 22:21:45 +0000
Subject: [PATCH] Finish implementing checking of class template partial
specializations
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73260 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/Basic/DiagnosticSemaKinds.td | 17 +++++++++--------
lib/Sema/Sema.h | 1 +
lib/Sema/SemaTemplate.cpp | 16 +++++++++++-----
lib/Sema/SemaTemplateInstantiate.cpp | 7 +++++--
test/SemaTemplate/temp_class_spec.cpp | 7 +++++++
test/SemaTemplate/temp_class_spec_neg.cpp | 11 ++++++++++-
www/cxx_status.html | 2 +-
7 files changed, 44 insertions(+), 17 deletions(-)
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 16d490f09b..899fd768dc 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -743,18 +743,19 @@ def err_template_spec_needs_header : Error<
def err_template_spec_extra_headers : Error<
"template specialization must have a single 'template<>' header">;
def err_template_spec_decl_out_of_scope_global : Error<
- "class template specialization of %0 must occur in the global scope">;
+ "class template %select{|partial }0specialization of %1 must occur in the "
+ "global scope">;
def err_template_spec_decl_out_of_scope : Error<
- "class template specialization of %0 not in namespace %1">;
+ "class template %select{|partial }0specialization of %1 not in namespace %2">;
def err_template_spec_decl_function_scope : Error<
- "%select{class template specialization|explicit instantiation}0 of %1 "
- "in function scope">;
+ "%select{class template specialization|class template partial specialization|"
+ "explicit instantiation}0 of %1 in function scope">;
def err_template_spec_redecl_out_of_scope : Error<
- "%select{class template specialization|explicit instantiation}0 of %1 "
- "not in a namespace enclosing %2">;
+ "%select{class template specialization|class template partial specialization|"
+ "explicit instantiation}0 of %1 not in a namespace enclosing %2">;
def err_template_spec_redecl_global_scope : Error<
- "%select{class template specialization|explicit instantiation}0 of %1 must "
- "occur at global scope">;
+ "%select{class template specialization|class template partial specialization|"
+ "explicit instantiation}0 of %1 must occur at global scope">;
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3315952723..c54b5947f1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1950,6 +1950,7 @@ public:
ClassTemplateSpecializationDecl *PrevDecl,
SourceLocation TemplateNameLoc,
SourceRange ScopeSpecifierRange,
+ bool PartialSpecialization,
bool ExplicitInstantiation);
bool CheckClassTemplatePartialSpecializationArgs(
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index b1a8ef2f7f..ec2907f65a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1932,6 +1932,7 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
ClassTemplateSpecializationDecl *PrevDecl,
SourceLocation TemplateNameLoc,
SourceRange ScopeSpecifierRange,
+ bool PartialSpecialization,
bool ExplicitInstantiation) {
// C++ [temp.expl.spec]p2:
// An explicit specialization shall be declared in the namespace
@@ -1947,8 +1948,9 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
// that encloses the one in which the explicit specialization was
// declared.
if (CurContext->getLookupContext()->isFunctionOrMethod()) {
+ int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
Diag(TemplateNameLoc, diag::err_template_spec_decl_function_scope)
- << ExplicitInstantiation << ClassTemplate;
+ << Kind << ClassTemplate;
return true;
}
@@ -1963,11 +1965,12 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
if (DC != TemplateContext) {
if (isa(TemplateContext))
Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope_global)
+ << PartialSpecialization
<< ClassTemplate << ScopeSpecifierRange;
else if (isa(TemplateContext))
Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope)
- << ClassTemplate << cast(TemplateContext)
- << ScopeSpecifierRange;
+ << PartialSpecialization << ClassTemplate
+ << cast(TemplateContext) << ScopeSpecifierRange;
Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
}
@@ -1981,16 +1984,17 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
// FIXME: In C++98, we would like to turn these errors into warnings,
// dependent on a -Wc++0x flag.
bool SuppressedDiag = false;
+ int Kind = ExplicitInstantiation? 2 : PartialSpecialization? 1 : 0;
if (isa(TemplateContext)) {
if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
- << ExplicitInstantiation << ClassTemplate << ScopeSpecifierRange;
+ << Kind << ClassTemplate << ScopeSpecifierRange;
else
SuppressedDiag = true;
} else if (isa(TemplateContext)) {
if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
- << ExplicitInstantiation << ClassTemplate
+ << Kind << ClassTemplate
<< cast(TemplateContext) << ScopeSpecifierRange;
else
SuppressedDiag = true;
@@ -2285,6 +2289,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
if (CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
TemplateNameLoc,
SS.getRange(),
+ isPartialSpecialization,
/*ExplicitInstantiation=*/false))
return true;
@@ -2440,6 +2445,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
if (CheckClassTemplateSpecializationScope(ClassTemplate, 0,
TemplateNameLoc,
SS.getRange(),
+ /*PartialSpecialization=*/false,
/*ExplicitInstantiation=*/true))
return true;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index e5a9675a03..936df1e97d 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -854,8 +854,11 @@ Sema::InstantiateClassTemplateSpecialization(
const TemplateArgumentList *TemplateArgs
= &ClassTemplateSpec->getTemplateArgs();
- // Determine whether any class template partial specializations
- // match the given template arguments.
+ // C++ [temp.class.spec]p7:
+ // Partial specialization declarations themselves are not found by
+ // name lookup. Rather, when the primary template name is used,
+ // any previously declared partial specializations of the primary
+ // template are also considered.
typedef std::pair MatchResult;
llvm::SmallVector Matched;
diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp
index ce1459b1d2..6fedce76ae 100644
--- a/test/SemaTemplate/temp_class_spec.cpp
+++ b/test/SemaTemplate/temp_class_spec.cpp
@@ -255,3 +255,10 @@ int is_nested_value_type_identity1[
//int is_nested_value_type_identity2[
// is_nested_value_type_identity::value? -1 : 1];
+
+// C++ [temp.class.spec]p4:
+template class A { }; //#1
+template class A { }; //#2
+template class A { }; //#3
+template class A { }; //#4
+template class A { }; //#5
diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp
index d303146dce..b9a12cb4de 100644
--- a/test/SemaTemplate/temp_class_spec_neg.cpp
+++ b/test/SemaTemplate/temp_class_spec_neg.cpp
@@ -1,8 +1,17 @@
// RUN: clang-cc -fsyntax-only -verify %s
template struct vector;
-// C++ [temp.class.spec]p9
+// C++ [temp.class.spec]p6:
+namespace N {
+ namespace M {
+ template struct A; // expected-note{{here}}
+ }
+}
+template
+struct N::M::A { }; // expected-error{{not in namespace}}
+
+// C++ [temp.class.spec]p9
// bullet 1
template struct A {};
template struct A {}; // expected-error{{depends on}}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 3a9a7290fc..06f541b534 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -1887,7 +1887,7 @@ welcome!
14.5.4 [temp.class.spec] |
|
|
- |
+ |
N/A |
|