[cfe-commits] r82789 - in /cfe/trunk: include/clang/AST/DeclarationName.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/PartialDiagnostic.h include/clang/Parse/Action.h lib/Parse/ParseDecl.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp test/Parser/cxx-template-decl.cpp test/SemaTemplate/explicit-instantiation.cpp

Douglas Gregor dgregor at apple.com
Fri Sep 25 11:43:01 PDT 2009


Author: dgregor
Date: Fri Sep 25 13:43:00 2009
New Revision: 82789

URL: http://llvm.org/viewvc/llvm-project?rev=82789&view=rev
Log:
WIP implementation of explicit instantiation of function templates,
member functions of class template specializations, and static data
members. The mechanics are (mostly) present, but the semantic analysis
is very weak.


Added:
    cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclarationName.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/PartialDiagnostic.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/Parser/cxx-template-decl.cpp

Modified: cfe/trunk/include/clang/AST/DeclarationName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=82789&r1=82788&r2=82789&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclarationName.h (original)
+++ cfe/trunk/include/clang/AST/DeclarationName.h Fri Sep 25 13:43:00 2009
@@ -16,6 +16,7 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/CanonicalType.h"
+#include "clang/Basic/PartialDiagnostic.h"
 
 namespace llvm {
   template <typename T> struct DenseMapInfo;
@@ -327,7 +328,15 @@
   return DB;
 }
 
-
+/// Insertion operator for partial diagnostics.  This allows binding
+/// DeclarationName's into a partial diagnostic with <<.
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+                                           DeclarationName N) {
+  PD.AddTaggedVal(N.getAsOpaqueInteger(),
+                  Diagnostic::ak_declarationname);
+  return PD;
+}
+  
 }  // end namespace clang
 
 namespace llvm {

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 25 13:43:00 2009
@@ -1036,7 +1036,26 @@
     "non-templated declaration is here">;
 def err_explicit_instantiation_out_of_scope : Error<
   "explicit instantiation of %0 not in a namespace enclosing %1">;
-
+def err_explicit_instantiation_requires_name : Error<
+  "explicit instantiation declaration requires a name">;
+def err_explicit_instantiation_of_typedef : Error<
+  "explicit instantiation of typedef %0">;
+def err_explicit_instantiation_not_known : Error<
+  "explicit instantiation of %0 does not refer to a function template, member "
+  "function, member class, or static data member">;
+def note_explicit_instantiation_here : Note<
+  "explicit instantiation refers here">;
+def err_explicit_instantiation_data_member_not_instantiated : Error<
+  "explicit instantiation refers to static data member %q0 that is not an "
+  "instantiation">;
+def err_explicit_instantiation_member_function_not_instantiated : Error<
+  "explicit instantiation refers to member function %q0 that is not an "
+  "instantiation">;
+def err_explicit_instantiation_ambiguous : Error<
+  "partial ordering for explicit instantiation of %0 is ambiguous">;
+def note_explicit_instantiation_candidate : Note<
+  "explicit instantiation candidate function template here %0">;
+  
 // C++ typename-specifiers
 def err_typename_nested_not_found : Error<"no type named %0 in %1">;
 def err_typename_nested_not_found_global : Error<

Modified: cfe/trunk/include/clang/Basic/PartialDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/PartialDiagnostic.h?rev=82789&r1=82788&r2=82789&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/PartialDiagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/PartialDiagnostic.h Fri Sep 25 13:43:00 2009
@@ -18,9 +18,12 @@
 #include "clang/AST/Type.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/STLExtras.h"
 
 namespace clang {
 
+class DeclarationName;
+  
 class PartialDiagnostic {
   struct Storage {
     Storage() : NumDiagArgs(0), NumDiagRanges(0) { }
@@ -132,6 +135,9 @@
     PD.AddSourceRange(R);
     return PD;
   }
+  
+  friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+                                             DeclarationName N);
 };
 
 inline PartialDiagnostic PDiag(unsigned DiagID) {

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=82789&r1=82788&r2=82789&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Sep 25 13:43:00 2009
@@ -1898,6 +1898,38 @@
     return DeclResult();
   }
 
+  /// \brief Process the explicit instantiation of a function template or a
+  /// member of a class template.
+  ///
+  /// This routine is invoked when an explicit instantiation of a
+  /// function template or member function of a class template specialization 
+  /// is encountered. In the following example,
+  /// ActOnExplicitInstantiation will be invoked to force the
+  /// instantiation of X<int>:
+  ///
+  /// \code
+  /// template<typename T> void f(T);
+  /// template void f(int); // explicit instantiation
+  /// \endcode
+  ///
+  /// \param S the current scope
+  ///
+  /// \param ExternLoc the location of the 'extern' keyword that specifies that
+  /// this is an extern template (if any).
+  ///
+  /// \param TemplateLoc the location of the 'template' keyword that
+  /// specifies that this is an explicit instantiation.
+  ///
+  /// \param D the declarator describing the declaration to be implicitly
+  /// instantiated.
+  virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+                                                SourceLocation ExternLoc,
+                                                SourceLocation TemplateLoc,
+                                                Declarator &D) {
+    return DeclResult();
+  }
+                             
+                              
   /// \brief Called when the parser has parsed a C++ typename
   /// specifier that ends in an identifier, e.g., "typename T::type".
   ///

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=82789&r1=82788&r2=82789&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Sep 25 13:43:00 2009
@@ -419,13 +419,36 @@
   }
 
   // Inform the current actions module that we just parsed this declarator.
