[cfe-commits] r68081 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/TemplateKinds.h include/clang/Parse/Action.h lib/AST/ASTContext.cpp lib/AST/Type.cpp lib/Parse/MinimalAction.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTemplate.cpp lib/Parse/Parser.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/metafun-apply.cpp test/SemaTemplate/nested-name-spec-template.cpp

Douglas Gregor dgregor at apple.com
Mon Mar 30 17:43:59 PDT 2009


Author: dgregor
Date: Mon Mar 30 19:43:58 2009
New Revision: 68081

URL: http://llvm.org/viewvc/llvm-project?rev=68081&view=rev
Log:
Parsing and AST representation for dependent template names that occur
within nested-name-specifiers, e.g., for the "apply" in

  typename MetaFun::template apply<T1, T2>::type

At present, we can't instantiate these nested-name-specifiers, so our
testing is sketchy.


Added:
    cfe/trunk/test/SemaTemplate/metafun-apply.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/TemplateKinds.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Parse/MinimalAction.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Mar 30 19:43:58 2009
@@ -699,6 +699,9 @@
 def note_typename_refers_here : Note<
     "referenced member %0 is declared here">;
 
+def err_template_kw_refers_to_non_template : Error<
+    "%0 following the 'template' keyword does not refer to a template">;
+
 def err_unexpected_typedef : Error<
   "unexpected type name %0: expected expression">;
 def err_unexpected_namespace : Error<

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

==============================================================================
--- cfe/trunk/include/clang/Basic/TemplateKinds.h (original)
+++ cfe/trunk/include/clang/Basic/TemplateKinds.h Mon Mar 30 19:43:58 2009
@@ -22,12 +22,14 @@
   /// The name refers to a function template or a set of overloaded
   /// functions that includes at least one function template.
   TNK_Function_template,
-  /// The name refers to a class template.
-  TNK_Class_template,
-  /// The name referes to a template template parameter.
-  TNK_Template_template_parm,
-  /// The name is dependent and is known to be a template name based
-  /// on syntax, e.g., "Alloc::template rebind<Other>".
+  /// The name refers to a template whose specialization produces a
+  /// type. The template itself could be a class template, template
+  /// template parameter, or C++0x template alias.
+  TNK_Type_template,
+  /// The name refers to a dependent template name. Whether the
+  /// template name is assumed to refer to a type template or a
+  /// function template depends on the context in which the template
+  /// name occurs.
   TNK_Dependent_template_name
 };
 

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Mar 30 19:43:58 2009
@@ -157,7 +157,7 @@
   /// returned, and \p TemplateDecl receives the declaration. An
   /// optional CXXScope can be passed to indicate the C++ scope in
   /// which the identifier will be found.
-  virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
+  virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
                                           TemplateTy &Template,
                                           const CXXScopeSpec *SS = 0) = 0;
 
@@ -1229,6 +1229,20 @@
     return TypeResult();
   };
 
+  /// \brief Form a dependent template name.
+  ///
+  /// This action forms a dependent template name given the template
+  /// name and its (presumably dependent) scope specifier. For
+  /// example, given "MetaFun::template apply", the scope specifier \p
+  /// SS will be "MetaFun::", \p TemplateKWLoc contains the location
+  /// of the "template" keyword, and "apply" is the \p Name.
+  virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
+                                                const IdentifierInfo &Name,
+                                                SourceLocation NameLoc,
+                                                const CXXScopeSpec &SS) {
+    return TemplateTy();
+  }
+
   /// \brief Process the declaration or definition of an explicit
   /// class template specialization or a class template partial
   /// specialization.
@@ -1568,7 +1582,7 @@
   virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
                                   const CXXScopeSpec *SS);
 
