[cfe-commits] r83436 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp test/SemaTemplate/class-template-spec.cpp test/SemaTemplate/temp_class_spec_neg.cpp

Douglas Gregor dgregor at apple.com
Tue Oct 6 17:13:32 PDT 2009


Author: dgregor
Date: Tue Oct  6 19:13:32 2009
New Revision: 83436

URL: http://llvm.org/viewvc/llvm-project?rev=83436&view=rev
Log:
Refactor checking of the scope of explicit template specialization
declarations and explicit template instantiations, improving
diagnostics and making the code usable for function template
specializations (as well as class template specializations and partial
specializations). 

Added:
    cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
    cfe/trunk/test/SemaTemplate/class-template-spec.cpp
    cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=83436&r1=83435&r2=83436&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Oct  6 19:13:32 2009
@@ -916,6 +916,34 @@
 def err_template_arg_extra_parens : Error<
   "non-type template argument cannot be surrounded by parentheses">;
 
+// C++ template specialization
+def err_template_spec_unknown_kind : Error<
+  "can only provide an explicit %select{<error>|<error>|specialization|"
+  "instantiation|instantiation}0 for a class template, function template, or "
+  "a member function, static data member, or member class of a class template">;
+def note_specialized_entity : Note<
+  "explicit %select{<error>|<error>|specialized|instantiated|instantiated}0 is "
+  "here">;
+def err_template_spec_decl_function_scope : Error<
+  "explicit %select{<error>|<error>|specialization|instantiation|"
+  "instantiation}0 of %1 in function scope">;
+def err_template_spec_decl_out_of_scope_global : Error<
+  "%select{class template|class template partial|function template|member "
+  "function|static data member|member class}0 specialization of %1 must "
+  "originally be declared in the global scope">;
+def err_template_spec_decl_out_of_scope : Error<
+  "%select{class template|class template partial|function template|member "
+  "function|static data member|member class}0 specialization of %1 must "
+  "originally be declared in namespace %2">;
+def err_template_spec_redecl_out_of_scope : Error<
+  "%select{class template|class template partial|function template|member "
+  "function|static data member|member class}0 specialization of %1 not in a "
+  "namespace enclosing %2">;
+def err_template_spec_redecl_global_scope : Error<
+  "%select{class template|class template partial|function template|member "
+  "function|static data member|member class}0 specialization of %1 must occur "
+  "at global scope">;
+
 // C++ class template specializations and out-of-line definitions
 def err_template_spec_needs_header : Error<
   "template specialization requires 'template<>'">;
@@ -931,20 +959,6 @@
 def err_template_qualified_declarator_no_match : Error<
   "nested name specifier %0 for declaration does not refer into a class, "
   "class template or class template partial specialization">;
-def err_template_spec_decl_out_of_scope_global : Error<
-  "class template %select{|partial }0specialization of %1 must occur in the "
-  "global scope">;
-def err_template_spec_decl_out_of_scope : Error<
-  "class template %select{|partial }0specialization of %1 not in namespace %2">;
-def err_template_spec_decl_function_scope : Error<
-  "%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|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|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<
@@ -978,7 +992,7 @@
     "arguments to identify a particular function template">;
 def note_function_template_spec_matched : Note<
     "function template matches specialization %0">;
-    
+
 // C++ Template Instantiation
 def err_template_recursion_depth_exceeded : Error<
   "recursive template instantiation exceeded maximum depth of %0">,

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=83436&r1=83435&r2=83436&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Oct  6 19:13:32 2009
@@ -2485,13 +2485,6 @@
                                                 const CXXScopeSpec &SS,
                                                 TypeTy *ObjectType);
 
-  bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
-                                    ClassTemplateSpecializationDecl *PrevDecl,
-                                             SourceLocation TemplateNameLoc,
-                                             SourceRange ScopeSpecifierRange,
-                                             bool PartialSpecialization,
-                                             bool ExplicitInstantiation);
-
   bool CheckClassTemplatePartialSpecializationArgs(
                                         TemplateParameterList *TemplateParams,
                               const TemplateArgumentListBuilder &TemplateArgs,

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=83436&r1=83435&r2=83436&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Oct  6 19:13:32 2009
@@ -2345,21 +2345,76 @@
     << TemplateParams->getSourceRange();
 }
 
