[cfe-commits] r65467 - in /cfe/trunk: docs/ include/clang/Basic/ include/clang/Lex/ include/clang/Parse/ lib/AST/ lib/Parse/ lib/Sema/ test/SemaTemplate/

Douglas Gregor dgregor at apple.com
Wed Feb 25 11:37:18 PST 2009


Author: dgregor
Date: Wed Feb 25 13:37:18 2009
New Revision: 65467

URL: http://llvm.org/viewvc/llvm-project?rev=65467&view=rev
Log:
Implement parsing of nested-name-specifiers that involve template-ids, e.g.,

  std::vector<int>::allocator_type

When we parse a template-id that names a type, it will become either a
template-id annotation (which is a parsed representation of a
template-id that has not yet been through semantic analysis) or a
typename annotation (where semantic analysis has resolved the
template-id to an actual type), depending on the context. We only
produce a type in contexts where we know that we only need type
information, e.g., in a type specifier. Otherwise, we create a
template-id annotation that can later be "upgraded" by transforming it
into a typename annotation when the parser needs a type. This occurs,
for example, when we've parsed "std::vector<int>" above and then see
the '::' after it. However, it means that when writing something like
this:

  template<> class Outer::Inner<int> { ... };

We have two tokens to represent Outer::Inner<int>: one token for the
nested name specifier Outer::, and one template-id annotation token
for Inner<int>, which will be passed to semantic analysis to define
the class template specialization.

Most of the churn in the template tests in this patch come from an
improvement in our error recovery from ill-formed template-ids.


Added:
    cfe/trunk/include/clang/Basic/TemplateKinds.h
    cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp
Modified:
    cfe/trunk/docs/InternalsManual.html
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.def
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/include/clang/Lex/Token.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Ownership.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/DeclTemplate.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/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/class-template-spec.cpp
    cfe/trunk/test/SemaTemplate/default-arguments.cpp
    cfe/trunk/test/SemaTemplate/temp_arg.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_template.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_type.cpp

Modified: cfe/trunk/docs/InternalsManual.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/InternalsManual.html?rev=65467&r1=65466&r2=65467&view=diff

==============================================================================
--- cfe/trunk/docs/InternalsManual.html (original)
+++ cfe/trunk/docs/InternalsManual.html Wed Feb 25 13:37:18 2009
@@ -628,12 +628,10 @@
 Action::ActOnCXXNestedNameSpecifier callbacks.  In the case of Sema, this is a
 <tt>DeclContext*</tt>.</li>
 
-<li><b>tok::annot_template_id</b>: This annotation token represents a C++
-template-id such as "foo<int, 4>", which may refer to a function or type
-depending on whether foo is a function template or class template.  The
-AnnotationValue pointer is a pointer to a malloc'd TemplateIdAnnotation object.
-FIXME: I don't think the parsing logic is right for this.  Shouldn't type
-templates be turned into annot_typename??</li>
+<li><b>tok::annot_template_id</b>: This annotation token represents a
+C++ template-id such as "foo<int, 4>", where "foo" is the name
+of a template. The AnnotationValue pointer is a pointer to a malloc'd
+TemplateIdAnnotation object. Depending on the context, a parsed template-id that names a type might become a typename annotation token (if all we care about is the named type, e.g., because it occurs in a type specifier) or might remain a template-id token (if we want to retain more source location information or produce a new type, e.g., in a declaration of a class template specialization). template-id annotation tokens that refer to a type can be "upgraded" to typename annotation tokens by the parser.</li>
 
 </ol>
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.def?rev=65467&r1=65466&r2=65467&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.def Wed Feb 25 13:37:18 2009
@@ -274,6 +274,10 @@
       "expected 'class' before '%0'")
 DIAG(err_template_spec_syntax_non_template, ERROR,
      "identifier followed by '<' indicates a class template specialization but %0 %select{does not refer to a template|refers to a function template|<unused>|refers to a template template parameter}1")
+DIAG(err_id_after_template_in_nested_name_spec, ERROR,
+     "expected template name after 'template' keyword in nested name specifier")
+DIAG(err_less_after_template_name_in_nested_name_spec, ERROR,
+     "expected '<' after 'template %0' in nested name specifier")
 
 // Language specific pragmas
 

Added: cfe/trunk/include/clang/Basic/TemplateKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TemplateKinds.h?rev=65467&view=auto

==============================================================================
--- cfe/trunk/include/clang/Basic/TemplateKinds.h (added)
+++ cfe/trunk/include/clang/Basic/TemplateKinds.h Wed Feb 25 13:37:18 2009
@@ -0,0 +1,37 @@
+//===--- TemplateKinds.h - Enum values for C++ Template Kinds ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the TemplateNameKind enum.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TEMPLATEKINDS_H
+#define LLVM_CLANG_TEMPLATEKINDS_H
+
+namespace clang {
+
+/// \brief Specifies the kind of template name that an identifier refers to.
+enum TemplateNameKind {
+  /// The name does not refer to a template.
+  TNK_Non_template = 0,
+  /// 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>".
+  TNK_Dependent_template_name
+};
+
+}
+#endif
+
+

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=65467&r1=65466&r2=65467&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Wed Feb 25 13:37:18 2009
@@ -431,7 +431,21 @@
     if (CachedLexPos != 0 && isBacktrackEnabled())
       AnnotatePreviousCachedTokens(Tok);
   }
-  
+
+  /// \brief Replace the last token with an annotation token. 
+  ///
+  /// Like AnnotateCachedTokens(), this routine replaces an
+  /// already-parsed (and resolved) token with an annotation
+  /// token. However, this routine only replaces the last token with
+  /// the annotation token; it does not affect any other cached
+  /// tokens. This function has no effect if backtracking is not
+  /// enabled.
+  void ReplaceLastTokenWithAnnotation(const Token &Tok) {
+    assert(Tok.isAnnotation() && "Expected annotation token");
+    if (CachedLexPos != 0 && isBacktrackEnabled())
+      CachedTokens[CachedLexPos-1] = Tok;
+  }
+
   /// Diag - Forwarding function for diagnostics.  This emits a diagnostic at
   /// the specified Token's location, translating the token's start
   /// position in the current buffer into a SourcePosition object for rendering.

