]> granicus.if.org Git - clang/commitdiff
Improve location information on "reused" class template specialization
authorDouglas Gregor <dgregor@apple.com>
Wed, 25 Feb 2009 22:18:32 +0000 (22:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 25 Feb 2009 22:18:32 +0000 (22:18 +0000)
decls. Test and document the semantic location of class template
specialization definitions that occur within a scope enclosing the
scope of the class template.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65478 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplate.cpp
test/SemaTemplate/class-template-spec.cpp

index db582edba2ef99ed93ee3cdfd6aed44b311a6d05..0c60520142ea64d4f035dd60c85714be615bd3a5 100644 (file)
@@ -687,8 +687,9 @@ Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
                                                 ConvertedTemplateArgs.size(),
                                                    0);
     ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
+    Decl->setLexicalDeclContext(CurContext);
   }
-
+  
   // Build the fully-sugared type for this class template
   // specialization, which refers back to the class template
   // specialization we created or found.
@@ -1611,6 +1612,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
 
   // Check the validity of the template headers that introduce this
   // template.
+  // FIXME: Once we have member templates, we'll need to check
+  // C++ [temp.expl.spec]p17-18, where we could have multiple levels of
+  // template<> headers.
   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
@@ -1684,8 +1688,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
     // arguments was referenced but not declared, reuse that
     // declaration node as our own, updating its source location to
     // reflect our new declaration.
-    // FIXME: update source locations
     Specialization = PrevDecl;
+    Specialization->setLocation(TemplateNameLoc);
     PrevDecl = 0;
   } else {
     // Create a new class template specialization declaration node for
@@ -1725,11 +1729,17 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
     }
   }
 
-  // FIXME: Do we want to create a nicely sugared type to use as the
-  // type for this explicit specialization?
+  // FIXME: We want to create a nicely sugared type to use as the
+  // type of this explicit specialization.
 
-  // Set the lexical context. If the tag has a C++ scope specifier,
-  // the lexical context will be different from the semantic context.
+  // C++ [temp.expl.spec]p9:
+  //   A template explicit specialization is in the scope of the
+  //   namespace in which the template was defined.
+  //
+  // We actually implement this paragraph where we set the semantic
+  // context (in the creation of the ClassTemplateSpecializationDecl),
+  // but we also maintain the lexical context where the actual
+  // definition occurs.
   Specialization->setLexicalDeclContext(CurContext);
   
   // We may be starting the definition of this specialization.
index 4ae1b9bdc9789afff0fbf528ed70b7c61eab5b2b..15c797a5daf46efcf05ed8035138f19cf9d91251 100644 (file)
@@ -52,8 +52,11 @@ template<> struct ::A<double>;
 namespace N {
   template<typename T> struct B; // expected-note 2{{template is declared here}}
 
+  template<> struct ::N::B<char>; // okay
   template<> struct ::N::B<short>; // okay
   template<> struct ::N::B<int>; // okay
+
+  int f(int);
 }
 
 template<> struct N::B<int> { }; // okay
@@ -65,3 +68,7 @@ namespace M {
 
   template<> struct ::A<long double>; // expected-error{{class template specialization of 'A' must occur in the global scope}}
 }
+
+template<> struct N::B<char> { 
+  int testf(int x) { return f(x); }
+};