]> granicus.if.org Git - clang/commitdiff
Semantic analysis for explicit instantiation of class templates. We
authorDouglas Gregor <dgregor@apple.com>
Wed, 13 May 2009 00:25:59 +0000 (00:25 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 13 May 2009 00:25:59 +0000 (00:25 +0000)
still aren't instantiating the definitions of class template members,
and core issues 275 and 259 will both affect the checking that we do
for explicit instantiations (but are not yet implemented).

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaType.cpp
test/SemaTemplate/temp_explicit.cpp
www/cxx_status.html

index ed56cad330e63d0c47d91711b041ecf10f84d5b8..466f5495eb473ee9693ff5bda65ffd8261a088fd 100644 (file)
@@ -704,8 +704,8 @@ def err_template_recursion_depth_exceeded : Error<
 def note_template_recursion_depth : Note<
   "use -ftemplate-depth-N to increase recursive template instantiation depth">;
 
-def err_template_implicit_instantiate_undefined : Error<
-  "implicit instantiation of undefined template %0">;
+def err_template_instantiate_undefined : Error<
+  "%select{implicit|explicit}0 instantiation of undefined template %1">;
 def err_implicit_instantiate_member_undefined : Error<
   "implicit instantiation of undefined member %0">;
 def note_template_class_instantiation_here : Note<
@@ -719,6 +719,15 @@ def err_field_instantiates_to_function : Error<
 def err_nested_name_spec_non_tag : Error<
   "type %0 cannot be used prior to '::' because it has no members">;
 
+// C++ Explicit Instantiation
+def err_explicit_instantiation_redef : Error<
+    "explicit instantiation of %0 occurs after "
+    "%select{|explicit specialization|implicit instantiation|explicit "
+    "instantiation}1">;
+def note_previous_instantiation : Note<
+    "previous %select{|explicit specialization|implicit instantiation|explicit "
+    "instantiation}0 is here">;
+
 // C++ typename-specifiers
 def err_typename_nested_not_found : Error<"no type named %0 in %1">;
 def err_typename_nested_not_found_global : Error<
index 83565095509beedb017228471bab8d22fb44daa6..2e617f573becadfe6b09a136f69f91a5a28e4599 100644 (file)
@@ -1895,6 +1895,19 @@ public:
                                    AttributeList *Attr,
                                  MultiTemplateParamsArg TemplateParameterLists);
 
+  virtual DeclResult
+  ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+                             unsigned TagSpec, 
+                             SourceLocation KWLoc,
+                             const CXXScopeSpec &SS,
+                             TemplateTy Template,
+                             SourceLocation TemplateNameLoc,
+                             SourceLocation LAngleLoc,
+                             ASTTemplateArgsPtr TemplateArgs,
+                             SourceLocation *TemplateArgLocs,
+                             SourceLocation RAngleLoc,
+                             AttributeList *Attr);
+
   bool CheckTemplateArgumentList(TemplateDecl *Template,
                                  SourceLocation TemplateLoc,
                                  SourceLocation LAngleLoc,
@@ -2092,7 +2105,8 @@ public:
   bool
   InstantiateClass(SourceLocation PointOfInstantiation,
                    CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
-                   const TemplateArgumentList &TemplateArgs);
+                   const TemplateArgumentList &TemplateArgs,
+                   bool ExplicitInstantiation);
 
   bool 
   InstantiateClassTemplateSpecialization(
index fc44217252a0eff3433bed60edf7ccb953b5fd80..c80bb882f6acbf35e3a68487d2b16c52ebbf90e2 100644 (file)
@@ -2141,6 +2141,141 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
   return DeclPtrTy::make(Specialization);
 }
 