Modified: cfe/trunk/include/clang/Lex/Token.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Token.h?rev=65467&r1=65466&r2=65467&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/Token.h (original)
+++ cfe/trunk/include/clang/Lex/Token.h Wed Feb 25 13:37:18 2009
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_TOKEN_H
 #define LLVM_CLANG_TOKEN_H
 
+#include "clang/Basic/TemplateKinds.h"
 #include "clang/Basic/TokenKinds.h"
 #include "clang/Basic/SourceLocation.h"
 
@@ -247,24 +248,62 @@
 
 /// TemplateIdAnnotation - Information about a template-id annotation
 /// token, which contains the template declaration, template
-/// arguments, and the source locations for important tokens.
+/// arguments, whether those template arguments were types or
+/// expressions, and the source locations for important tokens. All of
+/// the information about template arguments is allocated directly
+/// after this structure.
 struct TemplateIdAnnotation {
   /// TemplateNameLoc - The location of the template name within the
   /// source.
   SourceLocation TemplateNameLoc;
 
-  /// Template - The declaration of the template corresponding to the
+  /// FIXME: Temporarily stores the name of a specialization
+  IdentifierInfo *Name;
+
+  /// The declaration of the template corresponding to the
   /// template-name. This is an Action::DeclTy*.
   void *Template; 
 
-  /// LAngleLoc - The location of the '<' before the template argument
+  /// The kind of template that Template refers to.
+  TemplateNameKind Kind;
+
+  /// The location of the '<' before the template argument
   /// list. 
   SourceLocation LAngleLoc;
 
-  /// NumArgs - The number of template arguments. The arguments
-  /// themselves are Action::TemplateArgTy pointers allocated directly
-  /// following the TemplateIdAnnotation structure.
+  /// The location of the '>' after the template argument
+  /// list. 
+  SourceLocation RAngleLoc;
+
+  /// NumArgs - The number of template arguments.
   unsigned NumArgs; 
+
+  /// \brief Retrieves a pointer to the template arguments
+  void **getTemplateArgs() { return (void **)(this + 1); }
+
+  /// \brief Retrieves a pointer to the array of template argument
+  /// locations.
+  SourceLocation *getTemplateArgLocations() { 
+    return (SourceLocation *)(getTemplateArgs() + NumArgs);
+  }
+
+  /// \brief Retrieves a pointer to the array of flags that states
+  /// whether the template arguments are types.
+  bool *getTemplateArgIsType() { 
+    return (bool *)(getTemplateArgLocations() + NumArgs);
+  }
+
+  static TemplateIdAnnotation* Allocate(unsigned NumArgs) {
+    TemplateIdAnnotation *TemplateId 
+      = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + 
+                                       sizeof(void*) * NumArgs + 
+                                       sizeof(SourceLocation) * NumArgs +
+                                       sizeof(bool) * NumArgs);
+    TemplateId->NumArgs = NumArgs;
+    return TemplateId;
+  }
+
+  void Destroy() { free(this); }
 };
 
 }  // end namespace clang

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Feb 25 13:37:18 2009
@@ -16,6 +16,7 @@
 
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/TemplateKinds.h"
 #include "clang/Basic/TypeTraits.h"
 #include "clang/Parse/AccessSpecifier.h"
 #include "clang/Parse/Ownership.h"
@@ -134,20 +135,6 @@
   virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
                                   const CXXScopeSpec *SS = 0) = 0;
 
-  /// \brief Specifies the kind of template name. Returned from
-  /// isTemplateName.
-  enum TemplateNameKind {
-    /// The name does not refer to a template.
-    TNK_Non_template = 0,
-    /// 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
-  };
-
   /// \brief Determines whether the identifier II is a template name
   /// in the current scope. If so, the kind of template name is
   /// returned, and \p TemplateDecl receives the declaration. An
@@ -178,6 +165,22 @@
     return 0;
   }
 
+  /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+  /// nested-name-specifier that involves a template-id, e.g.,
+  /// "foo::bar<int, float>::", and now we need to build a scope
+  /// specifier. \p SS is empty or the previously parsed nested-name
+  /// part ("foo::"), \p Type is the already-parsed class template
+  /// specialization (or other template-id that names a type), \p
+  /// TypeRange is the source range where the type is located, and \p
+  /// CCLoc is the location of the trailing '::'.
+  virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+                                                  const CXXScopeSpec &SS,
+                                                  TypeTy *Type,
+                                                  SourceRange TypeRange,
+                                                  SourceLocation CCLoc) {
+    return 0; 
+  }
+
   /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
   /// scope or nested-name-specifier) is parsed, part of a declarator-id.
   /// After this method is called, according to [C++ 3.4.3p3], names should be

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Ownership.h (original)
+++ cfe/trunk/include/clang/Parse/Ownership.h Wed Feb 25 13:37:18 2009
@@ -538,7 +538,7 @@
     void **Args;
     bool *ArgIsType;
     mutable unsigned Count;
-
+    
 #if !defined(DISABLE_SMART_POINTERS)
     void destroy() {
       if (!Count)

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Feb 25 13:37:18 2009
@@ -993,7 +993,6 @@
   //===--------------------------------------------------------------------===//
   // C++ 14: Templates [temp]
   typedef llvm::SmallVector<DeclTy *, 4> TemplateParameterList;
-  typedef Action::TemplateNameKind TemplateNameKind;
 
   // C++ 14.1: Template Parameters [temp.param]
   DeclTy *ParseTemplateDeclarationOrSpecialization(unsigned Context);
@@ -1023,7 +1022,10 @@
                                         SourceLocation &RAngleLoc);
 
   void AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
-                               const CXXScopeSpec *SS = 0);
+                               const CXXScopeSpec *SS,
+                               SourceLocation TemplateKWLoc = SourceLocation(),
+                               bool AllowTypeAnnotation = true);
+  bool AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);
   bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
                                  TemplateArgIsTypeList &TemplateArgIsType,
                                  TemplateArgLocationList &TemplateArgLocations);

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

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Wed Feb 25 13:37:18 2009
@@ -162,7 +162,7 @@
     NumTemplateArgs(NumTemplateArgs), SpecializationKind(TSK_Undeclared) {
   TemplateArgument *Arg = reinterpret_cast<TemplateArgument *>(this + 1);
   for (unsigned ArgIdx = 0; ArgIdx < NumTemplateArgs; ++ArgIdx, ++Arg)
-    *Arg = TemplateArgs[ArgIdx];
+    new (Arg) TemplateArgument(TemplateArgs[ArgIdx]);
 }
                   
 ClassTemplateSpecializationDecl *

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