-/// \brief Check whether a class template specialization or explicit
-/// instantiation in the current context is well-formed.
+/// \brief Determine what kind of template specialization the given declaration
+/// is.
+static TemplateSpecializationKind getTemplateSpecializationKind(NamedDecl *D) {
+  if (!D)
+    return TSK_Undeclared;
+  
+  if (ClassTemplateSpecializationDecl *CTS 
+        = dyn_cast<ClassTemplateSpecializationDecl>(D))
+    return CTS->getSpecializationKind();
+  if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
+    return Function->getTemplateSpecializationKind();
+
+  // FIXME: static data members!
+  // FIXME: member classes of class templates!
+  return TSK_Undeclared;
+}
+
+/// \brief Check whether a specialization or explicit instantiation is
+/// well-formed in the current context.
 ///
-/// This routine determines whether a class template specialization or
+/// This routine determines whether a template specialization or
 /// explicit instantiation can be declared in the current context
-/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]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,
-                                            bool PartialSpecialization,
-                                            bool ExplicitInstantiation) {
+/// (C++ [temp.expl.spec]p2, C++0x [temp.explicit]p2).
+///
+/// \param S the semantic analysis object for which this check is being
+/// performed.
+///
+/// \param Specialized the entity being specialized or instantiated, which
+/// may be a kind of template (class template, function template, etc.) or
+/// a member of a class template (member function, static data member, 
+/// member class).
+///
+/// \param PrevDecl the previous declaration of this entity, if any.
+///
+/// \param Loc the location of the explicit specialization or instantiation of
+/// this entity.
+///
+/// \param IsPartialSpecialization whether this is a partial specialization of
+/// a class template.
+///
+/// \param TSK the kind of specialization or implicit instantiation being 
+/// performed.
+///
+/// \returns true if there was an error that we cannot recover from, false
+/// otherwise.
+static bool CheckTemplateSpecializationScope(Sema &S,
+                                             NamedDecl *Specialized,
+                                             NamedDecl *PrevDecl,
+                                             SourceLocation Loc,
+                                             bool IsPartialSpecialization,
+                                             TemplateSpecializationKind TSK) {
+  // Keep these "kind" numbers in sync with the %select statements in the
+  // various diagnostics emitted by this routine.
+  int EntityKind = 0;
+  if (isa<ClassTemplateDecl>(Specialized))
+    EntityKind = IsPartialSpecialization? 1 : 0;
+  else if (isa<FunctionTemplateDecl>(Specialized))
+    EntityKind = 2;
+  else if (isa<CXXMethodDecl>(Specialized))
+    EntityKind = 3;
+  else if (isa<VarDecl>(Specialized))
+    EntityKind = 4;
+  else if (isa<RecordDecl>(Specialized))
+    EntityKind = 5;
+  else {
+    S.Diag(Loc, diag::err_template_spec_unknown_kind) << TSK;
+    S.Diag(Specialized->getLocation(), diag::note_specialized_entity) << TSK;
+    return true;
+  }
+
   // 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
@@ -2373,66 +2428,68 @@
   //   the explicit specialization was declared, or in a namespace
   //   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)
-      << Kind << ClassTemplate;
+  if (S.CurContext->getLookupContext()->isFunctionOrMethod()) {
+    S.Diag(Loc, diag::err_template_spec_decl_function_scope)
+      << TSK << Specialized;
     return true;
   }
-
-  DeclContext *DC = CurContext->getEnclosingNamespaceContext();
-  DeclContext *TemplateContext
-    = ClassTemplate->getDeclContext()->getEnclosingNamespaceContext();
-  if ((!PrevDecl || PrevDecl->getSpecializationKind() == TSK_Undeclared) &&
-      !ExplicitInstantiation) {
-    // 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)
-          << PartialSpecialization
-          << ClassTemplate << ScopeSpecifierRange;
-      else if (isa<NamespaceDecl>(TemplateContext))
-        Diag(TemplateNameLoc, diag::err_template_spec_decl_out_of_scope)
-          << PartialSpecialization << 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)) {
-    // 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<TranslationUnitDecl>(TemplateContext)) {
-      if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
-        Diag(TemplateNameLoc, diag::err_template_spec_redecl_global_scope)
-          << Kind << ClassTemplate << ScopeSpecifierRange;
-      else
-        SuppressedDiag = true;
-    } else if (isa<NamespaceDecl>(TemplateContext)) {
-      if (!ExplicitInstantiation || getLangOptions().CPlusPlus0x)
-        Diag(TemplateNameLoc, diag::err_template_spec_redecl_out_of_scope)
-          << Kind << ClassTemplate
-          << cast<NamedDecl>(TemplateContext) << ScopeSpecifierRange;
-      else
-        SuppressedDiag = true;
+  
+  bool ComplainedAboutScope = false;
+  DeclContext *SpecializedContext
+    = Specialized->getDeclContext()->getEnclosingNamespaceContext();
+  if (TSK == TSK_ExplicitSpecialization) {
+    DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
+    if ((!PrevDecl || 
+         getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
+         getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){
+      // There is no prior declaration of this entity, so this
+      // specialization must be in the same context as the template
+      // itself.
+      if (!DC->Equals(SpecializedContext)) {
+        if (isa<TranslationUnitDecl>(SpecializedContext))
+          S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
+          << EntityKind << Specialized;
+        else if (isa<NamespaceDecl>(SpecializedContext))
+          S.Diag(Loc, diag::err_template_spec_decl_out_of_scope)
+          << EntityKind << Specialized
+          << cast<NamedDecl>(SpecializedContext);
+        
+        S.Diag(Specialized->getLocation(), diag::note_template_decl_here);
+        ComplainedAboutScope = true;
+      }
     }
-
-    if (!SuppressedDiag)
-      Diag(ClassTemplate->getLocation(), diag::note_template_decl_here);
   }
-
+  
+  // Make sure that this redeclaration (or definition) occurs in an enclosing 
+  // namespace. We perform this check for explicit specializations and, in 
+  // C++0x, for explicit instantiations as well (per DR275).
+  // FIXME: -Wc++0x should make these warnings.
+  // Note that HandleDeclarator() performs this check for explicit 
+  // specializations of function templates, static data members, and member
+  // functions, so we skip the check here for those kinds of entities.
+  // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
+  // Should we refactor the check, so that it occurs later?
+  if (!ComplainedAboutScope && !S.CurContext->Encloses(SpecializedContext) &&
+      ((TSK == TSK_ExplicitSpecialization &&
+        !(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) ||
+          isa<FunctionDecl>(Specialized))) || 
+        S.getLangOptions().CPlusPlus0x)) {
+    if (isa<TranslationUnitDecl>(SpecializedContext))
+      S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
+        << EntityKind << Specialized;
+    else if (isa<NamespaceDecl>(SpecializedContext))
+      S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
+        << EntityKind << Specialized
+        << cast<NamedDecl>(SpecializedContext);
+  
+    S.Diag(Specialized->getLocation(), diag::note_template_decl_here);
+  }
+  
+  // FIXME: check for specialization-after-instantiation errors and such.
+  
   return false;
 }
-
+                                             
 /// \brief Check the non-type template arguments of a class template
 /// partial specialization according to C++ [temp.class.spec]p9.
 ///
@@ -2714,11 +2771,9 @@
   // Check whether we can declare a class template specialization in
   // the current scope.
   if (TUK != TUK_Friend &&
-      CheckClassTemplateSpecializationScope(ClassTemplate, PrevDecl,
-                                            TemplateNameLoc,
-                                            SS.getRange(),
-                                            isPartialSpecialization,
-                                            /*ExplicitInstantiation=*/false))
+      CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl, 
+                                       TemplateNameLoc, isPartialSpecialization,
+                                       TSK_ExplicitSpecialization))
     return true;
 
   // The canonical type
