Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 71b914b

Browse files
committed
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56007 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 8bd3dc6 commit 71b914b

File tree

8 files changed

+151
-26
lines changed

8 files changed

+151
-26
lines changed

include/clang/Basic/DiagnosticKinds.def

+2
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,8 @@ DIAG(err_func_def_no_params, ERROR,
537537
"function definition does not declare parameters")
538538
DIAG(err_expected_lparen_after_type, ERROR,
539539
"expected '(' for function-style cast or type construction")
540+
DIAG(err_expected_equal_after_declarator, ERROR,
541+
"expected '=' after declarator")
540542

541543
//===----------------------------------------------------------------------===//
542544
// Semantic Analysis

include/clang/Parse/Action.h

+11
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,17 @@ class Action {
618618
return 0;
619619
}
620620

621+
/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
622+
/// C++ if/switch/while/for statement.
623+
/// e.g: "if (int x = f()) {...}"
624+
virtual ExprResult ActOnCXXConditionDeclarationExpr(Scope *S,
625+
SourceLocation StartLoc,
626+
Declarator &D,
627+
SourceLocation EqualLoc,
628+
ExprTy *AssignExprVal) {
629+
return 0;
630+
}
631+
621632
//===---------------------------- C++ Classes ---------------------------===//
622633
/// ActOnBaseSpecifier - Parsed a base specifier
623634
virtual void ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,

include/clang/Parse/DeclSpec.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,8 @@ class Declarator {
580580
TypeNameContext, // Abstract declarator for types.
581581
MemberContext, // Struct/Union field.
582582
BlockContext, // Declaration within a block in a function.
583-
ForContext // Declaration within first part of a for loop.
583+
ForContext, // Declaration within first part of a for loop.
584+
ConditionContext // Condition declaration in a C++ if/switch/while/for.
584585
};
585586
private:
586587
/// Context - Where we are parsing this declarator.

include/clang/Parse/Parser.h

+4
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,10 @@ class Parser {
436436
/// simple-type-specifier.
437437
void ParseCXXSimpleTypeSpecifier(DeclSpec &DS);
438438

439+
//===--------------------------------------------------------------------===//
440+
// C++ if/switch/while/for condition expression.
441+
ExprResult ParseCXXCondition();
442+
439443
//===--------------------------------------------------------------------===//
440444
// C99 6.7.8: Initialization.
441445
ExprResult ParseInitializer();

include/clang/Parse/Scope.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@ class Scope {
4444
/// just contain loop constructs but don't contain decls.
4545
DeclScope = 0x08,
4646

47+
/// ControlScope - The controlling scope in a if/switch/while/for statement.
48+
ControlScope = 0x10,
49+
4750
/// CXXClassScope - The scope of a C++ struct/union/class definition.
48-
CXXClassScope = 0x10,
51+
CXXClassScope = 0x20,
4952

5053
/// BlockScope - This is a scope that corresponds to a block object.
5154
/// Blocks serve as top-level scopes for some objects like labels, they
5255
/// also prevent things like break and continue. BlockScopes have the
5356
/// other flags set as well.
54-
BlockScope = 0x20
57+
BlockScope = 0x40
5558
};
5659
private:
5760
/// The parent scope for this scope. This is null for the translation-unit

lib/Parse/ParseExprCXX.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,55 @@ Parser::ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
153153
&CommaLocs[0], RParenLoc);
154154
}
155155

156+
/// ParseCXXCondition - if/switch/while/for condition expression.
157+
///
158+
/// condition:
159+
/// expression
160+
/// type-specifier-seq declarator '=' assignment-expression
161+
/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
162+
/// '=' assignment-expression
163+
///
164+
Parser::ExprResult Parser::ParseCXXCondition() {
165+
if (!isDeclarationSpecifier())
166+
return ParseExpression(); // expression
167+
168+
SourceLocation StartLoc = Tok.getLocation();
169+
170+
// type-specifier-seq
171+
DeclSpec DS;
172+
ParseSpecifierQualifierList(DS);
173+
174+
// declarator
175+
Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
176+
ParseDeclarator(DeclaratorInfo);
177+
178+
// simple-asm-expr[opt]
179+
if (Tok.is(tok::kw_asm)) {
180+
ExprResult AsmLabel = ParseSimpleAsm();
181+
if (AsmLabel.isInvalid) {
182+
SkipUntil(tok::semi);
183+
return true;
184+
}
185+
DeclaratorInfo.setAsmLabel(AsmLabel.Val);
186+
}
187+
188+
// If attributes are present, parse them.
189+
if (Tok.is(tok::kw___attribute))
190+
DeclaratorInfo.AddAttributes(ParseAttributes());
191+
192+
// '=' assignment-expression
193+
if (Tok.isNot(tok::equal))
194+
return Diag(Tok, diag::err_expected_equal_after_declarator);
195+
SourceLocation EqualLoc = ConsumeToken();
196+
ExprResult AssignExpr = ParseAssignmentExpression();
197+
if (AssignExpr.isInvalid)
198+
return true;
199+
200+
return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
201+
DeclaratorInfo,
202+
EqualLoc, AssignExpr.Val);
203+
}
204+
156205
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
157206
/// This should only be called when the current token is known to be part of
158207
/// simple-type-specifier.

