P0305R1: Parsing support for init-statements in 'if' and 'switch' statements.
No semantic analysis yet.
This is a pain to disambiguate correctly, because the parsing rules for the
declaration form of a condition and of an init-statement are quite different --
for a token sequence that looks like a declaration, we frequently need to
disambiguate all the way to the ')' or ';'.
We could do better here in some cases by stopping disambiguation once we've
decided whether we've got an expression or not (rather than keeping going until
we know whether it's an init-statement declaration or a condition declaration),
by unifying our parsing code for the two types of declaration and moving the
syntactic checks into Sema; if this has a measurable impact on parsing
performance, I'll look into that.
llvm-svn: 274169
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 5ca9933..fa8eb12 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1043,7 +1043,8 @@
/// ParseParenExprOrCondition:
/// [C ] '(' expression ')'
-/// [C++] '(' condition ')' [not allowed if OnlyAllowCondition=true]
+/// [C++] '(' condition ')'
+/// [C++1z] '(' init-statement[opt] condition ')'
///
/// This function parses and performs error recovery on the specified condition
/// or expression (depending on whether we're in C++ or C mode). This function
@@ -1052,14 +1053,15 @@
/// should try to recover harder. It returns false if the condition is
/// successfully parsed. Note that a successful parse can still have semantic
/// errors in the condition.
-bool Parser::ParseParenExprOrCondition(Sema::ConditionResult &Cond,
+bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
+ Sema::ConditionResult &Cond,
SourceLocation Loc,
Sema::ConditionKind CK) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
if (getLangOpts().CPlusPlus)
- Cond = ParseCXXCondition(Loc, CK);
+ Cond = ParseCXXCondition(InitStmt, Loc, CK);
else {
ExprResult CondExpr = ParseExpression();
@@ -1139,8 +1141,9 @@
ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
// Parse the condition.
+ StmtResult InitStmt;
Sema::ConditionResult Cond;
- if (ParseParenExprOrCondition(Cond, IfLoc,
+ if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
IsConstexpr ? Sema::ConditionKind::ConstexprIf
: Sema::ConditionKind::Boolean))
return StmtError();
@@ -1241,8 +1244,8 @@
if (ElseStmt.isInvalid())
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
- return Actions.ActOnIfStmt(IfLoc, IsConstexpr, Cond, ThenStmt.get(), ElseLoc,
- ElseStmt.get());
+ return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond,
+ ThenStmt.get(), ElseLoc, ElseStmt.get());
}
/// ParseSwitchStatement
@@ -1279,11 +1282,14 @@
ParseScope SwitchScope(this, ScopeFlags);
// Parse the condition.
+ StmtResult InitStmt;
Sema::ConditionResult Cond;
- if (ParseParenExprOrCondition(Cond, SwitchLoc, Sema::ConditionKind::Switch))
+ if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc,
+ Sema::ConditionKind::Switch))
return StmtError();
- StmtResult Switch = Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond);
+ StmtResult Switch =
+ Actions.ActOnStartOfSwitchStmt(SwitchLoc, InitStmt.get(), Cond);
if (Switch.isInvalid()) {
// Skip the switch body.
@@ -1366,7 +1372,8 @@
// Parse the condition.
Sema::ConditionResult Cond;
- if (ParseParenExprOrCondition(Cond, WhileLoc, Sema::ConditionKind::Boolean))
+ if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc,
+ Sema::ConditionKind::Boolean))
return StmtError();
// C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
@@ -1681,7 +1688,8 @@
// missing both semicolons.
} else {
if (getLangOpts().CPlusPlus)
- SecondPart = ParseCXXCondition(ForLoc, Sema::ConditionKind::Boolean);
+ SecondPart =
+ ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean);
else {
ExprResult SecondExpr = ParseExpression();
if (SecondExpr.isInvalid())