-  DeclPtrTy ThisDecl = TemplateInfo.TemplateParams?
-      Actions.ActOnTemplateDeclarator(CurScope,
+  DeclPtrTy ThisDecl;
+  switch (TemplateInfo.Kind) {
+  case ParsedTemplateInfo::NonTemplate:
+    ThisDecl = Actions.ActOnDeclarator(CurScope, D);
+    break;
+      
+  case ParsedTemplateInfo::Template:
+  case ParsedTemplateInfo::ExplicitSpecialization:
+    ThisDecl = Actions.ActOnTemplateDeclarator(CurScope,
                              Action::MultiTemplateParamsArg(Actions,
                                           TemplateInfo.TemplateParams->data(),
                                           TemplateInfo.TemplateParams->size()),
-                                    D)
-    : Actions.ActOnDeclarator(CurScope, D);
+                                               D);
+    break;
+      
+  case ParsedTemplateInfo::ExplicitInstantiation: {
+    Action::DeclResult ThisRes 
+      = Actions.ActOnExplicitInstantiation(CurScope,
+                                           TemplateInfo.ExternLoc,
+                                           TemplateInfo.TemplateLoc,
+                                           D);
+    if (ThisRes.isInvalid()) {
+      SkipUntil(tok::semi, true, true);
+      return DeclPtrTy();
+    }
+    
+    ThisDecl = ThisRes.get();
+    break;
+    }
+  }
 
   // Parse declarator '=' initializer.
   if (Tok.is(tok::equal)) {

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Sep 25 13:43:00 2009
@@ -2550,6 +2550,11 @@
                              SourceLocation NameLoc,
                              AttributeList *Attr);
 
+  virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+                                                SourceLocation ExternLoc,
+                                                SourceLocation TemplateLoc,
+                                                Declarator &D);
+    
   bool CheckTemplateArgumentList(TemplateDecl *Template,
                                  SourceLocation TemplateLoc,
                                  SourceLocation LAngleLoc,
@@ -2779,6 +2784,15 @@
   FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
                                                    FunctionTemplateDecl *FT2,
                                            TemplatePartialOrderingContext TPOC);
+  FunctionDecl *getMostSpecialized(FunctionDecl **Specializations,
+                                   unsigned NumSpecializations,
+                                   TemplatePartialOrderingContext TPOC,
+                                   SourceLocation Loc,
+                                   const PartialDiagnostic &NoneDiag,
+                                   const PartialDiagnostic &AmbigDiag,
+                                   const PartialDiagnostic &CandidateDiag,
+                                   unsigned *Index = 0);
+                                   
   ClassTemplatePartialSpecializationDecl *
   getMoreSpecializedPartialSpecialization(
                                   ClassTemplatePartialSpecializationDecl *PS1,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Sep 25 13:43:00 2009
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/Parse/DeclSpec.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/Basic/PartialDiagnostic.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/ADT/StringExtras.h"
 using namespace clang;
@@ -3326,6 +3327,180 @@
   return TagD;
 }
 
+Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
+                                                  SourceLocation ExternLoc,
+                                                  SourceLocation TemplateLoc,
+                                                  Declarator &D) {
+  // Explicit instantiations always require a name.
+  DeclarationName Name = GetNameForDeclarator(D);
+  if (!Name) {
+    if (!D.isInvalidType())
+      Diag(D.getDeclSpec().getSourceRange().getBegin(),
+           diag::err_explicit_instantiation_requires_name)
+        << D.getDeclSpec().getSourceRange()
+        << D.getSourceRange();
+    
+    return true;
+  }
+
+  // The scope passed in may not be a decl scope.  Zip up the scope tree until
+  // we find one that is.
+  while ((S->getFlags() & Scope::DeclScope) == 0 ||
+         (S->getFlags() & Scope::TemplateParamScope) != 0)
+    S = S->getParent();
+
+  // Determine the type of the declaration.
+  QualType R = GetTypeForDeclarator(D, S, 0);
+  if (R.isNull())
+    return true;
+  
+  if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+    // Cannot explicitly instantiate a typedef.
+    Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef)
+      << Name;
+    return true;
+  }
+
+  // Determine what kind of explicit instantiation we have.
+  TemplateSpecializationKind TSK
+    = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+                           : TSK_ExplicitInstantiationDeclaration;
+  
+  LookupResult Previous = LookupParsedName(S, &D.getCXXScopeSpec(),
+                                           Name, LookupOrdinaryName);
+
+  if (!R->isFunctionType()) {
+    // C++ [temp.explicit]p1:
+    //   A [...] static data member of a class template can be explicitly 
+    //   instantiated from the member definition associated with its class 
+    //   template.
+    if (Previous.isAmbiguous()) {
+      return DiagnoseAmbiguousLookup(Previous, Name, D.getIdentifierLoc(),
+                                     D.getSourceRange());
+    }
+    
+    VarDecl *Prev = dyn_cast_or_null<VarDecl>(Previous.getAsDecl());
+    if (!Prev || !Prev->isStaticDataMember()) {
+      // We expect to see a data data member here.
+      Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
+        << Name;
+      for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+           P != PEnd; ++P)
+        Diag(P->getLocation(), diag::note_explicit_instantiation_here);
+      return true;
+    }
+    
+    if (!Prev->getInstantiatedFromStaticDataMember()) {
+      // FIXME: Check for explicit specialization?
+      Diag(D.getIdentifierLoc(), 
+           diag::err_explicit_instantiation_data_member_not_instantiated)
+        << Prev;
+      Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
+      // FIXME: Can we provide a note showing where this was declared?
+      return true;
+    }
+    
+    // Instantiate static data member.
+    // FIXME: Note that this is an explicit instantiation.
+    if (TSK == TSK_ExplicitInstantiationDefinition)
+      InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false);
+    
+    // FIXME: Create an ExplicitInstantiation node?
+    return DeclPtrTy();
+  }
+  
+  // C++ [temp.explicit]p1:
+  //   A [...] function [...] can be explicitly instantiated from its template. 
+  //   A member function [...] of a class template can be explicitly 
+  //  instantiated from the member definition associated with its class 
+  //  template.
+  // FIXME: Implement this!
+  llvm::SmallVector<FunctionDecl *, 8> Matches;
+  for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+       P != PEnd; ++P) {
+    NamedDecl *Prev = *P;
+    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
+      // FIXME: If there were any explicitly-specified template arguments, 
+      // don't look for Method declarations.
+      if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
+        Matches.clear();
+        Matches.push_back(Method);
+        break;
+      }
+    }
+    
+    FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Prev);
+    if (!FunTmpl)
+      continue;
+
+    TemplateDeductionInfo Info(Context);
+    FunctionDecl *Specialization = 0;
+    if (TemplateDeductionResult TDK
+          = DeduceTemplateArguments(FunTmpl, /*FIXME:*/false, 0, 0, 
+                                    R, Specialization, Info)) {
+      // FIXME: Keep track of almost-matches?
+      (void)TDK;
+      continue;
+    }
+    
+    Matches.push_back(Specialization);
+  }
+  
+  // Find the most specialized function template specialization.
+  FunctionDecl *Specialization
+    = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other, 
+                         D.getIdentifierLoc(), 
+          PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
+          PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
+                PartialDiagnostic(diag::note_explicit_instantiation_candidate));
+
+  if (!Specialization)
+    return true;
+  
+  switch (Specialization->getTemplateSpecializationKind()) {
+  case TSK_Undeclared:
+    Diag(D.getIdentifierLoc(), 
+         diag::err_explicit_instantiation_member_function_not_instantiated)
+      << Specialization
+      << (Specialization->getTemplateSpecializationKind() ==
+          TSK_ExplicitSpecialization);
+    Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here);
+    return true;
+
+  case TSK_ExplicitSpecialization:
+    // C++ [temp.explicit]p4:
+    //   For a given set of template parameters, if an explicit instantiation
+    //   of a template appears after a declaration of an explicit 
+    //   specialization for that template, the explicit instantiation has no 
+    //   effect.
+    break;      
+
+  case TSK_ExplicitInstantiationDefinition:
+    // FIXME: Check that we aren't trying to perform an explicit instantiation
+    // declaration now.
+    // Fall through
+      
+  case TSK_ImplicitInstantiation:
+  case TSK_ExplicitInstantiationDeclaration:
+    // Instantiate the function, if this is an explicit instantiation 
+    // definition.
+    if (TSK == TSK_ExplicitInstantiationDefinition)
+      InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, 
+                                    false);
+      
+    // FIXME: setTemplateSpecializationKind doesn't (yet) work for 
+    // non-templated member functions.
+    if (!Specialization->getPrimaryTemplate())
+      break;
+      
+    Specialization->setTemplateSpecializationKind(TSK);
+    break;
+  }
+
+  // FIXME: Create some kind of ExplicitInstantiationDecl here.
+  return DeclPtrTy();
+}
+
 Sema::TypeResult
 Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
                         const CXXScopeSpec &SS, IdentifierInfo *Name,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Sep 25 13:43:00 2009