==============================================================================
--- cfe/trunk/lib/Parse/MinimalAction.cpp (original)
+++ cfe/trunk/lib/Parse/MinimalAction.cpp Wed Feb 25 13:37:18 2009
@@ -95,7 +95,7 @@
   return false;
 }
 
-Action::TemplateNameKind 
+TemplateNameKind 
 MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
                               DeclTy *&TemplateDecl,
                               const CXXScopeSpec *SS) {

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Feb 25 13:37:18 2009
@@ -558,21 +558,8 @@
       TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), 
                                             Tok.getLocation(), CurScope);
 
-      if (TypeRep == 0 && getLang().CPlusPlus && NextToken().is(tok::less)) {
-        // If we have a template name, annotate the token and try again.
-        DeclTy *Template = 0;
-        if (TemplateNameKind TNK =
-              Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope,
-                                     Template)) {
-          AnnotateTemplateIdToken(Template, TNK, 0);
-          continue;
-        }
-      }
-
       if (TypeRep == 0)
         goto DoneWithDeclSpec;
-      
-
 
       // C++: If the identifier is actually the name of the class type
       // being defined and the next token is a '(', then this is a
@@ -610,6 +597,25 @@
       // If a type specifier follows, it will be diagnosed elsewhere.
       continue;
     }
+
+      // type-name
+    case tok::annot_template_id: {
+      TemplateIdAnnotation *TemplateId 
+        = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+      if (TemplateId->Kind != TNK_Class_template) {
+        // This template-id does not refer to a type name, so we're
+        // done with the type-specifiers.
+        goto DoneWithDeclSpec;
+      }
+
+      // Turn the template-id annotation token into a type annotation
+      // token, then try again to parse it as a type-specifier.
+      if (AnnotateTemplateIdTokenAsType())
+        DS.SetTypeSpecError();
+
+      continue;
+    }
+
     // GNU attributes support.
     case tok::kw___attribute:
       DS.AddAttributes(ParseAttributes());
@@ -1749,7 +1755,7 @@
 ///         operator-function-id
 ///         conversion-function-id  [TODO]
 ///          '~' class-name         
-///         template-id             [TODO]
+///         template-id
 ///
 void Parser::ParseDirectDeclarator(Declarator &D) {
   DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
@@ -1768,21 +1774,9 @@
       if (Tok.is(tok::identifier)) {
         assert(Tok.getIdentifierInfo() && "Not an identifier?");
 
-        // If this identifier is followed by a '<', we may have a template-id.
-        DeclTy *Template;
-        Action::TemplateNameKind TNK;
-        if (getLang().CPlusPlus && NextToken().is(tok::less) &&
-            (TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), 
-                                          CurScope, Template))) {
-          IdentifierInfo *II = Tok.getIdentifierInfo();
-          AnnotateTemplateIdToken(Template, TNK, 0);
-          // FIXME: Set the declarator to a template-id. How? I don't
-          // know... for now, just use the identifier.
-          D.SetIdentifier(II, Tok.getLocation());
-        }
         // If this identifier is the name of the current class, it's a
         // constructor name. 
-        else if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)){
+        if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(),CurScope)){
           D.setConstructor(Actions.getTypeName(*Tok.getIdentifierInfo(),
                                                Tok.getLocation(), CurScope),
                            Tok.getLocation());
@@ -1791,6 +1785,21 @@
           D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
         ConsumeToken();
         goto PastIdentifier;
+      } else if (Tok.is(tok::annot_template_id)) {
+        TemplateIdAnnotation *TemplateId 
+          = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+
+        // FIXME: Could this template-id name a constructor?
+
+        // FIXME: This is an egregious hack, where we silently ignore
+        // the specialization (which should be a function template
+        // specialization name) and use the name instead. This hack
+        // will go away when we have support for function
+        // specializations.
+        D.SetIdentifier(TemplateId->Name, Tok.getLocation());
+        TemplateId->Destroy();
+        ConsumeToken();
+        goto PastIdentifier;
       } else if (Tok.is(tok::kw_operator)) {
         SourceLocation OperatorLoc = Tok.getLocation();
         SourceLocation EndLoc;

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Wed Feb 25 13:37:18 2009
@@ -309,75 +309,42 @@
   
   // Parse the (optional) nested-name-specifier.
   CXXScopeSpec SS;
-  if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
-    // FIXME: can we get a class template specialization or
-    // template-id token here?
-    if (Tok.isNot(tok::identifier))
+  if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS))
+    if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
       Diag(Tok, diag::err_expected_ident);
-  }
-
-
-  // These variables encode the simple-template-id that we might end
-  // up parsing below. We don't translate this into a type
-  // automatically because (1) we want to create a separate
-  // declaration for each specialization, and (2) we want to retain
-  // more information about source locations that types provide.
-  DeclTy *Template = 0;
-  SourceLocation LAngleLoc, RAngleLoc;
-  TemplateArgList TemplateArgs;
-  TemplateArgIsTypeList TemplateArgIsType;
-  TemplateArgLocationList TemplateArgLocations;
-  ASTTemplateArgsPtr TemplateArgsPtr(Actions, 0, 0, 0);
-  
 
   // Parse the (optional) class name or simple-template-id.
   IdentifierInfo *Name = 0;
   SourceLocation NameLoc;