@@ -3008,6 +3063,13 @@
   // FIXME: Check if the prior specialization has a point of instantiation.
   // If so, we have run afoul of C++ [temp.expl.spec]p6.
   
+  // Check the scope of this explicit specialization.
+  if (CheckTemplateSpecializationScope(*this, 
+                                       Specialization->getPrimaryTemplate(),
+                                       Specialization, FD->getLocation(), 
+                                       false, TSK_ExplicitSpecialization))
+    return true;
+  
   // Mark the prior declaration as an explicit specialization, so that later
   // clients know that this is an explicit specialization.
   // FIXME: Check for prior explicit instantiations?
@@ -3071,18 +3133,10 @@
     Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
   }
 
-  // C++0x [temp.explicit]p2:
-  //   [...] An explicit instantiation shall appear in an enclosing
-  //   namespace of its template. [...]
-  //
-  // This is C++ DR 275.
-  if (CheckClassTemplateSpecializationScope(ClassTemplate, 0,
-                                            TemplateNameLoc,
-                                            SS.getRange(),
-                                            /*PartialSpecialization=*/false,
-                                            /*ExplicitInstantiation=*/true))
-    return true;
-
+  TemplateSpecializationKind TSK
+    = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+                           : TSK_ExplicitInstantiationDeclaration;
+  
   // Translate the parser's template argument list in our AST format.
   llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
   translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
