[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