+  TemplateIdAnnotation *TemplateId = 0;
   if (Tok.is(tok::identifier)) {
     Name = Tok.getIdentifierInfo();
     NameLoc = ConsumeToken();
+  } else if (Tok.is(tok::annot_template_id)) {
+    TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+    NameLoc = ConsumeToken();
 
-    if (Tok.is(tok::less)) {
-      // This is a simple-template-id.
-      Action::TemplateNameKind TNK 
-        = Actions.isTemplateName(*Name, CurScope, Template, &SS);
-
-      bool Invalid = false;
-
-      // Parse the enclosed template argument list.
-      if (TNK != Action::TNK_Non_template)
-        Invalid = ParseTemplateIdAfterTemplateName(Template, NameLoc,
-                                                   &SS, true, LAngleLoc, 
-                                                   TemplateArgs,
-                                                   TemplateArgIsType,
-                                                   TemplateArgLocations,
-                                                   RAngleLoc);
-      
-      TemplateArgsPtr.reset(&TemplateArgs[0], &TemplateArgIsType[0],
-                            TemplateArgs.size());
+    if (TemplateId->Kind != TNK_Class_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 ';'.
+      SourceRange Range(NameLoc);
+      if (SS.isNotEmpty())
+        Range.setBegin(SS.getBeginLoc());
 
-      if (TNK != Action::TNK_Class_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 ';'.
-        SourceRange Range(NameLoc);
-        if (SS.isNotEmpty())
-          Range.setBegin(SS.getBeginLoc());
-        else if (!Invalid)
-          
-        Diag(LAngleLoc, diag::err_template_spec_syntax_non_template)
-          << Name << static_cast<int>(TNK) << Range;
-
-        DS.SetTypeSpecError();
-        SkipUntil(tok::semi, false, true);
-        return;
-      }
+      Diag(TemplateId->LAngleLoc, diag::err_template_spec_syntax_non_template)
+        << Name << static_cast<int>(TemplateId->Kind) << Range;
+      
+      DS.SetTypeSpecError();
+      SkipUntil(tok::semi, false, true);
+      TemplateId->Destroy();
+      return;
     }
   }
 
   // There are three options here.  If we have 'struct foo;', then
   // this is a forward declaration.  If we have 'struct foo {...' or
-  // 'struct fo :...' then this is a definition. Otherwise we have
+  // 'struct foo :...' then this is a definition. Otherwise we have
   // something like 'struct foo xyz', a reference.
   Action::TagKind TK;
   if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)))
@@ -387,35 +354,43 @@
   else
     TK = Action::TK_Reference;
 
-  if (!Name && TK != Action::TK_Definition) {
+  if (!Name && !TemplateId && TK != Action::TK_Definition) {
     // We have a declaration or reference to an anonymous class.
     Diag(StartLoc, diag::err_anon_type_definition)
       << DeclSpec::getSpecifierName(TagType);
 
     // Skip the rest of this declarator, up until the comma or semicolon.
     SkipUntil(tok::comma, true);
+
+    if (TemplateId)
+      TemplateId->Destroy();
     return;
   }
 
   // Create the tag portion of the class or class template.
   DeclTy *TagOrTempDecl;
-  if (Template && TK != Action::TK_Reference)
+  if (TemplateId && TK != Action::TK_Reference) {
     // Explicit specialization or class template partial
     // specialization. Let semantic analysis decide.
-
-    // FIXME: we want a source range covering the simple-template-id.
+    ASTTemplateArgsPtr TemplateArgsPtr(Actions, 
+                                       TemplateId->getTemplateArgs(),
+                                       TemplateId->getTemplateArgIsType(),
+                                       TemplateId->NumArgs);
     TagOrTempDecl 
       = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
-                                                 StartLoc, SS, /*Range*/
-                                                 Template, NameLoc, 
-                                                 LAngleLoc, TemplateArgsPtr,
-                                                 &TemplateArgLocations[0],
-                                                 RAngleLoc, Attr,
+                       StartLoc, SS,
+                       TemplateId->Template, 
+                       TemplateId->TemplateNameLoc, 
+                       TemplateId->LAngleLoc, 
+                       TemplateArgsPtr,
+                       TemplateId->getTemplateArgLocations(),
+                       TemplateId->RAngleLoc, 
+                       Attr,
                        Action::MultiTemplateParamsArg(Actions, 
                                     TemplateParams? &(*TemplateParams)[0] : 0,
                                  TemplateParams? TemplateParams->size() : 0));
-
-  else if (TemplateParams && TK != Action::TK_Reference)
+    TemplateId->Destroy();
+  } else if (TemplateParams && TK != Action::TK_Reference)
     TagOrTempDecl = Actions.ActOnClassTemplate(CurScope, TagType, TK, StartLoc,
                                                SS, Name, NameLoc, Attr,
                        Action::MultiTemplateParamsArg(Actions, 

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 25 13:37:18 2009
@@ -42,6 +42,8 @@
     return true;
   }
 
+  bool HasScopeSpecifier = false;
+
   if (Tok.is(tok::coloncolon)) {
     // ::new and ::delete aren't nested-name-specifiers.
     tok::TokenKind NextKind = NextToken().getKind();
@@ -53,32 +55,132 @@
     SS.setBeginLoc(CCLoc);
     SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
     SS.setEndLoc(CCLoc);
-  } else if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
-    SS.setBeginLoc(Tok.getLocation());
-  } else {
-    // Not a CXXScopeSpecifier.
-    return false;
+    HasScopeSpecifier = true;
   }
 