@@ -3111,6 +3165,16 @@
   ClassTemplateSpecializationDecl *PrevDecl
     = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
 
+  // C++0x [temp.explicit]p2:
+  //   [...] An explicit instantiation shall appear in an enclosing
+  //   namespace of its template. [...]
+  //
+  // This is C++ DR 275.
+  if (CheckTemplateSpecializationScope(*this, ClassTemplate, PrevDecl,
+                                       TemplateNameLoc, false, 
+                                       TSK))
+    return true;
+  
   ClassTemplateSpecializationDecl *Specialization = 0;
 
   bool SpecializationRequiresInstantiation = true;
@@ -3224,9 +3288,6 @@
   //
   // This check comes when we actually try to perform the
   // instantiation.
-  TemplateSpecializationKind TSK
-    = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
-                           : TSK_ExplicitInstantiationDeclaration;
   if (SpecializationRequiresInstantiation)
     InstantiateClassTemplateSpecialization(Specialization, TSK);
   else // Instantiate the members of this class template specialization.

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp?rev=83436&r1=83435&r2=83436&view=diff

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p1.cpp Tue Oct  6 19:13:32 2009
@@ -1,8 +1,10 @@
-// RUN: clang-cc -fsyntax-only %s
+// RUN: clang-cc -fsyntax-only -verify %s
 
 // This test creates cases where implicit instantiations of various entities
 // would cause a diagnostic, but provides expliict specializations for those
 // entities that avoid the diagnostic. The intent is to verify that 
+// implicit instantiations do not occur (because the explicit specialization 
+// is used instead).
 struct NonDefaultConstructible {
   NonDefaultConstructible(int);
 };

Added: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp?rev=83436&view=auto

