1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398 |
- //===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the Statement and Block portions of the Parser
- // interface.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/PrettyDeclStackTrace.h"
- #include "clang/Basic/Attributes.h"
- #include "clang/Basic/PrettyStackTrace.h"
- #include "clang/Parse/LoopHint.h"
- #include "clang/Parse/Parser.h"
- #include "clang/Parse/RAIIObjectsForParser.h"
- #include "clang/Sema/DeclSpec.h"
- #include "clang/Sema/Scope.h"
- #include "clang/Sema/TypoCorrection.h"
- using namespace clang;
- //===----------------------------------------------------------------------===//
- // C99 6.8: Statements and Blocks.
- //===----------------------------------------------------------------------===//
- /// Parse a standalone statement (for instance, as the body of an 'if',
- /// 'while', or 'for').
- StmtResult Parser::ParseStatement(SourceLocation *TrailingElseLoc,
- ParsedStmtContext StmtCtx) {
- 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;
- Res = ParseStatementOrDeclaration(Stmts, StmtCtx, TrailingElseLoc);
- } while (!Res.isInvalid() && !Res.get());
- return Res;
- }
- /// ParseStatementOrDeclaration - Read 'statement' or 'declaration'.
- /// StatementOrDeclaration:
- /// statement
- /// declaration
- ///
- /// statement:
- /// labeled-statement
- /// compound-statement
- /// expression-statement
- /// selection-statement
- /// iteration-statement
- /// jump-statement
- /// [C++] declaration-statement
- /// [C++] try-block
- /// [MS] seh-try-block
- /// [OBC] objc-throw-statement
- /// [OBC] objc-try-catch-statement
- /// [OBC] objc-synchronized-statement
- /// [GNU] asm-statement
- /// [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
- ///
- /// expression-statement:
- /// expression[opt] ';'
- ///
- /// jump-statement:
- /// 'goto' identifier ';'
- /// 'continue' ';'
- /// 'break' ';'
- /// 'return' expression[opt] ';'
- /// [GNU] 'goto' '*' expression ';'
- ///
- /// [OBC] objc-throw-statement:
- /// [OBC] '@' 'throw' expression ';'
- /// [OBC] '@' 'throw' ';'
- ///
- StmtResult
- Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
- ParsedStmtContext StmtCtx,
- SourceLocation *TrailingElseLoc) {
- ParenBraceBracketBalancer BalancerRAIIObj(*this);
- ParsedAttributesWithRange Attrs(AttrFactory);
- MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
- if (!MaybeParseOpenCLUnrollHintAttribute(Attrs))
- return StmtError();
- StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
- Stmts, StmtCtx, TrailingElseLoc, Attrs);
- assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) &&
- "attributes on empty statement");
- if (Attrs.empty() || Res.isInvalid())
- return Res;
- return Actions.ProcessStmtAttributes(Res.get(), Attrs, Attrs.Range);
- }
- namespace {
- class StatementFilterCCC final : public CorrectionCandidateCallback {
- public:
- StatementFilterCCC(Token nextTok) : NextToken(nextTok) {
- 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);
- WantCXXNamedCasts = false;
- }
- bool ValidateCandidate(const TypoCorrection &candidate) override {
- if (FieldDecl *FD = candidate.getCorrectionDeclAs<FieldDecl>())
- return !candidate.getCorrectionSpecifier() || isa<ObjCIvarDecl>(FD);
- if (NextToken.is(tok::equal))
- return candidate.getCorrectionDeclAs<VarDecl>();
- if (NextToken.is(tok::period) &&
- candidate.getCorrectionDeclAs<NamespaceDecl>())
- return false;
- return CorrectionCandidateCallback::ValidateCandidate(candidate);
- }
- std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return std::make_unique<StatementFilterCCC>(*this);
- }
- private:
- Token NextToken;
- };
- }
- StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(
- StmtVector &Stmts, ParsedStmtContext StmtCtx,
- SourceLocation *TrailingElseLoc, ParsedAttributesWithRange &Attrs) {
- const char *SemiError = nullptr;
- StmtResult Res;
- SourceLocation GNUAttributeLoc;
- // 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.
- Retry:
- tok::TokenKind Kind = Tok.getKind();
- SourceLocation AtLoc;
- switch (Kind) {
- case tok::at: // May be a @try or @throw statement
- {
- ProhibitAttributes(Attrs); // TODO: is it correct?
- AtLoc = ConsumeToken(); // consume @
- return ParseObjCAtStatement(AtLoc, StmtCtx);
- }
- case tok::code_completion:
- Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
- cutOffParsing();
- return StmtError();
- case tok::identifier: {
- Token Next = NextToken();
- if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement
- // identifier ':' statement
- return ParseLabeledStatement(Attrs, StmtCtx);
- }
- // Look up the identifier, and typo-correct it to a keyword if it's not
- // found.
- if (Next.isNot(tok::coloncolon)) {
- // Try to limit which sets of keywords should be included in typo
- // correction based on what the next token is.
- StatementFilterCCC CCC(Next);
- if (TryAnnotateName(&CCC) == ANK_Error) {
- // Handle errors here by skipping up to the next semicolon or '}', and
- // eat the semicolon if that's what stopped us.
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return StmtError();
- }
- // If the identifier was typo-corrected, try again.
- if (Tok.isNot(tok::identifier))
- goto Retry;
- }
- // Fall through
- LLVM_FALLTHROUGH;
- }
- default: {
- if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt ||
- (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) !=
- ParsedStmtContext()) &&
- (GNUAttributeLoc.isValid() || isDeclarationStatement())) {
- SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Decl;
- if (GNUAttributeLoc.isValid()) {
- DeclStart = GNUAttributeLoc;
- Decl = ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs,
- &GNUAttributeLoc);
- } else {
- Decl =
- ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, Attrs);
- }
- if (Attrs.Range.getBegin().isValid())
- DeclStart = Attrs.Range.getBegin();
- return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
- }
- if (Tok.is(tok::r_brace)) {
- Diag(Tok, diag::err_expected_statement);
- return StmtError();
- }
- return ParseExprStatement(StmtCtx);
- }
- case tok::kw___attribute: {
- GNUAttributeLoc = Tok.getLocation();
- ParseGNUAttributes(Attrs);
- goto Retry;
- }
- case tok::kw_case: // C99 6.8.1: labeled-statement
- return ParseCaseStatement(StmtCtx);
- case tok::kw_default: // C99 6.8.1: labeled-statement
- return ParseDefaultStatement(StmtCtx);
- case tok::l_brace: // C99 6.8.2: compound-statement
- return ParseCompoundStatement();
- case tok::semi: { // C99 6.8.3p3: expression[opt] ';'
- bool HasLeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
- return Actions.ActOnNullStmt(ConsumeToken(), HasLeadingEmptyMacro);
- }
- case tok::kw_if: // C99 6.8.4.1: if-statement
- return ParseIfStatement(TrailingElseLoc);
- case tok::kw_switch: // C99 6.8.4.2: switch-statement
- return ParseSwitchStatement(TrailingElseLoc);
- case tok::kw_while: // C99 6.8.5.1: while-statement
- return ParseWhileStatement(TrailingElseLoc);
- case tok::kw_do: // C99 6.8.5.2: do-statement
- Res = ParseDoStatement();
- SemiError = "do/while";
- break;
- case tok::kw_for: // C99 6.8.5.3: for-statement
- return ParseForStatement(TrailingElseLoc);
- case tok::kw_goto: // C99 6.8.6.1: goto-statement
- Res = ParseGotoStatement();
- SemiError = "goto";
- break;
- case tok::kw_continue: // C99 6.8.6.2: continue-statement
- Res = ParseContinueStatement();
- SemiError = "continue";
- break;
- case tok::kw_break: // C99 6.8.6.3: break-statement
- Res = ParseBreakStatement();
- SemiError = "break";
- break;
- case tok::kw_return: // C99 6.8.6.4: return-statement
- Res = ParseReturnStatement();
- SemiError = "return";
- break;
- case tok::kw_co_return: // C++ Coroutines: co_return statement
- Res = ParseReturnStatement();
- SemiError = "co_return";
- break;
- case tok::kw_asm: {
- ProhibitAttributes(Attrs);
- bool msAsm = false;
- Res = ParseAsmStatement(msAsm);
- Res = Actions.ActOnFinishFullStmt(Res.get());
- if (msAsm) return Res;
- SemiError = "asm";
- break;
- }
- 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();
- case tok::kw_try: // C++ 15: try-block
- return ParseCXXTryBlock();
- case tok::kw___try:
- ProhibitAttributes(Attrs); // TODO: is it correct?
- return ParseSEHTryBlock();
- case tok::kw___leave:
- Res = ParseSEHLeaveStatement();
- SemiError = "__leave";
- break;
- case tok::annot_pragma_vis:
- ProhibitAttributes(Attrs);
- HandlePragmaVisibility();
- return StmtEmpty();
- case tok::annot_pragma_pack:
- ProhibitAttributes(Attrs);
- HandlePragmaPack();
- return StmtEmpty();
- case tok::annot_pragma_msstruct:
- ProhibitAttributes(Attrs);
- HandlePragmaMSStruct();
- return StmtEmpty();
- case tok::annot_pragma_align:
- ProhibitAttributes(Attrs);
- HandlePragmaAlign();
- return StmtEmpty();
- 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();
- case tok::annot_pragma_fp_contract:
- ProhibitAttributes(Attrs);
- Diag(Tok, diag::err_pragma_fp_contract_scope);
- ConsumeAnnotationToken();
- return StmtError();
- case tok::annot_pragma_fp:
- ProhibitAttributes(Attrs);
- Diag(Tok, diag::err_pragma_fp_scope);
- ConsumeAnnotationToken();
- return StmtError();
- case tok::annot_pragma_fenv_access:
- ProhibitAttributes(Attrs);
- HandlePragmaFEnvAccess();
- return StmtEmpty();
- case tok::annot_pragma_opencl_extension:
- ProhibitAttributes(Attrs);
- HandlePragmaOpenCLExtension();
- return StmtEmpty();
- case tok::annot_pragma_captured:
- ProhibitAttributes(Attrs);
- return HandlePragmaCaptured();
- case tok::annot_pragma_openmp:
- ProhibitAttributes(Attrs);
- return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx);
- case tok::annot_pragma_ms_pointers_to_members:
- ProhibitAttributes(Attrs);
- HandlePragmaMSPointersToMembers();
- return StmtEmpty();
- case tok::annot_pragma_ms_pragma:
- ProhibitAttributes(Attrs);
- HandlePragmaMSPragma();
- return StmtEmpty();
- case tok::annot_pragma_ms_vtordisp:
- ProhibitAttributes(Attrs);
- HandlePragmaMSVtorDisp();
- return StmtEmpty();
- case tok::annot_pragma_loop_hint:
- ProhibitAttributes(Attrs);
- return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs);
- case tok::annot_pragma_dump:
- HandlePragmaDump();
- return StmtEmpty();
- case tok::annot_pragma_attribute:
- HandlePragmaAttribute();
- return StmtEmpty();
- }
- // If we reached this code, the statement must end in a semicolon.
- if (!TryConsumeToken(tok::semi) && !Res.isInvalid()) {
- // 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);
- // Skip until we see a } or ;, but don't eat it.
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- }
- return Res;
- }
- /// Parse an expression statement.
- StmtResult Parser::ParseExprStatement(ParsedStmtContext StmtCtx) {
- // If a case keyword is missing, this is where it should be inserted.
- Token OldToken = Tok;
- ExprStatementTokLoc = Tok.getLocation();
- // expression[opt] ';'
- ExprResult Expr(ParseExpression());
- 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.
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
- return Actions.ActOnExprStmtError();
- }
- 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 ");
- // Recover parsing as a case statement.
- return ParseCaseStatement(StmtCtx, /*MissingCase=*/true, Expr);
- }
- // Otherwise, eat the semicolon.
- ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return handleExprStmt(Expr, StmtCtx);
- }
- /// ParseSEHTryBlockCommon
- ///
- /// seh-try-block:
- /// '__try' compound-statement seh-handler
- ///
- /// seh-handler:
- /// seh-except-block
- /// seh-finally-block
- ///
- StmtResult Parser::ParseSEHTryBlock() {
- assert(Tok.is(tok::kw___try) && "Expected '__try'");
- SourceLocation TryLoc = ConsumeToken();
- if (Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- StmtResult TryBlock(ParseCompoundStatement(
- /*isStmtExpr=*/false,
- Scope::DeclScope | Scope::CompoundStmtScope | Scope::SEHTryScope));
- if (TryBlock.isInvalid())
- return TryBlock;
- StmtResult Handler;
- if (Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
- SourceLocation Loc = ConsumeToken();
- Handler = ParseSEHExceptBlock(Loc);
- } else if (Tok.is(tok::kw___finally)) {
- SourceLocation Loc = ConsumeToken();
- Handler = ParseSEHFinallyBlock(Loc);
- } else {
- return StmtError(Diag(Tok, diag::err_seh_expected_handler));
- }
- if(Handler.isInvalid())
- return Handler;
- return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
- TryLoc,
- TryBlock.get(),
- Handler.get());
- }
- /// 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);
- if (ExpectAndConsume(tok::l_paren))
- return StmtError();
- ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope |
- Scope::SEHExceptScope);
- if (getLangOpts().Borland) {
- Ident__exception_info->setIsPoisoned(false);
- Ident___exception_info->setIsPoisoned(false);
- Ident_GetExceptionInfo->setIsPoisoned(false);
- }
- ExprResult FilterExpr;
- {
- ParseScopeFlags FilterScope(this, getCurScope()->getFlags() |
- Scope::SEHFilterScope);
- FilterExpr = Actions.CorrectDelayedTyposInExpr(ParseExpression());
- }
- if (getLangOpts().Borland) {
- Ident__exception_info->setIsPoisoned(true);
- Ident___exception_info->setIsPoisoned(true);
- Ident_GetExceptionInfo->setIsPoisoned(true);
- }
- if(FilterExpr.isInvalid())
- return StmtError();
- if (ExpectAndConsume(tok::r_paren))
- return StmtError();
- if (Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- StmtResult Block(ParseCompoundStatement());
- if(Block.isInvalid())
- return Block;
- return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.get(), Block.get());
- }
- /// ParseSEHFinallyBlock - Handle __finally
- ///
- /// seh-finally-block:
- /// '__finally' compound-statement
- ///
- StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) {
- PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false),
- raii2(Ident___abnormal_termination, false),
- raii3(Ident_AbnormalTermination, false);
- if (Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- ParseScope FinallyScope(this, 0);
- Actions.ActOnStartSEHFinallyBlock();
- StmtResult Block(ParseCompoundStatement());
- if(Block.isInvalid()) {
- Actions.ActOnAbortSEHFinallyBlock();
- return Block;
- }
- return Actions.ActOnFinishSEHFinallyBlock(FinallyLoc, Block.get());
- }
- /// Handle __leave
- ///
- /// seh-leave-statement:
- /// '__leave' ';'
- ///
- StmtResult Parser::ParseSEHLeaveStatement() {
- SourceLocation LeaveLoc = ConsumeToken(); // eat the '__leave'.
- return Actions.ActOnSEHLeaveStmt(LeaveLoc, getCurScope());
- }
- /// ParseLabeledStatement - We have an identifier and a ':' after it.
- ///
- /// labeled-statement:
- /// identifier ':' statement
- /// [GNU] identifier ':' attributes[opt] statement
- ///
- StmtResult Parser::ParseLabeledStatement(ParsedAttributesWithRange &attrs,
- ParsedStmtContext StmtCtx) {
- assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
- "Not an identifier!");
- // The substatement is always a 'statement', not a 'declaration', but is
- // otherwise in the same context as the labeled-statement.
- StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
- Token IdentTok = Tok; // Save the whole token.
- ConsumeToken(); // eat the identifier.
- assert(Tok.is(tok::colon) && "Not a label!");
- // identifier ':' statement
- SourceLocation ColonLoc = ConsumeToken();
- // 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.
- SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx,
- nullptr, TempAttrs);
- if (!TempAttrs.empty() && !SubStmt.isInvalid())
- SubStmt = Actions.ProcessStmtAttributes(SubStmt.get(), TempAttrs,
- TempAttrs.Range);
- } else {
- Diag(Tok, diag::err_expected_after) << "__attribute__" << tok::semi;
- }
- }
- // If we've not parsed a statement yet, parse one now.
- if (!SubStmt.isInvalid() && !SubStmt.isUsable())
- SubStmt = ParseStatement(nullptr, StmtCtx);
- // Broken substmt shouldn't prevent the label from being added to the AST.
- if (SubStmt.isInvalid())
- SubStmt = Actions.ActOnNullStmt(ColonLoc);
- LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(),
- IdentTok.getLocation());
- Actions.ProcessDeclAttributeList(Actions.CurScope, LD, attrs);
- attrs.clear();
- return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc,
- SubStmt.get());
- }
- /// ParseCaseStatement
- /// labeled-statement:
- /// 'case' constant-expression ':' statement
- /// [GNU] 'case' constant-expression '...' constant-expression ':' statement
- ///
- StmtResult Parser::ParseCaseStatement(ParsedStmtContext StmtCtx,
- bool MissingCase, ExprResult Expr) {
- assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!");
- // The substatement is always a 'statement', not a 'declaration', but is
- // otherwise in the same context as the labeled-statement.
- StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
- // It is very very common for code to contain many case statements recursively
- // 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,
- // flatten this recursion into an iterative loop. This is complex and gross,
- // but all the grossness is constrained to ParseCaseStatement (and some
- // weirdness in the actions), so this is just local grossness :).
- // TopLevelCase - This is the highest level we have parsed. 'case 1' in the
- // example above.
- StmtResult TopLevelCase(true);
- // 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.
- Stmt *DeepestParsedCaseStmt = nullptr;
- // While we have case statements, eat and stack them.
- SourceLocation ColonLoc;
- do {
- SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() :
- ConsumeToken(); // eat the 'case'.
- ColonLoc = SourceLocation();
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteCase(getCurScope());
- cutOffParsing();
- return StmtError();
- }
- /// 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);
- ExprResult LHS;
- if (!MissingCase) {
- LHS = ParseCaseExpression(CaseLoc);
- if (LHS.isInvalid()) {
- // If constant-expression is parsed unsuccessfully, recover by skipping
- // current case statement (moving to the colon that ends it).
- if (!SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch))
- return StmtError();
- }
- } else {
- LHS = Expr;
- MissingCase = false;
- }
- // GNU case range extension.
- SourceLocation DotDotDotLoc;
- ExprResult RHS;
- if (TryConsumeToken(tok::ellipsis, DotDotDotLoc)) {
- Diag(DotDotDotLoc, diag::ext_gnu_case_range);
- RHS = ParseCaseExpression(CaseLoc);
- if (RHS.isInvalid()) {
- if (!SkipUntil(tok::colon, tok::r_brace, StopAtSemi | StopBeforeMatch))
- return StmtError();
- }
- }
- ColonProtection.restore();
- if (TryConsumeToken(tok::colon, ColonLoc)) {
- } else if (TryConsumeToken(tok::semi, ColonLoc) ||
- TryConsumeToken(tok::coloncolon, ColonLoc)) {
- // Treat "case blah;" or "case blah::" as a typo for "case blah:".
- Diag(ColonLoc, diag::err_expected_after)
- << "'case'" << tok::colon
- << FixItHint::CreateReplacement(ColonLoc, ":");
- } else {
- SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
- Diag(ExpectedLoc, diag::err_expected_after)
- << "'case'" << tok::colon
- << FixItHint::CreateInsertion(ExpectedLoc, ":");
- ColonLoc = ExpectedLoc;
- }
- StmtResult Case =
- Actions.ActOnCaseStmt(CaseLoc, LHS, DotDotDotLoc, RHS, ColonLoc);
- // 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.
- return ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
- // 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.
- Stmt *NextDeepest = Case.get();
- if (TopLevelCase.isInvalid())
- TopLevelCase = Case;
- else
- Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get());
- DeepestParsedCaseStmt = NextDeepest;
- }
- // Handle all case statements.
- } while (Tok.is(tok::kw_case));
- // If we found a non-case statement, start by parsing it.
- StmtResult SubStmt;
- if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
- } else {
- // Nicely diagnose the common error "switch (X) { case 4: }", which is
- // not valid. If ColonLoc doesn't point to a valid text location, there was
- // another parsing error, so avoid producing extra diagnostics.
- if (ColonLoc.isValid()) {
- SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
- << FixItHint::CreateInsertion(AfterColonLoc, " ;");
- }
- SubStmt = StmtError();
- }
- // Install the body into the most deeply-nested case.
- 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());
- }
- // Return the top level parsed statement tree.
- return TopLevelCase;
- }
- /// ParseDefaultStatement
- /// labeled-statement:
- /// 'default' ':' statement
- /// Note that this does not parse the 'statement' at the end.
- ///
- StmtResult Parser::ParseDefaultStatement(ParsedStmtContext StmtCtx) {
- assert(Tok.is(tok::kw_default) && "Not a default stmt!");
- // The substatement is always a 'statement', not a 'declaration', but is
- // otherwise in the same context as the labeled-statement.
- StmtCtx &= ~ParsedStmtContext::AllowDeclarationsInC;
- SourceLocation DefaultLoc = ConsumeToken(); // eat the 'default'.
- SourceLocation ColonLoc;
- if (TryConsumeToken(tok::colon, ColonLoc)) {
- } else if (TryConsumeToken(tok::semi, ColonLoc)) {
- // Treat "default;" as a typo for "default:".
- Diag(ColonLoc, diag::err_expected_after)
- << "'default'" << tok::colon
- << FixItHint::CreateReplacement(ColonLoc, ":");
- } else {
- SourceLocation ExpectedLoc = PP.getLocForEndOfToken(PrevTokLocation);
- Diag(ExpectedLoc, diag::err_expected_after)
- << "'default'" << tok::colon
- << FixItHint::CreateInsertion(ExpectedLoc, ":");
- ColonLoc = ExpectedLoc;
- }
- StmtResult SubStmt;
- if (Tok.isNot(tok::r_brace)) {
- SubStmt = ParseStatement(/*TrailingElseLoc=*/nullptr, StmtCtx);
- } else {
- // Diagnose the common error "switch (X) {... default: }", which is
- // not valid.
- SourceLocation AfterColonLoc = PP.getLocForEndOfToken(ColonLoc);
- Diag(AfterColonLoc, diag::err_label_end_of_compound_statement)
- << FixItHint::CreateInsertion(AfterColonLoc, " ;");
- SubStmt = true;
- }
- // Broken sub-stmt shouldn't prevent forming the case statement properly.
- if (SubStmt.isInvalid())
- SubStmt = Actions.ActOnNullStmt(ColonLoc);
- return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc,
- SubStmt.get(), getCurScope());
- }
- StmtResult Parser::ParseCompoundStatement(bool isStmtExpr) {
- return ParseCompoundStatement(isStmtExpr,
- Scope::DeclScope | Scope::CompoundStmtScope);
- }
- /// 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
- /// [GNU] '__extension__' declaration
- /// statement
- ///
- /// [GNU] label-declarations:
- /// [GNU] label-declaration
- /// [GNU] label-declarations label-declaration
- ///
- /// [GNU] label-declaration:
- /// [GNU] '__label__' identifier-list ';'
- ///
- StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
- unsigned ScopeFlags) {
- assert(Tok.is(tok::l_brace) && "Not a compount stmt!");
- // Enter a scope to hold everything within the compound stmt. Compound
- // statements can always hold declarations.
- ParseScope CompoundScope(this, ScopeFlags);
- // Parse the statements in the body.
- return ParseCompoundStatementBody(isStmtExpr);
- }
- /// 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;
- case tok::annot_pragma_fp:
- HandlePragmaFP();
- break;
- case tok::annot_pragma_fenv_access:
- HandlePragmaFEnvAccess();
- break;
- case tok::annot_pragma_ms_pointers_to_members:
- HandlePragmaMSPointersToMembers();
- break;
- case tok::annot_pragma_ms_pragma:
- HandlePragmaMSPragma();
- break;
- case tok::annot_pragma_ms_vtordisp:
- HandlePragmaMSVtorDisp();
- break;
- case tok::annot_pragma_dump:
- HandlePragmaDump();
- break;
- default:
- checkForPragmas = false;
- break;
- }
- }
- }
- /// Consume any extra semi-colons resulting in null statements,
- /// returning true if any tok::semi were consumed.
- bool Parser::ConsumeNullStmt(StmtVector &Stmts) {
- if (!Tok.is(tok::semi))
- return false;
- SourceLocation StartLoc = Tok.getLocation();
- SourceLocation EndLoc;
- while (Tok.is(tok::semi) && !Tok.hasLeadingEmptyMacro() &&
- Tok.getLocation().isValid() && !Tok.getLocation().isMacroID()) {
- EndLoc = Tok.getLocation();
- // Don't just ConsumeToken() this tok::semi, do store it in AST.
- StmtResult R =
- ParseStatementOrDeclaration(Stmts, ParsedStmtContext::SubStmt);
- 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;
- }
- StmtResult Parser::handleExprStmt(ExprResult E, ParsedStmtContext StmtCtx) {
- bool IsStmtExprResult = false;
- if ((StmtCtx & ParsedStmtContext::InStmtExpr) != ParsedStmtContext()) {
- // For GCC compatibility we skip past NullStmts.
- unsigned LookAhead = 0;
- while (GetLookAheadToken(LookAhead).is(tok::semi)) {
- ++LookAhead;
- }
- // Then look to see if the next two tokens close the statement expression;
- // if so, this expression statement is the last statement in a statment
- // expression.
- IsStmtExprResult = GetLookAheadToken(LookAhead).is(tok::r_brace) &&
- GetLookAheadToken(LookAhead + 1).is(tok::r_paren);
- }
- if (IsStmtExprResult)
- E = Actions.ActOnStmtExprResult(E);
- return Actions.ActOnExprStmt(E, /*DiscardedValue=*/!IsStmtExprResult);
- }
- /// ParseCompoundStatementBody - Parse a sequence of statements and invoke the
- /// ActOnCompoundStmt action. This expects the '{' to be the current token, and
- /// consume the '}' at the end of the block. It does not manipulate the scope
- /// stack.
- StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
- PrettyStackTraceLoc CrashInfo(PP.getSourceManager(),
- Tok.getLocation(),
- "in compound statement ('{}')");
- // Record the state of the FP_CONTRACT pragma, restore on leaving the
- // compound statement.
- Sema::FPContractStateRAII SaveFPContractState(Actions);
- InMessageExpressionRAIIObject InMessage(*this, false);
- BalancedDelimiterTracker T(*this, tok::l_brace);
- if (T.consumeOpen())
- return StmtError();
- Sema::CompoundScopeRAII CompoundScope(Actions, isStmtExpr);
- // Parse any pragmas at the beginning of the compound statement.
- ParseCompoundStatementLeadingPragmas();
- StmtVector Stmts;
- // "__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();
- SmallVector<Decl *, 8> DeclsInGroup;
- while (1) {
- if (Tok.isNot(tok::identifier)) {
- Diag(Tok, diag::err_expected) << tok::identifier;
- break;
- }
- IdentifierInfo *II = Tok.getIdentifierInfo();
- SourceLocation IdLoc = ConsumeToken();
- DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc));
- if (!TryConsumeToken(tok::comma))
- break;
- }
- DeclSpec DS(AttrFactory);
- DeclGroupPtrTy Res =
- Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup);
- StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation());
- ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
- if (R.isUsable())
- Stmts.push_back(R.get());
- }
- ParsedStmtContext SubStmtCtx =
- ParsedStmtContext::Compound |
- (isStmtExpr ? ParsedStmtContext::InStmtExpr : ParsedStmtContext());
- while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
- Tok.isNot(tok::eof)) {
- if (Tok.is(tok::annot_pragma_unused)) {
- HandlePragmaUnused();
- continue;
- }
- if (ConsumeNullStmt(Stmts))
- continue;
- StmtResult R;
- if (Tok.isNot(tok::kw___extension__)) {
- R = ParseStatementOrDeclaration(Stmts, SubStmtCtx);
- } 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.
- // FIXME: This loses extension expressions in the AST!
- SourceLocation ExtLoc = ConsumeToken();
- while (Tok.is(tok::kw___extension__))
- ConsumeToken();
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs, nullptr,
- /*MightBeObjCMessageSend*/ true);
- // If this is the start of a declaration, parse it as such.
- if (isDeclarationStatement()) {
- // __extension__ silences extension warnings in the subdeclaration.
- // FIXME: Save the __extension__ on the decl as a node somehow?
- ExtensionRAIIObject O(Diags);
- SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy Res =
- ParseDeclaration(DeclaratorContext::BlockContext, DeclEnd, attrs);
- R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd);
- } else {
- // Otherwise this was a unary __extension__ marker.
- ExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc));
- if (Res.isInvalid()) {
- SkipUntil(tok::semi);
- continue;
- }
- // Eat the semicolon at the end of stmt and convert the expr into a
- // statement.
- ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- R = handleExprStmt(Res, SubStmtCtx);
- if (R.isUsable())
- R = Actions.ProcessStmtAttributes(R.get(), attrs, attrs.Range);
- }
- }
- if (R.isUsable())
- Stmts.push_back(R.get());
- }
- SourceLocation CloseLoc = Tok.getLocation();
- // We broke out of the while loop because we found a '}' or EOF.
- if (!T.consumeClose())
- // Recover by creating a compound statement with what we parsed so far,
- // instead of dropping everything and returning StmtError();
- CloseLoc = T.getCloseLocation();
- return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
- Stmts, isStmtExpr);
- }
- /// ParseParenExprOrCondition:
- /// [C ] '(' expression ')'
- /// [C++] '(' condition ')'
- /// [C++1z] '(' init-statement[opt] condition ')'
- ///
- /// This function parses and performs error recovery on the specified condition
- /// or expression (depending on whether we're in C++ or C mode). This function
- /// 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.
- bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt,
- Sema::ConditionResult &Cond,
- SourceLocation Loc,
- Sema::ConditionKind CK) {
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- if (getLangOpts().CPlusPlus)
- Cond = ParseCXXCondition(InitStmt, Loc, CK);
- else {
- ExprResult CondExpr = ParseExpression();
- // If required, convert to a boolean value.
- if (CondExpr.isInvalid())
- Cond = Sema::ConditionError();
- else
- Cond = Actions.ActOnCondition(getCurScope(), Loc, CondExpr.get(), CK);
- }
- // 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.
- if (Cond.isInvalid() && Tok.isNot(tok::r_paren)) {
- 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;
- }
- // Otherwise the condition is valid or the rparen is present.
- T.consumeClose();
- // 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();
- }
- return false;
- }
- /// ParseIfStatement
- /// if-statement: [C99 6.8.4.1]
- /// 'if' '(' expression ')' statement
- /// 'if' '(' expression ')' statement 'else' statement
- /// [C++] 'if' '(' condition ')' statement
- /// [C++] 'if' '(' condition ')' statement 'else' statement
- ///
- StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
- assert(Tok.is(tok::kw_if) && "Not an if stmt!");
- SourceLocation IfLoc = ConsumeToken(); // eat the 'if'.
- bool IsConstexpr = false;
- if (Tok.is(tok::kw_constexpr)) {
- Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if
- : diag::ext_constexpr_if);
- IsConstexpr = true;
- ConsumeToken();
- }
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "if";
- SkipUntil(tok::semi);
- return StmtError();
- }
- bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
- // C99 6.8.4p3 - In C99, the if statement is a block. This is not
- // the case for C90.
- //
- // 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.
- // 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).
- //
- ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
- // Parse the condition.
- StmtResult InitStmt;
- Sema::ConditionResult Cond;
- if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc,
- IsConstexpr ? Sema::ConditionKind::ConstexprIf
- : Sema::ConditionKind::Boolean))
- return StmtError();
- llvm::Optional<bool> ConstexprCondition;
- if (IsConstexpr)
- ConstexprCondition = Cond.getKnownValue();
- // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
- // 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.
- //
- // 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.
- //
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
- // Read the 'then' stmt.
- SourceLocation ThenStmtLoc = Tok.getLocation();
- SourceLocation InnerStatementTrailingElseLoc;
- StmtResult ThenStmt;
- {
- EnterExpressionEvaluationContext PotentiallyDiscarded(
- Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr,
- Sema::ExpressionEvaluationContextRecord::EK_Other,
- /*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition);
- ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc);
- }
- // Pop the 'if' scope if needed.
- InnerScope.Exit();
- // If it has an else, parse it.
- SourceLocation ElseLoc;
- SourceLocation ElseStmtLoc;
- StmtResult ElseStmt;
- if (Tok.is(tok::kw_else)) {
- if (TrailingElseLoc)
- *TrailingElseLoc = Tok.getLocation();
- ElseLoc = ConsumeToken();
- ElseStmtLoc = Tok.getLocation();
- // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if
- // 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.
- //
- // C++ 6.4p1:
- // The substatement in a selection-statement (each substatement, in the else
- // form of the if statement) implicitly defines a local scope.
- //
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX,
- Tok.is(tok::l_brace));
- EnterExpressionEvaluationContext PotentiallyDiscarded(
- Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr,
- Sema::ExpressionEvaluationContextRecord::EK_Other,
- /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition);
- ElseStmt = ParseStatement();
- // Pop the 'else' scope if needed.
- InnerScope.Exit();
- } else if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteAfterIf(getCurScope());
- cutOffParsing();
- return StmtError();
- } else if (InnerStatementTrailingElseLoc.isValid()) {
- Diag(InnerStatementTrailingElseLoc, diag::warn_dangling_else);
- }
- IfScope.Exit();
- // If the then or else stmt is invalid and the other is valid (and present),
- // make turn the invalid one into a null stmt to avoid dropping the other
- // part. If both are invalid, return error.
- if ((ThenStmt.isInvalid() && ElseStmt.isInvalid()) ||
- (ThenStmt.isInvalid() && ElseStmt.get() == nullptr) ||
- (ThenStmt.get() == nullptr && ElseStmt.isInvalid())) {
- // Both invalid, or one is invalid and other is non-present: return error.
- return StmtError();
- }
- // Now if either are invalid, replace with a ';'.
- if (ThenStmt.isInvalid())
- ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc);
- if (ElseStmt.isInvalid())
- ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
- return Actions.ActOnIfStmt(IfLoc, IsConstexpr, InitStmt.get(), Cond,
- ThenStmt.get(), ElseLoc, ElseStmt.get());
- }
- /// ParseSwitchStatement
- /// switch-statement:
- /// 'switch' '(' expression ')' statement
- /// [C++] 'switch' '(' condition ')' statement
- StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) {
- assert(Tok.is(tok::kw_switch) && "Not a switch stmt!");
- SourceLocation SwitchLoc = ConsumeToken(); // eat the 'switch'.
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "switch";
- SkipUntil(tok::semi);
- return StmtError();
- }
- bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
- // C99 6.8.4p3 - In C99, the switch statement is a block. This is
- // not the case for C90. Start the switch scope.
- //
- // 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.
- // 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).
- //
- unsigned ScopeFlags = Scope::SwitchScope;
- if (C99orCXX)
- ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
- ParseScope SwitchScope(this, ScopeFlags);
- // Parse the condition.
- StmtResult InitStmt;
- Sema::ConditionResult Cond;
- if (ParseParenExprOrCondition(&InitStmt, Cond, SwitchLoc,
- Sema::ConditionKind::Switch))
- return StmtError();
- StmtResult Switch =
- Actions.ActOnStartOfSwitchStmt(SwitchLoc, InitStmt.get(), Cond);
- if (Switch.isInvalid()) {
- // Skip the switch body.
- // 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.
- if (Tok.is(tok::l_brace)) {
- ConsumeBrace();
- SkipUntil(tok::r_brace);
- } else
- SkipUntil(tok::semi);
- return Switch;
- }
- // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if
- // 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.
- //
- // 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++.
- //
- getCurScope()->AddFlags(Scope::BreakScope);
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
- // We have incremented the mangling number for the SwitchScope and the
- // InnerScope, which is one too many.
- if (C99orCXX)
- getCurScope()->decrementMSManglingNumber();
- // Read the body statement.
- StmtResult Body(ParseStatement(TrailingElseLoc));
- // Pop the scopes.
- InnerScope.Exit();
- SwitchScope.Exit();
- return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get());
- }
- /// ParseWhileStatement
- /// while-statement: [C99 6.8.5.1]
- /// 'while' '(' expression ')' statement
- /// [C++] 'while' '(' condition ')' statement
- StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) {
- assert(Tok.is(tok::kw_while) && "Not a while stmt!");
- SourceLocation WhileLoc = Tok.getLocation();
- ConsumeToken(); // eat the 'while'.
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "while";
- SkipUntil(tok::semi);
- return StmtError();
- }
- bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
- // C99 6.8.5p5 - In C99, the while statement is a block. This is not
- // the case for C90. Start the loop scope.
- //
- // 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.
- // 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).
- //
- unsigned ScopeFlags;
- if (C99orCXX)
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope |
- Scope::DeclScope | Scope::ControlScope;
- else
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
- ParseScope WhileScope(this, ScopeFlags);
- // Parse the condition.
- Sema::ConditionResult Cond;
- if (ParseParenExprOrCondition(nullptr, Cond, WhileLoc,
- Sema::ConditionKind::Boolean))
- return StmtError();
- // C99 6.8.5p5 - In C99, the body of the while statement is a scope, even if
- // 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.
- //
- // 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++.
- //
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
- // Read the body statement.
- StmtResult Body(ParseStatement(TrailingElseLoc));
- // Pop the body scope if needed.
- InnerScope.Exit();
- WhileScope.Exit();
- if (Cond.isInvalid() || Body.isInvalid())
- return StmtError();
- return Actions.ActOnWhileStmt(WhileLoc, Cond, Body.get());
- }
- /// ParseDoStatement
- /// do-statement: [C99 6.8.5.2]
- /// 'do' statement 'while' '(' expression ')' ';'
- /// Note: this lets the caller parse the end ';'.
- StmtResult Parser::ParseDoStatement() {
- assert(Tok.is(tok::kw_do) && "Not a do stmt!");
- SourceLocation DoLoc = ConsumeToken(); // eat the 'do'.
- // C99 6.8.5p5 - In C99, the do statement is a block. This is not
- // the case for C90. Start the loop scope.
- unsigned ScopeFlags;
- if (getLangOpts().C99)
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope | Scope::DeclScope;
- else
- ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
- ParseScope DoScope(this, ScopeFlags);
- // C99 6.8.5p5 - In C99, the body of the do statement is a scope, even if
- // 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.
- //
- // C++ 6.5p2:
- // The substatement in an iteration-statement implicitly defines a local scope
- // which is entered and exited each time through the loop.
- //
- bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
- // Read the body statement.
- StmtResult Body(ParseStatement());
- // Pop the body scope if needed.
- InnerScope.Exit();
- if (Tok.isNot(tok::kw_while)) {
- if (!Body.isInvalid()) {
- Diag(Tok, diag::err_expected_while);
- Diag(DoLoc, diag::note_matching) << "'do'";
- SkipUntil(tok::semi, StopBeforeMatch);
- }
- return StmtError();
- }
- SourceLocation WhileLoc = ConsumeToken();
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "do/while";
- SkipUntil(tok::semi, StopBeforeMatch);
- return StmtError();
- }
- // Parse the parenthesized expression.
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- // A do-while expression is not a condition, so can't have attributes.
- DiagnoseAndSkipCXX11Attributes();
- ExprResult Cond = ParseExpression();
- // Correct the typos in condition before closing the scope.
- if (Cond.isUsable())
- Cond = Actions.CorrectDelayedTyposInExpr(Cond);
- T.consumeClose();
- DoScope.Exit();
- if (Cond.isInvalid() || Body.isInvalid())
- return StmtError();
- return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, T.getOpenLocation(),
- Cond.get(), T.getCloseLocation());
- }
- bool Parser::isForRangeIdentifier() {
- assert(Tok.is(tok::identifier));
- const Token &Next = NextToken();
- if (Next.is(tok::colon))
- return true;
- if (Next.isOneOf(tok::l_square, tok::kw_alignas)) {
- TentativeParsingAction PA(*this);
- ConsumeToken();
- SkipCXX11Attributes();
- bool Result = Tok.is(tok::colon);
- PA.Revert();
- return Result;
- }
- return false;
- }
- /// ParseForStatement
- /// for-statement: [C99 6.8.5.3]
- /// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement
- /// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement
- /// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')'
- /// [C++] statement
- /// [C++0x] 'for'
- /// 'co_await'[opt] [Coroutines]
- /// '(' for-range-declaration ':' for-range-initializer ')'
- /// statement
- /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement
- /// [OBJC2] 'for' '(' expr 'in' expr ')' statement
- ///
- /// [C++] for-init-statement:
- /// [C++] expression-statement
- /// [C++] simple-declaration
- ///
- /// [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]
- StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
- assert(Tok.is(tok::kw_for) && "Not a for stmt!");
- SourceLocation ForLoc = ConsumeToken(); // eat the 'for'.
- SourceLocation CoawaitLoc;
- if (Tok.is(tok::kw_co_await))
- CoawaitLoc = ConsumeToken();
- if (Tok.isNot(tok::l_paren)) {
- Diag(Tok, diag::err_expected_lparen_after) << "for";
- SkipUntil(tok::semi);
- return StmtError();
- }
- bool C99orCXXorObjC = getLangOpts().C99 || getLangOpts().CPlusPlus ||
- getLangOpts().ObjC;
- // C99 6.8.5p5 - In C99, the for statement is a block. This is not
- // the case for C90. Start the loop scope.
- //
- // 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.
- // 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).
- // C++ 6.5.3p1:
- // Names declared in the for-init-statement are in the same declarative-region
- // as those declared in the condition.
- //
- unsigned ScopeFlags = 0;
- if (C99orCXXorObjC)
- ScopeFlags = Scope::DeclScope | Scope::ControlScope;
- ParseScope ForScope(this, ScopeFlags);
- BalancedDelimiterTracker T(*this, tok::l_paren);
- T.consumeOpen();
- ExprResult Value;
- bool ForEach = false;
- StmtResult FirstPart;
- Sema::ConditionResult SecondPart;
- ExprResult Collection;
- ForRangeInfo ForRangeInfo;
- FullExprArg ThirdPart(Actions);
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteOrdinaryName(getCurScope(),
- C99orCXXorObjC? Sema::PCC_ForInit
- : Sema::PCC_Expression);
- cutOffParsing();
- return StmtError();
- }
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX11Attributes(attrs);
- SourceLocation EmptyInitStmtSemiLoc;
- // Parse the first part of the for specifier.
- if (Tok.is(tok::semi)) { // for (;
- ProhibitAttributes(attrs);
- // no first part, eat the ';'.
- SourceLocation SemiLoc = Tok.getLocation();
- if (!Tok.hasLeadingEmptyMacro() && !SemiLoc.isMacroID())
- EmptyInitStmtSemiLoc = SemiLoc;
- ConsumeToken();
- } else if (getLangOpts().CPlusPlus && Tok.is(tok::identifier) &&
- isForRangeIdentifier()) {
- ProhibitAttributes(attrs);
- IdentifierInfo *Name = Tok.getIdentifierInfo();
- SourceLocation Loc = ConsumeToken();
- MaybeParseCXX11Attributes(attrs);
- ForRangeInfo.ColonLoc = ConsumeToken();
- if (Tok.is(tok::l_brace))
- ForRangeInfo.RangeExpr = ParseBraceInitializer();
- else
- ForRangeInfo.RangeExpr = ParseExpression();
- Diag(Loc, diag::err_for_range_identifier)
- << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus17)
- ? FixItHint::CreateInsertion(Loc, "auto &&")
- : FixItHint());
- ForRangeInfo.LoopVar = Actions.ActOnCXXForRangeIdentifier(
- getCurScope(), Loc, Name, attrs, attrs.Range.getEnd());
- } else if (isForInitDeclaration()) { // for (int X = 4;
- ParenBraceBracketBalancer BalancerRAIIObj(*this);
- // Parse declaration, which eats the ';'.
- if (!C99orCXXorObjC) { // Use of C99-style for loops in C90 mode?
- Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
- Diag(Tok, diag::warn_gcc_variable_decl_in_for_loop);
- }
- // In C++0x, "for (T NS:a" might not be a typo for ::
- bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
- ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
- SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
- DeclGroupPtrTy DG = ParseSimpleDeclaration(
- DeclaratorContext::ForContext, DeclEnd, attrs, false,
- MightBeForRangeStmt ? &ForRangeInfo : nullptr);
- FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
- if (ForRangeInfo.ParsedForRangeDecl()) {
- Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ?
- diag::warn_cxx98_compat_for_range : diag::ext_for_range);
- ForRangeInfo.LoopVar = FirstPart;
- FirstPart = StmtResult();
- } else if (Tok.is(tok::semi)) { // for (int x = 4;
- ConsumeToken();
- } else if ((ForEach = isTokIdentifier_in())) {
- Actions.ActOnForEachDeclStmt(DG);
- // ObjC: for (id x in expr)
- ConsumeToken(); // consume 'in'
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
- cutOffParsing();
- return StmtError();
- }
- Collection = ParseExpression();
- } else {
- Diag(Tok, diag::err_expected_semi_for);
- }
- } else {
- ProhibitAttributes(attrs);
- Value = Actions.CorrectDelayedTyposInExpr(ParseExpression());
- ForEach = isTokIdentifier_in();
- // Turn the expression into a stmt.
- if (!Value.isInvalid()) {
- if (ForEach)
- FirstPart = Actions.ActOnForEachLValueExpr(Value.get());
- else {
- // We already know this is not an init-statement within a for loop, so
- // if we are parsing a C++11 range-based for loop, we should treat this
- // expression statement as being a discarded value expression because
- // we will err below. This way we do not warn on an unused expression
- // that was an error in the first place, like with: for (expr : expr);
- bool IsRangeBasedFor =
- getLangOpts().CPlusPlus11 && !ForEach && Tok.is(tok::colon);
- FirstPart = Actions.ActOnExprStmt(Value, !IsRangeBasedFor);
- }
- }
- if (Tok.is(tok::semi)) {
- ConsumeToken();
- } else if (ForEach) {
- ConsumeToken(); // consume 'in'
- if (Tok.is(tok::code_completion)) {
- Actions.CodeCompleteObjCForCollection(getCurScope(), nullptr);
- cutOffParsing();
- return StmtError();
- }
- Collection = ParseExpression();
- } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::colon) && FirstPart.get()) {
- // 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();
- SkipUntil(tok::r_paren, StopBeforeMatch);
- SecondPart = Sema::ConditionError();
- } else {
- if (!Value.isInvalid()) {
- Diag(Tok, diag::err_expected_semi_for);
- } else {
- // Skip until semicolon or rparen, don't consume it.
- SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
- if (Tok.is(tok::semi))
- ConsumeToken();
- }
- }
- }
- // Parse the second part of the for specifier.
- getCurScope()->AddFlags(Scope::BreakScope | Scope::ContinueScope);
- if (!ForEach && !ForRangeInfo.ParsedForRangeDecl() &&
- !SecondPart.isInvalid()) {
- // Parse the second part of the for specifier.
- if (Tok.is(tok::semi)) { // for (...;;
- // no second part.
- } else if (Tok.is(tok::r_paren)) {
- // missing both semicolons.
- } else {
- if (getLangOpts().CPlusPlus) {
- // C++2a: We've parsed an init-statement; we might have a
- // for-range-declaration next.
- bool MightBeForRangeStmt = !ForRangeInfo.ParsedForRangeDecl();
- ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
- SecondPart =
- ParseCXXCondition(nullptr, ForLoc, Sema::ConditionKind::Boolean,
- MightBeForRangeStmt ? &ForRangeInfo : nullptr);
- if (ForRangeInfo.ParsedForRangeDecl()) {
- Diag(FirstPart.get() ? FirstPart.get()->getBeginLoc()
- : ForRangeInfo.ColonLoc,
- getLangOpts().CPlusPlus2a
- ? diag::warn_cxx17_compat_for_range_init_stmt
- : diag::ext_for_range_init_stmt)
- << (FirstPart.get() ? FirstPart.get()->getSourceRange()
- : SourceRange());
- if (EmptyInitStmtSemiLoc.isValid()) {
- Diag(EmptyInitStmtSemiLoc, diag::warn_empty_init_statement)
- << /*for-loop*/ 2
- << FixItHint::CreateRemoval(EmptyInitStmtSemiLoc);
- }
- }
- } else {
- ExprResult SecondExpr = ParseExpression();
- if (SecondExpr.isInvalid())
- SecondPart = Sema::ConditionError();
- else
- SecondPart =
- Actions.ActOnCondition(getCurScope(), ForLoc, SecondExpr.get(),
- Sema::ConditionKind::Boolean);
- }
- }
- }
- // Parse the third part of the for statement.
- if (!ForEach && !ForRangeInfo.ParsedForRangeDecl()) {
- if (Tok.isNot(tok::semi)) {
- if (!SecondPart.isInvalid())
- Diag(Tok, diag::err_expected_semi_for);
- else
- // Skip until semicolon or rparen, don't consume it.
- SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch);
- }
- if (Tok.is(tok::semi)) {
- ConsumeToken();
- }
- if (Tok.isNot(tok::r_paren)) { // for (...;...;)
- ExprResult Third = ParseExpression();
- // FIXME: The C++11 standard doesn't actually say that this is a
- // discarded-value expression, but it clearly should be.
- ThirdPart = Actions.MakeFullDiscardedValueExpr(Third.get());
- }
- }
- // Match the ')'.
- T.consumeClose();
- // C++ Coroutines [stmt.iter]:
- // 'co_await' can only be used for a range-based for statement.
- if (CoawaitLoc.isValid() && !ForRangeInfo.ParsedForRangeDecl()) {
- Diag(CoawaitLoc, diag::err_for_co_await_not_range_for);
- CoawaitLoc = SourceLocation();
- }
- // 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;
- StmtResult ForEachStmt;
- if (ForRangeInfo.ParsedForRangeDecl()) {
- ExprResult CorrectedRange =
- Actions.CorrectDelayedTyposInExpr(ForRangeInfo.RangeExpr.get());
- ForRangeStmt = Actions.ActOnCXXForRangeStmt(
- getCurScope(), ForLoc, CoawaitLoc, FirstPart.get(),
- ForRangeInfo.LoopVar.get(), ForRangeInfo.ColonLoc, CorrectedRange.get(),
- T.getCloseLocation(), Sema::BFRK_Build);
- // Similarly, we need to do the semantic analysis for a for-range
- // statement immediately in order to close over temporaries correctly.
- } else if (ForEach) {
- ForEachStmt = Actions.ActOnObjCForCollectionStmt(ForLoc,
- FirstPart.get(),
- Collection.get(),
- T.getCloseLocation());
- } 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());
- }
- }
- // C99 6.8.5p5 - In C99, the body of the for statement is a scope, even if
- // 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.
- //
- // 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++.
- //
- 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)
- getCurScope()->decrementMSManglingNumber();
- // Read the body statement.
- StmtResult Body(ParseStatement(TrailingElseLoc));
- // Pop the body scope if needed.
- InnerScope.Exit();
- // Leave the for-scope.
- ForScope.Exit();
- if (Body.isInvalid())
- return StmtError();
- if (ForEach)
- return Actions.FinishObjCForCollectionStmt(ForEachStmt.get(),
- Body.get());
- if (ForRangeInfo.ParsedForRangeDecl())
- return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
- return Actions.ActOnForStmt(ForLoc, T.getOpenLocation(), FirstPart.get(),
- SecondPart, ThirdPart, T.getCloseLocation(),
- Body.get());
- }
- /// ParseGotoStatement
- /// jump-statement:
- /// 'goto' identifier ';'
- /// [GNU] 'goto' '*' expression ';'
- ///
- /// Note: this lets the caller parse the end ';'.
- ///
- StmtResult Parser::ParseGotoStatement() {
- assert(Tok.is(tok::kw_goto) && "Not a goto stmt!");
- SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'.
- StmtResult Res;
- if (Tok.is(tok::identifier)) {
- LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
- Tok.getLocation());
- Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), LD);
- ConsumeToken();
- } else if (Tok.is(tok::star)) {
- // GNU indirect goto extension.
- Diag(Tok, diag::ext_gnu_indirect_goto);
- SourceLocation StarLoc = ConsumeToken();
- ExprResult R(ParseExpression());
- if (R.isInvalid()) { // Skip to the semicolon, but don't consume it.
- SkipUntil(tok::semi, StopBeforeMatch);
- return StmtError();
- }
- Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.get());
- } else {
- Diag(Tok, diag::err_expected) << tok::identifier;
- return StmtError();
- }
- return Res;
- }
- /// ParseContinueStatement
- /// jump-statement:
- /// 'continue' ';'
- ///
- /// Note: this lets the caller parse the end ';'.
- ///
- StmtResult Parser::ParseContinueStatement() {
- SourceLocation ContinueLoc = ConsumeToken(); // eat the 'continue'.
- return Actions.ActOnContinueStmt(ContinueLoc, getCurScope());
- }
- /// ParseBreakStatement
- /// jump-statement:
- /// 'break' ';'
- ///
- /// Note: this lets the caller parse the end ';'.
- ///
- StmtResult Parser::ParseBreakStatement() {
- SourceLocation BreakLoc = ConsumeToken(); // eat the 'break'.
- return Actions.ActOnBreakStmt(BreakLoc, getCurScope());
- }
- /// ParseReturnStatement
- /// jump-statement:
- /// 'return' expression[opt] ';'
- /// 'return' braced-init-list ';'
- /// 'co_return' expression[opt] ';'
- /// 'co_return' braced-init-list ';'
- StmtResult Parser::ParseReturnStatement() {
- assert((Tok.is(tok::kw_return) || Tok.is(tok::kw_co_return)) &&
- "Not a return stmt!");
- bool IsCoreturn = Tok.is(tok::kw_co_return);
- SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'.
- ExprResult R;
- if (Tok.isNot(tok::semi)) {
- if (!IsCoreturn)
- PreferredType.enterReturn(Actions, Tok.getLocation());
- // FIXME: Code completion for co_return.
- if (Tok.is(tok::code_completion) && !IsCoreturn) {
- Actions.CodeCompleteExpression(getCurScope(),
- PreferredType.get(Tok.getLocation()));
- cutOffParsing();
- return StmtError();
- }
- if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) {
- R = ParseInitializer();
- if (R.isUsable())
- Diag(R.get()->getBeginLoc(),
- getLangOpts().CPlusPlus11
- ? diag::warn_cxx98_compat_generalized_initializer_lists
- : diag::ext_generalized_initializer_lists)
- << R.get()->getSourceRange();
- } else
- R = ParseExpression();
- if (R.isInvalid()) {
- SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
- return StmtError();
- }
- }
- if (IsCoreturn)
- return Actions.ActOnCoreturnStmt(getCurScope(), ReturnLoc, R.get());
- return Actions.ActOnReturnStmt(ReturnLoc, R.get(), getCurScope());
- }
- StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts,
- ParsedStmtContext StmtCtx,
- SourceLocation *TrailingElseLoc,
- ParsedAttributesWithRange &Attrs) {
- // Create temporary attribute list.
- ParsedAttributesWithRange TempAttrs(AttrFactory);
- // Get loop hints and consume annotated token.
- while (Tok.is(tok::annot_pragma_loop_hint)) {
- LoopHint Hint;
- if (!HandlePragmaLoopHint(Hint))
- continue;
- ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.StateLoc,
- ArgsUnion(Hint.ValueExpr)};
- TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
- Hint.PragmaNameLoc->Loc, ArgHints, 4,
- ParsedAttr::AS_Pragma);
- }
- // Get the next statement.
- MaybeParseCXX11Attributes(Attrs);
- StmtResult S = ParseStatementOrDeclarationAfterAttributes(
- Stmts, StmtCtx, TrailingElseLoc, Attrs);
- Attrs.takeAllFrom(TempAttrs);
- return S;
- }
- Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
- assert(Tok.is(tok::l_brace));
- SourceLocation LBraceLoc = Tok.getLocation();
- PrettyDeclStackTraceEntry CrashInfo(Actions.Context, Decl, LBraceLoc,
- "parsing function body");
- // Save and reset current vtordisp stack if we have entered a C++ method body.
- bool IsCXXMethod =
- getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
- Sema::PragmaStackSentinelRAII
- PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
- // 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.
- StmtResult FnBody(ParseCompoundStatementBody());
- // If the function body could not be parsed, make a bogus compoundstmt.
- if (FnBody.isInvalid()) {
- Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
- }
- BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, FnBody.get());
- }
- /// ParseFunctionTryBlock - Parse a C++ function-try-block.
- ///
- /// function-try-block:
- /// 'try' ctor-initializer[opt] compound-statement handler-seq
- ///
- Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
- assert(Tok.is(tok::kw_try) && "Expected 'try'");
- SourceLocation TryLoc = ConsumeToken();
- PrettyDeclStackTraceEntry CrashInfo(Actions.Context, Decl, TryLoc,
- "parsing function try block");
- // Constructor initializer list?
- if (Tok.is(tok::colon))
- ParseConstructorInitializer(Decl);
- else
- Actions.ActOnDefaultCtorInitializers(Decl);
- // Save and reset current vtordisp stack if we have entered a C++ method body.
- bool IsCXXMethod =
- getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
- Sema::PragmaStackSentinelRAII
- PragmaStackSentinel(Actions, "InternalPragmaState", IsCXXMethod);
- SourceLocation LBraceLoc = Tok.getLocation();
- StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true));
- // If we failed to parse the try-catch, we just give the function an empty
- // compound statement as the body.
- if (FnBody.isInvalid()) {
- Sema::CompoundScopeRAII CompoundScope(Actions);
- FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, None, false);
- }
- BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, FnBody.get());
- }
- bool Parser::trySkippingFunctionBody() {
- assert(SkipFunctionBodies &&
- "Should only be called when SkipFunctionBodies is enabled");
- if (!PP.isCodeCompletionEnabled()) {
- SkipFunctionBody();
- return true;
- }
- // We're in code-completion mode. Skip parsing for all function bodies unless
- // the body contains the code-completion point.
- TentativeParsingAction PA(*this);
- 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) {
- PA.Commit();
- SkipMalformedDecl();
- return true;
- }
- 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;
- }
- /// ParseCXXTryBlock - Parse a C++ try-block.
- ///
- /// try-block:
- /// 'try' compound-statement handler-seq
- ///
- StmtResult Parser::ParseCXXTryBlock() {
- assert(Tok.is(tok::kw_try) && "Expected 'try'");
- SourceLocation TryLoc = ConsumeToken();
- 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]
- ///
- /// [Borland] try-block:
- /// 'try' compound-statement seh-except-block
- /// 'try' compound-statement seh-finally-block
- ///
- StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
- if (Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- StmtResult TryBlock(ParseCompoundStatement(
- /*isStmtExpr=*/false, Scope::DeclScope | Scope::TryScope |
- Scope::CompoundStmtScope |
- (FnTry ? Scope::FnTryCatchScope : 0)));
- if (TryBlock.isInvalid())
- return TryBlock;
- // Borland allows SEH-handlers with 'try'
- if ((Tok.is(tok::identifier) &&
- Tok.getIdentifierInfo() == getSEHExceptKeyword()) ||
- Tok.is(tok::kw___finally)) {
- // TODO: Factor into common return ParseSEHHandlerCommon(...)
- StmtResult Handler;
- if(Tok.getIdentifierInfo() == getSEHExceptKeyword()) {
- SourceLocation Loc = ConsumeToken();
- Handler = ParseSEHExceptBlock(Loc);
- }
- else {
- SourceLocation Loc = ConsumeToken();
- Handler = ParseSEHFinallyBlock(Loc);
- }
- if(Handler.isInvalid())
- return Handler;
- return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
- TryLoc,
- TryBlock.get(),
- Handler.get());
- }
- else {
- StmtVector Handlers;
- // C++11 attributes can't appear here, despite this context seeming
- // statement-like.
- DiagnoseAndSkipCXX11Attributes();
- if (Tok.isNot(tok::kw_catch))
- return StmtError(Diag(Tok, diag::err_expected_catch));
- while (Tok.is(tok::kw_catch)) {
- StmtResult Handler(ParseCXXCatchBlock(FnTry));
- if (!Handler.isInvalid())
- Handlers.push_back(Handler.get());
- }
- // Don't bother creating the full statement if we don't have any usable
- // handlers.
- if (Handlers.empty())
- return StmtError();
- return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.get(), Handlers);
- }
- }
- /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
- ///
- /// handler:
- /// 'catch' '(' exception-declaration ')' compound-statement
- ///
- /// exception-declaration:
- /// attribute-specifier-seq[opt] type-specifier-seq declarator
- /// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
- /// '...'
- ///
- StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
- assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
- SourceLocation CatchLoc = ConsumeToken();
- BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume())
- 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.
- ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope |
- Scope::CatchScope |
- (FnCatch ? Scope::FnTryCatchScope : 0));
- // exception-declaration is equivalent to '...' or a parameter-declaration
- // without default arguments.
- Decl *ExceptionDecl = nullptr;
- if (Tok.isNot(tok::ellipsis)) {
- ParsedAttributesWithRange Attributes(AttrFactory);
- MaybeParseCXX11Attributes(Attributes);
- DeclSpec DS(AttrFactory);
- DS.takeAttributesFrom(Attributes);
- if (ParseCXXTypeSpecifierSeq(DS))
- return StmtError();
- Declarator ExDecl(DS, DeclaratorContext::CXXCatchContext);
- ParseDeclarator(ExDecl);
- ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
- } else
- ConsumeToken();
- T.consumeClose();
- if (T.getCloseLocation().isInvalid())
- return StmtError();
- if (Tok.isNot(tok::l_brace))
- return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- // FIXME: Possible draft standard bug: attribute-specifier should be allowed?
- StmtResult Block(ParseCompoundStatement());
- if (Block.isInvalid())
- return Block;
- return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.get());
- }
- void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
- IfExistsCondition Result;
- if (ParseMicrosoftIfExistsCondition(Result))
- return;
- // 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)) {
- Diag(Tok, diag::err_expected) << tok::l_brace;
- return;
- }
- StmtResult Compound = ParseCompoundStatement();
- if (Compound.isInvalid())
- return;
- StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc,
- Result.IsIfExists,
- Result.SS,
- Result.Name,
- Compound.get());
- if (DepResult.isUsable())
- Stmts.push_back(DepResult.get());
- return;
- }
- BalancedDelimiterTracker Braces(*this, tok::l_brace);
- if (Braces.consumeOpen()) {
- Diag(Tok, diag::err_expected) << tok::l_brace;
- return;
- }
- switch (Result.Behavior) {
- case IEB_Parse:
- // Parse the statements below.
- break;
- case IEB_Dependent:
- llvm_unreachable("Dependent case handled above");
- case IEB_Skip:
- Braces.skipToEnd();
- return;
- }
- // Condition is true, parse the statements.
- while (Tok.isNot(tok::r_brace)) {
- StmtResult R =
- ParseStatementOrDeclaration(Stmts, ParsedStmtContext::Compound);
- if (R.isUsable())
- Stmts.push_back(R.get());
- }
- Braces.consumeClose();
- }
- bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
- MaybeParseGNUAttributes(Attrs);
- if (Attrs.empty())
- return true;
- if (Attrs.begin()->getKind() != ParsedAttr::AT_OpenCLUnrollHint)
- 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;
- }
|