-  // nested-name-specifier:
-  //   type-name '::'
-  //   namespace-name '::'
-  //   nested-name-specifier identifier '::'
-  //   nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
-  while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
-    IdentifierInfo *II = Tok.getIdentifierInfo();
-    SourceLocation IdLoc = ConsumeToken();
-    assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
-    SourceLocation CCLoc = ConsumeToken();
-    if (SS.isInvalid())
+  while (true) {
+    // nested-name-specifier:
+    //   type-name '::'
+    //   namespace-name '::'
+    //   nested-name-specifier identifier '::'
+    if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
+      // We have an identifier followed by a '::'. Lookup this name
+      // as the name in a nested-name-specifier.
+      IdentifierInfo *II = Tok.getIdentifierInfo();
+      SourceLocation IdLoc = ConsumeToken();
+      assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+      SourceLocation CCLoc = ConsumeToken();
+      
+      if (!HasScopeSpecifier) {
+        SS.setBeginLoc(IdLoc);
+        HasScopeSpecifier = true;
+      }
+      
+      if (SS.isInvalid())
+        continue;
+      
+      SS.setScopeRep(
+        Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
+      SS.setEndLoc(CCLoc);
       continue;
+    }
 
-    SS.setScopeRep(
-         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
-    SS.setEndLoc(CCLoc);
-  }
+    // nested-name-specifier:
+    //   type-name '::'
+    //   nested-name-specifier 'template'[opt] simple-template-id '::'
+    if ((Tok.is(tok::identifier) && NextToken().is(tok::less)) ||
+        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();
+        
+        if (Tok.isNot(tok::identifier)) {
+          Diag(Tok.getLocation(), 
+               diag::err_id_after_template_in_nested_name_spec)
+            << SourceRange(TemplateKWLoc);
+          break;
+        }
+
+        if (NextToken().isNot(tok::less)) {
+          Diag(NextToken().getLocation(),
+               diag::err_less_after_template_name_in_nested_name_spec)
+            << Tok.getIdentifierInfo()->getName()
+            << 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.
+      }
+
+      DeclTy *Template = 0;
+      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);
+      if (TNK) {
+        // We have found a template name, so annotate this this token
+        // with a template-id annotation. We do not permit the
+        // template-id to be translated into a type annotation,
+        // 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);
+        continue;
+      }
+    }
+
+    if (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)) {
+      // We have 
+      //
+      //   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.
+      TemplateIdAnnotation *TemplateId 
+        = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+
+      if (TemplateId->Kind == TNK_Class_template) {
+        if (AnnotateTemplateIdTokenAsType(&SS))
+          SS.setScopeRep(0);
+
+        assert(Tok.is(tok::annot_typename) && 
+               "AnnotateTemplateIdTokenAsType isn't working");
+
+        Token TypeToken = Tok;
+        ConsumeToken();
+        assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
+        SourceLocation CCLoc = ConsumeToken();
+        
+        if (!HasScopeSpecifier) {
+          SS.setBeginLoc(TypeToken.getLocation());
+          HasScopeSpecifier = true;
+        }
 
-  return true;
+        SS.setScopeRep(
+          Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, 
+                                              TypeToken.getAnnotationValue(),
+                                              TypeToken.getAnnotationRange(),
+                                              CCLoc));
+        SS.setEndLoc(CCLoc);
+        continue;
+      } else
+        assert(false && "FIXME: Only class template names supported here");
+    }
+
+    // We don't have any tokens that form the beginning of a
+    // nested-name-specifier, so we're done.
+    break;
+  }
+    
+  return HasScopeSpecifier;
 }
 
 /// ParseCXXIdExpression - Handle id-expression.

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Wed Feb 25 13:37:18 2009
@@ -444,16 +444,49 @@
   return false;
 }
                                               
-/// AnnotateTemplateIdToken - The current token is an identifier that
-/// refers to the template declaration Template, and is followed by a
-/// '<'. Turn this template-id into a template-id annotation token.
+/// \brief Replace the tokens that form a simple-template-id with an
+/// annotation token containing the complete template-id.
+///
+/// The first token in the stream must be the name of a template that
+/// is followed by a '<'. This routine will parse the complete
+/// simple-template-id and replace the tokens with a single annotation
+/// token with one of two different kinds: if the template-id names a
+/// type (and \p AllowTypeAnnotation is true), the annotation token is
+/// a type annotation that includes the optional nested-name-specifier
+/// (\p SS). Otherwise, the annotation token is a template-id
+/// annotation that does not include the optional
+/// nested-name-specifier.
+///
+/// \param Template  the declaration of the template named by the first
+/// token (an identifier), as returned from \c Action::isTemplateName().
+///
+/// \param TemplateNameKind the kind of template that \p Template
+/// refers to, as returned from \c Action::isTemplateName().
+///
+/// \param SS if non-NULL, the nested-name-specifier that precedes
+/// this template name.
+///
+/// \param TemplateKWLoc if valid, specifies that this template-id
+/// annotation was preceded by the 'template' keyword and gives the
+/// location of that keyword. If invalid (the default), then this
+/// template-id was not preceded by a 'template' keyword.
+///
+/// \param AllowTypeAnnotation if true (the default), then a
+/// simple-template-id that refers to a class template, template
+/// template parameter, or other template that produces a type will be
+/// replaced with a type annotation token. Otherwise, the
+/// simple-template-id is always replaced with a template-id
+/// annotation token.
 void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
-                                     const CXXScopeSpec *SS) {
+                                     const CXXScopeSpec *SS, 
+                                     SourceLocation TemplateKWLoc,
+                                     bool AllowTypeAnnotation) {
   assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
   assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
          "Parser isn't at the beginning of a template-id");
 
   // Consume the template-name.
+  IdentifierInfo *Name = Tok.getIdentifierInfo();
   SourceLocation TemplateNameLoc = ConsumeToken();
 
   // Parse the enclosed template argument list.
@@ -476,7 +509,7 @@
     return; 
 
   // Build the annotation token.
-  if (TNK == Action::TNK_Class_template) {
+  if (TNK == TNK_Class_template && AllowTypeAnnotation) {
     Action::TypeResult Type 
       = Actions.ActOnClassTemplateId(Template, TemplateNameLoc,
                                      LAngleLoc, TemplateArgsPtr,
@@ -487,34 +520,96 @@
 
     Tok.setKind(tok::annot_typename);
     Tok.setAnnotationValue(Type.get());
+    if (SS && SS->isNotEmpty())
+      Tok.setLocation(SS->getBeginLoc());
+    else if (TemplateKWLoc.isValid())
+      Tok.setLocation(TemplateKWLoc);
+    else 
+      Tok.setLocation(TemplateNameLoc);
   } else {
     // This is a function template. We'll be building a template-id
     // annotation token.
-    Tok.setKind(tok::annot_template_id);    
+    Tok.setKind(tok::annot_template_id);
     TemplateIdAnnotation *TemplateId 
-      = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + 
-                                       sizeof(void*) * TemplateArgs.size());
+      = TemplateIdAnnotation::Allocate(TemplateArgs.size());
     TemplateId->TemplateNameLoc = TemplateNameLoc;
+    TemplateId->Name = Name;
     TemplateId->Template = Template;
+    TemplateId->Kind = TNK;
     TemplateId->LAngleLoc = LAngleLoc;
-    TemplateId->NumArgs = TemplateArgs.size();
-    void **Args = (void**)(TemplateId + 1);
-    for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
+    TemplateId->RAngleLoc = RAngleLoc;
+    void **Args = TemplateId->getTemplateArgs();
+    bool *ArgIsType = TemplateId->getTemplateArgIsType();
+    SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations();
+    for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) {
       Args[Arg] = TemplateArgs[Arg];
+      ArgIsType[Arg] = TemplateArgIsType[Arg];
+      ArgLocs[Arg] = TemplateArgLocations[Arg];
+    }
     Tok.setAnnotationValue(TemplateId);
+    if (TemplateKWLoc.isValid())
+      Tok.setLocation(TemplateKWLoc);
+    else
+      Tok.setLocation(TemplateNameLoc);
+
+    TemplateArgsPtr.release();
   }
 
   // Common fields for the annotation token
   Tok.setAnnotationEndLoc(RAngleLoc);
