[cfe-commits] r60387 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h include/clang/Parse/Scope.h lib/Parse/ParseTemplate.cpp test/Parser/cxx-template-decl.cpp

Douglas Gregor doug.gregor at gmail.com
Mon Dec 1 16:41:28 PST 2008


Author: dgregor
Date: Mon Dec  1 18:41:28 2008
New Revision: 60387

URL: http://llvm.org/viewvc/llvm-project?rev=60387&view=rev
Log:
A little more scaffolding for parsing templates:
  - Template parameter scope to hold the template parameters
  - Template parameter context for parsing declarators
  - Actions for template type parameters and non-type template
    parameters


Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Scope.h
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/test/Parser/cxx-template-decl.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Dec  1 18:41:28 2008
@@ -852,6 +852,37 @@
   virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl) {
   }
 
+  //===---------------------------C++ Templates----------------------------===//
+
+  /// ActOnTypeParameter - Called when a C++ template type parameter
+  /// (e.g., "typename T") has been parsed. Typename specifies whether
+  /// the keyword "typename" was used to declare the type parameter
+  /// (otherwise, "class" was used), and KeyLoc is the location of the
+  /// "class" or "typename" keyword. ParamName is the name of the
+  /// parameter (NULL indicates an unnamed template parameter) and
+  /// ParamName is the location of the parameter name (if any). 
+  /// If the type parameter has a default argument, it will be added
+  /// later via ActOnTypeParameterDefault.
+  virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename, 
+				     SourceLocation KeyLoc,
+				     IdentifierInfo *ParamName,
+				     SourceLocation ParamNameLoc) {
+    return 0;
+  }
+
+  /// ActOnTypeParameterDefault - Adds a default argument (the type
+  /// Default) to the given template type parameter (TypeParam). 
+  virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, TypeTy *Default) {
+  }
+
+  /// ActOnNonTypeTemplateParameter - Called when a C++ non-type
+  /// template parameter (e.g., "int Size" in "template<int Size>
+  /// class Array") has been parsed. S is the current scope and D is
+  /// the parsed declarator.
+  virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D) {
+    return 0;
+  }
+
   //===----------------------- Obj-C Declarations -------------------------===//
   
   // ActOnStartClassInterface - this action is called immediately after parsing

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

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Mon Dec  1 18:41:28 2008
@@ -631,7 +631,8 @@
     MemberContext,       // Struct/Union field.
     BlockContext,        // Declaration within a block in a function.
     ForContext,          // Declaration within first part of a for loop.
-    ConditionContext     // Condition declaration in a C++ if/switch/while/for.
+    ConditionContext,    // Condition declaration in a C++ if/switch/while/for.
+    TemplateParamContext // Within a template parameter list.
   };
 
   /// DeclaratorKind - The kind of declarator this represents.
@@ -743,9 +744,11 @@
   }
   
   /// mayOmitIdentifier - Return true if the identifier is either optional or
-  /// not allowed.  This is true for typenames and prototypes.
+  /// not allowed.  This is true for typenames, prototypes, and template 
+  /// parameter lists.
   bool mayOmitIdentifier() const {
-    return Context == TypeNameContext || Context == PrototypeContext;
+    return Context == TypeNameContext || Context == PrototypeContext ||
+           Context == TemplateParamContext;
   }
 
   /// mayHaveIdentifier - Return true if the identifier is either optional or

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/trunk/include/clang/Parse/Scope.h Mon Dec  1 18:41:28 2008
@@ -54,7 +54,13 @@
     /// Blocks serve as top-level scopes for some objects like labels, they
     /// also prevent things like break and continue.  BlockScopes have the
     /// other flags set as well.
-    BlockScope = 0x40
+    BlockScope = 0x40,
+
+    /// TemplateParamScope - This is a scope that corresponds to the
+    /// template parameters of a C++ template. Template parameter
+    /// scope starts at the 'template' keyword and ends when the
+    /// template declaration ends.
+    TemplateParamScope = 0x80
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit
@@ -172,6 +178,12 @@
     return false;
   }
   
+  /// isTemplateParamScope - Return true if this scope is a C++
+  /// template parameter scope.
+  bool isTemplateParamScope() const {
+    return getFlags() & Scope::TemplateParamScope;
+  }
+
   /// Init - This is used by the parser to implement scope caching.
   ///
   void Init(Scope *Parent, unsigned ScopeFlags) {

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Dec  1 18:41:28 2008
@@ -40,15 +40,19 @@
   }
   SourceLocation TemplateLoc = ConsumeToken();
   
-  // Try to parse the template parameters, and the declaration if successful.
-  if(ParseTemplateParameters(0)) {
-    // For some reason, this is generating a compiler error when parsing the
-    // declaration. Apparently, ParseDeclaration doesn't want to match a
-    // function-definition, but will match a function declaration.
-    // TODO: ParseDeclarationOrFunctionDefinition
-    return ParseDeclaration(Context);
-  }
-  return 0;
+  // Enter template-parameter scope.
+  EnterScope(Scope::TemplateParamScope|Scope::DeclScope);
+
+  // Try to parse the template parameters, and the declaration if
+  // successful.
+  DeclTy *TemplateDecl = 0;
+  if(ParseTemplateParameters(0))
+    TemplateDecl = ParseDeclarationOrFunctionDefinition();
+
+  // Leave template-parameter scope.
+  ExitScope();
+
+  return TemplateDecl;
 }
 
 /// ParseTemplateParameters - Parses a template-parameter-list enclosed in
