@@ -19599,56 +19599,244 @@ when suppress_warning is TRUE.
1959919599} /* flush_to_end_of_source */
1960019600
1960119601
19602- void flush_if_or_else_statement(void )
19602+ static INLINE void flush_statement_header( )
1960319603/*
19604- Flush tokens of a dependent statement of an "if" or "else" statement.
19605- The current token is the token after the "if" or "else" keyword.
19604+ Flush the parenthesized header of a statement such as "while", "for",
19605+ "switch" or "catch". The current token is the token after the keyword (and
19606+ after any "co_await"), which should be the opening parenthesis. On return,
19607+ the current token is the token following the closing parenthesis (e.g., the
19608+ start of the controlled substatement).
19609+
19610+ Note: The caller is responsible for having set flushing_tokens to TRUE.
1960619611*/
1960719612{
19608- /* Special handling is needed for nested "if" statements so that
19609- substatements that are "else if" statements are handled properly. */
19610- if (curr_token == tok_if) {
19611- (void)get_token();
19612- if (curr_token == tok_not && next_token() == tok_consteval) {
19613- /* Skip the "not" token only if it is followed by "consteval". */
19613+ if (curr_token == tok_lparen) {
19614+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19615+ if (curr_token != tok_end_of_source) {
19616+ /* Skip the closing parenthesis. */
1961419617 (void)get_token();
1961519618 } /* if */
19616- if (curr_token == tok_consteval) {
19619+ } else {
19620+ pos_error(ec_exp_lparen, &error_position);
19621+ } /* if */
19622+ } /* flush_statement_header */
19623+
19624+
19625+ static void flush_one_statement()
19626+ /*
19627+ Flush the tokens of exactly one statement. The current token is the first
19628+ token of the statement.
19629+
19630+ On return, the current token is the last token of the statement. It is left
19631+ unconsumed so that the caller can fetch the next token after leaving the
19632+ flushing lexical state, which preserves pragma state (see
19633+ flush_if_or_else_statement).
19634+
19635+ Note: The caller is responsible for having set flushing_tokens to TRUE.
19636+ */
19637+ {
19638+ /* Note this routine is recursive because many statements have substatements,
19639+ e.g., "while (a) while (b) { }" is a single statement. */
19640+ /* Skip a leading attribute-specifier-seq. */
19641+ while (curr_token == tok_lbracket && next_token() == tok_lbracket) {
19642+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19643+ (void)get_token();
19644+ } /* while */
19645+ /* Skip the "template" of a C++26 "template for" expansion statement. The
19646+ rest of the statement is scanned like an ordinary "for" statement. */
19647+ if (curr_token == tok_template && next_token() == tok_for) {
19648+ (void)get_token();
19649+ } /* if */
19650+ switch (curr_token) {
19651+ case tok_lbrace:
19652+ /* Compound statement. */
19653+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19654+ break;
19655+ case tok_if:
19656+ /* Special handling is needed for nested "if" statements so that
19657+ substatements that are "else if" statements are handled properly. */
1961719658 (void)get_token();
19618- } else {
19619- if (curr_token == tok_constexpr) (void)get_token();
19620- if (curr_token == tok_lparen) {
19621- flush_until_matching_token_full(/*limit_flush=*/FALSE);
19659+ if (curr_token == tok_not && next_token() == tok_consteval) {
19660+ /* Skip the "not" token only if it is followed by "consteval". */
19661+ (void)get_token();
19662+ } /* if */
19663+ if (curr_token == tok_consteval) {
1962219664 (void)get_token();
1962319665 } else {
19624- pos_error(ec_exp_lparen, &error_position);
19666+ if (curr_token == tok_constexpr) (void)get_token();
19667+ if (curr_token == tok_lparen) {
19668+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19669+ (void)get_token();
19670+ } else {
19671+ pos_error(ec_exp_lparen, &error_position);
19672+ } /* if */
1962519673 } /* if */
19626- } /* if */
19627- flush_if_or_else_statement();
19628- if (curr_token == tok_else) {
19674+ flush_one_statement();
19675+ if (next_token() == tok_else) {
19676+ /* Consume the final token of the statement skipped by
19677+ flush_one_statement. */
19678+ (void)get_token();
19679+ /* Consume the "else". */
19680+ (void)get_token();
19681+ flush_one_statement();
19682+ } /* if */
19683+ break;
19684+ case tok_while:
19685+ case tok_switch:
19686+ #if MICROSOFT_EXTENSIONS_ALLOWED
19687+ case tok_for_each:
19688+ #endif /* MICROSOFT_EXTENSIONS_ALLOWED */
19689+ /* The controlled substatement is a statement in its own right. */
1962919690 (void)get_token();
19630- flush_if_or_else_statement();
19631- } /* if */
19632- } else {
19633- push_lexical_state_stack();
19634- curr_lexical_state_stack_entry->flushing_tokens = TRUE;
19635- /* If we found a left brace, skip the compound statement. */
19636- if (curr_token == tok_lbrace) {
19637- flush_until_matching_token_full(/*limit_flush=*/FALSE);
19638- } else {
19639- /* Initialize a local stop token set. Also stop on right brace and end
19640- of source for error cases. */
19641- a_token_set_array stop_tokens;
19642- clear_token_set_array(stop_tokens);
19643- incr_token_set_array_element(stop_tokens, tok_end_of_source);
19644- incr_token_set_array_element(stop_tokens, tok_rbrace);
19645- incr_token_set_array_element(stop_tokens, tok_semicolon);
19646- flush_tokens_with_stop_tokens_and_warning_flag(stop_tokens,
19691+ flush_statement_header();
19692+ flush_one_statement();
19693+ break;
19694+ #if UPC_EXTENSIONS_ALLOWED
19695+ case tok_upc_forall:
19696+ /* The upc_forall statement is similar to the standard for statement. */
19697+ FALLTHROUGH
19698+ #endif /* UPC_EXTENSIONS_ALLOWED */
19699+ case tok_for:
19700+ /* For statement and range-based for statement, which may have a
19701+ "co_await" between the "for" and the opening parenthesis. */
19702+ (void)get_token();
19703+ if (curr_token == tok_coroutine_await) (void)get_token();
19704+ flush_statement_header();
19705+ flush_one_statement();
19706+ break;
19707+ case tok_do:
19708+ /* "do statement while ( expression ) ;" */
19709+ (void)get_token();
19710+ flush_one_statement();
19711+ if (next_token() == tok_while) {
19712+ /* Consume the final token of the statement skipped by
19713+ flush_one_statement. */
19714+ (void)get_token();
19715+ /* Consume the "while". */
19716+ (void)get_token();
19717+ /* Leaves the current token on the ";" following the ")". */
19718+ flush_statement_header();
19719+ } /* if */
19720+ break;
19721+ case tok_try:
19722+ /* "try compound-statement handler-seq" */
19723+ (void)get_token();
19724+ if (curr_token == tok_lbrace) {
19725+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19726+ } /* if */
19727+ while (next_token() == tok_catch) {
19728+ /* Consume the final token of the preceding compound statement (the
19729+ "try" block or the previous handler). */
19730+ (void)get_token();
19731+ /* Consume the "catch". */
19732+ (void)get_token();
19733+ flush_statement_header();
19734+ if (curr_token == tok_lbrace) {
19735+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19736+ } /* if */
19737+ } /* while */
19738+ break;
19739+ #if MICROSOFT_EXTENSIONS_ALLOWED
19740+ case tok_microsoft_try:
19741+ /* "__try compound-statement __except ( expression ) compound-statement"
19742+ or "__try compound-statement __finally compound-statement". */
19743+ (void)get_token();
19744+ if (curr_token == tok_lbrace) {
19745+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19746+ } /* if */
19747+ if (next_token() == tok_except) {
19748+ /* Consume the final token of the "__try" compound statement. */
19749+ (void)get_token();
19750+ /* Consume the "__except". */
19751+ (void)get_token();
19752+ flush_statement_header();
19753+ } else if (next_token() == tok_identifier) {
19754+ /* Consume the final token of the "__try" compound statement. */
19755+ (void)get_token();
19756+ /* Consume the "__finally". */
19757+ (void)get_token();
19758+ } /* if */
19759+ if (curr_token == tok_lbrace) {
19760+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19761+ } /* if */
19762+ break;
19763+ #endif /* MICROSOFT_EXTENSIONS_ALLOWED */
19764+ case tok_case: {
19765+ /* A case label labels the statement that follows it. Skip to the
19766+ ":", allowing for conditional expressions in the case value. */
19767+ unsigned long quest_mark_count = 0;
19768+ (void)get_token();
19769+ while (curr_token != tok_end_of_source && curr_token != tok_semicolon &&
19770+ curr_token != tok_rbrace &&
19771+ (curr_token != tok_colon || quest_mark_count != 0)) {
19772+ if (curr_token == tok_quest_mark) {
19773+ quest_mark_count++;
19774+ } else if (curr_token == tok_colon) {
19775+ quest_mark_count--;
19776+ } else if (curr_token == tok_lparen || curr_token == tok_lbracket ||
19777+ curr_token == tok_lbrace) {
19778+ flush_until_matching_token_full(/*limit_flush=*/FALSE);
19779+ } /* if */
19780+ (void)get_token();
19781+ } /* while */
19782+ if (curr_token == tok_colon) {
19783+ (void)get_token();
19784+ flush_one_statement();
19785+ } /* if */
19786+ break;
19787+ }
19788+ case tok_default:
19789+ /* "default :" labels the statement that follows it. */
19790+ if (next_token() == tok_colon) {
19791+ (void)get_token();
19792+ (void)get_token();
19793+ flush_one_statement();
19794+ } /* if */
19795+ break;
19796+ case tok_identifier:
19797+ if (next_token() == tok_colon) {
19798+ /* A label definition labels the statement that follows it. */
19799+ (void)get_token();
19800+ (void)get_token();
19801+ flush_one_statement();
19802+ break;
19803+ } /* if */
19804+ /* Otherwise this is an expression or declaration statement. */
19805+ FALLTHROUGH
19806+ default:
19807+ { /* An expression statement, declaration, jump statement, empty
19808+ statement, etc. Such statements end at the first ";" that isn't
19809+ nested within parentheses, brackets or braces. Initialize a local
19810+ stop token set. Also stop on right brace and end of source for
19811+ error cases. */
19812+ a_token_set_array stop_tokens;
19813+ clear_token_set_array(stop_tokens);
19814+ incr_token_set_array_element(stop_tokens, tok_end_of_source);
19815+ incr_token_set_array_element(stop_tokens, tok_rbrace);
19816+ incr_token_set_array_element(stop_tokens, tok_semicolon);
19817+ flush_tokens_with_stop_tokens_and_warning_flag(
19818+ stop_tokens,
1964719819 /*suppress_warning=*/TRUE);
19648- } /* if */
19649- pop_lexical_state_stack();
19650- if (curr_token != tok_end_of_source) (void)get_token();
19651- } /* if */
19820+ }
19821+ break;
19822+ } /* switch */
19823+ } /* flush_one_statement */
19824+
19825+
19826+ void flush_if_or_else_statement(void)
19827+ /*
19828+ Flush tokens of a dependent statement of an "if" or "else" statement.
19829+ The current token is the token after the "if" or "else" keyword. Exactly one
19830+ statement is flushed, so for an unbraced dependent statement such as
19831+ "if constexpr (c) while (a) while (b) { } return;", the "return" is not
19832+ flushed. On return the current token is the first token after the statement.
19833+ */
19834+ {
19835+ push_lexical_state_stack();
19836+ curr_lexical_state_stack_entry->flushing_tokens = TRUE;
19837+ flush_one_statement();
19838+ pop_lexical_state_stack();
19839+ if (curr_token != tok_end_of_source) (void)get_token();
1965219840} /* flush_if_or_else_statement */
1965319841
1965419842
0 commit comments