@@ -1885,6 +1885,124 @@
     return 0;
 }
 
+/// \brief Determine if the two templates are equivalent.
+static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
+  if (T1 == T2)
+    return true;
+  
+  if (!T1 || !T2)
+    return false;
+  
+  return T1->getCanonicalDecl() == T2->getCanonicalDecl();
+}
+
+/// \brief Retrieve the most specialized of the given function template
+/// specializations.
+///
+/// \param Specializations the set of function template specializations that
+/// we will be comparing.
+///
+/// \param NumSpecializations the number of function template specializations in
+/// \p Specializations
+///
+/// \param TPOC the partial ordering context to use to compare the function
+/// template specializations.
+///
+/// \param Loc the location where the ambiguity or no-specializations 
+/// diagnostic should occur.
+///
+/// \param NoneDiag partial diagnostic used to diagnose cases where there are
+/// no matching candidates.
+///
+/// \param AmbigDiag partial diagnostic used to diagnose an ambiguity, if one
+/// occurs.
+///
+/// \param CandidateDiag partial diagnostic used for each function template
+/// specialization that is a candidate in the ambiguous ordering. One parameter
+/// in this diagnostic should be unbound, which will correspond to the string
+/// describing the template arguments for the function template specialization.
+///
+/// \param Index if non-NULL and the result of this function is non-nULL, 
+/// receives the index corresponding to the resulting function template
+/// specialization.
+///
+/// \returns the most specialized function template specialization, if 
+/// found. Otherwise, returns NULL.
+///
+/// \todo FIXME: Consider passing in the "also-ran" candidates that failed 
+/// template argument deduction.
+FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
+                                       unsigned NumSpecializations,
+                                       TemplatePartialOrderingContext TPOC,
+                                       SourceLocation Loc,
+                                       const PartialDiagnostic &NoneDiag,
+                                       const PartialDiagnostic &AmbigDiag,
+                                       const PartialDiagnostic &CandidateDiag,
+                                       unsigned *Index) {
+  if (NumSpecializations == 0) {
+    Diag(Loc, NoneDiag);
+    return 0;
+  }
+  
+  if (NumSpecializations == 1) {
+    if (Index)
+      *Index = 0;
+    
+    return Specializations[0];
+  }
+    
+  
+  // Find the function template that is better than all of the templates it
+  // has been compared to.
+  unsigned Best = 0;
+  FunctionTemplateDecl *BestTemplate 
+    = Specializations[Best]->getPrimaryTemplate();
+  assert(BestTemplate && "Not a function template specialization?");
+  for (unsigned I = 1; I != NumSpecializations; ++I) {
+    FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+    assert(Challenger && "Not a function template specialization?");
+    if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, 
+                                                  TPOC),
+                       Challenger)) {
+      Best = I;
+      BestTemplate = Challenger;
+    }
+  }
+  
+  // Make sure that the "best" function template is more specialized than all
+  // of the others.
+  bool Ambiguous = false;
+  for (unsigned I = 0; I != NumSpecializations; ++I) {
+    FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+    if (I != Best &&
+        !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, 
+                                                  TPOC),
+                        BestTemplate)) {
+      Ambiguous = true;
+      break;
+    }
+  }
+  
+  if (!Ambiguous) {
+    // We found an answer. Return it.
+    if (Index)
+      *Index = Best;
+    return Specializations[Best];
+  }
+  
+  // Diagnose the ambiguity.
+  Diag(Loc, AmbigDiag);
+  
+  // FIXME: Can we order the candidates in some sane way?
+  for (unsigned I = 0; I != NumSpecializations; ++I)
+    Diag(Specializations[I]->getLocation(), CandidateDiag)
+      << getTemplateArgumentBindingsText(
+            Specializations[I]->getPrimaryTemplate()->getTemplateParameters(),
+                         *Specializations[I]->getTemplateSpecializationArgs());
+  
+  return 0;
+}
+
 /// \brief Returns the more specialized class template partial specialization
 /// according to the rules of partial ordering of class template partial
 /// specializations (C++ [temp.class.order]).