@@ -153,13 +157,19 @@
 ///         'typename' identifier[opt]
 ///         'typename' identifier[opt] '=' type-id
 Parser::DeclTy *Parser::ParseTypeParameter() {
-  SourceLocation keyLoc = ConsumeToken();
+  assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) &&
+	 "A type-parameter starts with 'class' or 'typename'");
+
+  // Consume the 'class' or 'typename' keyword.
+  bool TypenameKeyword = Tok.is(tok::kw_typename);
+  SourceLocation KeyLoc = ConsumeToken();
 
   // Grab the template parameter name (if given)
-  IdentifierInfo* paramName = 0;
+  SourceLocation NameLoc;
+  IdentifierInfo* ParamName = 0;
   if(Tok.is(tok::identifier)) {
-    paramName = Tok.getIdentifierInfo();
-    ConsumeToken();
+    ParamName = Tok.getIdentifierInfo();
+    NameLoc = ConsumeToken();
   } else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
 	    Tok.is(tok::greater)) {
     // Unnamed template parameter. Don't have to do anything here, just
@@ -169,17 +179,18 @@
     return 0;
   }
   
+  DeclTy *TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword, 
+						 KeyLoc, ParamName, NameLoc);
+
   // Grab a default type id (if given).
-  TypeTy* defaultType = 0;
   if(Tok.is(tok::equal)) {
-    ConsumeToken();
-    defaultType = ParseTypeName();
-    if(!defaultType)
-      return 0;
+    SourceLocation EqualLoc = ConsumeToken();
+    TypeTy *DefaultType = ParseTypeName();
+    if(DefaultType)
+      Actions.ActOnTypeParameterDefault(TypeParam, DefaultType);
   }
   
-  // FIXME: Add an action for type parameters.
-  return 0;
+  return TypeParam;
 }
 
 /// ParseTemplateTemplateParameter - Handle the parsing of template
@@ -244,22 +255,21 @@
 /// but that didn't work out to well. Instead, this tries to recrate the basic
 /// parsing of parameter declarations, but tries to constrain it for template
 /// parameters.
-/// FIXME: We need to make ParseParameterDeclaration work for non-type 
-/// template parameters, too.
-Parser::DeclTy* Parser::ParseNonTypeTemplateParameter()
-{
-  SourceLocation startLoc = Tok.getLocation();
+/// FIXME: We need to make a ParseParameterDeclaration that works for
+/// non-type template parameters and normal function parameters.
+Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() {
+  SourceLocation StartLoc = Tok.getLocation();
 
   // Parse the declaration-specifiers (i.e., the type).
-  // FIXME:: The type should probably be restricted in some way... Not all
+  // FIXME: The type should probably be restricted in some way... Not all
   // declarators (parts of declarators?) are accepted for parameters.
-  DeclSpec ds;
-  ParseDeclarationSpecifiers(ds);
+  DeclSpec DS;
+  ParseDeclarationSpecifiers(DS);
 
   // Parse this as a typename.
-  Declarator decl(ds, Declarator::TypeNameContext);
-  ParseDeclarator(decl);
-  if(ds.getTypeSpecType() == DeclSpec::TST_unspecified && !ds.getTypeRep()) {
+  Declarator ParamDecl(DS, Declarator::TemplateParamContext);
+  ParseDeclarator(ParamDecl);
+  if(DS.getTypeSpecType() == DeclSpec::TST_unspecified && !DS.getTypeRep()) {
     // This probably shouldn't happen - and it's more of a Sema thing, but
     // basically we didn't parse the type name because we couldn't associate
     // it with an AST node. we should just skip to the comma or greater.
@@ -269,11 +279,8 @@
     return 0;
   }
 
-  // If there's an identifier after the typename, parse that as part of the
-  // declarator - or something.
-  if(Tok.is(tok::identifier)) {
-    ConsumeToken();
-  }
+  // Create the parameter. 
+  DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl);
 
   // Is there a default value? Parsing this can be fairly annoying because
   // we have to stop on the first non-nested (paren'd) '>' as the closure
@@ -283,6 +290,5 @@
     SkipUntil(tok::comma, tok::greater, true, true);
   }
   
-  // FIXME: Add an action for non-type template parameters.
-  return 0;
+  return Param;
 }

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

==============================================================================
--- cfe/trunk/test/Parser/cxx-template-decl.cpp (original)
+++ cfe/trunk/test/Parser/cxx-template-decl.cpp Mon Dec  1 18:41:28 2008
@@ -13,9 +13,8 @@
 template <typename T> void foo();
 template <typename T, typename U> void foo();
 
-// TODO Implement ParseDeclarationOrFunction()
-// Template function definitions. Not done yet.
-// template <typename T> void foo() { }
+// Template function definitions.
+template <typename T> void foo() { }
 
 // Template class (forward) declarations
 template <typename T> struct A;





More information about the cfe-commits mailing list