-  Tok.setLocation(TemplateNameLoc);
-  if (SS && SS->isNotEmpty())
-    Tok.setLocation(SS->getBeginLoc());
 
   // In case the tokens were cached, have Preprocessor replace them with the
   // annotation token.
   PP.AnnotateCachedTokens(Tok);
 }
 
+/// \brief Replaces a template-id annotation token with a type
+/// annotation token.
+///
+/// \returns true if there was an error, false otherwise.
+bool Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
+  assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens");
+
+  TemplateIdAnnotation *TemplateId 
+    = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+  assert(TemplateId->Kind == TNK_Class_template &&
+         "Only works for class templates");
+  
+  ASTTemplateArgsPtr TemplateArgsPtr(Actions, 
+                                     TemplateId->getTemplateArgs(),
+                                     TemplateId->getTemplateArgIsType(),
+                                     TemplateId->NumArgs);
+
+  Action::TypeResult Type 
+    = Actions.ActOnClassTemplateId(TemplateId->Template, 
+                                   TemplateId->TemplateNameLoc,
+                                   TemplateId->LAngleLoc, 
+                                   TemplateArgsPtr,
+                                   TemplateId->getTemplateArgLocations(),
+                                   TemplateId->RAngleLoc, SS);
+  if (Type.isInvalid()) {
+    // FIXME: better recovery?
+    ConsumeToken();
+    TemplateId->Destroy();
+    return true;
+  }
+
+  // Create the new "type" annotation token.
+  Tok.setKind(tok::annot_typename);
+  Tok.setAnnotationValue(Type.get());
+  if (SS && SS->isNotEmpty()) // it was a C++ qualified type name.
+    Tok.setLocation(SS->getBeginLoc());
+
+  // We might be backtracking, in which case we need to replace the
+  // template-id annotation token with the type annotation within the
+  // set of cached tokens. That way, we won't try to form the same
+  // class template specialization again.
+  PP.ReplaceLastTokenWithAnnotation(Tok);
+  TemplateId->Destroy();
+
+  return false;
+}
+
 /// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]).
 ///
 ///       template-argument: [C++ 14.2]

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

==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Wed Feb 25 13:37:18 2009
@@ -778,31 +778,41 @@
       // them with the annotation token.
       PP.AnnotateCachedTokens(Tok);
       return true;
-    } else if (!getLang().CPlusPlus) {
+    } 
+
+    if (!getLang().CPlusPlus) {
       // If we're in C, we can't have :: tokens at all (the lexer won't return
       // them).  If the identifier is not a type, then it can't be scope either,
       // just early exit. 
       return false;
     }
     
-    // If this is a template-id, annotate the template-id token.
+    // If this is a template-id, annotate with a template-id or type token.
     if (NextToken().is(tok::less)) {
       DeclTy *Template;
       if (TemplateNameKind TNK 
             = Actions.isTemplateName(*Tok.getIdentifierInfo(),
-                                     CurScope, Template, &SS)) {
+                                     CurScope, Template, &SS))
         AnnotateTemplateIdToken(Template, TNK, &SS);
-        return true;
-      }
     }
 
-    // We either have an identifier that is not a type name or we have
-    // just created a template-id that might be a type name. Both
-    // cases will be handled below.
+    // The current token, which is either an identifier or a
+    // template-id, is not part of the annotation. Fall through to
+    // push that token back into the stream and complete the C++ scope
+    // specifier annotation.
   }
 
-  // FIXME: check for a template-id token here, and look it up if it
-  // names a type.
+  if (Tok.is(tok::annot_template_id)) {
+    TemplateIdAnnotation *TemplateId 
+      = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+    if (TemplateId->Kind == TNK_Class_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
+      // annotation token to a type annotation token now.
+      return !AnnotateTemplateIdTokenAsType(&SS);
+    }
+  }
 
   if (SS.isEmpty())
     return false;
@@ -825,8 +835,8 @@
 }
 
 /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
-/// annotates C++ scope specifiers.  This returns true if the token was
-/// annotated.
+/// annotates C++ scope specifiers and template-ids.  This returns
+/// true if the token was annotated.
 /// 
 /// Note that this routine emits an error if you call it with ::new or ::delete
 /// as the current tokens, so only call it in contexts where these are invalid.
@@ -838,7 +848,7 @@
 
   CXXScopeSpec SS;
   if (!ParseOptionalCXXScopeSpecifier(SS))
-    return false;
+    return Tok.is(tok::annot_template_id);
 
   // Push the current token back into the token stream (or revert it if it is
   // cached) and use an annotation scope token for current token.

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb 25 13:37:18 2009
@@ -1338,6 +1338,20 @@
                                                   SourceLocation CCLoc,
                                                   IdentifierInfo &II);
 
+  /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+  /// nested-name-specifier that involves a template-id, e.g.,
+  /// "foo::bar<int, float>::", and now we need to build a scope
+  /// specifier. \p SS is empty or the previously parsed nested-name
+  /// part ("foo::"), \p Type is the already-parsed class template
+  /// specialization (or other template-id that names a type), \p
+  /// TypeRange is the source range where the type is located, and \p
+  /// CCLoc is the location of the trailing '::'.
+  virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+                                                  const CXXScopeSpec &SS,
+                                                  TypeTy *Type,
+                                                  SourceRange TypeRange,
+                                                  SourceLocation CCLoc);
+
   /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
   /// scope or nested-name-specifier) is parsed, part of a declarator-id.
   /// After this method is called, according to [C++ 3.4.3p3], names should be

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Feb 25 13:37:18 2009
@@ -74,6 +74,17 @@
   return 0;
 }
 
+Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
+                                                    const CXXScopeSpec &SS,
+                                                    TypeTy *Ty,
+                                                    SourceRange TypeRange,
+                                                    SourceLocation CCLoc) {
+  QualType Type = QualType::getFromOpaquePtr(Ty);
+  assert(Type->isRecordType() && 
+         "Types in a nested-name-specifier always refer to a record type");
+  return cast<DeclContext>(Type->getAsRecordType()->getDecl());
+}
+
 /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
 /// scope or nested-name-specifier) is parsed, part of a declarator-id.
 /// After this method is called, according to [C++ 3.4.3p3], names should be

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Feb 25 13:37:18 2009
@@ -26,9 +26,9 @@
 /// declaration if II names a template. An optional CXXScope can be
 /// passed to indicate the C++ scope in which the identifier will be
 /// found. 
-Sema::TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
-                                            DeclTy *&Template,
-                                            const CXXScopeSpec *SS) {
+TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
+                                      DeclTy *&Template,
+                                      const CXXScopeSpec *SS) {
   NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
 
   if (IIDecl) {

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=65467&r1=65466&r2=65467&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Wed Feb 25 13:37:18 2009
@@ -40,3 +40,5 @@
   x1->foo(); // okay: refers to #1
   x2->bar(); // okay: refers to #2
 }
+
+// FIXME: diagnose specializations in a different namespace

Modified: cfe/trunk/test/SemaTemplate/default-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-arguments.cpp?rev=65467&r1=65466&r2=65467&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/default-arguments.cpp (original)
+++ cfe/trunk/test/SemaTemplate/default-arguments.cpp Wed Feb 25 13:37:18 2009
@@ -5,8 +5,7 @@
 X<int, 1> *x1;
 X<int> *x2;
 
-X<> *x3; // expected-error{{too few template arguments for class template 'X'}} \
-        // FIXME: expected-error{{expected unqualified-id}}
+X<> *x3; // expected-error{{too few template arguments for class template 'X'}}
 
 template<typename U = float, int M> struct X;
 

Added: 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=65467&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp (added)
+++ cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp Wed Feb 25 13:37:18 2009
@@ -0,0 +1,50 @@
+// RUN: clang -fsyntax-only -verify %s
+
+namespace N { 
+  namespace M {
+    template<typename T> struct Promote; // expected-note{{previous definition is here}}
+    
+    template<> struct Promote<short> {
+      typedef int type;
+    };
+    
+    template<> struct Promote<int> {
+      typedef int type;
+    };
+    
+    template<> struct Promote<float> {
+      typedef double type;
+    };
+    
+    Promote<short>::type *ret_intptr(int* ip) { return ip; }
+    Promote<int>::type *ret_intptr2(int* ip) { return ip; }
+  }
+
+  M::Promote<int>::type *ret_intptr3(int* ip) { return ip; }
+  M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; }
+}
+
+N::M::Promote<int>::type *ret_intptr5(int* ip) { return ip; }
+::N::M::Promote<int>::type *ret_intptr6(int* ip) { return ip; }
+
+
+N::M::template; // expected-error{{expected template name after 'template' keyword in nested name specifier}} \
+               // expected-error{{expected unqualified-id}}
+
+N::M::template Promote; // expected-error{{expected '<' after 'template Promote' in nested name specifier}} \
+// expected-error{{C++ requires a type specifier for all declarations}} \
+// expected-error{{redefinition of 'Promote' as different kind of symbol}} \
+// expected-error{{no member named 'Promote'}}
+
+namespace N {
+  template<typename T> struct A;
+
+  template<>
+  struct A<int> {
+    struct X;
+  };
+}
+
+struct ::N::A<int>::X {
+  int foo;
+};

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg.cpp Wed Feb 25 13:37:18 2009
@@ -8,7 +8,5 @@
 
 A<int, 0, X> * a1;
 
-A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}} \
-          // expected-error{{unqualified-id}}
-A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}} \
-          // expected-error{{unqualified-id}}
+A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
+A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_nontype.cpp Wed Feb 25 13:37:18 2009
@@ -3,26 +3,21 @@
 
 A<0> *a0;
 
-A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}} \
-              // FIXME: expected-error{{unqualified-id}}
+A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int (void)'}}
 
-A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}} \
-              // FIXME: expected-error{{unqualified-id}}
+A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}}
 
 A<1 >> 2> *a3;
 
 // C++ [temp.arg.nontype]p5:
 A<A> *a4; // expected-error{{must have an integral or enumeration type}} \
-          // FIXME: the error message above is a bit lame \
-          // FIXME: expected-error{{expected unqualified-id}}
+          // FIXME: the error message above is a bit lame
 
 enum E { Enumerator = 17 };
-A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}} \
-          // FIXME: expected-error{{unqualified-id}}
+A<E> *a5; // expected-error{{template argument for non-type template parameter must be an expression}}
 template<E Value> struct A1; // expected-note{{template parameter is declared here}}
 A1<Enumerator> *a6; // okay
-A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}} \
-          // FIXME: expected-error{{expected unqualified-id}}
+A1<17> *a7; // expected-error{{non-type template argument of type 'int' cannot be converted to a value of type 'enum E'}}
 
 const long LongValue = 12345678;
 A<LongValue> *a8;
@@ -30,8 +25,7 @@
 A<ShortValue> *a9;
 
 int f(int);
-A<f(17)> *a10; // expected-error{{non-type template argument of type 'int' is not an integral constant expression}} \
-          // FIXME: expected-error{{expected unqualified-id}}
+A<f(17)> *a10; // expected-error{{non-type template argument of type 'int' is not an integral constant expression}}
 
 class X {
 public:
@@ -39,8 +33,7 @@
   X(int, int);
   operator int() const;
 };