Modified: cfe/trunk/test/Parser/cxx-template-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-decl.cpp?rev=82789&r1=82788&r2=82789&view=diff

==============================================================================
--- cfe/trunk/test/Parser/cxx-template-decl.cpp (original)
+++ cfe/trunk/test/Parser/cxx-template-decl.cpp Fri Sep 25 13:43:00 2009
@@ -2,7 +2,8 @@
 
 // Errors
 export class foo { };   // expected-error {{expected template}}
-template  x;            // expected-error {{C++ requires a type specifier for all declarations}}
+template  x;            // expected-error {{C++ requires a type specifier for all declarations}} \
+                        // expected-error {{does not refer}}
 export template x;      // expected-error {{expected '<' after 'template'}}
 export template<class T> class x0; // expected-note {{exported templates are unsupported}}
 template < ;            // expected-error {{parse error}} expected-error {{declaration does not declare anything}}

Added: cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp?rev=82789&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp (added)
+++ cfe/trunk/test/SemaTemplate/explicit-instantiation.cpp Fri Sep 25 13:43:00 2009
@@ -0,0 +1,57 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template void *; // expected-error{{expected unqualified-id}}
+
+template typedef void f0; // expected-error{{explicit instantiation of typedef}}
+
+int v0; // expected-note{{refers here}}
+template int v0; // expected-error{{does not refer}}
+
+template<typename T>
+struct X0 {
+  static T value;
+  
+  T f0(T x) {
+    return x + 1;  // expected-error{{invalid operands}}
+  } 
+  T* f0(T*, T*);
+  
+  template<typename U>
+  T f0(T, U);
+};
+
+template int X0<int>::value;
+
+struct NotDefaultConstructible {
+  NotDefaultConstructible(int);
+};
+
+template NotDefaultConstructible X0<NotDefaultConstructible>::value;
+
+template int X0<int>::f0(int);
+template int* X0<int>::f0(int*, int*);
+template int X0<int>::f0(int, float);
+
+template int X0<int>::f0(int) const; // expected-error{{does not refer}}
+template int* X0<int>::f0(int*, float*); // expected-error{{does not refer}}
+
+struct X1 { };
+typedef int X1::*MemPtr;
+
+template MemPtr X0<MemPtr>::f0(MemPtr); // expected-note{{requested here}}
+
+struct X2 {
+  int f0(int); // expected-note{{refers here}}
+  
+  template<typename T> T f1(T);
+  template<typename T> T* f1(T*);
+
+  template<typename T, typename U> void f2(T, U*); // expected-note{{candidate}}
+  template<typename T, typename U> void f2(T*, U); // expected-note{{candidate}}
+};
+
+template int X2::f0(int); // expected-error{{not an instantiation}}
+
+template int *X2::f1(int *); // okay
+
+template void X2::f2(int *, int *); // expected-error{{ambiguous}}





More information about the cfe-commits mailing list