[cfe-commits] r56007 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h include/clang/Parse/Scope.h lib/Parse/ParseExprCXX.cpp lib/Parse/ParseStmt.cpp test/Parser/cxx-condition.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Tue Sep 9 13:38:48 PDT 2008


Author: akirtzidis
Date: Tue Sep  9 15:38:47 2008
New Revision: 56007

URL: http://llvm.org/viewvc/llvm-project?rev=56007&view=rev
Log:
Implement parser support for the 'condition' part of C++ selection-statements and iteration-statements (if/switch/while/for).
Add new 'ActOnCXXConditionDeclarationExpr' action, called when the 'condition' is a declaration instead of an expression.

Added:
    cfe/trunk/test/Parser/cxx-condition.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Parse/Scope.h
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Sep  9 15:38:47 2008
@@ -537,6 +537,8 @@
      "function definition does not declare parameters")
 DIAG(err_expected_lparen_after_type, ERROR,
      "expected '(' for function-style cast or type construction")
+DIAG(err_expected_equal_after_declarator, ERROR,
+     "expected '=' after declarator")
 
 //===----------------------------------------------------------------------===//
 // Semantic Analysis

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Sep  9 15:38:47 2008
@@ -618,6 +618,17 @@
     return 0;
   }
 
+  /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
+  /// C++ if/switch/while/for statement.
+  /// e.g: "if (int x = f()) {...}"
+  virtual ExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
+                                                      SourceLocation StartLoc,
+                                                      Declarator &D,
+                                                      SourceLocation EqualLoc,
+                                                      ExprTy *AssignExprVal) {
+    return 0;
+  }
+
   //===---------------------------- C++ Classes ---------------------------===//
   /// ActOnBaseSpecifier - Parsed a base specifier
   virtual void ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,

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

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Tue Sep  9 15:38:47 2008
@@ -580,7 +580,8 @@
     TypeNameContext,     // Abstract declarator for types.
     MemberContext,       // Struct/Union field.
     BlockContext,        // Declaration within a block in a function.
-    ForContext           // Declaration within first part of a for loop.
+    ForContext,          // Declaration within first part of a for loop.
+    ConditionContext     // Condition declaration in a C++ if/switch/while/for.
   };
 private:
   /// Context - Where we are parsing this declarator.

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Sep  9 15:38:47 2008
@@ -437,6 +437,10 @@
   void ParseCXXSimpleTypeSpecifier(DeclSpec &DS);
 
   //===--------------------------------------------------------------------===//
+  // C++ if/switch/while/for condition expression.
+  ExprResult ParseCXXCondition();
+
+  //===--------------------------------------------------------------------===//
   // C99 6.7.8: Initialization.
   ExprResult ParseInitializer();
   ExprResult ParseInitializerWithPotentialDesignator();

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

==============================================================================
--- cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/trunk/include/clang/Parse/Scope.h Tue Sep  9 15:38:47 2008
@@ -44,14 +44,17 @@
     /// just contain loop constructs but don't contain decls.
     DeclScope = 0x08,
 
+    /// ControlScope - The controlling scope in a if/switch/while/for statement.
+    ControlScope = 0x10,
+
     /// CXXClassScope - The scope of a C++ struct/union/class definition.
-    CXXClassScope = 0x10,
+    CXXClassScope = 0x20,
     
     /// BlockScope - This is a scope that corresponds to a block object.
     /// 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 = 0x20
+    BlockScope = 0x40
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Sep  9 15:38:47 2008
@@ -153,6 +153,55 @@
                                            &CommaLocs[0], RParenLoc);
 }
 
+/// ParseCXXCondition - if/switch/while/for condition expression.
+///
+///       condition:
+///         expression
+///         type-specifier-seq declarator '=' assignment-expression
+/// [GNU]   type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
+///             '=' assignment-expression
+///
+Parser::ExprResult Parser::ParseCXXCondition() {
+  if (!isDeclarationSpecifier())
+    return ParseExpression(); // expression
+
+  SourceLocation StartLoc = Tok.getLocation();
+
+  // type-specifier-seq
+  DeclSpec DS;
+  ParseSpecifierQualifierList(DS);
+
+  // declarator
+  Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
+  ParseDeclarator(DeclaratorInfo);
+
+  // simple-asm-expr[opt]
+  if (Tok.is(tok::kw_asm)) {
+    ExprResult AsmLabel = ParseSimpleAsm();
+    if (AsmLabel.isInvalid) {
+      SkipUntil(tok::semi);
+      return true;
+    }
+    DeclaratorInfo.setAsmLabel(AsmLabel.Val);
+  }
+
+  // If attributes are present, parse them.
+  if (Tok.is(tok::kw___attribute))
+    DeclaratorInfo.AddAttributes(ParseAttributes());
+
+  // '=' assignment-expression
+  if (Tok.isNot(tok::equal))
+    return Diag(Tok, diag::err_expected_equal_after_declarator);
+  SourceLocation EqualLoc = ConsumeToken();
+  ExprResult AssignExpr = ParseAssignmentExpression();
+  if (AssignExpr.isInvalid)
+    return true;
+  
+  return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
+                                                  DeclaratorInfo,
+                                                  EqualLoc, AssignExpr.Val);
+}
+
 /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
 /// This should only be called when the current token is known to be part of
 /// simple-type-specifier.

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Tue Sep  9 15:38:47 2008
@@ -417,6 +417,8 @@
 ///       if-statement: [C99 6.8.4.1]
 ///         'if' '(' expression ')' statement
 ///         'if' '(' expression ')' statement 'else' statement