-  virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
+  virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
                                           TemplateTy &Template,
                                           const CXXScopeSpec *SS = 0);
 

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=68081&r1=68080&r2=68081&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Mar 30 19:43:58 2009
@@ -1373,8 +1373,6 @@
                                           const TemplateArgument *Args,
                                           unsigned NumArgs,
                                           QualType Canon) {
-  // FIXME: If Template is dependent, canonicalize it!
-
   if (!Canon.isNull())
     Canon = getCanonicalType(Canon);
 

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=68081&r1=68080&r2=68081&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Mar 30 19:43:58 2009
@@ -94,8 +94,12 @@
   if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
     return TOT->getUnderlyingType().getDesugaredType();
   if (const TemplateSpecializationType *Spec 
-        = dyn_cast<TemplateSpecializationType>(this))
-    return Spec->getCanonicalTypeInternal().getDesugaredType();
+        = dyn_cast<TemplateSpecializationType>(this)) {
+    QualType Canon = Spec->getCanonicalTypeInternal();
+    if (Canon->getAsTemplateSpecializationType())
+      return QualType(this, 0);
+    return Canon->getDesugaredType();
+  }
   if (const QualifiedNameType *QualName  = dyn_cast<QualifiedNameType>(this))
     return QualName->getNamedType().getDesugaredType();
 

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

==============================================================================
--- cfe/trunk/lib/Parse/MinimalAction.cpp (original)
+++ cfe/trunk/lib/Parse/MinimalAction.cpp Mon Mar 30 19:43:58 2009
@@ -134,7 +134,7 @@
 }
 
 TemplateNameKind 
-MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
+MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
                               TemplateTy &TemplateDecl,
                               const CXXScopeSpec *SS) {
   return TNK_Non_template;

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar 30 19:43:58 2009
@@ -513,7 +513,7 @@
       Token Next = NextToken();
       if (Next.is(tok::annot_template_id) && 
           static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
-          ->Kind == TNK_Class_template) {
+            ->Kind == TNK_Type_template) {
         // We have a qualified template-id, e.g., N::A<int>
         CXXScopeSpec SS;
         ParseOptionalCXXScopeSpecifier(SS);
@@ -640,7 +640,7 @@
     case tok::annot_template_id: {
       TemplateIdAnnotation *TemplateId 
         = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
-      if (TemplateId->Kind != TNK_Class_template) {
+      if (TemplateId->Kind != TNK_Type_template) {
         // This template-id does not refer to a type name, so we're
         // done with the type-specifiers.
         goto DoneWithDeclSpec;

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Mar 30 19:43:58 2009
@@ -307,7 +307,7 @@
   if (Tok.is(tok::annot_template_id)) {
     TemplateIdAnnotation *TemplateId 
       = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
-    if (TemplateId->Kind == TNK_Class_template) {
+    if (TemplateId->Kind == TNK_Type_template) {
       if (AnnotateTemplateIdTokenAsType(SS))
         return 0;
 
@@ -419,7 +419,7 @@
     TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
     NameLoc = ConsumeToken();
 
-    if (TemplateId->Kind != TNK_Class_template) {
+    if (TemplateId->Kind != TNK_Type_template) {
       // The template-name in the simple-template-id refers to
       // something other than a class template. Give an appropriate
       // error message and skip to the ';'.

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Mar 30 19:43:58 2009
@@ -92,9 +92,8 @@
         Tok.is(tok::kw_template)) {
       // Parse the optional 'template' keyword, then make sure we have
       // 'identifier <' after it.
-      SourceLocation TemplateKWLoc;
       if (Tok.is(tok::kw_template)) {
-        TemplateKWLoc = ConsumeToken();
+        SourceLocation TemplateKWLoc = ConsumeToken();
         
         if (Tok.isNot(tok::identifier)) {
           Diag(Tok.getLocation(), 
@@ -110,20 +109,20 @@
             << SourceRange(TemplateKWLoc, Tok.getLocation());
           break;
         }
-      }
-      else {
-        // FIXME: If the nested-name-specifier thus far is dependent,
-        // we need to break out of here, because this '<' is taken as
-        // an operator and not as part of a simple-template-id.
+
+        TemplateTy Template 
+          = Actions.ActOnDependentTemplateName(TemplateKWLoc,
+                                               *Tok.getIdentifierInfo(),
+                                               Tok.getLocation(),
+                                               SS);
+        AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
+                                &SS, TemplateKWLoc, false);
+        continue;
       }
 
       TemplateTy Template;
-      TemplateNameKind TNK = TNK_Non_template;
-      // FIXME: If the nested-name-specifier thus far is dependent,
-      // set TNK = TNK_Dependent_template_name and skip the
-      // "isTemplateName" check.
-      TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
-                                   CurScope, Template, &SS);
+      TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+                                                    CurScope, Template, &SS);
       if (TNK) {
         // We have found a template name, so annotate this this token
         // with a template-id annotation. We do not permit the
@@ -131,7 +130,7 @@
         // because some clients (e.g., the parsing of class template
         // specializations) still want to see the original template-id
         // token.
-        AnnotateTemplateIdToken(Template, TNK, &SS, TemplateKWLoc, false);
+        AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
         continue;
       }
     }
@@ -142,12 +141,13 @@
       //   simple-template-id '::'
       //
       // So we need to check whether the simple-template-id is of the
-      // right kind (it should name a type), and then convert it into
-      // a type within the nested-name-specifier.
+      // right kind (it should name a type or be dependent), and then
+      // convert it into a type within the nested-name-specifier.
       TemplateIdAnnotation *TemplateId 
         = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
 
-      if (TemplateId->Kind == TNK_Class_template) {
+      if (TemplateId->Kind == TNK_Type_template || 
+          TemplateId->Kind == TNK_Dependent_template_name) {
         if (AnnotateTemplateIdTokenAsType(&SS))
           SS.clear();
 
@@ -172,7 +172,7 @@
         SS.setEndLoc(CCLoc);
         continue;
       } else
-        assert(false && "FIXME: Only class template names supported here");
+        assert(false && "FIXME: Only type template names supported here");
     }
 
     // We don't have any tokens that form the beginning of a

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Mar 30 19:43:58 2009
@@ -531,8 +531,7 @@
     return; 
 
   // Build the annotation token.
-  // FIXME: Not just for class templates!
-  if (TNK == TNK_Class_template && AllowTypeAnnotation) {
+  if (TNK == TNK_Type_template && AllowTypeAnnotation) {
     Action::TypeResult Type 
       = Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
                                     LAngleLoc, TemplateArgsPtr,
@@ -550,8 +549,8 @@
     else 
       Tok.setLocation(TemplateNameLoc);
   } else {
-    // This is a function template. We'll be building a template-id
-    // annotation token.
+    // Build a template-id annotation token that can be processed
+    // later.
     Tok.setKind(tok::annot_template_id);
     TemplateIdAnnotation *TemplateId 
       = TemplateIdAnnotation::Allocate(TemplateArgs.size());
@@ -595,8 +594,9 @@
 
   TemplateIdAnnotation *TemplateId 
     = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
-  assert(TemplateId->Kind == TNK_Class_template &&
-         "Only works for class templates");
+  assert((TemplateId->Kind == TNK_Type_template ||
+          TemplateId->Kind == TNK_Dependent_template_name) &&
+         "Only works for type and dependent templates");
   
   ASTTemplateArgsPtr TemplateArgsPtr(Actions, 
                                      TemplateId->getTemplateArgs(),

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

==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Mar 30 19:43:58 2009
@@ -901,7 +901,7 @@
   if (Tok.is(tok::annot_template_id)) {
     TemplateIdAnnotation *TemplateId 
       = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
-    if (TemplateId->Kind == TNK_Class_template) {
+    if (TemplateId->Kind == TNK_Type_template) {
       // A template-id that refers to a type was parsed into a
       // template-id annotation in a context where we weren't allowed
       // to produce a type annotation token. Update the template-id

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Mar 30 19:43:58 2009
@@ -1690,7 +1690,7 @@
   //===--------------------------------------------------------------------===//
   // C++ Templates [C++ 14]
   //
-  virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
+  virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
                                           TemplateTy &Template,
                                           const CXXScopeSpec *SS = 0);
   bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
@@ -1756,6 +1756,11 @@
                       SourceLocation *TemplateArgLocs,
                       SourceLocation RAngleLoc);
   
+  virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
+                                                const IdentifierInfo &Name,
+                                                SourceLocation NameLoc,
+                                                const CXXScopeSpec &SS);
+
   bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
                                     ClassTemplateSpecializationDecl *PrevDecl,
                                              SourceLocation TemplateNameLoc,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Mar 30 19:43:58 2009
@@ -26,7 +26,7 @@
 /// declaration if II names a template. An optional CXXScope can be
 /// passed to indicate the C++ scope in which the identifier will be
 /// found. 
-TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
+TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
                                       TemplateTy &TemplateResult,
                                       const CXXScopeSpec *SS) {
   NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
@@ -38,10 +38,9 @@
     if ((Template = dyn_cast<TemplateDecl>(IIDecl))) {
       if (isa<FunctionTemplateDecl>(IIDecl))
         TNK = TNK_Function_template;
-      else if (isa<ClassTemplateDecl>(IIDecl))
-        TNK = TNK_Class_template;
-      else if (isa<TemplateTemplateParmDecl>(IIDecl))
-        TNK = TNK_Template_template_parm;
+      else if (isa<ClassTemplateDecl>(IIDecl) || 
+               isa<TemplateTemplateParmDecl>(IIDecl))
+        TNK = TNK_Type_template;
       else
         assert(false && "Unknown template declaration kind");
     } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
@@ -59,11 +58,11 @@
       if (Record->isInjectedClassName()) {
         Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record));
         if ((Template = Record->getDescribedClassTemplate()))
-          TNK = TNK_Class_template;
+          TNK = TNK_Type_template;
         else if (ClassTemplateSpecializationDecl *Spec
                    = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
           Template = Spec->getSpecializedTemplate();
-          TNK = TNK_Class_template;
+          TNK = TNK_Type_template;
         }
       }
     }
@@ -716,6 +715,56 @@
   }
 }
 
+/// \brief Build a canonical version of a template argument list. 
+///
+/// This function builds a canonical version of the given template
+/// argument list, where each of the template arguments has been
+/// converted into its canonical form. This routine is typically used
+/// to canonicalize a template argument list when the template name
+/// itself is dependent. When the template name refers to an actual
+/// template declaration, Sema::CheckTemplateArgumentList should be
+/// used to check and canonicalize the template arguments.
+///
+/// \param TemplateArgs The incoming template arguments.
+///
+/// \param NumTemplateArgs The number of template arguments in \p
+/// TemplateArgs.
+///
+/// \param Canonical A vector to be filled with the canonical versions
+/// of the template arguments.
+///
+/// \param Context The ASTContext in which the template arguments live.
+static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
+                                          unsigned NumTemplateArgs,
+                            llvm::SmallVectorImpl<TemplateArgument> &Canonical,
+                                          ASTContext &Context) {
+  Canonical.reserve(NumTemplateArgs);
+  for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
+    switch (TemplateArgs[Idx].getKind()) {
+    case TemplateArgument::Expression:
+      // FIXME: Build canonical expression (!)
+      Canonical.push_back(TemplateArgs[Idx]);
+      break;
+
+    case TemplateArgument::Declaration:
+      Canonical.push_back(TemplateArgument(SourceLocation(),
+                                           TemplateArgs[Idx].getAsDecl()));
+      break;
+
+    case TemplateArgument::Integral:
+      Canonical.push_back(TemplateArgument(SourceLocation(),
+                                           *TemplateArgs[Idx].getAsIntegral(),
+                                        TemplateArgs[Idx].getIntegralType()));
+
+    case TemplateArgument::Type: {
+      QualType CanonType 
+        = Context.getCanonicalType(TemplateArgs[Idx].getAsType());
+      Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
+    }
+    }
+  }
+}
+
 QualType Sema::CheckTemplateIdType(TemplateName Name,
                                    SourceLocation TemplateLoc,
                                    SourceLocation LAngleLoc,
@@ -723,7 +772,25 @@
                                    unsigned NumTemplateArgs,
                                    SourceLocation RAngleLoc) {
   TemplateDecl *Template = Name.getAsTemplateDecl();
-  assert(Template && "Cannot handle dependent template-names yet");
+  if (!Template) {
+    // The template name does not resolve to a template, so we just
+    // build a dependent template-id type.
+
+    // Canonicalize the template arguments to build the canonical
+    // template-id type.
+    llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs;
+    CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs,
+                                  CanonicalTemplateArgs, Context);
+
+    // FIXME: Get the canonical template-name
+    QualType CanonType
+      = Context.getTemplateSpecializationType(Name, &CanonicalTemplateArgs[0],
+                                              CanonicalTemplateArgs.size());
+
+    // Build the dependent template-id type.
+    return Context.getTemplateSpecializationType(Name, TemplateArgs,
+                                                 NumTemplateArgs, CanonType);
+  }
 
   // Check that the template argument list is well-formed for this
   // template.
@@ -808,6 +875,57 @@
   return Result.getAsOpaquePtr();
 }
 
+/// \brief Form a dependent template name.
+///
+/// This action forms a dependent template name given the template
+/// name and its (presumably dependent) scope specifier. For
+/// example, given "MetaFun::template apply", the scope specifier \p
+/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
+/// of the "template" keyword, and "apply" is the \p Name.
+Sema::TemplateTy 
+Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
+                                 const IdentifierInfo &Name,
+                                 SourceLocation NameLoc,
+                                 const CXXScopeSpec &SS) {
+  if (!SS.isSet() || SS.isInvalid())
+    return TemplateTy();
+
+  NestedNameSpecifier *Qualifier 
+    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+
+  // FIXME: member of the current instantiation
+
+  if (!Qualifier->isDependent()) {
+    // C++0x [temp.names]p5:
+    //   If a name prefixed by the keyword template is not the name of
+    //   a template, the program is ill-formed. [Note: the keyword
+    //   template may not be applied to non-template members of class
+    //   templates. -end note ] [ Note: as is the case with the
+    //   typename prefix, the template prefix is allowed in cases
+    //   where it is not strictly necessary; i.e., when the
+    //   nested-name-specifier or the expression on the left of the ->
+    //   or . is not dependent on a template-parameter, or the use
+    //   does not appear in the scope of a template. -end note]
+    //
+    // Note: C++03 was more strict here, because it banned the use of
+    // the "template" keyword prior to a template-name that was not a
+    // dependent name. C++ DR468 relaxed this requirement (the
+    // "template" keyword is now permitted). We follow the C++0x
+    // rules, even in C++03 mode, retroactively applying the DR.
+    TemplateTy Template;
+    TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS);
+    if (TNK == TNK_Non_template) {
+      Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
+        << &Name;
+      return TemplateTy();
+    }
+
+    return Template;
+  }
+
+  return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
+}
+
 /// \brief Check that the given template argument list is well-formed
 /// for specializing the given template.
 bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Mar 30 19:43:58 2009
