aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseStmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Parse/ParseStmt.cpp')
-rw-r--r--clang/lib/Parse/ParseStmt.cpp134
1 files changed, 79 insertions, 55 deletions
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 1f6c74aeae7e..1c8441fafc48 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/Attributes.h"
#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/TokenKinds.h"
#include "clang/Parse/LoopHint.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
@@ -21,6 +22,7 @@
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
@@ -36,8 +38,8 @@ StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc,
// We may get back a null statement if we found a #pragma. Keep going until
// we get an actual statement.
+ StmtVector Stmts;
do {
- StmtVector Stmts;
Res = ParseStatementOrDeclaration(Stmts, StmtCtx, TrailingElseLoc);
} while (!Res.isInvalid() && !Res.get());
@@ -188,7 +190,8 @@ Retry:
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
return StmtError();
- case tok::identifier: {
+ case tok::identifier:
+ ParseIdentifier: {
Token Next = NextToken();
if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
// Both C++11 and GNU attributes preceding the label appertain to the
@@ -222,7 +225,7 @@ Retry:
}
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
default: {
@@ -261,7 +264,19 @@ Retry:
return StmtError();
}
- return ParseExprStatement(StmtCtx);
+ switch (Tok.getKind()) {
+#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait:
+#include "clang/Basic/TransformTypeTraits.def"
+ if (NextToken().is(tok::less)) {
+ Tok.setKind(tok::identifier);
+ Diag(Tok, diag::ext_keyword_as_ident)
+ << Tok.getIdentifierInfo()->getName() << 0;
+ goto ParseIdentifier;
+ }
+ [[fallthrough]];
+ default:
+ return ParseExprStatement(StmtCtx);
+ }
}
case tok::kw___attribute: {
@@ -448,7 +463,7 @@ Retry:
// processing a #pragma omp clause.
ProhibitAttributes(CXX11Attrs);
ProhibitAttributes(GNUAttrs);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case tok::annot_attr_openmp:
// Do not prohibit attributes if they were OpenMP attributes.
return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);
@@ -665,9 +680,12 @@ StmtResult Parser::ParseSEHLeaveStatement() {
/// ParseLabeledStatement - We have an identifier and a ':' after it.
///
+/// label:
+/// identifier ':'
+/// [GNU] identifier ':' attributes[opt]
+///
/// labeled-statement:
-/// identifier ':' statement
-/// [GNU] identifier ':' attributes[opt] statement
+/// label statement
///
StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
ParsedStmtContext StmtCtx) {
@@ -711,6 +729,12 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &Attrs,
}
}
+ // The label may have no statement following it
+ if (SubStmt.isUnset() && Tok.is(tok::r_brace)) {
+ DiagnoseLabelAtEndOfCompoundStatement();
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
+ }
+
// If we've not parsed a statement yet, parse one now.
if (!SubStmt.isInvalid() && !SubStmt.isUsable())
SubStmt = ParseStatement(nullptr, StmtCtx);
@@ -741,7 +765,7 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
// otherwise in the same context as the labeled-statement.
StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
- // It is very very common for code to contain many case statements recursively
+ // It is very common for code to contain many case statements recursively
// nested, as in (but usually without indentation):
// case 1:
// case 2:
@@ -851,18 +875,13 @@ StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
// If we found a non-case statement, start by parsing it.
StmtResult SubStmt;
- if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
+ if (Tok.is(tok::r_brace)) {
+ // "switch (X) { case 4: }", is valid and is treated as if label was
+ // followed by a null statement.
+ DiagnoseLabelAtEndOfCompoundStatement();
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
} else {
- // Nicely diagnose the common error "switch (X) { case 4: }", which is
- // not valid. If ColonLoc doesn't point to a valid text location, there was
- // another parsing error, so avoid producing extra diagnostics.
- if (ColonLoc.isValid()) {
- SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
- << FixItHint::CreateInsertion(AfterColonLoc, " ;");
- }
- SubStmt = StmtError();
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
}
// Install the body into the most deeply-nested case.
@@ -908,15 +927,13 @@ StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) {
StmtResult SubStmt;
- if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
+ if (Tok.is(tok::r_brace)) {
+ // "switch (X) {... default: }", is valid and is treated as if label was
+ // followed by a null statement.
+ DiagnoseLabelAtEndOfCompoundStatement();
+ SubStmt = Actions.ActOnNullStmt(ColonLoc);
} else {
- // Diagnose the common error "switch (X) {... default: }", which is
- // not valid.
- SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
- << FixItHint::CreateInsertion(AfterColonLoc, " ;");
- SubStmt = true;
+ SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
}
// Broken sub-stmt shouldn't prevent forming the case statement properly.
@@ -956,7 +973,7 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
///
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
unsigned ScopeFlags) {
- assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
+ assert(Tok.is(tok::l_brace) && "Not a compound stmt!");
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
@@ -1033,6 +1050,18 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
}
+void Parser::DiagnoseLabelAtEndOfCompoundStatement() {
+ if (getLangOpts().CPlusPlus) {
+ Diag(Tok, getLangOpts().CPlusPlus2b
+ ? diag::warn_cxx20_compat_label_end_of_compound_statement
+ : diag::ext_cxx_label_end_of_compound_statement);
+ } else {
+ Diag(Tok, getLangOpts().C2x
+ ? diag::warn_c2x_compat_label_end_of_compound_statement
+ : diag::ext_c_label_end_of_compound_statement);
+ }
+}
+
/// Consume any extra semi-colons resulting in null statements,
/// returning true if any tok::semi were consumed.
bool Parser::ConsumeNullStmt(StmtVector &Stmts) {
@@ -1082,10 +1111,10 @@ StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) {
return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult);
}
-/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
-/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
-/// consume the '}' at the end of the block. It does not manipulate the scope
-/// stack.
+/// ParseCompoundStatementBody - Parse a sequence of statements optionally
+/// followed by a label and invoke the ActOnCompoundStmt action. This expects
+/// the '{' to be the current token, and consume the '}' at the end of the
+/// block. It does not manipulate the scope stack.
StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
Tok.getLocation(),
@@ -1242,20 +1271,20 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
/// 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.
-/// Additionally, if LParenLoc and RParenLoc are non-null, it will assign
-/// the location of the outer-most '(' and ')', respectively, to them.
+/// Additionally, it will assign the location of the outer-most '(' and ')',
+/// to LParenLoc and RParenLoc, respectively.
bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
Sema::ConditionResult &Cond,
SourceLocation Loc,
- Sema::ConditionKind CK, bool MissingOK,
- SourceLocation *LParenLoc,
- SourceLocation *RParenLoc) {
+ Sema::ConditionKind CK,
+ SourceLocation &LParenLoc,
+ SourceLocation &RParenLoc) {
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
SourceLocation Start = Tok.getLocation();
if (getLangOpts().CPlusPlus) {
- Cond = ParseCXXCondition(InitStmt, Loc, CK, MissingOK);
+ Cond = ParseCXXCondition(InitStmt, Loc, CK, false);
} else {
ExprResult CondExpr = ParseExpression();
@@ -1264,7 +1293,7 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
Cond = Sema::ConditionError();
else
Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK,
- MissingOK);
+ /*MissingOK=*/false);
}
// If the parser was confused by the condition and we don't have a ')', try to
@@ -1284,18 +1313,13 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
Actions.PreferredConditionType(CK));
if (!CondExpr.isInvalid())
Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK,
- MissingOK);
+ /*MissingOK=*/false);
}
// Either the condition is valid or the rparen is present.
T.consumeClose();
-
- if (LParenLoc != nullptr) {
- *LParenLoc = T.getOpenLocation();
- }
- if (RParenLoc != nullptr) {
- *RParenLoc = T.getCloseLocation();
- }
+ LParenLoc = T.getOpenLocation();
+ RParenLoc = T.getCloseLocation();
// Check for extraneous ')'s to catch things like "if (foo())) {". We know
// that all callers are looking for a statement after the condition, so ")"
@@ -1465,13 +1489,13 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
Sema::ConditionResult Cond;
SourceLocation LParen;
SourceLocation RParen;
- llvm::Optional<bool> ConstexprCondition;
+ std::optional<bool> ConstexprCondition;
if (!IsConsteval) {
if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
IsConstexpr ? Sema::ConditionKind::ConstexprIf
: Sema::ConditionKind::Boolean,
- /*MissingOK=*/false, &LParen, &RParen))
+ LParen, RParen))
return StmtError();
if (IsConstexpr)
@@ -1666,8 +1690,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
SourceLocation LParen;
SourceLocation RParen;
if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc,
- Sema::ConditionKind::Switch,
- /*MissingOK=*/false, &LParen, &RParen))
+ Sema::ConditionKind::Switch, LParen, RParen))
return StmtError();
StmtResult Switch = Actions.ActOnStartOfSwitchStmt(
@@ -1757,8 +1780,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
SourceLocation LParen;
SourceLocation RParen;
if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc,
- Sema::ConditionKind::Boolean,
- /*MissingOK=*/false, &LParen, &RParen))
+ Sema::ConditionKind::Boolean, LParen, RParen))
return StmtError();
// C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
@@ -2430,7 +2452,8 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
// If the function body could not be parsed, make a bogus compoundstmt.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
+ FnBody =
+ Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false);
}
BodyScope.Exit();
@@ -2467,7 +2490,8 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
// compound statement as the body.
if (FnBody.isInvalid()) {
Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
+ FnBody =
+ Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, std::nullopt, false);
}
BodyScope.Exit();