2006-11-05 15:46:30 +08:00
|
|
|
//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
|
2006-08-09 13:47:47 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2006-08-09 13:47:47 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Statement and Block portions of the Parser
|
|
|
|
// interface.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-03-23 08:07:18 +08:00
|
|
|
#include "clang/AST/PrettyDeclStackTrace.h"
|
2014-06-06 20:40:24 +08:00
|
|
|
#include "clang/Basic/Attributes.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Basic/PrettyStackTrace.h"
|
2018-11-28 12:36:31 +08:00
|
|
|
#include "clang/Parse/LoopHint.h"
|
2016-07-19 03:02:11 +08:00
|
|
|
#include "clang/Parse/Parser.h"
|
2017-03-23 23:11:07 +08:00
|
|
|
#include "clang/Parse/RAIIObjectsForParser.h"
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Sema/DeclSpec.h"
|
|
|
|
#include "clang/Sema/Scope.h"
|
2012-08-18 08:55:03 +08:00
|
|
|
#include "clang/Sema/TypoCorrection.h"
|
2006-08-09 13:47:47 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// C99 6.8: Statements and Blocks.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a standalone statement (for instance, as the body of an 'if',
|
2013-10-29 06:04:30 +08:00
|
|
|
/// 'while', or 'for').
|
2016-01-13 19:18:54 +08:00
|
|
|
StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc,
|
2019-02-15 08:27:53 +08:00
|
|
|
ParsedStmtContext StmtCtx) {
|
2013-10-29 06:04:30 +08:00
|
|
|
StmtResult Res;
|
|
|
|
|
|
|
|
// We may get back a null statement if we found a #pragma. Keep going until
|
|
|
|
// we get an actual statement.
|
|
|
|
do {
|
|
|
|
StmtVector Stmts;
|
2019-02-15 08:27:53 +08:00
|
|
|
Res = ParseStatementOrDeclaration(Stmts, StmtCtx, TrailingElseLoc);
|
2013-10-29 06:04:30 +08:00
|
|
|
} while (!Res.isInvalid() && !Res.get());
|
|
|
|
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2006-08-09 13:47:47 +08:00
|
|
|
/// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
|
|
|
|
/// StatementOrDeclaration:
|
|
|
|
/// statement
|
|
|
|
/// declaration
|
|
|
|
///
|
|
|
|
/// statement:
|
|
|
|
/// labeled-statement
|
|
|
|
/// compound-statement
|
|
|
|
/// expression-statement
|
|
|
|
/// selection-statement
|
|
|
|
/// iteration-statement
|
|
|
|
/// jump-statement
|
2008-09-08 02:58:01 +08:00
|
|
|
/// [C++] declaration-statement
|
2008-12-22 00:41:36 +08:00
|
|
|
/// [C++] try-block
|
2011-04-28 09:08:34 +08:00
|
|
|
/// [MS] seh-try-block
|
2007-10-05 04:19:06 +08:00
|
|
|
/// [OBC] objc-throw-statement
|
|
|
|
/// [OBC] objc-try-catch-statement
|
2008-01-30 02:21:32 +08:00
|
|
|
/// [OBC] objc-synchronized-statement
|
2006-08-15 14:03:28 +08:00
|
|
|
/// [GNU] asm-statement
|
2006-08-09 13:47:47 +08:00
|
|
|
/// [OMP] openmp-construct [TODO]
|
|
|
|
///
|
|
|
|
/// labeled-statement:
|
|
|
|
/// identifier ':' statement
|
|
|
|
/// 'case' constant-expression ':' statement
|
|
|
|
/// 'default' ':' statement
|
|
|
|
///
|
|
|
|
/// selection-statement:
|
|
|
|
/// if-statement
|
|
|
|
/// switch-statement
|
|
|
|
///
|
|
|
|
/// iteration-statement:
|
|
|
|
/// while-statement
|
|
|
|
/// do-statement
|
|
|
|
/// for-statement
|
|
|
|
///
|
2006-08-10 12:59:57 +08:00
|
|
|
/// expression-statement:
|
|
|
|
/// expression[opt] ';'
|
|
|
|
///
|
2006-08-09 13:47:47 +08:00
|
|
|
/// jump-statement:
|
|
|
|
/// 'goto' identifier ';'
|
|
|
|
/// 'continue' ';'
|
|
|
|
/// 'break' ';'
|
|
|
|
/// 'return' expression[opt] ';'
|
2006-08-10 13:45:44 +08:00
|
|
|
/// [GNU] 'goto' '*' expression ';'
|
2006-08-09 13:47:47 +08:00
|
|
|
///
|
2007-10-05 04:19:06 +08:00
|
|
|
/// [OBC] objc-throw-statement:
|
|
|
|
/// [OBC] '@' 'throw' expression ';'
|
2009-09-09 23:08:12 +08:00
|
|
|
/// [OBC] '@' 'throw' ';'
|
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult
|
2016-01-13 19:18:54 +08:00
|
|
|
Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
|
2019-02-15 08:27:53 +08:00
|
|
|
ParsedStmtContext StmtCtx,
|
2011-12-23 07:26:17 +08:00
|
|
|
SourceLocation *TrailingElseLoc) {
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2010-06-17 18:52:18 +08:00
|
|
|
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2012-04-14 08:33:13 +08:00
|
|
|
ParsedAttributesWithRange Attrs(AttrFactory);
|
2014-05-21 14:02:52 +08:00
|
|
|
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
|
2016-02-20 02:30:11 +08:00
|
|
|
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs))
|
|
|
|
return StmtError();
|
2012-04-14 08:33:13 +08:00
|
|
|
|
2016-01-13 19:18:54 +08:00
|
|
|
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
|
2019-02-15 08:27:53 +08:00
|
|
|
Stmts, StmtCtx, TrailingElseLoc, Attrs);
|
2012-04-14 08:33:13 +08:00
|
|
|
|
|
|
|
assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
|
|
|
|
"attributes on empty statement");
|
|
|
|
|
|
|
|
if (Attrs.empty() || Res.isInvalid())
|
|
|
|
return Res;
|
|
|
|
|
2018-07-13 05:09:05 +08:00
|
|
|
return Actions.ProcessStmtAttributes(Res.get(), Attrs, Attrs.Range);
|
2012-04-14 08:33:13 +08:00
|
|
|
}
|
|
|
|
|
2013-09-28 03:40:12 +08:00
|
|
|
namespace {
|
2019-03-26 01:08:51 +08:00
|
|
|
class StatementFilterCCC final : public CorrectionCandidateCallback {
|
2013-09-28 03:40:12 +08:00
|
|
|
public:
|
|
|
|
StatementFilterCCC(Token nextTok) : NextToken(nextTok) {
|
2015-06-18 18:59:26 +08:00
|
|
|
WantTypeSpecifiers = nextTok.isOneOf(tok::l_paren, tok::less, tok::l_square,
|
|
|
|
tok::identifier, tok::star, tok::amp);
|
|
|
|
WantExpressionKeywords =
|
|
|
|
nextTok.isOneOf(tok::l_paren, tok::identifier, tok::arrow, tok::period);
|
|
|
|
WantRemainingKeywords =
|
|
|
|
nextTok.isOneOf(tok::l_paren, tok::semi, tok::identifier, tok::l_brace);
|
2013-09-28 03:40:12 +08:00
|
|
|
WantCXXNamedCasts = false;
|
|
|
|
}
|
|
|
|
|
2014-03-12 13:09:18 +08:00
|
|
|
bool ValidateCandidate(const TypoCorrection &candidate) override {
|
2013-09-28 03:40:12 +08:00
|
|
|
if (FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>())
|
2013-10-02 06:00:28 +08:00
|
|
|
return !candidate.getCorrectionSpecifier() || isa<ObjCIvarDecl>(FD);
|
2013-09-28 03:40:16 +08:00
|
|
|
if (NextToken.is(tok::equal))
|
|
|
|
return candidate.getCorrectionDeclAs<VarDecl>();
|
2013-09-28 07:54:23 +08:00
|
|
|
if (NextToken.is(tok::period) &&
|
|
|
|
candidate.getCorrectionDeclAs<NamespaceDecl>())
|
|
|
|
return false;
|
2013-09-28 03:40:12 +08:00
|
|
|
return CorrectionCandidateCallback::ValidateCandidate(candidate);
|
|
|
|
}
|
|
|
|
|
2019-03-26 01:08:51 +08:00
|
|
|
std::unique_ptr<CorrectionCandidateCallback> clone() override {
|
|
|
|
return llvm::make_unique<StatementFilterCCC>(*this);
|
|
|
|
}
|
|
|
|
|
2013-09-28 03:40:12 +08:00
|
|
|
private:
|
|
|
|
Token NextToken;
|
|
|
|
};
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2013-09-28 03:40:12 +08:00
|
|
|
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
|
|
|
|
StmtVector &Stmts, ParsedStmtContext StmtCtx,
|
|
|
|
SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) {
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *SemiError = nullptr;
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Res;
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2006-08-10 13:45:44 +08:00
|
|
|
// Cases in this switch statement should fall through if the parser expects
|
|
|
|
// the token to end in a semicolon (in which case SemiError should be set),
|
|
|
|
// or they directly 'return;' if not.
|
2011-04-24 13:37:28 +08:00
|
|
|
Retry:
|
2007-09-20 03:14:32 +08:00
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
|
|
|
SourceLocation AtLoc;
|
|
|
|
switch (Kind) {
|
|
|
|
case tok::at: // May be a @try or @throw statement
|
|
|
|
{
|
2012-04-14 08:33:13 +08:00
|
|
|
ProhibitAttributes(Attrs); // TODO: is it correct?
|
2007-09-20 03:14:32 +08:00
|
|
|
AtLoc = ConsumeToken(); // consume @
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseObjCAtStatement(AtLoc, StmtCtx);
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
|
2009-09-22 04:51:25 +08:00
|
|
|
case tok::code_completion:
|
2010-08-27 07:41:50 +08:00
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return StmtError();
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-04-24 13:37:28 +08:00
|
|
|
case tok::identifier: {
|
|
|
|
Token Next = NextToken();
|
|
|
|
if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
|
2008-07-13 05:04:42 +08:00
|
|
|
// identifier ':' statement
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseLabeledStatement(Attrs, StmtCtx);
|
2008-07-13 05:04:42 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2012-08-18 08:55:03 +08:00
|
|
|
// Look up the identifier, and typo-correct it to a keyword if it's not
|
|
|
|
// found.
|
2011-04-27 12:48:22 +08:00
|
|
|
if (Next.isNot(tok::coloncolon)) {
|
2012-08-18 08:55:03 +08:00
|
|
|
// Try to limit which sets of keywords should be included in typo
|
|
|
|
// correction based on what the next token is.
|
2019-03-26 01:08:51 +08:00
|
|
|
StatementFilterCCC CCC(Next);
|
|
|
|
if (TryAnnotateName(/*IsAddressOfOperand*/ false, &CCC) == ANK_Error) {
|
2011-04-24 13:37:28 +08:00
|
|
|
// Handle errors here by skipping up to the next semicolon or '}', and
|
|
|
|
// eat the semicolon if that's what stopped us.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2011-04-24 13:37:28 +08:00
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
|
|
|
return StmtError();
|
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2012-08-18 08:55:03 +08:00
|
|
|
// If the identifier was typo-corrected, try again.
|
|
|
|
if (Tok.isNot(tok::identifier))
|
|
|
|
goto Retry;
|
2011-04-24 13:37:28 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-04-24 13:37:28 +08:00
|
|
|
// Fall through
|
2017-06-02 05:28:26 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2011-04-24 13:37:28 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2009-03-25 01:04:48 +08:00
|
|
|
default: {
|
2016-08-02 00:39:29 +08:00
|
|
|
if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
|
2019-02-15 08:27:53 +08:00
|
|
|
(StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
|
|
|
|
ParsedStmtContext()) &&
|
2016-01-13 19:18:54 +08:00
|
|
|
isDeclarationStatement()) {
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
2017-12-29 13:41:00 +08:00
|
|
|
DeclGroupPtrTy Decl = ParseDeclaration(DeclaratorContext::BlockContext,
|
2012-04-14 08:33:13 +08:00
|
|
|
DeclEnd, Attrs);
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
|
2009-03-25 01:04:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Tok.is(tok::r_brace)) {
|
2006-08-11 02:26:31 +08:00
|
|
|
Diag(Tok, diag::err_expected_statement);
|
2008-12-12 03:30:53 +08:00
|
|
|
return StmtError();
|
2006-08-11 02:26:31 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseExprStatement(StmtCtx);
|
2009-03-25 01:04:48 +08:00
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2006-08-10 13:59:48 +08:00
|
|
|
case tok::kw_case: // C99 6.8.1: labeled-statement
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseCaseStatement(StmtCtx);
|
2006-08-10 13:59:48 +08:00
|
|
|
case tok::kw_default: // C99 6.8.1: labeled-statement
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseDefaultStatement(StmtCtx);
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
case tok::l_brace: // C99 6.8.2: compound-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
return ParseCompoundStatement();
|
2010-11-20 10:04:01 +08:00
|
|
|
case tok::semi: { // C99 6.8.3p3: expression[opt] ';'
|
2011-09-02 05:53:45 +08:00
|
|
|
bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
|
|
|
|
return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro);
|
2010-11-20 10:04:01 +08:00
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
case tok::kw_if: // C99 6.8.4.1: if-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
return ParseIfStatement(TrailingElseLoc);
|
2006-08-10 12:59:57 +08:00
|
|
|
case tok::kw_switch: // C99 6.8.4.2: switch-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
return ParseSwitchStatement(TrailingElseLoc);
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
case tok::kw_while: // C99 6.8.5.1: while-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
return ParseWhileStatement(TrailingElseLoc);
|
2006-08-10 12:59:57 +08:00
|
|
|
case tok::kw_do: // C99 6.8.5.2: do-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
Res = ParseDoStatement();
|
2009-06-14 08:07:48 +08:00
|
|
|
SemiError = "do/while";
|
2006-08-10 12:59:57 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_for: // C99 6.8.5.3: for-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
return ParseForStatement(TrailingElseLoc);
|
2006-08-10 13:45:44 +08:00
|
|
|
|
|
|
|
case tok::kw_goto: // C99 6.8.6.1: goto-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
Res = ParseGotoStatement();
|
2009-06-14 08:07:48 +08:00
|
|
|
SemiError = "goto";
|
2006-08-10 13:45:44 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_continue: // C99 6.8.6.2: continue-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
Res = ParseContinueStatement();
|
2009-06-14 08:07:48 +08:00
|
|
|
SemiError = "continue";
|
2006-08-10 12:59:57 +08:00
|
|
|
break;
|
2006-08-10 13:45:44 +08:00
|
|
|
case tok::kw_break: // C99 6.8.6.3: break-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
Res = ParseBreakStatement();
|
2009-06-14 08:07:48 +08:00
|
|
|
SemiError = "break";
|
2006-08-10 13:45:44 +08:00
|
|
|
break;
|
|
|
|
case tok::kw_return: // C99 6.8.6.4: return-statement
|
2012-04-14 08:33:13 +08:00
|
|
|
Res = ParseReturnStatement();
|
2009-06-14 08:07:48 +08:00
|
|
|
SemiError = "return";
|
2006-08-10 13:45:44 +08:00
|
|
|
break;
|
2015-10-22 12:46:14 +08:00
|
|
|
case tok::kw_co_return: // C++ Coroutines: co_return statement
|
|
|
|
Res = ParseReturnStatement();
|
|
|
|
SemiError = "co_return";
|
|
|
|
break;
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2008-12-22 00:41:36 +08:00
|
|
|
case tok::kw_asm: {
|
2012-04-14 08:33:13 +08:00
|
|
|
ProhibitAttributes(Attrs);
|
2008-02-07 11:50:06 +08:00
|
|
|
bool msAsm = false;
|
|
|
|
Res = ParseAsmStatement(msAsm);
|
2010-11-02 10:33:08 +08:00
|
|
|
Res = Actions.ActOnFinishFullStmt(Res.get());
|
2012-08-24 05:35:17 +08:00
|
|
|
if (msAsm) return Res;
|
2009-06-14 08:07:48 +08:00
|
|
|
SemiError = "asm";
|
2006-08-15 14:03:28 +08:00
|
|
|
break;
|
2006-08-09 13:47:47 +08:00
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2014-06-25 08:28:35 +08:00
|
|
|
case tok::kw___if_exists:
|
|
|
|
case tok::kw___if_not_exists:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
ParseMicrosoftIfExistsStatement(Stmts);
|
|
|
|
// An __if_exists block is like a compound statement, but it doesn't create
|
|
|
|
// a new scope.
|
|
|
|
return StmtEmpty();
|
|
|
|
|
2008-12-22 00:41:36 +08:00
|
|
|
case tok::kw_try: // C++ 15: try-block
|
2012-04-14 08:33:13 +08:00
|
|
|
return ParseCXXTryBlock();
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
case tok::kw___try:
|
2012-04-14 08:33:13 +08:00
|
|
|
ProhibitAttributes(Attrs); // TODO: is it correct?
|
|
|
|
return ParseSEHTryBlock();
|
2012-02-24 07:47:16 +08:00
|
|
|
|
2014-07-07 06:32:59 +08:00
|
|
|
case tok::kw___leave:
|
|
|
|
Res = ParseSEHLeaveStatement();
|
|
|
|
SemiError = "__leave";
|
|
|
|
break;
|
|
|
|
|
2012-02-24 07:47:16 +08:00
|
|
|
case tok::annot_pragma_vis:
|
2012-04-14 08:33:13 +08:00
|
|
|
ProhibitAttributes(Attrs);
|
2012-02-24 07:47:16 +08:00
|
|
|
HandlePragmaVisibility();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
|
|
|
case tok::annot_pragma_pack:
|
2012-04-14 08:33:13 +08:00
|
|
|
ProhibitAttributes(Attrs);
|
2012-02-24 07:47:16 +08:00
|
|
|
HandlePragmaPack();
|
|
|
|
return StmtEmpty();
|
2012-10-04 10:36:51 +08:00
|
|
|
|
2012-10-10 06:46:54 +08:00
|
|
|
case tok::annot_pragma_msstruct:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaMSStruct();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
2012-10-09 07:52:38 +08:00
|
|
|
case tok::annot_pragma_align:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaAlign();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
2012-10-10 06:46:54 +08:00
|
|
|
case tok::annot_pragma_weak:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaWeak();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
|
|
|
case tok::annot_pragma_weakalias:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaWeakAlias();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
|
|
|
case tok::annot_pragma_redefine_extname:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaRedefineExtname();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
2012-10-04 10:36:51 +08:00
|
|
|
case tok::annot_pragma_fp_contract:
|
2013-11-16 05:10:54 +08:00
|
|
|
ProhibitAttributes(Attrs);
|
2012-10-21 09:10:01 +08:00
|
|
|
Diag(Tok, diag::err_pragma_fp_contract_scope);
|
2017-05-19 03:21:48 +08:00
|
|
|
ConsumeAnnotationToken();
|
2012-10-21 09:10:01 +08:00
|
|
|
return StmtError();
|
|
|
|
|
2017-04-05 05:18:36 +08:00
|
|
|
case tok::annot_pragma_fp:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
Diag(Tok, diag::err_pragma_fp_scope);
|
2017-05-19 03:21:48 +08:00
|
|
|
ConsumeAnnotationToken();
|
2017-04-05 05:18:36 +08:00
|
|
|
return StmtError();
|
|
|
|
|
2018-08-15 01:06:56 +08:00
|
|
|
case tok::annot_pragma_fenv_access:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaFEnvAccess();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
2012-10-04 10:36:51 +08:00
|
|
|
case tok::annot_pragma_opencl_extension:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaOpenCLExtension();
|
|
|
|
return StmtEmpty();
|
2013-03-22 14:34:35 +08:00
|
|
|
|
2013-04-17 02:41:26 +08:00
|
|
|
case tok::annot_pragma_captured:
|
2013-09-17 05:17:44 +08:00
|
|
|
ProhibitAttributes(Attrs);
|
2013-04-17 02:41:26 +08:00
|
|
|
return HandlePragmaCaptured();
|
|
|
|
|
2013-03-22 14:34:35 +08:00
|
|
|
case tok::annot_pragma_openmp:
|
2013-09-17 05:17:44 +08:00
|
|
|
ProhibitAttributes(Attrs);
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);
|
2013-07-19 11:13:43 +08:00
|
|
|
|
2014-02-11 03:50:15 +08:00
|
|
|
case tok::annot_pragma_ms_pointers_to_members:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaMSPointersToMembers();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
2014-04-09 06:30:47 +08:00
|
|
|
case tok::annot_pragma_ms_pragma:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaMSPragma();
|
|
|
|
return StmtEmpty();
|
2014-06-06 20:40:24 +08:00
|
|
|
|
2015-11-20 15:02:57 +08:00
|
|
|
case tok::annot_pragma_ms_vtordisp:
|
|
|
|
ProhibitAttributes(Attrs);
|
|
|
|
HandlePragmaMSVtorDisp();
|
|
|
|
return StmtEmpty();
|
|
|
|
|
2014-06-06 20:40:24 +08:00
|
|
|
case tok::annot_pragma_loop_hint:
|
|
|
|
ProhibitAttributes(Attrs);
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs);
|
2016-01-13 05:59:26 +08:00
|
|
|
|
|
|
|
case tok::annot_pragma_dump:
|
|
|
|
HandlePragmaDump();
|
2017-04-18 22:33:39 +08:00
|
|
|
return StmtEmpty();
|
|
|
|
|
|
|
|
case tok::annot_pragma_attribute:
|
|
|
|
HandlePragmaAttribute();
|
2016-01-13 05:59:26 +08:00
|
|
|
return StmtEmpty();
|
2008-12-22 00:41:36 +08:00
|
|
|
}
|
|
|
|
|
2006-08-10 13:45:44 +08:00
|
|
|
// If we reached this code, the statement must end in a semicolon.
|
2014-01-10 19:19:30 +08:00
|
|
|
if (!TryConsumeToken(tok::semi) && !Res.isInvalid()) {
|
2009-06-14 08:23:56 +08:00
|
|
|
// If the result was valid, then we do want to diagnose this. Use
|
|
|
|
// ExpectAndConsume to emit the diagnostic, even though we know it won't
|
|
|
|
// succeed.
|
|
|
|
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_stmt, SemiError);
|
2008-11-14 02:52:53 +08:00
|
|
|
// Skip until we see a } or ;, but don't eat it.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2006-08-10 13:45:44 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2006-08-09 13:47:47 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse an expression statement.
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) {
|
2011-04-24 13:37:28 +08:00
|
|
|
// If a case keyword is missing, this is where it should be inserted.
|
|
|
|
Token OldToken = Tok;
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2016-10-18 18:55:01 +08:00
|
|
|
ExprStatementTokLoc = Tok.getLocation();
|
|
|
|
|
2011-04-24 13:37:28 +08:00
|
|
|
// expression[opt] ';'
|
2011-04-27 14:18:01 +08:00
|
|
|
ExprResult Expr(ParseExpression());
|
2011-04-24 13:37:28 +08:00
|
|
|
if (Expr.isInvalid()) {
|
|
|
|
// If the expression is invalid, skip ahead to the next semicolon or '}'.
|
|
|
|
// Not doing this opens us up to the possibility of infinite loops if
|
|
|
|
// ParseExpression does not consume any tokens.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2011-04-24 13:37:28 +08:00
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
2013-03-22 10:10:40 +08:00
|
|
|
return Actions.ActOnExprStmtError();
|
2011-04-24 13:37:28 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-04-24 13:37:28 +08:00
|
|
|
if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
|
|
|
|
Actions.CheckCaseExpression(Expr.get())) {
|
|
|
|
// If a constant expression is followed by a colon inside a switch block,
|
|
|
|
// suggest a missing case keyword.
|
|
|
|
Diag(OldToken, diag::err_expected_case_before_expression)
|
|
|
|
<< FixItHint::CreateInsertion(OldToken.getLocation(), "case ");
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-04-24 13:37:28 +08:00
|
|
|
// Recover parsing as a case statement.
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseCaseStatement(StmtCtx, /*MissingCase=*/true, Expr);
|
2011-04-24 13:37:28 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-04-24 13:37:28 +08:00
|
|
|
// Otherwise, eat the semicolon.
|
|
|
|
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
|
2019-02-15 08:27:53 +08:00
|
|
|
return handleExprStmt(Expr, StmtCtx);
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
2011-04-24 13:37:28 +08:00
|
|
|
|
2011-04-28 09:08:34 +08:00
|
|
|
/// ParseSEHTryBlockCommon
|
|
|
|
///
|
|
|
|
/// seh-try-block:
|
|
|
|
/// '__try' compound-statement seh-handler
|
|
|
|
///
|
|
|
|
/// seh-handler:
|
|
|
|
/// seh-except-block
|
|
|
|
/// seh-finally-block
|
|
|
|
///
|
2015-02-25 09:43:27 +08:00
|
|
|
StmtResult Parser::ParseSEHTryBlock() {
|
|
|
|
assert(Tok.is(tok::kw___try) && "Expected '__try'");
|
|
|
|
SourceLocation TryLoc = ConsumeToken();
|
|
|
|
|
2015-02-25 10:22:06 +08:00
|
|
|
if (Tok.isNot(tok::l_brace))
|
2013-12-24 17:48:30 +08:00
|
|
|
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
|
2011-04-28 09:08:34 +08:00
|
|
|
|
2017-08-10 23:43:06 +08:00
|
|
|
StmtResult TryBlock(ParseCompoundStatement(
|
|
|
|
/*isStmtExpr=*/false,
|
|
|
|
Scope::DeclScope | Scope::CompoundStmtScope | Scope::SEHTryScope));
|
|
|
|
if (TryBlock.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return TryBlock;
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
StmtResult Handler;
|
2012-04-14 08:33:13 +08:00
|
|
|
if (Tok.is(tok::identifier) &&
|
2011-10-21 11:57:52 +08:00
|
|
|
Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
|
2011-04-28 09:08:34 +08:00
|
|
|
SourceLocation Loc = ConsumeToken();
|
|
|
|
Handler = ParseSEHExceptBlock(Loc);
|
|
|
|
} else if (Tok.is(tok::kw___finally)) {
|
|
|
|
SourceLocation Loc = ConsumeToken();
|
|
|
|
Handler = ParseSEHFinallyBlock(Loc);
|
|
|
|
} else {
|
2015-02-25 10:22:06 +08:00
|
|
|
return StmtError(Diag(Tok, diag::err_seh_expected_handler));
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if(Handler.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Handler;
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
|
|
|
|
TryLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
TryBlock.get(),
|
2014-07-26 04:52:51 +08:00
|
|
|
Handler.get());
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseSEHExceptBlock - Handle __except
|
|
|
|
///
|
|
|
|
/// seh-except-block:
|
|
|
|
/// '__except' '(' seh-filter-expression ')' compound-statement
|
|
|
|
///
|
|
|
|
StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
|
|
|
|
PoisonIdentifierRAIIObject raii(Ident__exception_code, false),
|
|
|
|
raii2(Ident___exception_code, false),
|
|
|
|
raii3(Ident_GetExceptionCode, false);
|
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::l_paren))
|
2011-04-28 09:08:34 +08:00
|
|
|
return StmtError();
|
|
|
|
|
Initial support for Win64 SEH IR emission
The lowering looks a lot like normal EH lowering, with the exception
that the exceptions are caught by executing filter expression code
instead of matching typeinfo globals. The filter expressions are
outlined into functions which are used in landingpad clauses where
typeinfo would normally go.
Major aspects that still need work:
- Non-call exceptions in __try bodies won't work yet. The plan is to
outline the __try block in the frontend to keep things simple.
- Filter expressions cannot use local variables until capturing is
implemented.
- __finally blocks will not run after exceptions. Fixing this requires
work in the LLVM SEH preparation pass.
The IR lowering looks like this:
// C code:
bool safe_div(int n, int d, int *r) {
__try {
*r = normal_div(n, d);
} __except(_exception_code() == EXCEPTION_INT_DIVIDE_BY_ZERO) {
return false;
}
return true;
}
; LLVM IR:
define i32 @filter(i8* %e, i8* %fp) {
%ehptrs = bitcast i8* %e to i32**
%ehrec = load i32** %ehptrs
%code = load i32* %ehrec
%matches = icmp eq i32 %code, i32 u0xC0000094
%matches.i32 = zext i1 %matches to i32
ret i32 %matches.i32
}
define i1 zeroext @safe_div(i32 %n, i32 %d, i32* %r) {
%rr = invoke i32 @normal_div(i32 %n, i32 %d)
to label %normal unwind to label %lpad
normal:
store i32 %rr, i32* %r
ret i1 1
lpad:
%ehvals = landingpad {i8*, i32} personality i32 (...)* @__C_specific_handler
catch i8* bitcast (i32 (i8*, i8*)* @filter to i8*)
%ehptr = extractvalue {i8*, i32} %ehvals, i32 0
%sel = extractvalue {i8*, i32} %ehvals, i32 1
%filter_sel = call i32 @llvm.eh.seh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filter to i8*))
%matches = icmp eq i32 %sel, %filter_sel
br i1 %matches, label %eh.except, label %eh.resume
eh.except:
ret i1 false
eh.resume:
resume
}
Reviewers: rjmccall, rsmith, majnemer
Differential Revision: http://reviews.llvm.org/D5607
llvm-svn: 226760
2015-01-22 09:36:17 +08:00
|
|
|
ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope |
|
|
|
|
Scope::SEHExceptScope);
|
2011-04-28 09:08:34 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().Borland) {
|
2011-04-28 11:14:31 +08:00
|
|
|
Ident__exception_info->setIsPoisoned(false);
|
|
|
|
Ident___exception_info->setIsPoisoned(false);
|
|
|
|
Ident_GetExceptionInfo->setIsPoisoned(false);
|
|
|
|
}
|
Initial support for Win64 SEH IR emission
The lowering looks a lot like normal EH lowering, with the exception
that the exceptions are caught by executing filter expression code
instead of matching typeinfo globals. The filter expressions are
outlined into functions which are used in landingpad clauses where
typeinfo would normally go.
Major aspects that still need work:
- Non-call exceptions in __try bodies won't work yet. The plan is to
outline the __try block in the frontend to keep things simple.
- Filter expressions cannot use local variables until capturing is
implemented.
- __finally blocks will not run after exceptions. Fixing this requires
work in the LLVM SEH preparation pass.
The IR lowering looks like this:
// C code:
bool safe_div(int n, int d, int *r) {
__try {
*r = normal_div(n, d);
} __except(_exception_code() == EXCEPTION_INT_DIVIDE_BY_ZERO) {
return false;
}
return true;
}
; LLVM IR:
define i32 @filter(i8* %e, i8* %fp) {
%ehptrs = bitcast i8* %e to i32**
%ehrec = load i32** %ehptrs
%code = load i32* %ehrec
%matches = icmp eq i32 %code, i32 u0xC0000094
%matches.i32 = zext i1 %matches to i32
ret i32 %matches.i32
}
define i1 zeroext @safe_div(i32 %n, i32 %d, i32* %r) {
%rr = invoke i32 @normal_div(i32 %n, i32 %d)
to label %normal unwind to label %lpad
normal:
store i32 %rr, i32* %r
ret i1 1
lpad:
%ehvals = landingpad {i8*, i32} personality i32 (...)* @__C_specific_handler
catch i8* bitcast (i32 (i8*, i8*)* @filter to i8*)
%ehptr = extractvalue {i8*, i32} %ehvals, i32 0
%sel = extractvalue {i8*, i32} %ehvals, i32 1
%filter_sel = call i32 @llvm.eh.seh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filter to i8*))
%matches = icmp eq i32 %sel, %filter_sel
br i1 %matches, label %eh.except, label %eh.resume
eh.except:
ret i1 false
eh.resume:
resume
}
Reviewers: rjmccall, rsmith, majnemer
Differential Revision: http://reviews.llvm.org/D5607
llvm-svn: 226760
2015-01-22 09:36:17 +08:00
|
|
|
|
|
|
|
ExprResult FilterExpr;
|
|
|
|
{
|
|
|
|
ParseScopeFlags FilterScope(this, getCurScope()->getFlags() |
|
|
|
|
Scope::SEHFilterScope);
|
2015-04-03 06:09:32 +08:00
|
|
|
FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
Initial support for Win64 SEH IR emission
The lowering looks a lot like normal EH lowering, with the exception
that the exceptions are caught by executing filter expression code
instead of matching typeinfo globals. The filter expressions are
outlined into functions which are used in landingpad clauses where
typeinfo would normally go.
Major aspects that still need work:
- Non-call exceptions in __try bodies won't work yet. The plan is to
outline the __try block in the frontend to keep things simple.
- Filter expressions cannot use local variables until capturing is
implemented.
- __finally blocks will not run after exceptions. Fixing this requires
work in the LLVM SEH preparation pass.
The IR lowering looks like this:
// C code:
bool safe_div(int n, int d, int *r) {
__try {
*r = normal_div(n, d);
} __except(_exception_code() == EXCEPTION_INT_DIVIDE_BY_ZERO) {
return false;
}
return true;
}
; LLVM IR:
define i32 @filter(i8* %e, i8* %fp) {
%ehptrs = bitcast i8* %e to i32**
%ehrec = load i32** %ehptrs
%code = load i32* %ehrec
%matches = icmp eq i32 %code, i32 u0xC0000094
%matches.i32 = zext i1 %matches to i32
ret i32 %matches.i32
}
define i1 zeroext @safe_div(i32 %n, i32 %d, i32* %r) {
%rr = invoke i32 @normal_div(i32 %n, i32 %d)
to label %normal unwind to label %lpad
normal:
store i32 %rr, i32* %r
ret i1 1
lpad:
%ehvals = landingpad {i8*, i32} personality i32 (...)* @__C_specific_handler
catch i8* bitcast (i32 (i8*, i8*)* @filter to i8*)
%ehptr = extractvalue {i8*, i32} %ehvals, i32 0
%sel = extractvalue {i8*, i32} %ehvals, i32 1
%filter_sel = call i32 @llvm.eh.seh.typeid.for(i8* bitcast (i32 (i8*, i8*)* @filter to i8*))
%matches = icmp eq i32 %sel, %filter_sel
br i1 %matches, label %eh.except, label %eh.resume
eh.except:
ret i1 false
eh.resume:
resume
}
Reviewers: rjmccall, rsmith, majnemer
Differential Revision: http://reviews.llvm.org/D5607
llvm-svn: 226760
2015-01-22 09:36:17 +08:00
|
|
|
}
|
2011-04-28 11:14:31 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().Borland) {
|
2011-04-28 11:14:31 +08:00
|
|
|
Ident__exception_info->setIsPoisoned(true);
|
|
|
|
Ident___exception_info->setIsPoisoned(true);
|
|
|
|
Ident_GetExceptionInfo->setIsPoisoned(true);
|
|
|
|
}
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
if(FilterExpr.isInvalid())
|
|
|
|
return StmtError();
|
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::r_paren))
|
2011-04-28 09:08:34 +08:00
|
|
|
return StmtError();
|
|
|
|
|
2015-02-25 10:22:06 +08:00
|
|
|
if (Tok.isNot(tok::l_brace))
|
|
|
|
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
|
|
|
|
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Block(ParseCompoundStatement());
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
if(Block.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Block;
|
2011-04-28 09:08:34 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.get(), Block.get());
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseSEHFinallyBlock - Handle __finally
|
|
|
|
///
|
|
|
|
/// seh-finally-block:
|
|
|
|
/// '__finally' compound-statement
|
|
|
|
///
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) {
|
2011-04-28 09:08:34 +08:00
|
|
|
PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false),
|
|
|
|
raii2(Ident___abnormal_termination, false),
|
|
|
|
raii3(Ident_AbnormalTermination, false);
|
|
|
|
|
2015-02-25 10:22:06 +08:00
|
|
|
if (Tok.isNot(tok::l_brace))
|
|
|
|
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
|
|
|
|
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
ParseScope FinallyScope(this, 0);
|
|
|
|
Actions.ActOnStartSEHFinallyBlock();
|
|
|
|
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Block(ParseCompoundStatement());
|
2015-03-09 11:17:15 +08:00
|
|
|
if(Block.isInvalid()) {
|
|
|
|
Actions.ActOnAbortSEHFinallyBlock();
|
2012-08-24 05:35:17 +08:00
|
|
|
return Block;
|
2015-03-09 11:17:15 +08:00
|
|
|
}
|
2011-04-28 09:08:34 +08:00
|
|
|
|
Warn when jumping out of a __finally block via continue, break, return, __leave.
Since continue, break, return are much more common than __finally, this tries
to keep the work for continue, break, return O(1). Sema keeps a stack of active
__finally scopes (to do this, ActOnSEHFinally() is split into
ActOnStartSEHFinally() and ActOnFinishSEHFinally()), and the various jump
statements then check if the current __finally scope (if present) is deeper
than then destination scope of the jump.
The same warning for goto statements is still missing.
This is the moral equivalent of MSVC's C4532.
llvm-svn: 231623
2015-03-09 10:47:59 +08:00
|
|
|
return Actions.ActOnFinishSEHFinallyBlock(FinallyLoc, Block.get());
|
2011-04-24 13:37:28 +08:00
|
|
|
}
|
|
|
|
|
2014-07-07 06:32:59 +08:00
|
|
|
/// Handle __leave
|
|
|
|
///
|
|
|
|
/// seh-leave-statement:
|
|
|
|
/// '__leave' ';'
|
|
|
|
///
|
|
|
|
StmtResult Parser::ParseSEHLeaveStatement() {
|
|
|
|
SourceLocation LeaveLoc = ConsumeToken(); // eat the '__leave'.
|
|
|
|
return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope());
|
|
|
|
}
|
|
|
|
|
2008-07-10 06:53:07 +08:00
|
|
|
/// ParseLabeledStatement - We have an identifier and a ':' after it.
|
2006-08-11 02:31:37 +08:00
|
|
|
///
|
|
|
|
/// labeled-statement:
|
|
|
|
/// identifier ':' statement
|
2006-08-15 12:50:22 +08:00
|
|
|
/// [GNU] identifier ':' attributes[opt] statement
|
2006-08-11 02:31:37 +08:00
|
|
|
///
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs,
|
|
|
|
ParsedStmtContext StmtCtx) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
|
2006-11-06 02:39:59 +08:00
|
|
|
"Not an identifier!");
|
2006-08-11 02:31:37 +08:00
|
|
|
|
2019-02-15 08:27:53 +08:00
|
|
|
// The substatement is always a 'statement', not a 'declaration', but is
|
|
|
|
// otherwise in the same context as the labeled-statement.
|
|
|
|
StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
|
|
|
|
|
2007-07-21 00:59:19 +08:00
|
|
|
Token IdentTok = Tok; // Save the whole token.
|
2006-08-11 02:31:37 +08:00
|
|
|
ConsumeToken(); // eat the identifier.
|
2008-07-10 06:53:07 +08:00
|
|
|
|
|
|
|
assert(Tok.is(tok::colon) && "Not a label!");
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2006-08-11 02:31:37 +08:00
|
|
|
// identifier ':' statement
|
2008-07-10 06:53:07 +08:00
|
|
|
SourceLocation ColonLoc = ConsumeToken();
|
2006-08-15 12:50:22 +08:00
|
|
|
|
2013-11-16 06:45:29 +08:00
|
|
|
// Read label attributes, if present.
|
|
|
|
StmtResult SubStmt;
|
|
|
|
if (Tok.is(tok::kw___attribute)) {
|
|
|
|
ParsedAttributesWithRange TempAttrs(AttrFactory);
|
|
|
|
ParseGNUAttributes(TempAttrs);
|
|
|
|
|
|
|
|
// In C++, GNU attributes only apply to the label if they are followed by a
|
|
|
|
// semicolon, to disambiguate label attributes from attributes on a labeled
|
|
|
|
// declaration.
|
|
|
|
//
|
|
|
|
// This doesn't quite match what GCC does; if the attribute list is empty
|
|
|
|
// and followed by a semicolon, GCC will reject (it appears to parse the
|
|
|
|
// attributes as part of a statement in that case). That looks like a bug.
|
|
|
|
if (!getLangOpts().CPlusPlus || Tok.is(tok::semi))
|
|
|
|
attrs.takeAllFrom(TempAttrs);
|
|
|
|
else if (isDeclarationStatement()) {
|
|
|
|
StmtVector Stmts;
|
|
|
|
// FIXME: We should do this whether or not we have a declaration
|
|
|
|
// statement, but that doesn't work correctly (because ProhibitAttributes
|
|
|
|
// can't handle GNU attributes), so only call it in the one case where
|
|
|
|
// GNU attributes are allowed.
|
2019-02-15 08:27:53 +08:00
|
|
|
SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx,
|
|
|
|
nullptr, TempAttrs);
|
2013-11-16 06:45:29 +08:00
|
|
|
if (!TempAttrs.empty() && !SubStmt.isInvalid())
|
2018-07-13 05:09:05 +08:00
|
|
|
SubStmt = Actions.ProcessStmtAttributes(SubStmt.get(), TempAttrs,
|
|
|
|
TempAttrs.Range);
|
2013-11-16 06:45:29 +08:00
|
|
|
} else {
|
2014-01-01 11:08:43 +08:00
|
|
|
Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi;
|
2013-11-16 06:45:29 +08:00
|
|
|
}
|
|
|
|
}
|
2006-08-15 12:50:22 +08:00
|
|
|
|
2013-11-16 06:45:29 +08:00
|
|
|
// If we've not parsed a statement yet, parse one now.
|
|
|
|
if (!SubStmt.isInvalid() && !SubStmt.isUsable())
|
2019-02-15 08:27:53 +08:00
|
|
|
SubStmt = ParseStatement(nullptr, StmtCtx);
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2008-07-10 06:53:07 +08:00
|
|
|
// Broken substmt shouldn't prevent the label from being added to the AST.
|
2008-12-09 21:15:23 +08:00
|
|
|
if (SubStmt.isInvalid())
|
2008-07-10 06:53:07 +08:00
|
|
|
SubStmt = Actions.ActOnNullStmt(ColonLoc);
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-02-18 09:27:55 +08:00
|
|
|
LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(),
|
|
|
|
IdentTok.getLocation());
|
2018-07-13 05:09:05 +08:00
|
|
|
Actions.ProcessDeclAttributeList(Actions.CurScope, LD, attrs);
|
|
|
|
attrs.clear();
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-02-18 09:27:55 +08:00
|
|
|
return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc,
|
|
|
|
SubStmt.get());
|
2008-07-10 06:53:07 +08:00
|
|
|
}
|
2006-08-11 02:26:31 +08:00
|
|
|
|
2006-08-10 13:59:48 +08:00
|
|
|
/// ParseCaseStatement
|
|
|
|
/// labeled-statement:
|
|
|
|
/// 'case' constant-expression ':' statement
|
2006-08-14 06:09:58 +08:00
|
|
|
/// [GNU] 'case' constant-expression '...' constant-expression ':' statement
|
2006-08-14 05:54:02 +08:00
|
|
|
///
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
|
|
|
|
bool MissingCase, ExprResult Expr) {
|
2011-04-22 06:48:40 +08:00
|
|
|
assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2019-02-15 08:27:53 +08:00
|
|
|
// The substatement is always a 'statement', not a 'declaration', but is
|
|
|
|
// otherwise in the same context as the labeled-statement.
|
|
|
|
StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
|
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// It is very very common for code to contain many case statements recursively
|
|
|
|
// nested, as in (but usually without indentation):
|
|
|
|
// case 1:
|
|
|
|
// case 2:
|
|
|
|
// case 3:
|
|
|
|
// case 4:
|
|
|
|
// case 5: etc.
|
|
|
|
//
|
|
|
|
// Parsing this naively works, but is both inefficient and can cause us to run
|
|
|
|
// out of stack space in our recursive descent parser. As a special case,
|
2009-03-05 02:24:58 +08:00
|
|
|
// flatten this recursion into an iterative loop. This is complex and gross,
|
2009-03-04 12:23:07 +08:00
|
|
|
// but all the grossness is constrained to ParseCaseStatement (and some
|
2013-11-16 06:45:29 +08:00
|
|
|
// weirdness in the actions), so this is just local grossness :).
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// TopLevelCase - This is the highest level we have parsed. 'case 1' in the
|
|
|
|
// example above.
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult TopLevelCase(true);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// DeepestParsedCaseStmt - This is the deepest statement we have parsed, which
|
|
|
|
// gets updated each time a new case is parsed, and whose body is unset so
|
|
|
|
// far. When parsing 'case 4', this is the 'case 3' node.
|
2014-05-21 14:02:52 +08:00
|
|
|
Stmt *DeepestParsedCaseStmt = nullptr;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// While we have case statements, eat and stack them.
|
2011-06-13 13:50:12 +08:00
|
|
|
SourceLocation ColonLoc;
|
2009-03-04 12:23:07 +08:00
|
|
|
do {
|
2011-04-22 05:44:26 +08:00
|
|
|
SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() :
|
|
|
|
ConsumeToken(); // eat the 'case'.
|
2014-05-21 22:48:43 +08:00
|
|
|
ColonLoc = SourceLocation();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-09-22 02:10:23 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.CodeCompleteCase(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return StmtError();
|
2009-09-22 02:10:23 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2009-12-10 08:38:54 +08:00
|
|
|
/// We don't want to treat 'case x : y' as a potential typo for 'case x::y'.
|
|
|
|
/// Disable this form of error recovery while we're parsing the case
|
|
|
|
/// expression.
|
|
|
|
ColonProtectionRAIIObject ColonProtection(*this);
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2014-05-21 22:48:43 +08:00
|
|
|
ExprResult LHS;
|
|
|
|
if (!MissingCase) {
|
2018-07-27 02:41:30 +08:00
|
|
|
LHS = ParseCaseExpression(CaseLoc);
|
2014-05-21 22:48:43 +08:00
|
|
|
if (LHS.isInvalid()) {
|
|
|
|
// If constant-expression is parsed unsuccessfully, recover by skipping
|
|
|
|
// current case statement (moving to the colon that ends it).
|
2018-07-27 02:41:30 +08:00
|
|
|
if (!SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch))
|
|
|
|
return StmtError();
|
2014-05-21 22:48:43 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
LHS = Expr;
|
|
|
|
MissingCase = false;
|
2009-03-04 12:23:07 +08:00
|
|
|
}
|
2006-08-10 13:59:48 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// GNU case range extension.
|
|
|
|
SourceLocation DotDotDotLoc;
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult RHS;
|
2013-12-24 17:48:30 +08:00
|
|
|
if (TryConsumeToken(tok::ellipsis, DotDotDotLoc)) {
|
|
|
|
Diag(DotDotDotLoc, diag::ext_gnu_case_range);
|
2018-07-27 02:41:30 +08:00
|
|
|
RHS = ParseCaseExpression(CaseLoc);
|
2009-03-04 12:23:07 +08:00
|
|
|
if (RHS.isInvalid()) {
|
2018-07-27 02:41:30 +08:00
|
|
|
if (!SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch))
|
|
|
|
return StmtError();
|
2009-03-04 12:23:07 +08:00
|
|
|
}
|
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2009-12-10 08:38:54 +08:00
|
|
|
ColonProtection.restore();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2013-12-24 17:48:30 +08:00
|
|
|
if (TryConsumeToken(tok::colon, ColonLoc)) {
|
2014-04-14 00:52:03 +08:00
|
|
|
} else if (TryConsumeToken(tok::semi, ColonLoc) ||
|
|
|
|
TryConsumeToken(tok::coloncolon, ColonLoc)) {
|
|
|
|
// Treat "case blah;" or "case blah::" as a typo for "case blah:".
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(ColonLoc, diag::err_expected_after)
|
|
|
|
<< "'case'" << tok::colon
|
|
|
|
<< FixItHint::CreateReplacement(ColonLoc, ":");
|
2011-01-22 17:28:32 +08:00
|
|
|
} else {
|
2010-12-24 06:56:40 +08:00
|
|
|
SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(ExpectedLoc, diag::err_expected_after)
|
|
|
|
<< "'case'" << tok::colon
|
|
|
|
<< FixItHint::CreateInsertion(ExpectedLoc, ":");
|
2010-12-24 06:56:40 +08:00
|
|
|
ColonLoc = ExpectedLoc;
|
2006-08-14 06:09:58 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Case =
|
2018-07-27 02:41:30 +08:00
|
|
|
Actions.ActOnCaseStmt(CaseLoc, LHS, DotDotDotLoc, RHS, ColonLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// If we had a sema error parsing this case, then just ignore it and
|
|
|
|
// continue parsing the sub-stmt.
|
|
|
|
if (Case.isInvalid()) {
|
|
|
|
if (TopLevelCase.isInvalid()) // No parsed case stmts.
|
2019-02-15 08:27:53 +08:00
|
|
|
return ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
|
2009-03-04 12:23:07 +08:00
|
|
|
// Otherwise, just don't add it as a nested case.
|
|
|
|
} else {
|
|
|
|
// If this is the first case statement we parsed, it becomes TopLevelCase.
|
|
|
|
// Otherwise we link it into the current chain.
|
2010-08-23 14:44:23 +08:00
|
|
|
Stmt *NextDeepest = Case.get();
|
2009-03-04 12:23:07 +08:00
|
|
|
if (TopLevelCase.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
TopLevelCase = Case;
|
2009-03-04 12:23:07 +08:00
|
|
|
else
|
2010-08-24 07:25:46 +08:00
|
|
|
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get());
|
2009-03-04 12:23:07 +08:00
|
|
|
DeepestParsedCaseStmt = NextDeepest;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// Handle all case statements.
|
|
|
|
} while (Tok.is(tok::kw_case));
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// If we found a non-case statement, start by parsing it.
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult SubStmt;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
if (Tok.isNot(tok::r_brace)) {
|
2019-02-15 08:27:53 +08:00
|
|
|
SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
|
2009-03-04 12:23:07 +08:00
|
|
|
} else {
|
|
|
|
// Nicely diagnose the common error "switch (X) { case 4: }", which is
|
2014-05-21 22:48:43 +08:00
|
|
|
// 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();
|
2006-10-16 13:52:41 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// Install the body into the most deeply-nested case.
|
2014-05-21 22:48:43 +08:00
|
|
|
if (DeepestParsedCaseStmt) {
|
|
|
|
// Broken sub-stmt shouldn't prevent forming the case statement properly.
|
|
|
|
if (SubStmt.isInvalid())
|
|
|
|
SubStmt = Actions.ActOnNullStmt(SourceLocation());
|
|
|
|
Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get());
|
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2009-03-04 12:23:07 +08:00
|
|
|
// Return the top level parsed statement tree.
|
2012-08-24 05:35:17 +08:00
|
|
|
return TopLevelCase;
|
2006-08-10 13:59:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDefaultStatement
|
|
|
|
/// labeled-statement:
|
|
|
|
/// 'default' ':' statement
|
|
|
|
/// Note that this does not parse the 'statement' at the end.
|
|
|
|
///
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::kw_default) && "Not a default stmt!");
|
2019-02-15 08:27:53 +08:00
|
|
|
|
|
|
|
// The substatement is always a 'statement', not a 'declaration', but is
|
|
|
|
// otherwise in the same context as the labeled-statement.
|
|
|
|
StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
|
|
|
|
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
|
2006-08-10 13:59:48 +08:00
|
|
|
|
2010-12-24 06:56:40 +08:00
|
|
|
SourceLocation ColonLoc;
|
2013-12-24 17:48:30 +08:00
|
|
|
if (TryConsumeToken(tok::colon, ColonLoc)) {
|
|
|
|
} else if (TryConsumeToken(tok::semi, ColonLoc)) {
|
2014-01-10 19:19:30 +08:00
|
|
|
// Treat "default;" as a typo for "default:".
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(ColonLoc, diag::err_expected_after)
|
|
|
|
<< "'default'" << tok::colon
|
|
|
|
<< FixItHint::CreateReplacement(ColonLoc, ":");
|
2011-01-22 17:28:32 +08:00
|
|
|
} else {
|
2010-12-24 06:56:40 +08:00
|
|
|
SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(ExpectedLoc, diag::err_expected_after)
|
|
|
|
<< "'default'" << tok::colon
|
|
|
|
<< FixItHint::CreateInsertion(ExpectedLoc, ":");
|
2010-12-24 06:56:40 +08:00
|
|
|
ColonLoc = ExpectedLoc;
|
2006-10-16 13:52:41 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2012-02-17 09:35:32 +08:00
|
|
|
StmtResult SubStmt;
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::r_brace)) {
|
2019-02-15 08:27:53 +08:00
|
|
|
SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
|
2012-02-17 09:35:32 +08:00
|
|
|
} else {
|
|
|
|
// Diagnose the common error "switch (X) {... default: }", which is
|
|
|
|
// not valid.
|
2011-06-14 23:24:38 +08:00
|
|
|
SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
|
2012-02-17 09:35:32 +08:00
|
|
|
Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
|
|
|
|
<< FixItHint::CreateInsertion(AfterColonLoc, " ;");
|
|
|
|
SubStmt = true;
|
2006-08-10 13:59:48 +08:00
|
|
|
}
|
2006-10-16 13:52:41 +08:00
|
|
|
|
2012-02-17 09:35:32 +08:00
|
|
|
// Broken sub-stmt shouldn't prevent forming the case statement properly.
|
2008-12-09 21:15:23 +08:00
|
|
|
if (SubStmt.isInvalid())
|
2012-02-17 09:35:32 +08:00
|
|
|
SubStmt = Actions.ActOnNullStmt(ColonLoc);
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2008-12-29 00:13:43 +08:00
|
|
|
return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
|
2010-08-24 07:25:46 +08:00
|
|
|
SubStmt.get(), getCurScope());
|
2006-08-10 13:59:48 +08:00
|
|
|
}
|
|
|
|
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
|
2017-08-10 23:43:06 +08:00
|
|
|
return ParseCompoundStatement(isStmtExpr,
|
|
|
|
Scope::DeclScope | Scope::CompoundStmtScope);
|
2011-07-07 06:04:06 +08:00
|
|
|
}
|
2006-08-10 13:59:48 +08:00
|
|
|
|
2006-08-09 13:47:47 +08:00
|
|
|
/// ParseCompoundStatement - Parse a "{}" block.
|
|
|
|
///
|
|
|
|
/// compound-statement: [C99 6.8.2]
|
|
|
|
/// { block-item-list[opt] }
|
|
|
|
/// [GNU] { label-declarations block-item-list } [TODO]
|
|
|
|
///
|
|
|
|
/// block-item-list:
|
|
|
|
/// block-item
|
|
|
|
/// block-item-list block-item
|
|
|
|
///
|
|
|
|
/// block-item:
|
|
|
|
/// declaration
|
2007-08-27 09:01:57 +08:00
|
|
|
/// [GNU] '__extension__' declaration
|
2006-08-09 13:47:47 +08:00
|
|
|
/// statement
|
|
|
|
///
|
|
|
|
/// [GNU] label-declarations:
|
|
|
|
/// [GNU] label-declaration
|
|
|
|
/// [GNU] label-declarations label-declaration
|
|
|
|
///
|
|
|
|
/// [GNU] label-declaration:
|
|
|
|
/// [GNU] '__label__' identifier-list ';'
|
|
|
|
///
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
|
2011-07-07 06:04:06 +08:00
|
|
|
unsigned ScopeFlags) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2007-08-26 14:24:45 +08:00
|
|
|
// Enter a scope to hold everything within the compound stmt. Compound
|
|
|
|
// statements can always hold declarations.
|
2011-07-07 06:04:06 +08:00
|
|
|
ParseScope CompoundScope(this, ScopeFlags);
|
2007-01-21 14:52:16 +08:00
|
|
|
|
|
|
|
// Parse the statements in the body.
|
2008-12-12 03:30:53 +08:00
|
|
|
return ParseCompoundStatementBody(isStmtExpr);
|
2007-01-21 14:52:16 +08:00
|
|
|
}
|
|
|
|
|
2012-11-04 06:29:05 +08:00
|
|
|
/// Parse any pragmas at the start of the compound expression. We handle these
|
|
|
|
/// separately since some pragmas (FP_CONTRACT) must appear before any C
|
|
|
|
/// statement in the compound, but may be intermingled with other pragmas.
|
|
|
|
void Parser::ParseCompoundStatementLeadingPragmas() {
|
|
|
|
bool checkForPragmas = true;
|
|
|
|
while (checkForPragmas) {
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::annot_pragma_vis:
|
|
|
|
HandlePragmaVisibility();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_pack:
|
|
|
|
HandlePragmaPack();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_msstruct:
|
|
|
|
HandlePragmaMSStruct();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_align:
|
|
|
|
HandlePragmaAlign();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_weak:
|
|
|
|
HandlePragmaWeak();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_weakalias:
|
|
|
|
HandlePragmaWeakAlias();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_redefine_extname:
|
|
|
|
HandlePragmaRedefineExtname();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_opencl_extension:
|
|
|
|
HandlePragmaOpenCLExtension();
|
|
|
|
break;
|
|
|
|
case tok::annot_pragma_fp_contract:
|
|
|
|
HandlePragmaFPContract();
|
|
|
|
break;
|
2017-04-05 05:18:36 +08:00
|
|
|
case tok::annot_pragma_fp:
|
|
|
|
HandlePragmaFP();
|
|
|
|
break;
|
2018-08-15 01:06:56 +08:00
|
|
|
case tok::annot_pragma_fenv_access:
|
|
|
|
HandlePragmaFEnvAccess();
|
|
|
|
break;
|
2014-02-11 03:50:15 +08:00
|
|
|
case tok::annot_pragma_ms_pointers_to_members:
|
|
|
|
HandlePragmaMSPointersToMembers();
|
|
|
|
break;
|
2014-04-09 06:30:47 +08:00
|
|
|
case tok::annot_pragma_ms_pragma:
|
|
|
|
HandlePragmaMSPragma();
|
|
|
|
break;
|
2015-11-20 15:02:57 +08:00
|
|
|
case tok::annot_pragma_ms_vtordisp:
|
|
|
|
HandlePragmaMSVtorDisp();
|
|
|
|
break;
|
2016-01-13 05:59:26 +08:00
|
|
|
case tok::annot_pragma_dump:
|
|
|
|
HandlePragmaDump();
|
|
|
|
break;
|
2012-11-04 06:29:05 +08:00
|
|
|
default:
|
|
|
|
checkForPragmas = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
[clang][Parse] Diagnose useless null statements / empty init-statements
Summary:
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.
While that is great, there is at least one more source of need-less semis - 'null statements'.
Sometimes, they are needed:
```
for(int x = 0; continueToDoWork(x); x++)
; // Ugly code, but the semi is needed here.
```
But sometimes they are just there for no reason:
```
switch(X) {
case 0:
return -2345;
case 5:
return 0;
default:
return 42;
}; // <- oops
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.
```
Additionally:
```
if(; // <- empty init-statement
true)
;
switch (; // empty init-statement
x) {
...
}
for (; // <- empty init-statement
int y : S())
;
}
As usual, things may or may not go sideways in the presence of macros.
While evaluating this diag on my codebase of interest, it was unsurprisingly
discovered that Google Test macros are *very* prone to this.
And it seems many issues are deep within the GTest itself, not
in the snippets passed from the codebase that uses GTest.
So after some thought, i decided not do issue a diagnostic if the semi
is within *any* macro, be it either from the normal header, or system header.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=39111 | PR39111 ]]
Reviewers: rsmith, aaron.ballman, efriedma
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52695
llvm-svn: 347339
2018-11-21 02:59:05 +08:00
|
|
|
/// 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.
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult R =
|
|
|
|
ParseStatementOrDeclaration(Stmts, ParsedStmtContext::SubStmt);
|
[clang][Parse] Diagnose useless null statements / empty init-statements
Summary:
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.
While that is great, there is at least one more source of need-less semis - 'null statements'.
Sometimes, they are needed:
```
for(int x = 0; continueToDoWork(x); x++)
; // Ugly code, but the semi is needed here.
```
But sometimes they are just there for no reason:
```
switch(X) {
case 0:
return -2345;
case 5:
return 0;
default:
return 42;
}; // <- oops
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.
```
Additionally:
```
if(; // <- empty init-statement
true)
;
switch (; // empty init-statement
x) {
...
}
for (; // <- empty init-statement
int y : S())
;
}
As usual, things may or may not go sideways in the presence of macros.
While evaluating this diag on my codebase of interest, it was unsurprisingly
discovered that Google Test macros are *very* prone to this.
And it seems many issues are deep within the GTest itself, not
in the snippets passed from the codebase that uses GTest.
So after some thought, i decided not do issue a diagnostic if the semi
is within *any* macro, be it either from the normal header, or system header.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=39111 | PR39111 ]]
Reviewers: rsmith, aaron.ballman, efriedma
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52695
llvm-svn: 347339
2018-11-21 02:59:05 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) {
|
|
|
|
bool IsStmtExprResult = false;
|
|
|
|
if ((StmtCtx & ParsedStmtContext::InStmtExpr) != ParsedStmtContext()) {
|
|
|
|
// Look ahead to see if the next two tokens close the statement expression;
|
2019-01-05 00:58:14 +08:00
|
|
|
// if so, this expression statement is the last statement in a
|
|
|
|
// statment expression.
|
2019-02-15 08:27:53 +08:00
|
|
|
IsStmtExprResult = Tok.is(tok::r_brace) && NextToken().is(tok::r_paren);
|
2019-01-05 00:58:14 +08:00
|
|
|
}
|
2019-02-15 08:27:53 +08:00
|
|
|
|
|
|
|
if (IsStmtExprResult)
|
|
|
|
E = Actions.ActOnStmtExprResult(E);
|
|
|
|
return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult);
|
2019-01-05 00:58:14 +08:00
|
|
|
}
|
|
|
|
|
2007-01-21 14:52:16 +08:00
|
|
|
/// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
|
2007-09-16 22:56:35 +08:00
|
|
|
/// ActOnCompoundStmt action. This expects the '{' to be the current token, and
|
2007-01-21 14:52:16 +08:00
|
|
|
/// consume the '}' at the end of the block. It does not manipulate the scope
|
|
|
|
/// stack.
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
2009-09-09 23:08:12 +08:00
|
|
|
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
|
2009-03-05 08:00:31 +08:00
|
|
|
Tok.getLocation(),
|
|
|
|
"in compound statement ('{}')");
|
2012-10-02 12:45:10 +08:00
|
|
|
|
|
|
|
// Record the state of the FP_CONTRACT pragma, restore on leaving the
|
|
|
|
// compound statement.
|
|
|
|
Sema::FPContractStateRAII SaveFPContractState(Actions);
|
|
|
|
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_brace);
|
|
|
|
if (T.consumeOpen())
|
|
|
|
return StmtError();
|
2007-01-21 14:52:16 +08:00
|
|
|
|
2018-02-03 08:44:57 +08:00
|
|
|
Sema::CompoundScopeRAII CompoundScope(Actions, isStmtExpr);
|
2012-02-15 06:14:32 +08:00
|
|
|
|
2012-11-04 06:29:05 +08:00
|
|
|
// Parse any pragmas at the beginning of the compound statement.
|
|
|
|
ParseCompoundStatementLeadingPragmas();
|
2011-01-18 02:58:44 +08:00
|
|
|
|
2012-11-04 06:29:05 +08:00
|
|
|
StmtVector Stmts;
|
2012-10-21 09:10:01 +08:00
|
|
|
|
2011-02-18 10:08:43 +08:00
|
|
|
// "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
|
|
|
|
// only allowed at the start of a compound stmt regardless of the language.
|
|
|
|
while (Tok.is(tok::kw___label__)) {
|
|
|
|
SourceLocation LabelLoc = ConsumeToken();
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Decl *, 8> DeclsInGroup;
|
2011-02-18 10:08:43 +08:00
|
|
|
while (1) {
|
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::identifier;
|
2011-02-18 10:08:43 +08:00
|
|
|
break;
|
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-02-18 10:08:43 +08:00
|
|
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation IdLoc = ConsumeToken();
|
2011-03-06 02:21:20 +08:00
|
|
|
DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc));
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2013-12-24 17:48:30 +08:00
|
|
|
if (!TryConsumeToken(tok::comma))
|
2011-02-18 10:08:43 +08:00
|
|
|
break;
|
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2013-07-09 20:05:01 +08:00
|
|
|
DeclGroupPtrTy Res =
|
|
|
|
Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
|
2011-02-18 10:08:43 +08:00
|
|
|
StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation());
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2012-04-29 00:12:17 +08:00
|
|
|
ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
|
2011-02-18 10:08:43 +08:00
|
|
|
if (R.isUsable())
|
2014-05-29 18:55:11 +08:00
|
|
|
Stmts.push_back(R.get());
|
2011-02-18 10:08:43 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2019-02-15 08:27:53 +08:00
|
|
|
ParsedStmtContext SubStmtCtx =
|
|
|
|
ParsedStmtContext::Compound |
|
|
|
|
(isStmtExpr ? ParsedStmtContext::InStmtExpr : ParsedStmtContext());
|
|
|
|
|
2015-11-18 07:32:01 +08:00
|
|
|
while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
|
|
|
|
Tok.isNot(tok::eof)) {
|
2011-01-18 02:58:44 +08:00
|
|
|
if (Tok.is(tok::annot_pragma_unused)) {
|
|
|
|
HandlePragmaUnused();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
[clang][Parse] Diagnose useless null statements / empty init-statements
Summary:
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.
While that is great, there is at least one more source of need-less semis - 'null statements'.
Sometimes, they are needed:
```
for(int x = 0; continueToDoWork(x); x++)
; // Ugly code, but the semi is needed here.
```
But sometimes they are just there for no reason:
```
switch(X) {
case 0:
return -2345;
case 5:
return 0;
default:
return 42;
}; // <- oops
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.
```
Additionally:
```
if(; // <- empty init-statement
true)
;
switch (; // empty init-statement
x) {
...
}
for (; // <- empty init-statement
int y : S())
;
}
As usual, things may or may not go sideways in the presence of macros.
While evaluating this diag on my codebase of interest, it was unsurprisingly
discovered that Google Test macros are *very* prone to this.
And it seems many issues are deep within the GTest itself, not
in the snippets passed from the codebase that uses GTest.
So after some thought, i decided not do issue a diagnostic if the semi
is within *any* macro, be it either from the normal header, or system header.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=39111 | PR39111 ]]
Reviewers: rsmith, aaron.ballman, efriedma
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52695
llvm-svn: 347339
2018-11-21 02:59:05 +08:00
|
|
|
if (ConsumeNullStmt(Stmts))
|
|
|
|
continue;
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult R;
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::kw___extension__)) {
|
2019-02-15 08:27:53 +08:00
|
|
|
R = ParseStatementOrDeclaration(Stmts, SubStmtCtx);
|
2007-08-27 09:01:57 +08:00
|
|
|
} else {
|
|
|
|
// __extension__ can start declarations and it can also be a unary
|
|
|
|
// operator for expressions. Consume multiple __extension__ markers here
|
|
|
|
// until we can determine which is which.
|
2009-01-27 16:43:38 +08:00
|
|
|
// FIXME: This loses extension expressions in the AST!
|
2007-08-27 09:01:57 +08:00
|
|
|
SourceLocation ExtLoc = ConsumeToken();
|
2007-10-10 01:41:39 +08:00
|
|
|
while (Tok.is(tok::kw___extension__))
|
2007-08-27 09:01:57 +08:00
|
|
|
ConsumeToken();
|
2008-10-20 14:51:33 +08:00
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2014-05-21 14:02:52 +08:00
|
|
|
MaybeParseCXX11Attributes(attrs, nullptr,
|
|
|
|
/*MightBeObjCMessageSend*/ true);
|
2009-11-21 16:43:09 +08:00
|
|
|
|
2007-08-27 09:01:57 +08:00
|
|
|
// If this is the start of a declaration, parse it as such.
|
2008-10-05 08:06:24 +08:00
|
|
|
if (isDeclarationStatement()) {
|
2009-05-17 07:40:44 +08:00
|
|
|
// __extension__ silences extension warnings in the subdeclaration.
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
// FIXME: Save the __extension__ on the decl as a node somehow?
|
2009-05-17 07:40:44 +08:00
|
|
|
ExtensionRAIIObject O(Diags);
|
|
|
|
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
2017-12-29 13:41:00 +08:00
|
|
|
DeclGroupPtrTy Res =
|
|
|
|
ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, attrs);
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
|
2007-08-27 09:01:57 +08:00
|
|
|
} else {
|
2009-01-27 16:43:38 +08:00
|
|
|
// Otherwise this was a unary __extension__ marker.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc));
|
2008-03-13 14:32:11 +08:00
|
|
|
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2007-08-27 09:01:57 +08:00
|
|
|
SkipUntil(tok::semi);
|
|
|
|
continue;
|
|
|
|
}
|
2009-01-19 02:03:53 +08:00
|
|
|
|
2008-10-20 14:51:33 +08:00
|
|
|
// Eat the semicolon at the end of stmt and convert the expr into a
|
|
|
|
// statement.
|
2010-09-07 23:23:11 +08:00
|
|
|
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
|
2019-02-15 08:27:53 +08:00
|
|
|
R = handleExprStmt(Res, SubStmtCtx);
|
|
|
|
if (R.isUsable())
|
|
|
|
R = Actions.ProcessStmtAttributes(R.get(), attrs, attrs.Range);
|
2007-08-27 09:01:57 +08:00
|
|
|
}
|
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2008-12-09 21:15:23 +08:00
|
|
|
if (R.isUsable())
|
2014-05-29 18:55:11 +08:00
|
|
|
Stmts.push_back(R.get());
|
2006-10-16 13:52:41 +08:00
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2012-03-24 10:26:51 +08:00
|
|
|
SourceLocation CloseLoc = Tok.getLocation();
|
|
|
|
|
2006-08-09 13:47:47 +08:00
|
|
|
// We broke out of the while loop because we found a '}' or EOF.
|
2012-12-31 07:36:56 +08:00
|
|
|
if (!T.consumeClose())
|
2012-03-24 10:26:51 +08:00
|
|
|
// Recover by creating a compound statement with what we parsed so far,
|
|
|
|
// instead of dropping everything and returning StmtError();
|
2012-12-31 07:36:56 +08:00
|
|
|
CloseLoc = T.getCloseLocation();
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2012-03-24 10:26:51 +08:00
|
|
|
return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
|
2012-08-24 05:35:17 +08:00
|
|
|
Stmts, isStmtExpr);
|
2006-08-09 13:47:47 +08:00
|
|
|
}
|
2006-08-10 12:23:57 +08:00
|
|
|
|
2008-12-12 14:31:07 +08:00
|
|
|
/// ParseParenExprOrCondition:
|
|
|
|
/// [C ] '(' expression ')'
|
2016-06-30 05:17:59 +08:00
|
|
|
/// [C++] '(' condition ')'
|
|
|
|
/// [C++1z] '(' init-statement[opt] condition ')'
|
2008-12-12 14:31:07 +08:00
|
|
|
///
|
|
|
|
/// 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
|
|
|
|
/// goes out of its way to recover well. It returns true if there was a parser
|
|
|
|
/// error (the right paren couldn't be found), which indicates that the caller
|
|
|
|
/// 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.
|
2016-06-30 05:17:59 +08:00
|
|
|
bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
|
|
|
|
Sema::ConditionResult &Cond,
|
2010-05-07 01:25:47 +08:00
|
|
|
SourceLocation Loc,
|
2016-06-24 03:02:52 +08:00
|
|
|
Sema::ConditionKind CK) {
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus)
|
2016-06-30 05:17:59 +08:00
|
|
|
Cond = ParseCXXCondition(InitStmt, Loc, CK);
|
2009-11-25 08:27:52 +08:00
|
|
|
else {
|
2016-06-24 03:02:52 +08:00
|
|
|
ExprResult CondExpr = ParseExpression();
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2010-05-07 01:25:47 +08:00
|
|
|
// If required, convert to a boolean value.
|
2016-06-24 03:02:52 +08:00
|
|
|
if (CondExpr.isInvalid())
|
|
|
|
Cond = Sema::ConditionError();
|
|
|
|
else
|
|
|
|
Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK);
|
2009-11-25 08:27:52 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-12 14:31:07 +08:00
|
|
|
// If the parser was confused by the condition and we don't have a ')', try to
|
|
|
|
// recover by skipping ahead to a semi and bailing out. If condexp is
|
|
|
|
// semantically invalid but we have well formed code, keep going.
|
2016-06-24 03:02:52 +08:00
|
|
|
if (Cond.isInvalid() && Tok.isNot(tok::r_paren)) {
|
2008-12-12 14:31:07 +08:00
|
|
|
SkipUntil(tok::semi);
|
|
|
|
// Skipping may have stopped if it found the containing ')'. If so, we can
|
|
|
|
// continue parsing the if statement.
|
|
|
|
if (Tok.isNot(tok::r_paren))
|
|
|
|
return true;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-12-12 14:31:07 +08:00
|
|
|
// Otherwise the condition is valid or the rparen is present.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2012-07-11 05:35:27 +08:00
|
|
|
|
2012-04-29 00:24:20 +08:00
|
|
|
// Check for extraneous ')'s to catch things like "if (foo())) {". We know
|
|
|
|
// that all callers are looking for a statement after the condition, so ")"
|
|
|
|
// isn't valid.
|
|
|
|
while (Tok.is(tok::r_paren)) {
|
|
|
|
Diag(Tok, diag::err_extraneous_rparen_in_condition)
|
|
|
|
<< FixItHint::CreateRemoval(Tok.getLocation());
|
|
|
|
ConsumeParen();
|
|
|
|
}
|
2012-07-11 05:35:27 +08:00
|
|
|
|
2008-12-12 14:31:07 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-10 12:23:57 +08:00
|
|
|
/// ParseIfStatement
|
|
|
|
/// if-statement: [C99 6.8.4.1]
|
|
|
|
/// 'if' '(' expression ')' statement
|
|
|
|
/// 'if' '(' expression ')' statement 'else' statement
|
2008-09-10 04:38:47 +08:00
|
|
|
/// [C++] 'if' '(' condition ')' statement
|
|
|
|
/// [C++] 'if' '(' condition ')' statement 'else' statement
|
2006-10-16 13:52:41 +08:00
|
|
|
///
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::kw_if) && "Not an if stmt!");
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
|
2006-08-10 12:23:57 +08:00
|
|
|
|
2016-06-24 03:16:49 +08:00
|
|
|
bool IsConstexpr = false;
|
|
|
|
if (Tok.is(tok::kw_constexpr)) {
|
2017-12-05 04:27:34 +08:00
|
|
|
Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if
|
2016-06-24 03:16:49 +08:00
|
|
|
: diag::ext_constexpr_if);
|
|
|
|
IsConstexpr = true;
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "if";
|
2006-08-10 12:23:57 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 03:30:53 +08:00
|
|
|
return StmtError();
|
2006-08-10 12:23:57 +08:00
|
|
|
}
|
2008-09-10 04:38:47 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
|
2008-09-11 11:06:46 +08:00
|
|
|
|
2007-08-27 07:08:06 +08:00
|
|
|
// C99 6.8.4p3 - In C99, the if statement is a block. This is not
|
|
|
|
// the case for C90.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.4p3:
|
|
|
|
// A name introduced by a declaration in a condition is in scope from its
|
|
|
|
// point of declaration until the end of the substatements controlled by the
|
|
|
|
// condition.
|
2008-09-12 07:08:39 +08:00
|
|
|
// C++ 3.3.2p4:
|
|
|
|
// Names declared in the for-init-statement, and in the condition of if,
|
|
|
|
// while, for, and switch statements are local to the if, while, for, or
|
|
|
|
// switch statement (including the controlled statement).
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
|
2007-08-27 07:08:06 +08:00
|
|
|
|
2006-08-10 12:23:57 +08:00
|
|
|
// Parse the condition.
|
2016-06-30 05:17:59 +08:00
|
|
|
StmtResult InitStmt;
|
2016-06-24 03:02:52 +08:00
|
|
|
Sema::ConditionResult Cond;
|
2016-06-30 05:17:59 +08:00
|
|
|
if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
|
2016-06-24 03:16:49 +08:00
|
|
|
IsConstexpr ? Sema::ConditionKind::ConstexprIf
|
|
|
|
: Sema::ConditionKind::Boolean))
|
2008-12-12 14:31:07 +08:00
|
|
|
return StmtError();
|
2008-12-12 14:19:11 +08:00
|
|
|
|
2016-06-24 03:16:49 +08:00
|
|
|
llvm::Optional<bool> ConstexprCondition;
|
|
|
|
if (IsConstexpr)
|
|
|
|
ConstexprCondition = Cond.getKnownValue();
|
|
|
|
|
2007-08-22 13:28:50 +08:00
|
|
|
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
|
2007-08-22 13:33:11 +08:00
|
|
|
// 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.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.4p1:
|
|
|
|
// The substatement in a selection-statement (each substatement, in the else
|
|
|
|
// form of the if statement) implicitly defines a local scope.
|
|
|
|
//
|
|
|
|
// For C++ we create a scope for the condition and a new scope for
|
|
|
|
// substatements because:
|
|
|
|
// -When the 'then' scope exits, we want the condition declaration to still be
|
|
|
|
// active for the 'else' scope too.
|
|
|
|
// -Sema will detect name clashes by considering declarations of a
|
|
|
|
// 'ControlScope' as part of its direct subscope.
|
|
|
|
// -If we wanted the condition and substatement to be in the same scope, we
|
|
|
|
// would have to notify ParseStatement not to create a new scope. It's
|
|
|
|
// simpler to let it create a new scope.
|
|
|
|
//
|
2014-03-05 16:57:59 +08:00
|
|
|
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
|
2008-09-10 04:38:47 +08:00
|
|
|
|
2007-10-29 13:08:52 +08:00
|
|
|
// Read the 'then' stmt.
|
|
|
|
SourceLocation ThenStmtLoc = Tok.getLocation();
|
2011-12-23 07:26:17 +08:00
|
|
|
|
|
|
|
SourceLocation InnerStatementTrailingElseLoc;
|
2016-06-24 03:16:49 +08:00
|
|
|
StmtResult ThenStmt;
|
|
|
|
{
|
|
|
|
EnterExpressionEvaluationContext PotentiallyDiscarded(
|
2017-04-02 05:30:49 +08:00
|
|
|
Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr,
|
2018-07-13 02:45:41 +08:00
|
|
|
Sema::ExpressionEvaluationContextRecord::EK_Other,
|
2016-06-24 03:16:49 +08:00
|
|
|
/*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition);
|
|
|
|
ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
|
|
|
|
}
|
2007-05-28 13:38:24 +08:00
|
|
|
|
2007-08-22 13:16:28 +08:00
|
|
|
// Pop the 'if' scope if needed.
|
2008-12-10 14:34:36 +08:00
|
|
|
InnerScope.Exit();
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2006-08-10 12:23:57 +08:00
|
|
|
// If it has an else, parse it.
|
2006-10-16 13:52:41 +08:00
|
|
|
SourceLocation ElseLoc;
|
2007-10-29 13:08:52 +08:00
|
|
|
SourceLocation ElseStmtLoc;
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult ElseStmt;
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.is(tok::kw_else)) {
|
2011-12-23 07:26:17 +08:00
|
|
|
if (TrailingElseLoc)
|
|
|
|
*TrailingElseLoc = Tok.getLocation();
|
|
|
|
|
2006-10-16 14:06:51 +08:00
|
|
|
ElseLoc = ConsumeToken();
|
2010-04-12 14:12:50 +08:00
|
|
|
ElseStmtLoc = Tok.getLocation();
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2007-08-22 13:28:50 +08:00
|
|
|
// C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
|
2007-08-22 13:33:11 +08:00
|
|
|
// 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.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.4p1:
|
|
|
|
// The substatement in a selection-statement (each substatement, in the else
|
|
|
|
// form of the if statement) implicitly defines a local scope.
|
|
|
|
//
|
2016-06-24 03:16:49 +08:00
|
|
|
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX,
|
|
|
|
Tok.is(tok::l_brace));
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2016-06-24 03:16:49 +08:00
|
|
|
EnterExpressionEvaluationContext PotentiallyDiscarded(
|
2017-04-02 05:30:49 +08:00
|
|
|
Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr,
|
2018-07-13 02:45:41 +08:00
|
|
|
Sema::ExpressionEvaluationContextRecord::EK_Other,
|
2016-06-24 03:16:49 +08:00
|
|
|
/*ShouldEnter=*/ConstexprCondition && *ConstexprCondition);
|
2006-10-16 13:52:41 +08:00
|
|
|
ElseStmt = ParseStatement();
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2007-08-22 13:16:28 +08:00
|
|
|
// Pop the 'else' scope if needed.
|
2008-12-10 14:34:36 +08:00
|
|
|
InnerScope.Exit();
|
2011-07-30 16:36:53 +08:00
|
|
|
} else if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteAfterIf(getCurScope());
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return StmtError();
|
2011-12-23 07:26:17 +08:00
|
|
|
} else if (InnerStatementTrailingElseLoc.isValid()) {
|
|
|
|
Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
|
2006-08-10 12:23:57 +08:00
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2008-12-10 14:34:36 +08:00
|
|
|
IfScope.Exit();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2007-10-29 13:08:52 +08:00
|
|
|
// If the then or else stmt is invalid and the other is valid (and present),
|
2009-09-09 23:08:12 +08:00
|
|
|
// make turn the invalid one into a null stmt to avoid dropping the other
|
2007-10-29 13:08:52 +08:00
|
|
|
// part. If both are invalid, return error.
|
2008-12-09 21:15:23 +08:00
|
|
|
if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) ||
|
2014-05-21 14:02:52 +08:00
|
|
|
(ThenStmt.isInvalid() && ElseStmt.get() == nullptr) ||
|
|
|
|
(ThenStmt.get() == nullptr && ElseStmt.isInvalid())) {
|
2008-11-26 06:21:31 +08:00
|
|
|
// Both invalid, or one is invalid and other is non-present: return error.
|
2008-12-12 03:30:53 +08:00
|
|
|
return StmtError();
|
2007-10-29 13:08:52 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-10-29 13:08:52 +08:00
|
|
|
// Now if either are invalid, replace with a ';'.
|
2008-12-09 21:15:23 +08:00
|
|
|
if (ThenStmt.isInvalid())
|
2007-10-29 13:08:52 +08:00
|
|
|
ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (ElseStmt.isInvalid())
|
2007-10-29 13:08:52 +08:00
|
|
|
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2016-06-30 05:17:59 +08:00
|
|
|
return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond,
|
|
|
|
ThenStmt.get(), ElseLoc, ElseStmt.get());
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseSwitchStatement
|
|
|
|
/// switch-statement:
|
|
|
|
/// 'switch' '(' expression ')' statement
|
2008-09-10 04:38:47 +08:00
|
|
|
/// [C++] 'switch' '(' condition ')' statement
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
|
2006-08-10 12:59:57 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "switch";
|
2006-08-10 12:59:57 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2007-08-27 07:08:06 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
|
2008-09-11 11:06:46 +08:00
|
|
|
|
2007-08-27 07:08:06 +08:00
|
|
|
// C99 6.8.4p3 - In C99, the switch statement is a block. This is
|
|
|
|
// not the case for C90. Start the switch scope.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.4p3:
|
|
|
|
// A name introduced by a declaration in a condition is in scope from its
|
|
|
|
// point of declaration until the end of the substatements controlled by the
|
|
|
|
// condition.
|
2008-09-12 07:08:39 +08:00
|
|
|
// C++ 3.3.2p4:
|
|
|
|
// Names declared in the for-init-statement, and in the condition of if,
|
|
|
|
// while, for, and switch statements are local to the if, while, for, or
|
|
|
|
// switch statement (including the controlled statement).
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
2014-01-23 23:05:00 +08:00
|
|
|
unsigned ScopeFlags = Scope::SwitchScope;
|
2008-12-12 14:31:07 +08:00
|
|
|
if (C99orCXX)
|
|
|
|
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope SwitchScope(this, ScopeFlags);
|
2006-11-06 07:47:55 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
// Parse the condition.
|
2016-06-30 05:17:59 +08:00
|
|
|
StmtResult InitStmt;
|
2016-06-24 03:02:52 +08:00
|
|
|
Sema::ConditionResult Cond;
|
2016-06-30 05:17:59 +08:00
|
|
|
if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc,
|
|
|
|
Sema::ConditionKind::Switch))
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2008-12-18 06:19:57 +08:00
|
|
|
|
2016-06-30 05:17:59 +08:00
|
|
|
StmtResult Switch =
|
|
|
|
Actions.ActOnStartOfSwitchStmt(SwitchLoc, InitStmt.get(), Cond);
|
2010-05-07 01:25:47 +08:00
|
|
|
|
|
|
|
if (Switch.isInvalid()) {
|
2011-10-08 19:31:46 +08:00
|
|
|
// Skip the switch body.
|
2010-05-07 01:25:47 +08:00
|
|
|
// FIXME: This is not optimal recovery, but parsing the body is more
|
|
|
|
// dangerous due to the presence of case and default statements, which
|
|
|
|
// will have no place to connect back with the switch.
|
2010-05-21 07:20:59 +08:00
|
|
|
if (Tok.is(tok::l_brace)) {
|
|
|
|
ConsumeBrace();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_brace);
|
2010-05-21 07:20:59 +08:00
|
|
|
} else
|
2010-05-07 01:25:47 +08:00
|
|
|
SkipUntil(tok::semi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Switch;
|
2010-05-07 01:25:47 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2007-08-22 13:28:50 +08:00
|
|
|
// C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
|
2007-08-22 13:33:11 +08:00
|
|
|
// 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.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.4p1:
|
|
|
|
// The substatement in a selection-statement (each substatement, in the else
|
|
|
|
// form of the if statement) implicitly defines a local scope.
|
|
|
|
//
|
|
|
|
// See comments in ParseIfStatement for why we create a scope for the
|
|
|
|
// condition and a new scope for substatement in C++.
|
|
|
|
//
|
2014-01-23 23:05:00 +08:00
|
|
|
getCurScope()->AddFlags(Scope::BreakScope);
|
2014-03-05 16:57:59 +08:00
|
|
|
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2014-06-17 08:09:05 +08:00
|
|
|
// We have incremented the mangling number for the SwitchScope and the
|
|
|
|
// InnerScope, which is one too many.
|
|
|
|
if (C99orCXX)
|
2015-03-20 05:54:30 +08:00
|
|
|
getCurScope()->decrementMSManglingNumber();
|
2014-06-17 08:09:05 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
// Read the body statement.
|
2011-12-23 07:26:17 +08:00
|
|
|
StmtResult Body(ParseStatement(TrailingElseLoc));
|
2006-11-06 07:47:55 +08:00
|
|
|
|
2010-01-24 09:50:29 +08:00
|
|
|
// Pop the scopes.
|
2008-12-10 14:34:36 +08:00
|
|
|
InnerScope.Exit();
|
|
|
|
SwitchScope.Exit();
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
|
2006-08-10 12:23:57 +08:00
|
|
|
}
|
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
/// ParseWhileStatement
|
|
|
|
/// while-statement: [C99 6.8.5.1]
|
|
|
|
/// 'while' '(' expression ')' statement
|
2008-09-10 04:38:47 +08:00
|
|
|
/// [C++] 'while' '(' condition ')' statement
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::kw_while) && "Not a while stmt!");
|
2006-10-16 13:52:41 +08:00
|
|
|
SourceLocation WhileLoc = Tok.getLocation();
|
2006-08-10 12:59:57 +08:00
|
|
|
ConsumeToken(); // eat the 'while'.
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "while";
|
2006-08-10 12:59:57 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
|
2008-09-11 11:06:46 +08:00
|
|
|
|
2007-08-27 07:08:06 +08:00
|
|
|
// C99 6.8.5p5 - In C99, the while statement is a block. This is not
|
|
|
|
// the case for C90. Start the loop scope.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.4p3:
|
|
|
|
// A name introduced by a declaration in a condition is in scope from its
|
|
|
|
// point of declaration until the end of the substatements controlled by the
|
|
|
|
// condition.
|
2008-09-12 07:08:39 +08:00
|
|
|
// C++ 3.3.2p4:
|
|
|
|
// Names declared in the for-init-statement, and in the condition of if,
|
|
|
|
// while, for, and switch statements are local to the if, while, for, or
|
|
|
|
// switch statement (including the controlled statement).
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
2008-12-10 14:34:36 +08:00
|
|
|
unsigned ScopeFlags;
|
2008-09-11 11:06:46 +08:00
|
|
|
if (C99orCXX)
|
2008-12-10 14:34:36 +08:00
|
|
|
ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
|
|
|
|
Scope::DeclScope | Scope::ControlScope;
|
2007-08-27 07:08:06 +08:00
|
|
|
else
|
2008-12-10 14:34:36 +08:00
|
|
|
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
|
|
|
|
ParseScope WhileScope(this, ScopeFlags);
|
2006-11-06 07:47:55 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
// Parse the condition.
|
2016-06-24 03:02:52 +08:00
|
|
|
Sema::ConditionResult Cond;
|
2016-06-30 05:17:59 +08:00
|
|
|
if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc,
|
|
|
|
Sema::ConditionKind::Boolean))
|
2008-12-12 14:31:07 +08:00
|
|
|
return StmtError();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2013-12-03 15:36:55 +08:00
|
|
|
// C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
|
2007-08-22 13:33:11 +08:00
|
|
|
// 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.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.5p2:
|
|
|
|
// The substatement in an iteration-statement implicitly defines a local scope
|
|
|
|
// which is entered and exited each time through the loop.
|
|
|
|
//
|
|
|
|
// See comments in ParseIfStatement for why we create a scope for the
|
|
|
|
// condition and a new scope for substatement in C++.
|
|
|
|
//
|
2014-03-05 16:57:59 +08:00
|
|
|
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
// Read the body statement.
|
2011-12-23 07:26:17 +08:00
|
|
|
StmtResult Body(ParseStatement(TrailingElseLoc));
|
2006-11-06 07:47:55 +08:00
|
|
|
|
2007-08-22 13:28:50 +08:00
|
|
|
// Pop the body scope if needed.
|
2008-12-10 14:34:36 +08:00
|
|
|
InnerScope.Exit();
|
|
|
|
WhileScope.Exit();
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
if (Cond.isInvalid() || Body.isInvalid())
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
|
|
|
|
2016-06-24 03:02:52 +08:00
|
|
|
return Actions.ActOnWhileStmt(WhileLoc, Cond, Body.get());
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDoStatement
|
|
|
|
/// do-statement: [C99 6.8.5.2]
|
|
|
|
/// 'do' statement 'while' '(' expression ')' ';'
|
2006-08-10 13:45:44 +08:00
|
|
|
/// Note: this lets the caller parse the end ';'.
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseDoStatement() {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::kw_do) && "Not a do stmt!");
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2007-08-27 07:08:06 +08:00
|
|
|
// C99 6.8.5p5 - In C99, the do statement is a block. This is not
|
|
|
|
// the case for C90. Start the loop scope.
|
2008-12-10 14:34:36 +08:00
|
|
|
unsigned ScopeFlags;
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().C99)
|
2008-12-10 14:34:36 +08:00
|
|
|
ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
|
2007-08-27 07:08:06 +08:00
|
|
|
else
|
2008-12-10 14:34:36 +08:00
|
|
|
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2008-12-10 14:34:36 +08:00
|
|
|
ParseScope DoScope(this, ScopeFlags);
|
2006-11-06 07:47:55 +08:00
|
|
|
|
2013-12-03 15:36:55 +08:00
|
|
|
// C99 6.8.5p5 - In C99, the body of the do statement is a scope, even if
|
2007-08-22 13:33:11 +08:00
|
|
|
// 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.
|
2008-09-11 12:46:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.5p2:
|
|
|
|
// The substatement in an iteration-statement implicitly defines a local scope
|
|
|
|
// which is entered and exited each time through the loop.
|
|
|
|
//
|
2014-03-05 16:57:59 +08:00
|
|
|
bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
|
|
|
|
ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
// Read the body statement.
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Body(ParseStatement());
|
2006-08-10 12:59:57 +08:00
|
|
|
|
2007-08-22 13:28:50 +08:00
|
|
|
// Pop the body scope if needed.
|
2008-12-10 14:34:36 +08:00
|
|
|
InnerScope.Exit();
|
2007-08-22 13:28:50 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::kw_while)) {
|
2008-12-09 21:15:23 +08:00
|
|
|
if (!Body.isInvalid()) {
|
2008-11-14 02:52:53 +08:00
|
|
|
Diag(Tok, diag::err_expected_while);
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(DoLoc, diag::note_matching) << "'do'";
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::semi, StopBeforeMatch);
|
2008-11-14 02:52:53 +08:00
|
|
|
}
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation WhileLoc = ConsumeToken();
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "do/while";
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::semi, StopBeforeMatch);
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2013-10-15 09:34:54 +08:00
|
|
|
// Parse the parenthesized expression.
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
2012-07-11 05:35:27 +08:00
|
|
|
|
2013-10-15 09:34:54 +08:00
|
|
|
// A do-while expression is not a condition, so can't have attributes.
|
|
|
|
DiagnoseAndSkipCXX11Attributes();
|
2012-06-23 13:07:58 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Cond = ParseExpression();
|
2017-10-31 06:55:11 +08:00
|
|
|
// Correct the typos in condition before closing the scope.
|
|
|
|
if (Cond.isUsable())
|
|
|
|
Cond = Actions.CorrectDelayedTyposInExpr(Cond);
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-12-10 14:34:36 +08:00
|
|
|
DoScope.Exit();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2008-12-12 03:48:14 +08:00
|
|
|
if (Cond.isInvalid() || Body.isInvalid())
|
|
|
|
return StmtError();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(),
|
|
|
|
Cond.get(), T.getCloseLocation());
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
|
|
|
|
2014-06-19 19:42:00 +08:00
|
|
|
bool Parser::isForRangeIdentifier() {
|
|
|
|
assert(Tok.is(tok::identifier));
|
|
|
|
|
|
|
|
const Token &Next = NextToken();
|
|
|
|
if (Next.is(tok::colon))
|
|
|
|
return true;
|
|
|
|
|
2015-06-18 18:59:26 +08:00
|
|
|
if (Next.isOneOf(tok::l_square, tok::kw_alignas)) {
|
2014-06-19 19:42:00 +08:00
|
|
|
TentativeParsingAction PA(*this);
|
|
|
|
ConsumeToken();
|
|
|
|
SkipCXX11Attributes();
|
|
|
|
bool Result = Tok.is(tok::colon);
|
|
|
|
PA.Revert();
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
/// ParseForStatement
|
|
|
|
/// for-statement: [C99 6.8.5.3]
|
|
|
|
/// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
|
|
|
|
/// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
|
2008-09-10 04:38:47 +08:00
|
|
|
/// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
|
|
|
|
/// [C++] statement
|
2015-10-22 12:46:14 +08:00
|
|
|
/// [C++0x] 'for'
|
|
|
|
/// 'co_await'[opt] [Coroutines]
|
|
|
|
/// '(' for-range-declaration ':' for-range-initializer ')'
|
|
|
|
/// statement
|
2008-01-04 01:55:25 +08:00
|
|
|
/// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
|
|
|
|
/// [OBJC2] 'for' '(' expr 'in' expr ')' statement
|
2008-09-10 04:38:47 +08:00
|
|
|
///
|
|
|
|
/// [C++] for-init-statement:
|
|
|
|
/// [C++] expression-statement
|
|
|
|
/// [C++] simple-declaration
|
|
|
|
///
|
2011-04-15 06:09:26 +08:00
|
|
|
/// [C++0x] for-range-declaration:
|
|
|
|
/// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator
|
|
|
|
/// [C++0x] for-range-initializer:
|
|
|
|
/// [C++0x] expression
|
|
|
|
/// [C++0x] braced-init-list [TODO]
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::kw_for) && "Not a for stmt!");
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2015-10-22 12:46:14 +08:00
|
|
|
SourceLocation CoawaitLoc;
|
|
|
|
if (Tok.is(tok::kw_co_await))
|
|
|
|
CoawaitLoc = ConsumeToken();
|
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2008-11-18 15:48:38 +08:00
|
|
|
Diag(Tok, diag::err_expected_lparen_after) << "for";
|
2006-08-10 12:59:57 +08:00
|
|
|
SkipUntil(tok::semi);
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2012-07-11 05:35:27 +08:00
|
|
|
bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus ||
|
2018-10-31 04:31:30 +08:00
|
|
|
getLangOpts().ObjC;
|
2008-09-11 11:06:46 +08:00
|
|
|
|
2007-08-27 07:08:06 +08:00
|
|
|
// C99 6.8.5p5 - In C99, the for statement is a block. This is not
|
|
|
|
// the case for C90. Start the loop scope.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.4p3:
|
|
|
|
// A name introduced by a declaration in a condition is in scope from its
|
|
|
|
// point of declaration until the end of the substatements controlled by the
|
|
|
|
// condition.
|
2008-09-12 07:08:39 +08:00
|
|
|
// C++ 3.3.2p4:
|
|
|
|
// Names declared in the for-init-statement, and in the condition of if,
|
|
|
|
// while, for, and switch statements are local to the if, while, for, or
|
|
|
|
// switch statement (including the controlled statement).
|
2008-09-11 11:06:46 +08:00
|
|
|
// C++ 6.5.3p1:
|
|
|
|
// Names declared in the for-init-statement are in the same declarative-region
|
|
|
|
// as those declared in the condition.
|
|
|
|
//
|
2014-01-23 23:05:00 +08:00
|
|
|
unsigned ScopeFlags = 0;
|
2009-04-22 08:54:41 +08:00
|
|
|
if (C99orCXXorObjC)
|
2014-01-23 23:05:00 +08:00
|
|
|
ScopeFlags = Scope::DeclScope | Scope::ControlScope;
|
2008-12-10 14:34:36 +08:00
|
|
|
|
|
|
|
ParseScope ForScope(this, ScopeFlags);
|
2006-08-10 12:59:57 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Value;
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2018-09-29 02:44:09 +08:00
|
|
|
bool ForEach = false;
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult FirstPart;
|
2016-06-24 03:02:52 +08:00
|
|
|
Sema::ConditionResult SecondPart;
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Collection;
|
2018-09-29 02:44:09 +08:00
|
|
|
ForRangeInfo ForRangeInfo;
|
2010-05-07 01:25:47 +08:00
|
|
|
FullExprArg ThirdPart(Actions);
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2009-09-22 04:51:25 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2011-10-08 19:31:46 +08:00
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(),
|
2010-08-27 07:41:50 +08:00
|
|
|
C99orCXXorObjC? Sema::PCC_ForInit
|
|
|
|
: Sema::PCC_Expression);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return StmtError();
|
2009-09-22 04:51:25 +08:00
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2012-06-23 13:07:58 +08:00
|
|
|
ParsedAttributesWithRange attrs(AttrFactory);
|
2013-01-02 20:01:23 +08:00
|
|
|
MaybeParseCXX11Attributes(attrs);
|
2012-06-23 13:07:58 +08:00
|
|
|
|
[clang][Parse] Diagnose useless null statements / empty init-statements
Summary:
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.
While that is great, there is at least one more source of need-less semis - 'null statements'.
Sometimes, they are needed:
```
for(int x = 0; continueToDoWork(x); x++)
; // Ugly code, but the semi is needed here.
```
But sometimes they are just there for no reason:
```
switch(X) {
case 0:
return -2345;
case 5:
return 0;
default:
return 42;
}; // <- oops
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.
```
Additionally:
```
if(; // <- empty init-statement
true)
;
switch (; // empty init-statement
x) {
...
}
for (; // <- empty init-statement
int y : S())
;
}
As usual, things may or may not go sideways in the presence of macros.
While evaluating this diag on my codebase of interest, it was unsurprisingly
discovered that Google Test macros are *very* prone to this.
And it seems many issues are deep within the GTest itself, not
in the snippets passed from the codebase that uses GTest.
So after some thought, i decided not do issue a diagnostic if the semi
is within *any* macro, be it either from the normal header, or system header.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=39111 | PR39111 ]]
Reviewers: rsmith, aaron.ballman, efriedma
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52695
llvm-svn: 347339
2018-11-21 02:59:05 +08:00
|
|
|
SourceLocation EmptyInitStmtSemiLoc;
|
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
// Parse the first part of the for specifier.
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.is(tok::semi)) { // for (;
|
2012-06-23 13:07:58 +08:00
|
|
|
ProhibitAttributes(attrs);
|
2006-08-10 13:19:57 +08:00
|
|
|
// no first part, eat the ';'.
|
[clang][Parse] Diagnose useless null statements / empty init-statements
Summary:
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.
While that is great, there is at least one more source of need-less semis - 'null statements'.
Sometimes, they are needed:
```
for(int x = 0; continueToDoWork(x); x++)
; // Ugly code, but the semi is needed here.
```
But sometimes they are just there for no reason:
```
switch(X) {
case 0:
return -2345;
case 5:
return 0;
default:
return 42;
}; // <- oops
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.
```
Additionally:
```
if(; // <- empty init-statement
true)
;
switch (; // empty init-statement
x) {
...
}
for (; // <- empty init-statement
int y : S())
;
}
As usual, things may or may not go sideways in the presence of macros.
While evaluating this diag on my codebase of interest, it was unsurprisingly
discovered that Google Test macros are *very* prone to this.
And it seems many issues are deep within the GTest itself, not
in the snippets passed from the codebase that uses GTest.
So after some thought, i decided not do issue a diagnostic if the semi
is within *any* macro, be it either from the normal header, or system header.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=39111 | PR39111 ]]
Reviewers: rsmith, aaron.ballman, efriedma
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52695
llvm-svn: 347339
2018-11-21 02:59:05 +08:00
|
|
|
SourceLocation SemiLoc = Tok.getLocation();
|
|
|
|
if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID())
|
|
|
|
EmptyInitStmtSemiLoc = SemiLoc;
|
2006-08-10 13:19:57 +08:00
|
|
|
ConsumeToken();
|
2014-06-19 19:42:00 +08:00
|
|
|
} else if (getLangOpts().CPlusPlus && Tok.is(tok::identifier) &&
|
|
|
|
isForRangeIdentifier()) {
|
|
|
|
ProhibitAttributes(attrs);
|
|
|
|
IdentifierInfo *Name = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation Loc = ConsumeToken();
|
|
|
|
MaybeParseCXX11Attributes(attrs);
|
|
|
|
|
2018-09-29 02:44:09 +08:00
|
|
|
ForRangeInfo.ColonLoc = ConsumeToken();
|
2014-06-19 19:42:00 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
2018-09-29 02:44:09 +08:00
|
|
|
ForRangeInfo.RangeExpr = ParseBraceInitializer();
|
2014-06-19 19:42:00 +08:00
|
|
|
else
|
2018-09-29 02:44:09 +08:00
|
|
|
ForRangeInfo.RangeExpr = ParseExpression();
|
2014-06-19 19:42:00 +08:00
|
|
|
|
2014-11-27 09:54:27 +08:00
|
|
|
Diag(Loc, diag::err_for_range_identifier)
|
2017-12-05 04:27:34 +08:00
|
|
|
<< ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17)
|
2014-06-19 19:42:00 +08:00
|
|
|
? FixItHint::CreateInsertion(Loc, "auto &&")
|
|
|
|
: FixItHint());
|
|
|
|
|
2018-09-29 02:44:09 +08:00
|
|
|
ForRangeInfo.LoopVar = Actions.ActOnCXXForRangeIdentifier(
|
|
|
|
getCurScope(), Loc, Name, attrs, attrs.Range.getEnd());
|
2011-12-20 09:50:37 +08:00
|
|
|
} else if (isForInitDeclaration()) { // for (int X = 4;
|
2018-06-27 07:20:26 +08:00
|
|
|
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
|
|
|
|
2006-08-10 13:19:57 +08:00
|
|
|
// Parse declaration, which eats the ';'.
|
2018-06-29 05:36:00 +08:00
|
|
|
if (!C99orCXXorObjC) { // Use of C99-style for loops in C90 mode?
|
2006-08-10 13:22:36 +08:00
|
|
|
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
|
2018-06-29 05:36:00 +08:00
|
|
|
Diag(Tok, diag::warn_gcc_variable_decl_in_for_loop);
|
|
|
|
}
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
// In C++0x, "for (T NS:a" might not be a typo for ::
|
2012-03-11 15:00:24 +08:00
|
|
|
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
|
2011-04-15 06:09:26 +08:00
|
|
|
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
|
|
|
|
|
fix a FIXME, providing accurate source range info for DeclStmt's. The end
of the range is now the ';' location. For something like this:
$ cat t2.c
#define bool int
void f(int x, int y) {
bool b = !x && y;
}
We used to produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14> <----
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <line:4:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
Now we produce:
$ clang-cc t2.c -ast-dump
typedef char *__builtin_va_list;
void f(int x, int y)
(CompoundStmt 0x2201f10 <t2.c:3:22, line:5:1>
(DeclStmt 0x2201ef0 <line:2:14, line:4:17> <------
0x2201a20 "int b =
(BinaryOperator 0x2201ed0 <col:10, col:16> 'int' '&&'
(UnaryOperator 0x2201e90 <col:10, col:11> 'int' prefix '!'
(DeclRefExpr 0x2201c90 <col:11> 'int' ParmVar='x' 0x2201a50))
(DeclRefExpr 0x2201eb0 <col:16> 'int' ParmVar='y' 0x2201e10))")
llvm-svn: 68288
2009-04-02 12:16:50 +08:00
|
|
|
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
2014-05-08 19:28:25 +08:00
|
|
|
DeclGroupPtrTy DG = ParseSimpleDeclaration(
|
2017-12-29 13:41:00 +08:00
|
|
|
DeclaratorContext::ForContext, DeclEnd, attrs, false,
|
2018-09-29 02:44:09 +08:00
|
|
|
MightBeForRangeStmt ? &ForRangeInfo : nullptr);
|
2009-03-30 01:27:48 +08:00
|
|
|
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
|
2018-09-29 02:44:09 +08:00
|
|
|
if (ForRangeInfo.ParsedForRangeDecl()) {
|
|
|
|
Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ?
|
2011-10-15 13:09:34 +08:00
|
|
|
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
|
2018-09-29 02:44:09 +08:00
|
|
|
ForRangeInfo.LoopVar = FirstPart;
|
|
|
|
FirstPart = StmtResult();
|
2011-04-15 06:09:26 +08:00
|
|
|
} else if (Tok.is(tok::semi)) { // for (int x = 4;
|
2009-03-30 01:27:48 +08:00
|
|
|
ConsumeToken();
|
|
|
|
} else if ((ForEach = isTokIdentifier_in())) {
|
2009-11-20 06:12:37 +08:00
|
|
|
Actions.ActOnForEachDeclStmt(DG);
|
2009-09-09 23:08:12 +08:00
|
|
|
// ObjC: for (id x in expr)
|
2008-01-04 01:55:25 +08:00
|
|
|
ConsumeToken(); // consume 'in'
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2010-08-24 05:17:50 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return StmtError();
|
2010-08-24 05:17:50 +08:00
|
|
|
}
|
2010-05-07 01:25:47 +08:00
|
|
|
Collection = ParseExpression();
|
2009-03-30 01:27:48 +08:00
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_semi_for);
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
2006-08-10 12:59:57 +08:00
|
|
|
} else {
|
2012-06-23 13:07:58 +08:00
|
|
|
ProhibitAttributes(attrs);
|
2014-11-21 06:06:40 +08:00
|
|
|
Value = Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
2006-11-05 04:18:38 +08:00
|
|
|
|
2010-12-04 11:47:34 +08:00
|
|
|
ForEach = isTokIdentifier_in();
|
|
|
|
|
2007-06-27 09:06:29 +08:00
|
|
|
// Turn the expression into a stmt.
|
2010-12-04 11:47:34 +08:00
|
|
|
if (!Value.isInvalid()) {
|
|
|
|
if (ForEach)
|
|
|
|
FirstPart = Actions.ActOnForEachLValueExpr(Value.get());
|
2019-01-05 00:58:14 +08:00
|
|
|
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);
|
|
|
|
}
|
2010-12-04 11:47:34 +08:00
|
|
|
}
|
2008-12-10 08:02:53 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
2006-08-10 13:19:57 +08:00
|
|
|
ConsumeToken();
|
2010-12-04 11:47:34 +08:00
|
|
|
} else if (ForEach) {
|
2008-01-04 01:55:25 +08:00
|
|
|
ConsumeToken(); // consume 'in'
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2010-08-24 05:17:50 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2016-01-16 07:43:25 +08:00
|
|
|
Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
|
|
|
return StmtError();
|
2010-08-24 05:17:50 +08:00
|
|
|
}
|
2010-05-07 01:25:47 +08:00
|
|
|
Collection = ParseExpression();
|
2013-01-02 19:42:31 +08:00
|
|
|
} else if (getLangOpts().CPlusPlus11 && Tok.is(tok::colon) && FirstPart.get()) {
|
2011-12-21 06:56:20 +08:00
|
|
|
// User tried to write the reasonable, but ill-formed, for-range-statement
|
|
|
|
// for (expr : expr) { ... }
|
|
|
|
Diag(Tok, diag::err_for_range_expected_decl)
|
|
|
|
<< FirstPart.get()->getSourceRange();
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopBeforeMatch);
|
2016-06-24 03:02:52 +08:00
|
|
|
SecondPart = Sema::ConditionError();
|
2009-03-30 00:50:03 +08:00
|
|
|
} else {
|
2011-02-17 11:38:46 +08:00
|
|
|
if (!Value.isInvalid()) {
|
|
|
|
Diag(Tok, diag::err_expected_semi_for);
|
|
|
|
} else {
|
|
|
|
// Skip until semicolon or rparen, don't consume it.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
|
2011-02-17 11:38:46 +08:00
|
|
|
if (Tok.is(tok::semi))
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2006-08-10 13:19:57 +08:00
|
|
|
}
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2014-01-23 23:05:00 +08:00
|
|
|
|
|
|
|
// Parse the second part of the for specifier.
|
|
|
|
getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
|
2018-09-29 02:44:09 +08:00
|
|
|
if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() &&
|
|
|
|
!SecondPart.isInvalid()) {
|
2008-01-04 01:55:25 +08:00
|
|
|
// Parse the second part of the for specifier.
|
|
|
|
if (Tok.is(tok::semi)) { // for (...;;
|
|
|
|
// no second part.
|
2011-02-17 11:38:46 +08:00
|
|
|
} else if (Tok.is(tok::r_paren)) {
|
|
|
|
// missing both semicolons.
|
2008-01-04 01:55:25 +08:00
|
|
|
} else {
|
2018-09-29 02:44:09 +08:00
|
|
|
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);
|
2016-06-30 05:17:59 +08:00
|
|
|
SecondPart =
|
2018-09-29 02:44:09 +08:00
|
|
|
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());
|
[clang][Parse] Diagnose useless null statements / empty init-statements
Summary:
clang has `-Wextra-semi` (D43162), which is not dictated by the currently selected standard.
While that is great, there is at least one more source of need-less semis - 'null statements'.
Sometimes, they are needed:
```
for(int x = 0; continueToDoWork(x); x++)
; // Ugly code, but the semi is needed here.
```
But sometimes they are just there for no reason:
```
switch(X) {
case 0:
return -2345;
case 5:
return 0;
default:
return 42;
}; // <- oops
;;;;;;;;;;; <- OOOOPS, still not diagnosed. Clearly this is junk.
```
Additionally:
```
if(; // <- empty init-statement
true)
;
switch (; // empty init-statement
x) {
...
}
for (; // <- empty init-statement
int y : S())
;
}
As usual, things may or may not go sideways in the presence of macros.
While evaluating this diag on my codebase of interest, it was unsurprisingly
discovered that Google Test macros are *very* prone to this.
And it seems many issues are deep within the GTest itself, not
in the snippets passed from the codebase that uses GTest.
So after some thought, i decided not do issue a diagnostic if the semi
is within *any* macro, be it either from the normal header, or system header.
Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=39111 | PR39111 ]]
Reviewers: rsmith, aaron.ballman, efriedma
Reviewed By: aaron.ballman
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D52695
llvm-svn: 347339
2018-11-21 02:59:05 +08:00
|
|
|
if (EmptyInitStmtSemiLoc.isValid()) {
|
|
|
|
Diag(EmptyInitStmtSemiLoc, diag::warn_empty_init_statement)
|
|
|
|
<< /*for-loop*/ 2
|
|
|
|
<< FixItHint::CreateRemoval(EmptyInitStmtSemiLoc);
|
|
|
|
}
|
2018-09-29 02:44:09 +08:00
|
|
|
}
|
|
|
|
} else {
|
2016-06-24 03:02:52 +08:00
|
|
|
ExprResult SecondExpr = ParseExpression();
|
|
|
|
if (SecondExpr.isInvalid())
|
|
|
|
SecondPart = Sema::ConditionError();
|
|
|
|
else
|
|
|
|
SecondPart =
|
|
|
|
Actions.ActOnCondition(getCurScope(), ForLoc, SecondExpr.get(),
|
|
|
|
Sema::ConditionKind::Boolean);
|
2010-05-07 01:25:47 +08:00
|
|
|
}
|
2008-01-04 01:55:25 +08:00
|
|
|
}
|
2018-09-29 02:44:09 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2018-09-29 02:44:09 +08:00
|
|
|
// Parse the third part of the for statement.
|
|
|
|
if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) {
|
2011-02-17 11:38:46 +08:00
|
|
|
if (Tok.isNot(tok::semi)) {
|
2016-06-24 03:02:52 +08:00
|
|
|
if (!SecondPart.isInvalid())
|
2011-02-17 11:38:46 +08:00
|
|
|
Diag(Tok, diag::err_expected_semi_for);
|
|
|
|
else
|
|
|
|
// Skip until semicolon or rparen, don't consume it.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
|
2011-02-17 11:38:46 +08:00
|
|
|
}
|
|
|
|
|
2008-01-04 01:55:25 +08:00
|
|
|
if (Tok.is(tok::semi)) {
|
|
|
|
ConsumeToken();
|
|
|
|
}
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2010-05-07 01:25:47 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) { // for (...;...;)
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Third = ParseExpression();
|
2013-01-15 06:39:08 +08:00
|
|
|
// FIXME: The C++11 standard doesn't actually say that this is a
|
|
|
|
// discarded-value expression, but it clearly should be.
|
2014-05-29 18:55:11 +08:00
|
|
|
ThirdPart = Actions.MakeFullDiscardedValueExpr(Third.get());
|
2010-05-07 01:25:47 +08:00
|
|
|
}
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2006-08-11 07:14:52 +08:00
|
|
|
// Match the ')'.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2015-10-22 12:46:14 +08:00
|
|
|
// C++ Coroutines [stmt.iter]:
|
|
|
|
// 'co_await' can only be used for a range-based for statement.
|
2018-09-29 02:44:09 +08:00
|
|
|
if (CoawaitLoc.isValid() && !ForRangeInfo.ParsedForRangeDecl()) {
|
2015-10-22 12:46:14 +08:00
|
|
|
Diag(CoawaitLoc, diag::err_for_co_await_not_range_for);
|
|
|
|
CoawaitLoc = SourceLocation();
|
|
|
|
}
|
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
// We need to perform most of the semantic analysis for a C++0x for-range
|
|
|
|
// statememt before parsing the body, in order to be able to deduce the type
|
|
|
|
// of an auto-typed loop variable.
|
|
|
|
StmtResult ForRangeStmt;
|
2012-07-04 06:00:52 +08:00
|
|
|
StmtResult ForEachStmt;
|
2012-07-11 05:35:27 +08:00
|
|
|
|
2018-09-29 02:44:09 +08:00
|
|
|
if (ForRangeInfo.ParsedForRangeDecl()) {
|
2016-02-03 01:33:09 +08:00
|
|
|
ExprResult CorrectedRange =
|
2018-09-29 02:44:09 +08:00
|
|
|
Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get());
|
2015-10-27 14:02:45 +08:00
|
|
|
ForRangeStmt = Actions.ActOnCXXForRangeStmt(
|
|
|
|
getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(),
|
2018-09-29 02:44:09 +08:00
|
|
|
ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, CorrectedRange.get(),
|
2015-10-27 14:02:45 +08:00
|
|
|
T.getCloseLocation(), Sema::BFRK_Build);
|
2011-07-27 09:07:15 +08:00
|
|
|
|
|
|
|
// Similarly, we need to do the semantic analysis for a for-range
|
|
|
|
// statement immediately in order to close over temporaries correctly.
|
|
|
|
} else if (ForEach) {
|
2012-08-17 05:47:25 +08:00
|
|
|
ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
FirstPart.get(),
|
|
|
|
Collection.get(),
|
2012-07-04 06:00:52 +08:00
|
|
|
T.getCloseLocation());
|
2015-04-30 12:23:23 +08:00
|
|
|
} else {
|
|
|
|
// In OpenMP loop region loop control variable must be captured and be
|
|
|
|
// private. Perform analysis of first part (if any).
|
|
|
|
if (getLangOpts().OpenMP && FirstPart.isUsable()) {
|
|
|
|
Actions.ActOnOpenMPLoopInitialization(ForLoc, FirstPart.get());
|
|
|
|
}
|
2011-07-27 09:07:15 +08:00
|
|
|
}
|
|
|
|
|
2013-12-03 15:36:55 +08:00
|
|
|
// C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
|
2007-08-22 13:33:11 +08:00
|
|
|
// 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.
|
2008-09-11 11:06:46 +08:00
|
|
|
//
|
|
|
|
// C++ 6.5p2:
|
|
|
|
// The substatement in an iteration-statement implicitly defines a local scope
|
|
|
|
// which is entered and exited each time through the loop.
|
|
|
|
//
|
|
|
|
// See comments in ParseIfStatement for why we create a scope for
|
|
|
|
// for-init-statement/condition and a new scope for substatement in C++.
|
|
|
|
//
|
2014-03-05 16:57:59 +08:00
|
|
|
ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC,
|
|
|
|
Tok.is(tok::l_brace));
|
|
|
|
|
|
|
|
// The body of the for loop has the same local mangling number as the
|
|
|
|
// for-init-statement.
|
|
|
|
// It will only be incremented if the body contains other things that would
|
|
|
|
// normally increment the mangling number (like a compound statement).
|
|
|
|
if (C99orCXXorObjC)
|
2015-03-20 05:54:30 +08:00
|
|
|
getCurScope()->decrementMSManglingNumber();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2006-08-10 12:59:57 +08:00
|
|
|
// Read the body statement.
|
2011-12-23 07:26:17 +08:00
|
|
|
StmtResult Body(ParseStatement(TrailingElseLoc));
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-08-22 13:28:50 +08:00
|
|
|
// Pop the body scope if needed.
|
2008-12-10 14:34:36 +08:00
|
|
|
InnerScope.Exit();
|
2007-08-22 13:28:50 +08:00
|
|
|
|
2006-11-06 07:47:55 +08:00
|
|
|
// Leave the for-scope.
|
2008-12-10 14:34:36 +08:00
|
|
|
ForScope.Exit();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
|
|
|
if (Body.isInvalid())
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2008-12-10 08:02:53 +08:00
|
|
|
|
2011-04-15 06:09:26 +08:00
|
|
|
if (ForEach)
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.FinishObjCForCollectionStmt(ForEachStmt.get(),
|
|
|
|
Body.get());
|
2011-04-15 06:09:26 +08:00
|
|
|
|
2018-09-29 02:44:09 +08:00
|
|
|
if (ForRangeInfo.ParsedForRangeDecl())
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
|
2010-05-07 01:25:47 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(),
|
2016-06-24 03:02:52 +08:00
|
|
|
SecondPart, ThirdPart, T.getCloseLocation(),
|
|
|
|
Body.get());
|
2006-08-10 12:59:57 +08:00
|
|
|
}
|
2006-08-10 12:23:57 +08:00
|
|
|
|
2006-08-10 13:45:44 +08:00
|
|
|
/// ParseGotoStatement
|
|
|
|
/// jump-statement:
|
|
|
|
/// 'goto' identifier ';'
|
|
|
|
/// [GNU] 'goto' '*' expression ';'
|
|
|
|
///
|
|
|
|
/// Note: this lets the caller parse the end ';'.
|
|
|
|
///
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseGotoStatement() {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Res;
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
2011-02-18 09:27:55 +08:00
|
|
|
LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation());
|
|
|
|
Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), LD);
|
2006-08-10 13:45:44 +08:00
|
|
|
ConsumeToken();
|
2009-04-28 08:51:18 +08:00
|
|
|
} else if (Tok.is(tok::star)) {
|
2006-08-10 13:45:44 +08:00
|
|
|
// GNU indirect goto extension.
|
|
|
|
Diag(Tok, diag::ext_gnu_indirect_goto);
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation StarLoc = ConsumeToken();
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult R(ParseExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::semi, StopBeforeMatch);
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-10-16 13:52:41 +08:00
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.get());
|
2007-07-22 12:13:33 +08:00
|
|
|
} else {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::identifier;
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-08-10 13:45:44 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2006-08-10 13:45:44 +08:00
|
|
|
}
|
|
|
|
|
2006-11-06 07:47:55 +08:00
|
|
|
/// ParseContinueStatement
|
|
|
|
/// jump-statement:
|
|
|
|
/// 'continue' ';'
|
|
|
|
///
|
|
|
|
/// Note: this lets the caller parse the end ';'.
|
|
|
|
///
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseContinueStatement() {
|
2006-11-06 07:47:55 +08:00
|
|
|
SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnContinueStmt(ContinueLoc, getCurScope());
|
2006-11-06 07:47:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseBreakStatement
|
|
|
|
/// jump-statement:
|
|
|
|
/// 'break' ';'
|
|
|
|
///
|
|
|
|
/// Note: this lets the caller parse the end ';'.
|
|
|
|
///
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseBreakStatement() {
|
2006-11-06 07:47:55 +08:00
|
|
|
SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
|
2010-07-03 01:43:08 +08:00
|
|
|
return Actions.ActOnBreakStmt(BreakLoc, getCurScope());
|
2006-11-06 07:47:55 +08:00
|
|
|
}
|
|
|
|
|
2006-08-10 13:45:44 +08:00
|
|
|
/// ParseReturnStatement
|
|
|
|
/// jump-statement:
|
|
|
|
/// 'return' expression[opt] ';'
|
2015-10-22 12:46:14 +08:00
|
|
|
/// 'return' braced-init-list ';'
|
|
|
|
/// 'co_return' expression[opt] ';'
|
|
|
|
/// 'co_return' braced-init-list ';'
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseReturnStatement() {
|
2015-10-22 12:46:14 +08:00
|
|
|
assert((Tok.is(tok::kw_return) || Tok.is(tok::kw_co_return)) &&
|
|
|
|
"Not a return stmt!");
|
|
|
|
bool IsCoreturn = Tok.is(tok::kw_co_return);
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
|
2008-12-12 03:48:14 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult R;
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::semi)) {
|
2019-02-01 04:20:32 +08:00
|
|
|
if (!IsCoreturn)
|
|
|
|
PreferredType.enterReturn(Actions, Tok.getLocation());
|
2015-10-22 12:46:14 +08:00
|
|
|
// FIXME: Code completion for co_return.
|
|
|
|
if (Tok.is(tok::code_completion) && !IsCoreturn) {
|
2019-02-01 04:20:32 +08:00
|
|
|
Actions.CodeCompleteExpression(getCurScope(),
|
|
|
|
PreferredType.get(Tok.getLocation()));
|
2011-09-04 11:32:15 +08:00
|
|
|
cutOffParsing();
|
2010-05-30 09:49:25 +08:00
|
|
|
return StmtError();
|
|
|
|
}
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) {
|
2011-03-12 07:10:44 +08:00
|
|
|
R = ParseInitializer();
|
2011-10-15 13:09:34 +08:00
|
|
|
if (R.isUsable())
|
2018-08-10 05:08:08 +08:00
|
|
|
Diag(R.get()->getBeginLoc(),
|
|
|
|
getLangOpts().CPlusPlus11
|
|
|
|
? diag::warn_cxx98_compat_generalized_initializer_lists
|
|
|
|
: diag::ext_generalized_initializer_lists)
|
|
|
|
<< R.get()->getSourceRange();
|
2011-03-12 07:10:44 +08:00
|
|
|
} else
|
2015-01-04 16:07:54 +08:00
|
|
|
R = ParseExpression();
|
2013-12-04 11:51:59 +08:00
|
|
|
if (R.isInvalid()) {
|
|
|
|
SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
|
2008-12-12 03:48:14 +08:00
|
|
|
return StmtError();
|
2006-10-16 13:52:41 +08:00
|
|
|
}
|
2006-08-13 00:59:03 +08:00
|
|
|
}
|
2015-10-22 14:13:50 +08:00
|
|
|
if (IsCoreturn)
|
2017-03-07 07:38:15 +08:00
|
|
|
return Actions.ActOnCoreturnStmt(getCurScope(), ReturnLoc, R.get());
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
|
2006-08-10 13:45:44 +08:00
|
|
|
}
|
2006-08-15 14:03:28 +08:00
|
|
|
|
2016-01-13 19:18:54 +08:00
|
|
|
StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
|
2019-02-15 08:27:53 +08:00
|
|
|
ParsedStmtContext StmtCtx,
|
2014-06-06 20:40:24 +08:00
|
|
|
SourceLocation *TrailingElseLoc,
|
|
|
|
ParsedAttributesWithRange &Attrs) {
|
|
|
|
// Create temporary attribute list.
|
|
|
|
ParsedAttributesWithRange TempAttrs(AttrFactory);
|
|
|
|
|
2014-07-22 02:08:34 +08:00
|
|
|
// Get loop hints and consume annotated token.
|
2014-06-06 20:40:24 +08:00
|
|
|
while (Tok.is(tok::annot_pragma_loop_hint)) {
|
2014-08-01 04:15:14 +08:00
|
|
|
LoopHint Hint;
|
|
|
|
if (!HandlePragmaLoopHint(Hint))
|
|
|
|
continue;
|
2014-06-06 20:40:24 +08:00
|
|
|
|
2014-08-01 04:15:14 +08:00
|
|
|
ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc,
|
2014-06-06 20:40:24 +08:00
|
|
|
ArgsUnion(Hint.ValueExpr)};
|
2014-07-22 02:08:34 +08:00
|
|
|
TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
|
|
|
|
Hint.PragmaNameLoc->Loc, ArgHints, 4,
|
2018-07-13 23:07:47 +08:00
|
|
|
ParsedAttr::AS_Pragma);
|
2014-06-06 20:40:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the next statement.
|
|
|
|
MaybeParseCXX11Attributes(Attrs);
|
|
|
|
|
|
|
|
StmtResult S = ParseStatementOrDeclarationAfterAttributes(
|
2019-02-15 08:27:53 +08:00
|
|
|
Stmts, StmtCtx, TrailingElseLoc, Attrs);
|
2014-06-06 20:40:24 +08:00
|
|
|
|
|
|
|
Attrs.takeAllFrom(TempAttrs);
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2011-03-17 01:05:57 +08:00
|
|
|
Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
|
2009-03-05 08:49:17 +08:00
|
|
|
assert(Tok.is(tok::l_brace));
|
|
|
|
SourceLocation LBraceLoc = Tok.getLocation();
|
2009-04-27 04:35:05 +08:00
|
|
|
|
2018-03-23 08:07:18 +08:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, Decl, LBraceLoc,
|
2010-08-27 07:41:50 +08:00
|
|
|
"parsing function body");
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-11-20 15:02:57 +08:00
|
|
|
// Save and reset current vtordisp stack if we have entered a C++ method body.
|
|
|
|
bool IsCXXMethod =
|
|
|
|
getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
|
2016-04-29 19:27:00 +08:00
|
|
|
Sema::PragmaStackSentinelRAII
|
|
|
|
PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
|
2015-11-20 15:02:57 +08:00
|
|
|
|
2007-11-09 03:01:26 +08:00
|
|
|
// Do not enter a scope for the brace, as the arguments are in the same scope
|
|
|
|
// (the function body) as the body itself. Instead, just read the statement
|
|
|
|
// list and put it into a CompoundStmt for safe keeping.
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult FnBody(ParseCompoundStatementBody());
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2007-11-09 03:01:26 +08:00
|
|
|
// If the function body could not be parsed, make a bogus compoundstmt.
|
2012-02-15 06:14:32 +08:00
|
|
|
if (FnBody.isInvalid()) {
|
|
|
|
Sema::CompoundScopeRAII CompoundScope(Actions);
|
2013-08-20 04:51:20 +08:00
|
|
|
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
|
2012-02-15 06:14:32 +08:00
|
|
|
}
|
2008-12-12 03:30:53 +08:00
|
|
|
|
2011-03-17 01:05:57 +08:00
|
|
|
BodyScope.Exit();
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnFinishFunctionBody(Decl, FnBody.get());
|
2007-12-01 16:06:07 +08:00
|
|
|
}
|
2008-12-22 00:41:36 +08:00
|
|
|
|
2009-04-27 04:35:05 +08:00
|
|
|
/// ParseFunctionTryBlock - Parse a C++ function-try-block.
|
|
|
|
///
|
|
|
|
/// function-try-block:
|
|
|
|
/// 'try' ctor-initializer[opt] compound-statement handler-seq
|
|
|
|
///
|
2011-03-17 01:05:57 +08:00
|
|
|
Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
|
2009-04-27 04:35:05 +08:00
|
|
|
assert(Tok.is(tok::kw_try) && "Expected 'try'");
|
|
|
|
SourceLocation TryLoc = ConsumeToken();
|
|
|
|
|
2018-03-23 08:07:18 +08:00
|
|
|
PrettyDeclStackTraceEntry CrashInfo(Actions.Context, Decl, TryLoc,
|
2010-08-27 07:41:50 +08:00
|
|
|
"parsing function try block");
|
2009-04-27 04:35:05 +08:00
|
|
|
|
|
|
|
// Constructor initializer list?
|
|
|
|
if (Tok.is(tok::colon))
|
|
|
|
ParseConstructorInitializer(Decl);
|
2011-09-08 04:36:12 +08:00
|
|
|
else
|
|
|
|
Actions.ActOnDefaultCtorInitializers(Decl);
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2015-11-20 15:02:57 +08:00
|
|
|
// Save and reset current vtordisp stack if we have entered a C++ method body.
|
|
|
|
bool IsCXXMethod =
|
|
|
|
getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
|
2016-04-29 19:27:00 +08:00
|
|
|
Sema::PragmaStackSentinelRAII
|
|
|
|
PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
|
2015-11-20 15:02:57 +08:00
|
|
|
|
2009-04-27 05:08:36 +08:00
|
|
|
SourceLocation LBraceLoc = Tok.getLocation();
|
2012-11-10 09:04:23 +08:00
|
|
|
StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true));
|
2009-04-27 04:35:05 +08:00
|
|
|
// If we failed to parse the try-catch, we just give the function an empty
|
|
|
|
// compound statement as the body.
|
2012-02-15 06:14:32 +08:00
|
|
|
if (FnBody.isInvalid()) {
|
|
|
|
Sema::CompoundScopeRAII CompoundScope(Actions);
|
2013-08-20 04:51:20 +08:00
|
|
|
FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
|
2012-02-15 06:14:32 +08:00
|
|
|
}
|
2009-04-27 04:35:05 +08:00
|
|
|
|
2011-03-17 01:05:57 +08:00
|
|
|
BodyScope.Exit();
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnFinishFunctionBody(Decl, FnBody.get());
|
2009-04-27 04:35:05 +08:00
|
|
|
}
|
|
|
|
|
2012-04-12 18:11:59 +08:00
|
|
|
bool Parser::trySkippingFunctionBody() {
|
|
|
|
assert(SkipFunctionBodies &&
|
|
|
|
"Should only be called when SkipFunctionBodies is enabled");
|
2012-11-01 01:29:28 +08:00
|
|
|
if (!PP.isCodeCompletionEnabled()) {
|
2016-06-17 05:40:06 +08:00
|
|
|
SkipFunctionBody();
|
2012-11-01 01:29:28 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-01-04 06:33:06 +08:00
|
|
|
// We're in code-completion mode. Skip parsing for all function bodies unless
|
|
|
|
// the body contains the code-completion point.
|
|
|
|
TentativeParsingAction PA(*this);
|
2016-06-17 05:40:06 +08:00
|
|
|
bool IsTryCatch = Tok.is(tok::kw_try);
|
|
|
|
CachedTokens Toks;
|
|
|
|
bool ErrorInPrologue = ConsumeAndStoreFunctionPrologue(Toks);
|
|
|
|
if (llvm::any_of(Toks, [](const Token &Tok) {
|
|
|
|
return Tok.is(tok::code_completion);
|
|
|
|
})) {
|
|
|
|
PA.Revert();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (ErrorInPrologue) {
|
2011-01-04 06:33:06 +08:00
|
|
|
PA.Commit();
|
2016-06-17 05:40:06 +08:00
|
|
|
SkipMalformedDecl();
|
2011-01-04 06:33:06 +08:00
|
|
|
return true;
|
|
|
|
}
|
2016-06-17 05:40:06 +08:00
|
|
|
if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
|
|
|
|
PA.Revert();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
while (IsTryCatch && Tok.is(tok::kw_catch)) {
|
|
|
|
if (!SkipUntil(tok::l_brace, StopAtCodeCompletion) ||
|
|
|
|
!SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
|
|
|
|
PA.Revert();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PA.Commit();
|
|
|
|
return true;
|
2011-01-04 06:33:06 +08:00
|
|
|
}
|
|
|
|
|
2008-12-22 00:41:36 +08:00
|
|
|
/// ParseCXXTryBlock - Parse a C++ try-block.
|
|
|
|
///
|
|
|
|
/// try-block:
|
|
|
|
/// 'try' compound-statement handler-seq
|
|
|
|
///
|
2012-04-14 08:33:13 +08:00
|
|
|
StmtResult Parser::ParseCXXTryBlock() {
|
2008-12-22 00:41:36 +08:00
|
|
|
assert(Tok.is(tok::kw_try) && "Expected 'try'");
|
|
|
|
|
|
|
|
SourceLocation TryLoc = ConsumeToken();
|
2009-04-27 04:35:05 +08:00
|
|
|
return ParseCXXTryBlockCommon(TryLoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseCXXTryBlockCommon - Parse the common part of try-block and
|
|
|
|
/// function-try-block.
|
|
|
|
///
|
|
|
|
/// try-block:
|
|
|
|
/// 'try' compound-statement handler-seq
|
|
|
|
///
|
|
|
|
/// function-try-block:
|
|
|
|
/// 'try' ctor-initializer[opt] compound-statement handler-seq
|
|
|
|
///
|
|
|
|
/// handler-seq:
|
|
|
|
/// handler handler-seq[opt]
|
|
|
|
///
|
2011-04-28 09:08:34 +08:00
|
|
|
/// [Borland] try-block:
|
|
|
|
/// 'try' compound-statement seh-except-block
|
2013-12-06 00:25:25 +08:00
|
|
|
/// 'try' compound-statement seh-finally-block
|
2011-04-28 09:08:34 +08:00
|
|
|
///
|
2012-11-10 09:04:23 +08:00
|
|
|
StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
|
2008-12-22 00:41:36 +08:00
|
|
|
if (Tok.isNot(tok::l_brace))
|
2013-12-24 17:48:30 +08:00
|
|
|
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
|
2012-04-14 08:33:13 +08:00
|
|
|
|
2017-08-10 23:43:06 +08:00
|
|
|
StmtResult TryBlock(ParseCompoundStatement(
|
|
|
|
/*isStmtExpr=*/false, Scope::DeclScope | Scope::TryScope |
|
|
|
|
Scope::CompoundStmtScope |
|
|
|
|
(FnTry ? Scope::FnTryCatchScope : 0)));
|
2008-12-22 00:41:36 +08:00
|
|
|
if (TryBlock.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return TryBlock;
|
2008-12-22 00:41:36 +08:00
|
|
|
|
2011-04-28 09:08:34 +08:00
|
|
|
// Borland allows SEH-handlers with 'try'
|
2012-07-11 05:35:27 +08:00
|
|
|
|
2012-04-14 08:33:13 +08:00
|
|
|
if ((Tok.is(tok::identifier) &&
|
|
|
|
Tok.getIdentifierInfo() == getSEHExceptKeyword()) ||
|
|
|
|
Tok.is(tok::kw___finally)) {
|
2011-04-28 09:08:34 +08:00
|
|
|
// TODO: Factor into common return ParseSEHHandlerCommon(...)
|
|
|
|
StmtResult Handler;
|
2011-10-21 11:57:52 +08:00
|
|
|
if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
|
2011-04-28 09:08:34 +08:00
|
|
|
SourceLocation Loc = ConsumeToken();
|
|
|
|
Handler = ParseSEHExceptBlock(Loc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SourceLocation Loc = ConsumeToken();
|
|
|
|
Handler = ParseSEHFinallyBlock(Loc);
|
|
|
|
}
|
|
|
|
if(Handler.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Handler;
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
|
|
|
|
TryLoc,
|
2014-05-29 18:55:11 +08:00
|
|
|
TryBlock.get(),
|
2014-07-26 04:52:51 +08:00
|
|
|
Handler.get());
|
2008-12-22 00:41:36 +08:00
|
|
|
}
|
2011-04-28 09:08:34 +08:00
|
|
|
else {
|
2012-08-24 06:51:59 +08:00
|
|
|
StmtVector Handlers;
|
2013-10-15 09:34:54 +08:00
|
|
|
|
|
|
|
// C++11 attributes can't appear here, despite this context seeming
|
|
|
|
// statement-like.
|
|
|
|
DiagnoseAndSkipCXX11Attributes();
|
2011-04-28 09:08:34 +08:00
|
|
|
|
|
|
|
if (Tok.isNot(tok::kw_catch))
|
|
|
|
return StmtError(Diag(Tok, diag::err_expected_catch));
|
|
|
|
while (Tok.is(tok::kw_catch)) {
|
2012-11-10 09:04:23 +08:00
|
|
|
StmtResult Handler(ParseCXXCatchBlock(FnTry));
|
2011-04-28 09:08:34 +08:00
|
|
|
if (!Handler.isInvalid())
|
2014-05-29 18:55:11 +08:00
|
|
|
Handlers.push_back(Handler.get());
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
|
|
|
// Don't bother creating the full statement if we don't have any usable
|
|
|
|
// handlers.
|
|
|
|
if (Handlers.empty())
|
|
|
|
return StmtError();
|
2008-12-22 00:41:36 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.get(), Handlers);
|
2011-04-28 09:08:34 +08:00
|
|
|
}
|
2008-12-22 00:41:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
|
|
|
|
///
|
2013-01-29 17:02:09 +08:00
|
|
|
/// handler:
|
|
|
|
/// 'catch' '(' exception-declaration ')' compound-statement
|
2008-12-22 00:41:36 +08:00
|
|
|
///
|
2013-01-29 17:02:09 +08:00
|
|
|
/// exception-declaration:
|
|
|
|
/// attribute-specifier-seq[opt] type-specifier-seq declarator
|
|
|
|
/// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
|
|
|
|
/// '...'
|
2008-12-22 00:41:36 +08:00
|
|
|
///
|
2012-11-10 09:04:23 +08:00
|
|
|
StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
|
2008-12-22 00:41:36 +08:00
|
|
|
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
|
|
|
|
|
|
|
|
SourceLocation CatchLoc = ConsumeToken();
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
2014-01-01 11:08:43 +08:00
|
|
|
if (T.expectAndConsume())
|
2008-12-22 00:41:36 +08:00
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
// C++ 3.3.2p3:
|
|
|
|
// The name in a catch exception-declaration is local to the handler and
|
|
|
|
// shall not be redeclared in the outermost block of the handler.
|
2019-03-23 00:08:29 +08:00
|
|
|
ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope |
|
Un-revert "[coroutines][PR40978] Emit error for co_yield within catch block"
Summary:
https://reviews.llvm.org/D59076 added a new coroutine error that
prevented users from using 'co_await' or 'co_yield' within a exception
handler. However, it was reverted in https://reviews.llvm.org/rC356774
because it caused a regression in nested scopes in C++ catch statements,
as documented by https://bugs.llvm.org/show_bug.cgi?id=41171.
The issue was due to an incorrect use of a `clang::ParseScope`. To fix:
1. Add a regression test for catch statement parsing that mimics the bug
report from https://bugs.llvm.org/show_bug.cgi?id=41171.
2. Re-apply the coroutines error patch from
https://reviews.llvm.org/D59076, but this time with the correct
ParseScope behavior.
Reviewers: GorNishanov, tks2103, rsmith, riccibruno, jbulow
Reviewed By: riccibruno
Subscribers: EricWF, jdoerfert, lewissbaker, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D59752
llvm-svn: 356865
2019-03-25 08:53:10 +08:00
|
|
|
Scope::CatchScope |
|
|
|
|
(FnCatch ? Scope::FnTryCatchScope : 0));
|
2008-12-22 00:41:36 +08:00
|
|
|
|
|
|
|
// exception-declaration is equivalent to '...' or a parameter-declaration
|
|
|
|
// without default arguments.
|
2014-05-21 14:02:52 +08:00
|
|
|
Decl *ExceptionDecl = nullptr;
|
2008-12-22 00:41:36 +08:00
|
|
|
if (Tok.isNot(tok::ellipsis)) {
|
2013-01-29 17:02:09 +08:00
|
|
|
ParsedAttributesWithRange Attributes(AttrFactory);
|
|
|
|
MaybeParseCXX11Attributes(Attributes);
|
|
|
|
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2013-01-29 17:02:09 +08:00
|
|
|
DS.takeAttributesFrom(Attributes);
|
|
|
|
|
2008-12-23 03:15:10 +08:00
|
|
|
if (ParseCXXTypeSpecifierSeq(DS))
|
|
|
|
return StmtError();
|
2013-01-29 17:02:09 +08:00
|
|
|
|
2017-12-29 13:41:00 +08:00
|
|
|
Declarator ExDecl(DS, DeclaratorContext::CXXCatchContext);
|
2008-12-22 00:41:36 +08:00
|
|
|
ParseDeclarator(ExDecl);
|
2010-07-03 01:43:08 +08:00
|
|
|
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
|
2008-12-22 00:41:36 +08:00
|
|
|
} else
|
|
|
|
ConsumeToken();
|
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
if (T.getCloseLocation().isInvalid())
|
2008-12-22 00:41:36 +08:00
|
|
|
return StmtError();
|
|
|
|
|
|
|
|
if (Tok.isNot(tok::l_brace))
|
2013-12-24 17:48:30 +08:00
|
|
|
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
|
2008-12-22 00:41:36 +08:00
|
|
|
|
2009-11-21 16:43:09 +08:00
|
|
|
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
|
2019-03-23 00:08:29 +08:00
|
|
|
StmtResult Block(ParseCompoundStatement());
|
2008-12-22 00:41:36 +08:00
|
|
|
if (Block.isInvalid())
|
2012-08-24 05:35:17 +08:00
|
|
|
return Block;
|
2008-12-22 00:41:36 +08:00
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.get());
|
2008-12-22 00:41:36 +08:00
|
|
|
}
|
2011-05-07 04:48:22 +08:00
|
|
|
|
|
|
|
void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
|
2011-10-25 06:31:10 +08:00
|
|
|
IfExistsCondition Result;
|
2011-05-08 01:30:27 +08:00
|
|
|
if (ParseMicrosoftIfExistsCondition(Result))
|
2011-05-07 04:48:22 +08:00
|
|
|
return;
|
2011-10-08 19:31:46 +08:00
|
|
|
|
2011-10-25 06:31:10 +08:00
|
|
|
// Handle dependent statements by parsing the braces as a compound statement.
|
|
|
|
// This is not the same behavior as Visual C++, which don't treat this as a
|
|
|
|
// compound statement, but for Clang's type checking we can't have anything
|
|
|
|
// inside these braces escaping to the surrounding code.
|
|
|
|
if (Result.Behavior == IEB_Dependent) {
|
|
|
|
if (!Tok.is(tok::l_brace)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
2012-04-14 08:33:13 +08:00
|
|
|
return;
|
2011-10-25 06:31:10 +08:00
|
|
|
}
|
2012-04-14 08:33:13 +08:00
|
|
|
|
|
|
|
StmtResult Compound = ParseCompoundStatement();
|
2011-10-25 09:33:02 +08:00
|
|
|
if (Compound.isInvalid())
|
|
|
|
return;
|
2012-04-14 08:33:13 +08:00
|
|
|
|
2011-10-25 09:33:02 +08:00
|
|
|
StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc,
|
|
|
|
Result.IsIfExists,
|
2012-04-14 08:33:13 +08:00
|
|
|
Result.SS,
|
2011-10-25 09:33:02 +08:00
|
|
|
Result.Name,
|
|
|
|
Compound.get());
|
|
|
|
if (DepResult.isUsable())
|
|
|
|
Stmts.push_back(DepResult.get());
|
2011-10-25 06:31:10 +08:00
|
|
|
return;
|
|
|
|
}
|
2012-04-14 08:33:13 +08:00
|
|
|
|
2011-10-25 06:31:10 +08:00
|
|
|
BalancedDelimiterTracker Braces(*this, tok::l_brace);
|
|
|
|
if (Braces.consumeOpen()) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::l_brace;
|
2011-05-07 04:48:22 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-10-25 06:31:10 +08:00
|
|
|
switch (Result.Behavior) {
|
|
|
|
case IEB_Parse:
|
|
|
|
// Parse the statements below.
|
|
|
|
break;
|
2012-07-11 05:35:27 +08:00
|
|
|
|
2011-10-25 06:31:10 +08:00
|
|
|
case IEB_Dependent:
|
|
|
|
llvm_unreachable("Dependent case handled above");
|
2012-07-11 05:35:27 +08:00
|
|
|
|
2011-10-25 06:31:10 +08:00
|
|
|
case IEB_Skip:
|
|
|
|
Braces.skipToEnd();
|
2011-05-07 04:48:22 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Condition is true, parse the statements.
|
|
|
|
while (Tok.isNot(tok::r_brace)) {
|
2019-02-15 08:27:53 +08:00
|
|
|
StmtResult R =
|
|
|
|
ParseStatementOrDeclaration(Stmts, ParsedStmtContext::Compound);
|
2011-05-07 04:48:22 +08:00
|
|
|
if (R.isUsable())
|
2014-05-29 18:55:11 +08:00
|
|
|
Stmts.push_back(R.get());
|
2011-05-07 04:48:22 +08:00
|
|
|
}
|
2011-10-25 06:31:10 +08:00
|
|
|
Braces.consumeClose();
|
2011-05-07 04:48:22 +08:00
|
|
|
}
|
2016-02-20 02:30:11 +08:00
|
|
|
|
|
|
|
bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
|
|
|
|
MaybeParseGNUAttributes(Attrs);
|
|
|
|
|
|
|
|
if (Attrs.empty())
|
|
|
|
return true;
|
|
|
|
|
2018-07-13 23:07:47 +08:00
|
|
|
if (Attrs.begin()->getKind() != ParsedAttr::AT_OpenCLUnrollHint)
|
2016-02-20 02:30:11 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
|
|
|
|
Diag(Tok, diag::err_opencl_unroll_hint_on_non_loop);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|