+/// [C++]   'if' '(' condition ')' statement
+/// [C++]   'if' '(' condition ')' statement 'else' statement
 ///
 Parser::StmtResult Parser::ParseIfStatement() {
   assert(Tok.is(tok::kw_if) && "Not an if stmt!");
@@ -427,17 +429,27 @@
     SkipUntil(tok::semi);
     return true;
   }
-  
+
+  bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
   // C99 6.8.4p3 - In C99, the if statement is a block.  This is not
   // the case for C90.
-  if (getLang().C99)
-    EnterScope(Scope::DeclScope);
+  if (C99orCXX)
+    EnterScope(Scope::DeclScope | Scope::ControlScope);
 
   // Parse the condition.
-  ExprResult CondExp = ParseSimpleParenExpression();
+  ExprResult CondExp;
+  if (getLang().CPlusPlus) {
+    SourceLocation LParenLoc = ConsumeParen();
+    CondExp = ParseCXXCondition();
+    MatchRHSPunctuation(tok::r_paren, LParenLoc);
+  } else {
+    CondExp = ParseSimpleParenExpression();
+  }
+
   if (CondExp.isInvalid) {
     SkipUntil(tok::semi);
-    if (getLang().C99)
+    if (C99orCXX)
       ExitScope();
     return true;
   }
@@ -445,9 +457,9 @@
   // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do this
   // if the body isn't a compound statement to avoid push/pop in common cases.
-  bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
+  bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
   if (NeedsInnerScope) EnterScope(Scope::DeclScope);
-  
+
   // Read the 'then' stmt.
   SourceLocation ThenStmtLoc = Tok.getLocation();
   StmtResult ThenStmt = ParseStatement();
@@ -467,7 +479,7 @@
     // there is no compound stmt.  C90 does not have this clause.  We only do
     // this if the body isn't a compound statement to avoid push/pop in common
     // cases.
-    NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
+    NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
     if (NeedsInnerScope) EnterScope(Scope::DeclScope);
     
     ElseStmtLoc = Tok.getLocation();
@@ -477,7 +489,7 @@
     if (NeedsInnerScope) ExitScope();
   }
   
-  if (getLang().C99)
+  if (C99orCXX)
     ExitScope();
 
   // If the then or else stmt is invalid and the other is valid (and present),
@@ -505,6 +517,7 @@
 /// ParseSwitchStatement
 ///       switch-statement:
 ///         'switch' '(' expression ')' statement
+/// [C++]   'switch' '(' condition ')' statement
 Parser::StmtResult Parser::ParseSwitchStatement() {
   assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
   SourceLocation SwitchLoc = ConsumeToken();  // eat the 'switch'.
@@ -515,15 +528,24 @@
     return true;
   }
 
+  bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
   // C99 6.8.4p3 - In C99, the switch statement is a block.  This is
   // not the case for C90.  Start the switch scope.
-  if (getLang().C99)
-    EnterScope(Scope::BreakScope|Scope::DeclScope);
+  if (C99orCXX)
+    EnterScope(Scope::BreakScope | Scope::DeclScope | Scope::ControlScope);
   else
     EnterScope(Scope::BreakScope);
 
   // Parse the condition.