==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp Tue Oct  6 19:13:32 2009
@@ -0,0 +1,114 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test creates cases where implicit instantiations of various entities
+// would cause a diagnostic, but provides expliict specializations for those
+// entities that avoid the diagnostic. The specializations are alternately
+// declarations and definitions, and the intent of this test is to verify
+// that we allow specializations only in the appropriate namespaces (and
+// nowhere else).
+struct NonDefaultConstructible {
+  NonDefaultConstructible(int);
+};
+
+
+// C++ [temp.expl.spec]p1:
+//   An explicit specialization of any of the following:
+
+//     -- function template
+namespace N0 {
+  template<typename T> void f0(T) { // expected-note{{here}}
+    T t;
+  }
+
+  template<> void f0(NonDefaultConstructible) { }
+
+  void test_f0(NonDefaultConstructible NDC) {
+    f0(NDC);
+  }
+  
+  template<> void f0(int);
+  template<> void f0(long);
+}
+
+template<> void N0::f0(int) { } // okay
+
+namespace N1 {
+  template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
+}
+
+template<> void N0::f0(double) { } // expected-error{{originally be declared}}
+
+// FIXME: update the remainder of this test to check for scopes properly.
+//     -- class template
+template<typename T>
+struct X0 {
+  static T member;
+  
+  void f1(T t) {
+    t = 17;
+  }
+  
+  struct Inner : public T { };
+  
+  template<typename U>
+  struct InnerTemplate : public T { };
+  
+  template<typename U>
+  void ft1(T t, U u);
+};
+
+template<typename T> 
+template<typename U>
+void X0<T>::ft1(T t, U u) {
+  t = u;
+}
+
+template<typename T> T X0<T>::member;
+
+template<> struct X0<void> { };
+X0<void> test_X0;
+
+
+//     -- member function of a class template
+template<> void X0<void*>::f1(void *) { }
+
+void test_spec(X0<void*> xvp, void *vp) {
+  xvp.f1(vp);
+}
+
+//     -- static data member of a class template
+template<> 
+NonDefaultConstructible X0<NonDefaultConstructible>::member = 17;
+
+NonDefaultConstructible &get_static_member() {
+  return X0<NonDefaultConstructible>::member;
+}
+
+//    -- member class of a class template
+template<>
+struct X0<void*>::Inner { };
+
+X0<void*>::Inner inner0;
+
+//    -- member class template of a class template
+template<>
+template<>
+struct X0<void*>::InnerTemplate<int> { };
+
+X0<void*>::InnerTemplate<int> inner_template0;
+
+//    -- member function template of a class template
+template<>
+template<>
+void X0<void*>::ft1(void*, const void*) { }
+
+void test_func_template(X0<void *> xvp, void *vp, const void *cvp) {
+  xvp.ft1(vp, cvp);
+}
+
+// example from the standard:
+template<class T> class stream;
+template<> class stream<char> { /* ... */ };
+template<class T> class Array { /* ... */ }; 
+template<class T> void sort(Array<T>& v) { /* ... */ }
+template<> void sort<char*>(Array<char*>&) ;

Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-spec.cpp?rev=83436&r1=83435&r2=83436&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Tue Oct  6 19:13:32 2009
@@ -85,12 +85,12 @@
 
 template<> struct N::B<int> { }; // okay
 
-template<> struct N::B<float> { }; // expected-error{{class template specialization of 'B' not in namespace 'N'}}
+template<> struct N::B<float> { }; // expected-error{{originally}}
 
 namespace M {
   template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}}
 
-  template<> struct ::A<long double>; // expected-error{{class template specialization of 'A' must occur in the global scope}}
+  template<> struct ::A<long double>; // expected-error{{originally}}
 }
 
 template<> struct N::B<char> { 

Modified: cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp?rev=83436&r1=83435&r2=83436&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp Tue Oct  6 19:13:32 2009
@@ -9,7 +9,7 @@
 }
 
 template<typename T>
-struct N::M::A<T*> { }; // expected-error{{not in namespace}}
+struct N::M::A<T*> { }; // expected-error{{originally}}
 
 // C++ [temp.class.spec]p9
 //   bullet 1
@@ -25,7 +25,7 @@
 
 template< int X, int (*array_ptr)[X] > class A2 {}; // expected-note{{here}}
 int array[5]; 
-template< int X > class A2<X,&array> { }; // expected-error{{specializes}}
+template< int X > class A2<X, &array> { }; // expected-error{{specializes}}
 
 template<typename T, int N, template<typename X> class TT>
 struct Test0;





More information about the cfe-commits mailing list