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