aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/ParseStmt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Parse/ParseStmt.cpp')
-rw-r--r--lib/Parse/ParseStmt.cpp151
1 files changed, 118 insertions, 33 deletions
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index deb10af4b17b..2974e6a245b0 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -15,10 +15,10 @@
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/Attributes.h"
#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Parse/LoopHint.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/LoopHint.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
using namespace clang;
@@ -348,6 +348,11 @@ Retry:
ConsumeAnnotationToken();
return StmtError();
+ case tok::annot_pragma_fenv_access:
+ ProhibitAttributes(Attrs);
+ HandlePragmaFEnvAccess();
+ return StmtEmpty();
+
case tok::annot_pragma_opencl_extension:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
@@ -434,7 +439,7 @@ StmtResult Parser::ParseExprStatement() {
// Otherwise, eat the semicolon.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Expr);
+ return Actions.ActOnExprStmt(Expr, isExprValueDiscarded());
}
/// ParseSEHTryBlockCommon
@@ -902,6 +907,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
case tok::annot_pragma_fp:
HandlePragmaFP();
break;
+ case tok::annot_pragma_fenv_access:
+ HandlePragmaFEnvAccess();
+ break;
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
@@ -922,6 +930,44 @@ void Parser::ParseCompoundStatementLeadingPragmas() {
}
+/// Consume any extra semi-colons resulting in null statements,
+/// returning true if any tok::semi were consumed.
+bool Parser::ConsumeNullStmt(StmtVector &Stmts) {
+ if (!Tok.is(tok::semi))
+ return false;
+
+ SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+
+ while (Tok.is(tok::semi) && !Tok.hasLeadingEmptyMacro() &&
+ Tok.getLocation().isValid() && !Tok.getLocation().isMacroID()) {
+ EndLoc = Tok.getLocation();
+
+ // Don't just ConsumeToken() this tok::semi, do store it in AST.
+ StmtResult R = ParseStatementOrDeclaration(Stmts, ACK_Any);
+ if (R.isUsable())
+ Stmts.push_back(R.get());
+ }
+
+ // Did not consume any extra semi.
+ if (EndLoc.isInvalid())
+ return false;
+
+ Diag(StartLoc, diag::warn_null_statement)
+ << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
+ return true;
+}
+
+bool Parser::isExprValueDiscarded() {
+ if (Actions.isCurCompoundStmtAStmtExpr()) {
+ // Look to see if the next two tokens close the statement expression;
+ // if so, this expression statement is the last statement in a
+ // statment expression.
+ return Tok.isNot(tok::r_brace) || NextToken().isNot(tok::r_paren);
+ }
+ return true;
+}
+
/// 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
@@ -984,6 +1030,9 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
continue;
}
+ if (ConsumeNullStmt(Stmts))
+ continue;
+
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
R = ParseStatementOrDeclaration(Stmts, ACK_Any);
@@ -1023,7 +1072,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// Eat the semicolon at the end of stmt and convert the expr into a
// statement.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- R = Actions.ActOnExprStmt(Res);
+ R = Actions.ActOnExprStmt(Res, isExprValueDiscarded());
}
}
@@ -1534,7 +1583,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus ||
- getLangOpts().ObjC1;
+ getLangOpts().ObjC;
// C99 6.8.5p5 - In C99, the for statement is a block. This is not
// the case for C90. Start the loop scope.
@@ -1562,11 +1611,11 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ExprResult Value;
- bool ForEach = false, ForRange = false;
+ bool ForEach = false;
StmtResult FirstPart;
Sema::ConditionResult SecondPart;
ExprResult Collection;
- ForRangeInit ForRangeInit;
+ ForRangeInfo ForRangeInfo;
FullExprArg ThirdPart(Actions);
if (Tok.is(tok::code_completion)) {
@@ -1580,10 +1629,15 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);
+ SourceLocation EmptyInitStmtSemiLoc;
+
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
ProhibitAttributes(attrs);
// no first part, eat the ';'.
+ SourceLocation SemiLoc = Tok.getLocation();
+ if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID())
+ EmptyInitStmtSemiLoc = SemiLoc;
ConsumeToken();
} else if (getLangOpts().CPlusPlus && Tok.is(tok::identifier) &&
isForRangeIdentifier()) {
@@ -1592,20 +1646,19 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
SourceLocation Loc = ConsumeToken();
MaybeParseCXX11Attributes(attrs);
- ForRangeInit.ColonLoc = ConsumeToken();
+ ForRangeInfo.ColonLoc = ConsumeToken();
if (Tok.is(tok::l_brace))
- ForRangeInit.RangeExpr = ParseBraceInitializer();
+ ForRangeInfo.RangeExpr = ParseBraceInitializer();
else
- ForRangeInit.RangeExpr = ParseExpression();
+ ForRangeInfo.RangeExpr = ParseExpression();
Diag(Loc, diag::err_for_range_identifier)
<< ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17)
? FixItHint::CreateInsertion(Loc, "auto &&")
: FixItHint());
- FirstPart = Actions.ActOnCXXForRangeIdentifier(getCurScope(), Loc, Name,
- attrs, attrs.Range.getEnd());
- ForRange = true;
+ ForRangeInfo.LoopVar = Actions.ActOnCXXForRangeIdentifier(
+ getCurScope(), Loc, Name, attrs, attrs.Range.getEnd());
} else if (isForInitDeclaration()) { // for (int X = 4;
ParenBraceBracketBalancer BalancerRAIIObj(*this);
@@ -1622,13 +1675,13 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
DeclGroupPtrTy DG = ParseSimpleDeclaration(
DeclaratorContext::ForContext, DeclEnd, attrs, false,
- MightBeForRangeStmt ? &ForRangeInit : nullptr);
+ MightBeForRangeStmt ? &ForRangeInfo : nullptr);
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
- if (ForRangeInit.ParsedForRangeDecl()) {
- Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus11 ?
+ if (ForRangeInfo.ParsedForRangeDecl()) {
+ Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
-
- ForRange = true;
+ ForRangeInfo.LoopVar = FirstPart;
+ FirstPart = StmtResult();
} else if (Tok.is(tok::semi)) { // for (int x = 4;
ConsumeToken();
} else if ((ForEach = isTokIdentifier_in())) {
@@ -1655,8 +1708,16 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (!Value.isInvalid()) {
if (ForEach)
FirstPart = Actions.ActOnForEachLValueExpr(Value.get());
- else
- FirstPart = Actions.ActOnExprStmt(Value);
+ else {
+ // We already know this is not an init-statement within a for loop, so
+ // if we are parsing a C++11 range-based for loop, we should treat this
+ // expression statement as being a discarded value expression because
+ // we will err below. This way we do not warn on an unused expression
+ // that was an error in the first place, like with: for (expr : expr);
+ bool IsRangeBasedFor =
+ getLangOpts().CPlusPlus11 && !ForEach && Tok.is(tok::colon);
+ FirstPart = Actions.ActOnExprStmt(Value, !IsRangeBasedFor);
+ }
}
if (Tok.is(tok::semi)) {
@@ -1691,17 +1752,38 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// Parse the second part of the for specifier.
getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
- if (!ForEach && !ForRange && !SecondPart.isInvalid()) {
+ if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() &&
+ !SecondPart.isInvalid()) {
// Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
} else if (Tok.is(tok::r_paren)) {
// missing both semicolons.
} else {
- if (getLangOpts().CPlusPlus)
+ if (getLangOpts().CPlusPlus) {
+ // C++2a: We've parsed an init-statement; we might have a
+ // for-range-declaration next.
+ bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl();
+ ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
SecondPart =
- ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean);
- else {
+ ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean,
+ MightBeForRangeStmt ? &ForRangeInfo : nullptr);
+
+ if (ForRangeInfo.ParsedForRangeDecl()) {
+ Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc()
+ : ForRangeInfo.ColonLoc,
+ getLangOpts().CPlusPlus2a
+ ? diag::warn_cxx17_compat_for_range_init_stmt
+ : diag::ext_for_range_init_stmt)
+ << (FirstPart.get() ? FirstPart.get()->getSourceRange()
+ : SourceRange());
+ if (EmptyInitStmtSemiLoc.isValid()) {
+ Diag(EmptyInitStmtSemiLoc, diag::warn_empty_init_statement)
+ << /*for-loop*/ 2
+ << FixItHint::CreateRemoval(EmptyInitStmtSemiLoc);
+ }
+ }
+ } else {
ExprResult SecondExpr = ParseExpression();
if (SecondExpr.isInvalid())
SecondPart = Sema::ConditionError();
@@ -1711,7 +1793,10 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
Sema::ConditionKind::Boolean);
}
}
+ }
+ // Parse the third part of the for statement.
+ if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) {
if (Tok.isNot(tok::semi)) {
if (!SecondPart.isInvalid())
Diag(Tok, diag::err_expected_semi_for);
@@ -1724,7 +1809,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
ConsumeToken();
}
- // Parse the third part of the for specifier.
if (Tok.isNot(tok::r_paren)) { // for (...;...;)
ExprResult Third = ParseExpression();
// FIXME: The C++11 standard doesn't actually say that this is a
@@ -1737,7 +1821,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// C++ Coroutines [stmt.iter]:
// 'co_await' can only be used for a range-based for statement.
- if (CoawaitLoc.isValid() && !ForRange) {
+ if (CoawaitLoc.isValid() && !ForRangeInfo.ParsedForRangeDecl()) {
Diag(CoawaitLoc, diag::err_for_co_await_not_range_for);
CoawaitLoc = SourceLocation();
}
@@ -1748,12 +1832,12 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
StmtResult ForRangeStmt;
StmtResult ForEachStmt;
- if (ForRange) {
+ if (ForRangeInfo.ParsedForRangeDecl()) {
ExprResult CorrectedRange =
- Actions.CorrectDelayedTyposInExpr(ForRangeInit.RangeExpr.get());
+ Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get());
ForRangeStmt = Actions.ActOnCXXForRangeStmt(
getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(),
- ForRangeInit.ColonLoc, CorrectedRange.get(),
+ ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, CorrectedRange.get(),
T.getCloseLocation(), Sema::BFRK_Build);
// Similarly, we need to do the semantic analysis for a for-range
@@ -1808,7 +1892,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
return Actions.FinishObjCForCollectionStmt(ForEachStmt.get(),
Body.get());
- if (ForRange)
+ if (ForRangeInfo.ParsedForRangeDecl())
return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(),
@@ -1897,10 +1981,11 @@ StmtResult Parser::ParseReturnStatement() {
if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) {
R = ParseInitializer();
if (R.isUsable())
- Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_generalized_initializer_lists :
- diag::ext_generalized_initializer_lists)
- << R.get()->getSourceRange();
+ Diag(R.get()->getBeginLoc(),
+ getLangOpts().CPlusPlus11
+ ? diag::warn_cxx98_compat_generalized_initializer_lists
+ : diag::ext_generalized_initializer_lists)
+ << R.get()->getSourceRange();
} else
R = ParseExpression();
if (R.isInvalid()) {