-  ExprResult Cond = ParseSimpleParenExpression();
+  ExprResult Cond;
+  if (getLang().CPlusPlus) {
+    SourceLocation LParenLoc = ConsumeParen();
+    Cond = ParseCXXCondition();
+    MatchRHSPunctuation(tok::r_paren, LParenLoc);
+  } else {
+    Cond = ParseSimpleParenExpression();
+  }
   
   if (Cond.isInvalid) {
     ExitScope();
@@ -535,7 +557,7 @@
   // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do this
   // if the body isn't a compound statement to avoid push/pop in common cases.
-  bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
+  bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
   if (NeedsInnerScope) EnterScope(Scope::DeclScope);
   
   // Read the body statement.
@@ -557,6 +579,7 @@
 /// ParseWhileStatement
 ///       while-statement: [C99 6.8.5.1]
 ///         'while' '(' expression ')' statement
+/// [C++]   'while' '(' condition ')' statement
 Parser::StmtResult Parser::ParseWhileStatement() {
   assert(Tok.is(tok::kw_while) && "Not a while stmt!");
   SourceLocation WhileLoc = Tok.getLocation();
@@ -568,20 +591,30 @@
     return true;
   }
   
+  bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
   // C99 6.8.5p5 - In C99, the while statement is a block.  This is not
   // the case for C90.  Start the loop scope.
-  if (getLang().C99)
-    EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope);
+  if (C99orCXX)
+    EnterScope(Scope::BreakScope | Scope::ContinueScope |
+               Scope::DeclScope  | Scope::ControlScope);
   else
     EnterScope(Scope::BreakScope | Scope::ContinueScope);
 
   // Parse the condition.
-  ExprResult Cond = ParseSimpleParenExpression();
+  ExprResult Cond;
+  if (getLang().CPlusPlus) {
+    SourceLocation LParenLoc = ConsumeParen();
+    Cond = ParseCXXCondition();
+    MatchRHSPunctuation(tok::r_paren, LParenLoc);
+  } else {
+    Cond = ParseSimpleParenExpression();
+  }
   
   // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do this
   // if the body isn't a compound statement to avoid push/pop in common cases.
-  bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
+  bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
   if (NeedsInnerScope) EnterScope(Scope::DeclScope);
   
   // Read the body statement.
@@ -654,8 +687,15 @@
 ///       for-statement: [C99 6.8.5.3]
 ///         'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
 ///         'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
+/// [C++]   'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
+/// [C++]       statement
 /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
 /// [OBJC2] 'for' '(' expr 'in' expr ')' statement
+///
+/// [C++] for-init-statement:
+/// [C++]   expression-statement
+/// [C++]   simple-declaration
+///
 Parser::StmtResult Parser::ParseForStatement() {
   assert(Tok.is(tok::kw_for) && "Not a for stmt!");
   SourceLocation ForLoc = ConsumeToken();  // eat the 'for'.
@@ -666,10 +706,13 @@
     return true;
   }
   
+  bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
+
   // C99 6.8.5p5 - In C99, the for statement is a block.  This is not
   // the case for C90.  Start the loop scope.
-  if (getLang().C99)
-    EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope);
+  if (C99orCXX)
+    EnterScope(Scope::BreakScope | Scope::ContinueScope |
+               Scope::DeclScope  | Scope::ControlScope);
   else
     EnterScope(Scope::BreakScope | Scope::ContinueScope);
 
@@ -687,11 +730,11 @@
     ConsumeToken();
   } else if (isDeclarationSpecifier()) {  // for (int X = 4;
     // Parse declaration, which eats the ';'.
-    if (!getLang().C99)   // Use of C99-style for loops in C90 mode?
+    if (!C99orCXX)   // Use of C99-style for loops in C90 mode?
       Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
     
     SourceLocation DeclStart = Tok.getLocation();
-    DeclTy *aBlockVarDecl = ParseDeclaration(Declarator::ForContext);
+    DeclTy *aBlockVarDecl = ParseSimpleDeclaration(Declarator::ForContext);
     // FIXME: Pass in the right location for the end of the declstmt.
     StmtResult stmtResult = Actions.ActOnDeclStmt(aBlockVarDecl, DeclStart,
                                                   DeclStart);
@@ -732,7 +775,8 @@
       // no second part.
       Value = ExprResult();
     } else {
-      Value = ParseExpression();
+      Value = getLang().CPlusPlus ? ParseCXXCondition()
+                                  : ParseExpression();
       if (!Value.isInvalid)
         SecondPart = Value.Val;
     }
@@ -764,7 +808,7 @@
   // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
   // there is no compound stmt.  C90 does not have this clause.  We only do this
   // if the body isn't a compound statement to avoid push/pop in common cases.
-  bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
+  bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
   if (NeedsInnerScope) EnterScope(Scope::DeclScope);
   
   // Read the body statement.

Added: cfe/trunk/test/Parser/cxx-condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-condition.cpp?rev=56007&view=auto

==============================================================================
--- cfe/trunk/test/Parser/cxx-condition.cpp (added)
+++ cfe/trunk/test/Parser/cxx-condition.cpp Tue Sep  9 15:38:47 2008
@@ -0,0 +1,11 @@
+// RUN: clang -parse-noop %s -verify
+
+void f() {
+  int a;
+  while (a) ;
+  while (int x) ; // expected-error {{expected '=' after declarator}}
+  while (float x = 0) ;
+  if (const int x = a) ;
+  switch (int x = a+10) {}
+  for (; int x = ++a; ) ;
+}





More information about the cfe-commits mailing list