+Sema::DeclResult
+Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
+                                 unsigned TagSpec, 
+                                 SourceLocation KWLoc,
+                                 const CXXScopeSpec &SS,
+                                 TemplateTy TemplateD,
+                                 SourceLocation TemplateNameLoc,
+                                 SourceLocation LAngleLoc,
+                                 ASTTemplateArgsPtr TemplateArgsIn,
+                                 SourceLocation *TemplateArgLocs,
+                                 SourceLocation RAngleLoc,
+                                 AttributeList *Attr) {
+  // Find the class template we're specializing
+  TemplateName Name = TemplateD.getAsVal<TemplateName>();
+  ClassTemplateDecl *ClassTemplate 
+    = cast<ClassTemplateDecl>(Name.getAsTemplateDecl());
+
+  // Check that the specialization uses the same tag kind as the
+  // original template.
+  TagDecl::TagKind Kind;
+  switch (TagSpec) {
+  default: assert(0 && "Unknown tag type!");
+  case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
+  case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
+  case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
+  }
+  if (!isAcceptableTagRedeclaration(
+                              ClassTemplate->getTemplatedDecl()->getTagKind(),
+                                    Kind)) {
+    Diag(KWLoc, diag::err_use_with_wrong_tag) 
+      << ClassTemplate
+      << CodeModificationHint::CreateReplacement(KWLoc, 
+                            ClassTemplate->getTemplatedDecl()->getKindName());
+    Diag(ClassTemplate->getTemplatedDecl()->getLocation(), 
+         diag::note_previous_use);
+    Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
+  }
+
+  // Translate the parser's template argument list in our AST format.
+  llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+  translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+
+  // Check that the template argument list is well-formed for this
+  // template.
+  llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
+  if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, 
+                                &TemplateArgs[0], TemplateArgs.size(),
+                                RAngleLoc, ConvertedTemplateArgs))
+    return true;
+
+  assert((ConvertedTemplateArgs.size() == 
+            ClassTemplate->getTemplateParameters()->size()) &&
+         "Converted template argument list is too short!");
+  
+  // Find the class template specialization declaration that
+  // corresponds to these arguments.
+  llvm::FoldingSetNodeID ID;
+  ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+                                           ConvertedTemplateArgs.size());
+  void *InsertPos = 0;
+  ClassTemplateSpecializationDecl *PrevDecl
+    = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+
+  ClassTemplateSpecializationDecl *Specialization = 0;
+
+  if (PrevDecl) {
+    if (PrevDecl->getSpecializationKind() != TSK_Undeclared) {
+      // This particular specialization has already been declared or
+      // instantiated. We cannot explicitly instantiate it.
+      Diag(TemplateNameLoc, diag::err_explicit_instantiation_redef)
+        << Context.getTypeDeclType(PrevDecl)
+        << (int)PrevDecl->getSpecializationKind();
+      Diag(PrevDecl->getLocation(), diag::note_previous_instantiation)
+        << (int)PrevDecl->getSpecializationKind();
+      return DeclPtrTy::make(PrevDecl);
+    }
+
+    // Since the only prior class template specialization with these
+    // arguments was referenced but not declared, reuse that
+    // declaration node as our own, updating its source location to
+    // reflect our new declaration.
+    Specialization = PrevDecl;
+    Specialization->setLocation(TemplateNameLoc);
+    PrevDecl = 0;
+  } else {
+    // Create a new class template specialization declaration node for
+    // this explicit specialization.
+    Specialization
+      = ClassTemplateSpecializationDecl::Create(Context, 
+                                             ClassTemplate->getDeclContext(),
+                                                TemplateNameLoc,
+                                                ClassTemplate,
+                                                &ConvertedTemplateArgs[0],
+                                                ConvertedTemplateArgs.size(),
+                                                0);
+
+    ClassTemplate->getSpecializations().InsertNode(Specialization, 
+                                                   InsertPos);
+  }
+
+  // Build the fully-sugared type for this explicit instantiation as
+  // the user wrote in the explicit instantiation itself. This means
+  // that we'll pretty-print the type retrieved from the
+  // specialization's declaration the way that the user actually wrote
+  // the explicit instantiation, rather than formatting the name based
+  // on the "canonical" representation used to store the template
+  // arguments in the specialization.
+  QualType WrittenTy 
+    = Context.getTemplateSpecializationType(Name, 
+                                            &TemplateArgs[0],
+                                            TemplateArgs.size(),
+                                  Context.getTypeDeclType(Specialization));
+  Specialization->setTypeAsWritten(WrittenTy);
+  TemplateArgsIn.release();
+
+  // Add the explicit instantiation into its lexical context. However,
+  // since explicit instantiations are never found by name lookup, we
+  // just put it into the declaration context directly.
+  Specialization->setLexicalDeclContext(CurContext);
+  CurContext->addDecl(Context, Specialization);
+
+  // C++ [temp.explicit]p3:
+  //
+  //   A definition of a class template or class member template
+  //   shall be in scope at the point of the explicit instantiation of
+  //   the class template or class member template.
+  //
+  // This check comes when we actually try to perform the
+  // instantiation.
+  if (InstantiateClassTemplateSpecialization(Specialization, true))
+    return true;
+
+  return DeclPtrTy::make(Specialization);
+}
+
 Sema::TypeResult
 Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
                         const IdentifierInfo &II, SourceLocation IdLoc) {
index 0fe6cee882c382b443dd1af4a7c3c97d20de3145..ce8cbe0f434f04070f9ffc7206d12f3d7f02d3c2 100644 (file)
@@ -666,7 +666,8 @@ Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
 bool
 Sema::InstantiateClass(SourceLocation PointOfInstantiation,
                        CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
-                       const TemplateArgumentList &TemplateArgs) {
+                       const TemplateArgumentList &TemplateArgs,
+                       bool ExplicitInstantiation) {
   bool Invalid = false;
   
   CXXRecordDecl *PatternDef 
@@ -678,8 +679,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
         << Context.getTypeDeclType(Instantiation);
       Diag(Pattern->getLocation(), diag::note_member_of_template_here);
     } else {
-      Diag(PointOfInstantiation, 
-           diag::err_template_implicit_instantiate_undefined)
+      Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
+        << ExplicitInstantiation
         << Context.getTypeDeclType(Instantiation);
       Diag(Pattern->getLocation(), diag::note_template_decl_here);
     }
@@ -766,7 +767,8 @@ Sema::InstantiateClassTemplateSpecialization(
 
   return InstantiateClass(ClassTemplateSpec->getLocation(),
                           ClassTemplateSpec, Pattern,
-                          ClassTemplateSpec->getTemplateArgs());
+                          ClassTemplateSpec->getTemplateArgs(),
+                          ExplicitInstantiation);
 }
 
 /// \brief Instantiate a nested-name-specifier.