-A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}} \
-                   // FIXME:expected-error{{expected unqualified-id}}
+A<X(17, 42)> *a11; // expected-error{{non-type template argument of type 'class X' must have an integral or enumeration type}}
 
 template<X const *Ptr> struct A2;
 
@@ -50,8 +43,7 @@
 A2<X_ptr> *a12;
 A2<array_of_Xs> *a13;
 A2<&an_X> *a13_2;
-A2<(&an_X)> *a13_2; // expected-error{{non-type template argument cannot be surrounded by parentheses}} \
-                    // FIXME: expected-error{{unqualified-id}}
+A2<(&an_X)> *a13_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}
 
 float f(float);
 
@@ -66,10 +58,8 @@
 A3<&h> *a14_2;
 A3<f> *a14_3;
 A3<&f> *a14_4;
-A3<h2> *a14_6;  // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}} \
-// FIXME: expected-error{{expected unqualified-id}}
-A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}}\
-// FIXME: expected-error{{expected unqualified-id}}
+A3<h2> *a14_6;  // expected-error{{non-type template argument of type 'float (*)(float)' cannot be converted to a value of type 'int (*)(int)'}}
+A3<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (*)(int)'}}
 // FIXME: the first error includes the string <overloaded function
 // type>, which makes Doug slightly unhappy.
 
@@ -79,18 +69,15 @@
 volatile X * X_volatile_ptr;
 template<X const &AnX> struct A4; // expected-note 2{{template parameter is declared here}}
 A4<an_X> *a15_1; // okay
-A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}} \
-                  // FIXME: expected-error{{expected unqualified-id}}
-A4<y> *15_3; //  expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}}\
-                  // FIXME: expected-error{{expected unqualified-id}}
+A4<*X_volatile_ptr> *a15_2; // expected-error{{reference binding of non-type template parameter of type 'class X const &' to template argument of type 'class X volatile' ignores qualifiers}}
+A4<y> *15_3; //  expected-error{{non-type template parameter of reference type 'class X const &' cannot bind to template argument of type 'struct Y'}} \
+            // FIXME: expected-error{{expected unqualified-id}}
 
 template<int (&fr)(int)> struct A5; // expected-note 2{{template parameter is declared here}}
 A5<h> *a16_1;
 A5<f> *a16_3;
-A5<h2> *a16_6;  // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}} \
-// FIXME: expected-error{{expected unqualified-id}}
-A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}\
-// FIXME: expected-error{{expected unqualified-id}}
+A5<h2> *a16_6;  // expected-error{{non-type template argument of type 'float (float)' cannot be converted to a value of type 'int (&)(int)'}}
+A5<g> *a14_7; // expected-error{{non-type template argument of type '<overloaded function type>' cannot be converted to a value of type 'int (&)(int)'}}
 // FIXME: the first error includes the string <overloaded function
 // type>, which makes Doug slightly unhappy.
 
@@ -106,15 +93,12 @@
 template<int (Z::*pmf)(int)> struct A6; // expected-note{{template parameter is declared here}}
 A6<&Z::foo> *a17_1;
 A6<&Z::bar> *a17_2;
-A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}} \
-// FIXME: expected-error{{expected unqualified-id}}
+A6<&Z::baz> *a17_3; // expected-error{{non-type template argument of type 'double (struct Z::*)(double)' cannot be converted to a value of type 'int (struct Z::*)(int)'}}
 
 
 template<int Z::*pm> struct A7;  // expected-note{{template parameter is declared here}}
 template<int Z::*pm> struct A7c;
 A7<&Z::int_member> *a18_1;
 A7c<&Z::int_member> *a18_2;
-A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}} \
-              // FIXME: expected-error{{unqualified-id}}
-A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}} \
-          // FIXME: expected-error{{expected unqualified-id}}
+A7<&Z::float_member> *a18_3; // expected-error{{non-type template argument of type 'float struct Z::*' cannot be converted to a value of type 'int struct Z::*'}}
+A7c<(&Z::int_member)> *a18_3; // expected-error{{non-type template argument cannot be surrounded by parentheses}}

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_template.cpp Wed Feb 25 13:37:18 2009
@@ -20,23 +20,18 @@
 A<N::Z> *a2;
 A< ::N::Z> *a3;
 
-A<Y> *a4; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
-          // FIXME::expected-error{{expected unqualified-id}}
-A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
-          // FIXME::expected-error{{expected unqualified-id}}
-B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
-          // FIXME::expected-error{{expected unqualified-id}}
+A<Y> *a4; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
+B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
 C<Y> *a7;
-C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} \
-          // FIXME::expected-error{{expected unqualified-id}}
+C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
 
 template<typename T> void f(int);
 
 // FIXME: we're right to provide an error message, but it should say
 // that we need a class template. We won't get this right until name
 // lookup of 'f' returns a TemplateDecl.
-A<f> *a9; // expected-error{{template argument for template template parameter must be a template}} \
-          // expected-error{{unqualified-id}}
+A<f> *a9; // expected-error{{template argument for template template parameter must be a template}}
 
 // FIXME: The code below is ill-formed, because of the evil digraph '<:'. 
 // We should provide a much better error message than we currently do.

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_type.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_type.cpp Wed Feb 25 13:37:18 2009
@@ -2,11 +2,9 @@
 template<typename T> class A; // expected-note 2 {{template parameter is declared here}}
 
 // [temp.arg.type]p1
-A<0> *a1; // expected-error{{template argument for template type parameter must be a type}} \
-          // expected-error{{unqualified-id}}
+A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
 
-A<A> *a2; // expected-error{{template argument for template type parameter must be a type}} \
-          // expected-error{{unqualified-id}}
+A<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
 
 A<int> *a3;
 A<int()> *a4; 
@@ -16,13 +14,12 @@
 // [temp.arg.type]p2
 void f() {
   class X { };
-  A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}}\
-                // FIXME: expected-error{{expected expression}}
+  A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}} \
+                // FIXME: expected-error{{use of undeclared identifier 'a'}}
 }
 
 struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
-A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}} \
-                            // FIXME: expected-error{{expected unqualified-id}}
+A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}}
 
 // FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
 // belongs somewhere in the template instantiation section).





More information about the cfe-commits mailing list