@@ -475,7 +475,7 @@
   // FIXME: Need to instantiate into the template name.
   return SemaRef.CheckTemplateIdType(T->getTemplateName(),
                                      Loc,
-                                     SourceLocation(),
+                                    SourceLocation(),
                                      &InstantiatedTemplateArgs[0],
                                      InstantiatedTemplateArgs.size(),
                                      SourceLocation());

Added: cfe/trunk/test/SemaTemplate/metafun-apply.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/metafun-apply.cpp?rev=68081&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/metafun-apply.cpp (added)
+++ cfe/trunk/test/SemaTemplate/metafun-apply.cpp Mon Mar 30 19:43:58 2009
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only %s
+
+struct add_pointer {
+  template<typename T>
+  struct apply {
+    typedef T* type;
+  };
+};
+
+struct add_reference {
+  template<typename T>
+  struct apply {
+    typedef T& type;
+  };
+};
+
+template<typename MetaFun, typename T>
+struct apply1 {
+  typedef typename MetaFun::template apply<T>::type type;
+};
+
+#if 0
+// FIXME: The code below requires template instantiation for dependent
+// template-names that occur within nested-name-specifiers.
+int i;
+
+apply1<add_pointer, int>::type ip = &i;
+apply1<add_reference, int>::type ir = i;
+#endif

Modified: cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp?rev=68081&r1=68080&r2=68081&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp Mon Mar 30 19:43:58 2009
@@ -42,8 +42,21 @@
   struct A<int> {
     struct X;
   };
+
+  struct B;
 }
 
 struct ::N::A<int>::X {
   int foo;
 };
+
+#if 0
+// FIXME: the following crashes the parser, because Sema has no way to
+// community that the "dependent" template-name N::template B doesn't
+// actually refer to a template.
+template<typename T>
+struct TestA {
+  typedef typename N::template B<T>::type type; // xpected-error{{'B' following the 'template' keyword does not refer to a template}}
+  // FIXME: should show what B *does* refer to.
+};
+#endif





More information about the cfe-commits mailing list