lib/Parse/ParseStmt.cpp

+67-23
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
417417
/// if-statement: [C99 6.8.4.1]
418418
/// 'if' '(' expression ')' statement
419419
/// 'if' '(' expression ')' statement 'else' statement
420+
/// [C++] 'if' '(' condition ')' statement
421+
/// [C++] 'if' '(' condition ')' statement 'else' statement
420422
///
421423
Parser::StmtResult Parser::ParseIfStatement() {
422424
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
@@ -427,27 +429,37 @@ Parser::StmtResult Parser::ParseIfStatement() {
427429
SkipUntil(tok::semi);
428430
return true;
429431
}
430-
432+
433+
bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
434+
431435
// C99 6.8.4p3 - In C99, the if statement is a block. This is not
432436
// the case for C90.
433-
if (getLang().C99)
434-
EnterScope(Scope::DeclScope);
437+
if (C99orCXX)
438+
EnterScope(Scope::DeclScope | Scope::ControlScope);
435439

436440
// Parse the condition.
437-
ExprResult CondExp = ParseSimpleParenExpression();
441+
ExprResult CondExp;
442+
if (getLang().CPlusPlus) {
443+
SourceLocation LParenLoc = ConsumeParen();
444+
CondExp = ParseCXXCondition();
445+
MatchRHSPunctuation(tok::r_paren, LParenLoc);
446+
} else {
447+
CondExp = ParseSimpleParenExpression();
448+
}
449+
438450
if (CondExp.isInvalid) {
439451
SkipUntil(tok::semi);
440-
if (getLang().C99)
452+
if (C99orCXX)
441453
ExitScope();
442454
return true;
443455
}
444456

445457
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
446458
// there is no compound stmt. C90 does not have this clause. We only do this
447459
// if the body isn't a compound statement to avoid push/pop in common cases.
448-
bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
460+
bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
449461
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
450-
462+
451463
// Read the 'then' stmt.
452464
SourceLocation ThenStmtLoc = Tok.getLocation();
453465
StmtResult ThenStmt = ParseStatement();
@@ -467,7 +479,7 @@ Parser::StmtResult Parser::ParseIfStatement() {
467479
// there is no compound stmt. C90 does not have this clause. We only do
468480
// this if the body isn't a compound statement to avoid push/pop in common
469481
// cases.
470-
NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
482+
NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
471483
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
472484

473485
ElseStmtLoc = Tok.getLocation();
@@ -477,7 +489,7 @@ Parser::StmtResult Parser::ParseIfStatement() {
477489
if (NeedsInnerScope) ExitScope();
478490
}
479491

480-
if (getLang().C99)
492+
if (C99orCXX)
481493
ExitScope();
482494

483495
// If the then or else stmt is invalid and the other is valid (and present),
@@ -505,6 +517,7 @@ Parser::StmtResult Parser::ParseIfStatement() {
505517
/// ParseSwitchStatement
506518
/// switch-statement:
507519
/// 'switch' '(' expression ')' statement
520+
/// [C++] 'switch' '(' condition ')' statement
508521
Parser::StmtResult Parser::ParseSwitchStatement() {
509522
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
510523
SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
@@ -515,15 +528,24 @@ Parser::StmtResult Parser::ParseSwitchStatement() {
515528
return true;
516529
}
517530

531+
bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
532+
518533
// C99 6.8.4p3 - In C99, the switch statement is a block. This is
519534
// not the case for C90. Start the switch scope.
520-
if (getLang().C99)
521-
EnterScope(Scope::BreakScope|Scope::DeclScope);
535+
if (C99orCXX)
536+
EnterScope(Scope::BreakScope | Scope::DeclScope | Scope::ControlScope);
522537
else
523538
EnterScope(Scope::BreakScope);
524539

525540
// Parse the condition.
526-
ExprResult Cond = ParseSimpleParenExpression();
541+
ExprResult Cond;
542+
if (getLang().CPlusPlus) {
543+
SourceLocation LParenLoc = ConsumeParen();
544+
Cond = ParseCXXCondition();
545+
MatchRHSPunctuation(tok::r_paren, LParenLoc);
546+
} else {
547+
Cond = ParseSimpleParenExpression();
548+
}
527549

528550
if (Cond.isInvalid) {
529551
ExitScope();
@@ -535,7 +557,7 @@ Parser::StmtResult Parser::ParseSwitchStatement() {
535557
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
536558
// there is no compound stmt. C90 does not have this clause. We only do this
537559
// if the body isn't a compound statement to avoid push/pop in common cases.
538-
bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
560+
bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
539561
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
540562

541563
// Read the body statement.
@@ -557,6 +579,7 @@ Parser::StmtResult Parser::ParseSwitchStatement() {
557579
/// ParseWhileStatement
558580
/// while-statement: [C99 6.8.5.1]
559581
/// 'while' '(' expression ')' statement
582+
/// [C++] 'while' '(' condition ')' statement
560583
Parser::StmtResult Parser::ParseWhileStatement() {
561584
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
562585
SourceLocation WhileLoc = Tok.getLocation();
@@ -568,20 +591,30 @@ Parser::StmtResult Parser::ParseWhileStatement() {
568591
return true;
569592
}
570593

594+
bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
595+
571596
// C99 6.8.5p5 - In C99, the while statement is a block. This is not
572597
// the case for C90. Start the loop scope.
573-
if (getLang().C99)
574-
EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope);
598+
if (C99orCXX)
599+
EnterScope(Scope::BreakScope | Scope::ContinueScope |
600+
Scope::DeclScope | Scope::ControlScope);
575601
else
576602
EnterScope(Scope::BreakScope | Scope::ContinueScope);
577603

578604
// Parse the condition.
579-
ExprResult Cond = ParseSimpleParenExpression();
605+
ExprResult Cond;
606+
if (getLang().CPlusPlus) {
607+
SourceLocation LParenLoc = ConsumeParen();
608+
Cond = ParseCXXCondition();
609+
MatchRHSPunctuation(tok::r_paren, LParenLoc);
610+
} else {
611+
Cond = ParseSimpleParenExpression();
612+
}
580613

581614
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
582615
// there is no compound stmt. C90 does not have this clause. We only do this
583616
// if the body isn't a compound statement to avoid push/pop in common cases.
584-
bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
617+
bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
585618
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
586619

587620
// Read the body statement.
@@ -654,8 +687,15 @@ Parser::StmtResult Parser::ParseDoStatement() {
654687
/// for-statement: [C99 6.8.5.3]
655688
/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
656689
/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
690+
/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
691+
/// [C++] statement
657692
/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
658693
/// [OBJC2] 'for' '(' expr 'in' expr ')' statement
694+
///
695+
/// [C++] for-init-statement:
696+
/// [C++] expression-statement
697+
/// [C++] simple-declaration
698+
///
659699
Parser::StmtResult Parser::ParseForStatement() {
660700
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
661701
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
@@ -666,10 +706,13 @@ Parser::StmtResult Parser::ParseForStatement() {
666706
return true;
667707
}
668708

709+
bool C99orCXX = getLang().C99 || getLang().CPlusPlus;
710+
669711
// C99 6.8.5p5 - In C99, the for statement is a block. This is not
670712
// the case for C90. Start the loop scope.
671-
if (getLang().C99)
672-
EnterScope(Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope);
713+
if (C99orCXX)
714+
EnterScope(Scope::BreakScope | Scope::ContinueScope |
715+
Scope::DeclScope | Scope::ControlScope);
673716
else
674717
EnterScope(Scope::BreakScope | Scope::ContinueScope);
675718

@@ -687,11 +730,11 @@ Parser::StmtResult Parser::ParseForStatement() {
687730
ConsumeToken();
688731
} else if (isDeclarationSpecifier()) { // for (int X = 4;
689732
// Parse declaration, which eats the ';'.
690-
if (!getLang().C99) // Use of C99-style for loops in C90 mode?
733+
if (!C99orCXX) // Use of C99-style for loops in C90 mode?
691734
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
692735

693736
SourceLocation DeclStart = Tok.getLocation();
694-
DeclTy *aBlockVarDecl = ParseDeclaration(Declarator::ForContext);
737+
DeclTy *aBlockVarDecl = ParseSimpleDeclaration(Declarator::ForContext);
695738
// FIXME: Pass in the right location for the end of the declstmt.
696739
StmtResult stmtResult = Actions.ActOnDeclStmt(aBlockVarDecl, DeclStart,
697740
DeclStart);
@@ -732,7 +775,8 @@ Parser::StmtResult Parser::ParseForStatement() {
732775
// no second part.
733776
Value = ExprResult();
734777
} else {
735-
Value = ParseExpression();
778+
Value = getLang().CPlusPlus ? ParseCXXCondition()
779+
: ParseExpression();
736780
if (!Value.isInvalid)
737781
SecondPart = Value.Val;
738782
}
@@ -764,7 +808,7 @@ Parser::StmtResult Parser::ParseForStatement() {
764808
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
765809
// there is no compound stmt. C90 does not have this clause. We only do this
766810
// if the body isn't a compound statement to avoid push/pop in common cases.
767-
bool NeedsInnerScope = getLang().C99 && Tok.isNot(tok::l_brace);
811+
bool NeedsInnerScope = C99orCXX && Tok.isNot(tok::l_brace);
768812
if (NeedsInnerScope) EnterScope(Scope::DeclScope);
769813

770814
// Read the body statement.

test/Parser/cxx-condition.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: clang -parse-noop %s -verify
2+
3+
void f() {
4+
int a;
5+
while (a) ;
6+
while (int x) ; // expected-error {{expected '=' after declarator}}
7+
while (float x = 0) ;
8+
if (const int x = a) ;
9+
switch (int x = a+10) {}
10+
for (; int x = ++a; ) ;
11+
}

0 commit comments

Comments
 (0)