index f3a31ea0deb1cf14713b34204cabf523e10af5d1..d04a5ad6c591b8f00b787bc0de1fdb089940cc92 100644 (file)
@@ -1115,7 +1115,8 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
              Parent && !Spec; Parent = Parent->getParent())
           Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
         assert(Spec && "Not a member of a class template specialization?");
-        return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs());
+        return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(),
+                                /*ExplicitInstantiation=*/false);
       }
     }
   }
index 884fc38167f660106dc9c5e1af078155d89d0e55..527532cfa9b7828bfb6049e6be985668251b2d33 100644 (file)
@@ -7,8 +7,9 @@ namespace N {
   template<typename T, typename U = T> class X1 { };
 }
 
+// Check the syntax of explicit instantiations.
 template class X0<int, float>;
-template class X0<int>;
+template class X0<int>; // expected-note{{previous}}
 
 template class N::X1<int>;
 template class ::N::X1<int, float>;
@@ -16,4 +17,32 @@ template class ::N::X1<int, float>;
 using namespace N;
 template class X1<float>;
 
+// Check for some bogus syntax that probably means that the user
+// wanted to write an explicit specialization, but forgot the '<>'
+// after 'template'.
 template class X0<double> { }; // expected-error{{explicit specialization}}
+
+// Check for explicit instantiations that come after other kinds of
+// instantiations or declarations.
+template class X0<int, int>; // expected-error{{after}}
+
+template<> class X0<char> { }; // expected-note{{previous}}
+template class X0<char>; // expected-error{{after}}
+
+void foo(X0<short>) { } // expected-note{{previous}}
+template class X0<short>;  // expected-error{{after}}
+
+// Check that explicit instantiations actually produce definitions. We
+// determine whether this happens by placing semantic errors in the
+// definition of the template we're instantiating.
+template<typename T> struct X2; // expected-note{{declared here}}
+
+template struct X2<float>; // expected-error{{undefined template}}
+
+template<typename T>
+struct X2 {
+  void f0(T*); // expected-error{{pointer to a reference}}
+};
+
+template struct X2<int>; // okay
+template struct X2<int&>; // expected-note{{in instantiation of}}
index 9be7ffc274964d3e1c306520124c5199782f0605..d85d451f559e3390fafea941945d419788570ae8 100644 (file)
@@ -2055,7 +2055,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;14.7.2 [temp.explicit]</td>
   <td class="basic" align="center"></td>
   <td class="basic" align="center"></td>
-  <td class="broken" align="center"></td>
+  <td class="basic" align="center"></td>
   <td class="broken" align="center"></td>
   <td>Function templates cannot be instantiated</td>  
 </tr>