<commit_before>//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Statement and Block portions of the Parser
// interface.
//
//===----------------------------------------------------------------------===//

#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;

//===----------------------------------------------------------------------===//
// C99 6.8: Statements and Blocks.
//===----------------------------------------------------------------------===//

/// 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
/// [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, bool OnlyStatement) {
  const char *SemiError = 0;
  StmtResult Res;
  
  ParenBraceBracketBalancer BalancerRAIIObj(*this);

  ParsedAttributesWithRange attrs(AttrFactory);
  MaybeParseCXX0XAttributes(attrs);

  // 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.
  tok::TokenKind Kind  = Tok.getKind();
  SourceLocation AtLoc;
  switch (Kind) {
  case tok::at: // May be a @try or @throw statement
    {
      AtLoc = ConsumeToken();  // consume @
      return ParseObjCAtStatement(AtLoc);
    }

  case tok::code_completion:
    Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
    ConsumeCodeCompletionToken();
    return ParseStatementOrDeclaration(Stmts, OnlyStatement);
      
  case tok::identifier:
    if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
      // identifier ':' statement
      return ParseLabeledStatement(attrs);
    }
    // PASS THROUGH.

  default: {
    if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
      SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
      DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext,
                                             DeclEnd, attrs);
      return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
    }

    if (Tok.is(tok::r_brace)) {
      Diag(Tok, diag::err_expected_statement);
      return StmtError();
    }

    // If a case keyword is missing, this is where it should be inserted.
    Token OldToken = Tok;

    // FIXME: Use the attributes
    // 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=*/true, /*DontConsume=*/true);
      if (Tok.is(tok::semi))
        ConsumeToken();
      return StmtError();
    }

    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 keywork.
      Diag(OldToken, diag::err_expected_case_before_expression)
          << FixItHint::CreateInsertion(OldToken.getLocation(), "case ");

      // Recover parsing as a case statement.
      return ParseCaseStatement(attrs, /*MissingCase=*/true, Expr);
    }

    // Otherwise, eat the semicolon.
    ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
    return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
  }

  case tok::kw_case:                // C99 6.8.1: labeled-statement
    return ParseCaseStatement(attrs);
  case tok::kw_default:             // C99 6.8.1: labeled-statement
    return ParseDefaultStatement(attrs);

  case tok::l_brace:                // C99 6.8.2: compound-statement
    return ParseCompoundStatement(attrs);
  case tok::semi: {                 // C99 6.8.3p3: expression[opt] ';'
    bool LeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
    return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacro);
  }

  case tok::kw_if:                  // C99 6.8.4.1: if-statement
    return ParseIfStatement(attrs);
  case tok::kw_switch:              // C99 6.8.4.2: switch-statement
    return ParseSwitchStatement(attrs);

  case tok::kw_while:               // C99 6.8.5.1: while-statement
    return ParseWhileStatement(attrs);
  case tok::kw_do:                  // C99 6.8.5.2: do-statement
    Res = ParseDoStatement(attrs);
    SemiError = "do/while";
    break;
  case tok::kw_for:                 // C99 6.8.5.3: for-statement
    return ParseForStatement(attrs);

  case tok::kw_goto:                // C99 6.8.6.1: goto-statement
    Res = ParseGotoStatement(attrs);
    SemiError = "goto";
    break;
  case tok::kw_continue:            // C99 6.8.6.2: continue-statement
    Res = ParseContinueStatement(attrs);
    SemiError = "continue";
    break;
  case tok::kw_break:               // C99 6.8.6.3: break-statement
    Res = ParseBreakStatement(attrs);
    SemiError = "break";
    break;
  case tok::kw_return:              // C99 6.8.6.4: return-statement
    Res = ParseReturnStatement(attrs);
    SemiError = "return";
    break;

  case tok::kw_asm: {
    ProhibitAttributes(attrs);
    bool msAsm = false;
    Res = ParseAsmStatement(msAsm);
    Res = Actions.ActOnFinishFullStmt(Res.get());
    if (msAsm) return move(Res);
    SemiError = "asm";
    break;
  }

  case tok::kw_try:                 // C++ 15: try-block
    return ParseCXXTryBlock(attrs);
  }

  // If we reached this code, the statement must end in a semicolon.
  if (Tok.is(tok::semi)) {
    ConsumeToken();
  } else if (!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, true, true);
  }

  return move(Res);
}

/// ParseLabeledStatement - We have an identifier and a ':' after it.
///
///       labeled-statement:
///         identifier ':' statement
/// [GNU]   identifier ':' attributes[opt] statement
///
StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) {
  assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
         "Not an identifier!");

  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.
  MaybeParseGNUAttributes(attrs);

  StmtResult SubStmt(ParseStatement());

  // 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());
  if (AttributeList *Attrs = attrs.getList())
    Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs);
  
  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(ParsedAttributes &attrs, bool MissingCase,
                                      ExprResult Expr) {
  assert(MissingCase || Tok.is(tok::kw_case) && "Not a case stmt!");
  // FIXME: Use attributes?

  // It is very very common for code to contain many case statements recursively
  // nested, as in (but usually without indentation):<commit_msg>Fix gcc warning. Add parens to this assert, incidentally reassociating it, but the condition is the same either way.<commit_after>//===--- ParseStmt.cpp - Statement and Block Parser -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Statement and Block portions of the Parser
// interface.
//
//===----------------------------------------------------------------------===//

#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;

//===----------------------------------------------------------------------===//
// C99 6.8: Statements and Blocks.
//===----------------------------------------------------------------------===//

/// 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
/// [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, bool OnlyStatement) {
  const char *SemiError = 0;
  StmtResult Res;
  
  ParenBraceBracketBalancer BalancerRAIIObj(*this);

  ParsedAttributesWithRange attrs(AttrFactory);
  MaybeParseCXX0XAttributes(attrs);

  // 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.
  tok::TokenKind Kind  = Tok.getKind();
  SourceLocation AtLoc;
  switch (Kind) {
  case tok::at: // May be a @try or @throw statement
    {
      AtLoc = ConsumeToken();  // consume @
      return ParseObjCAtStatement(AtLoc);
    }

  case tok::code_completion:
    Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement);
    ConsumeCodeCompletionToken();
    return ParseStatementOrDeclaration(Stmts, OnlyStatement);
      
  case tok::identifier:
    if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement
      // identifier ':' statement
      return ParseLabeledStatement(attrs);
    }
    // PASS THROUGH.

  default: {
    if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) {
      SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
      DeclGroupPtrTy Decl = ParseDeclaration(Stmts, Declarator::BlockContext,
                                             DeclEnd, attrs);
      return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd);
    }

    if (Tok.is(tok::r_brace)) {
      Diag(Tok, diag::err_expected_statement);
      return StmtError();
    }

    // If a case keyword is missing, this is where it should be inserted.
    Token OldToken = Tok;

    // FIXME: Use the attributes
    // 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=*/true, /*DontConsume=*/true);
      if (Tok.is(tok::semi))
        ConsumeToken();
      return StmtError();
    }

    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 keywork.
      Diag(OldToken, diag::err_expected_case_before_expression)
          << FixItHint::CreateInsertion(OldToken.getLocation(), "case ");

      // Recover parsing as a case statement.
      return ParseCaseStatement(attrs, /*MissingCase=*/true, Expr);
    }

    // Otherwise, eat the semicolon.
    ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
    return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
  }

  case tok::kw_case:                // C99 6.8.1: labeled-statement
    return ParseCaseStatement(attrs);
  case tok::kw_default:             // C99 6.8.1: labeled-statement
    return ParseDefaultStatement(attrs);

  case tok::l_brace:                // C99 6.8.2: compound-statement
    return ParseCompoundStatement(attrs);
  case tok::semi: {                 // C99 6.8.3p3: expression[opt] ';'
    bool LeadingEmptyMacro = Tok.hasLeadingEmptyMacro();
    return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacro);
  }

  case tok::kw_if:                  // C99 6.8.4.1: if-statement
    return ParseIfStatement(attrs);
  case tok::kw_switch:              // C99 6.8.4.2: switch-statement
    return ParseSwitchStatement(attrs);

  case tok::kw_while:               // C99 6.8.5.1: while-statement
    return ParseWhileStatement(attrs);
  case tok::kw_do:                  // C99 6.8.5.2: do-statement
    Res = ParseDoStatement(attrs);
    SemiError = "do/while";
    break;
  case tok::kw_for:                 // C99 6.8.5.3: for-statement
    return ParseForStatement(attrs);

  case tok::kw_goto:                // C99 6.8.6.1: goto-statement
    Res = ParseGotoStatement(attrs);
    SemiError = "goto";
    break;
  case tok::kw_continue:            // C99 6.8.6.2: continue-statement
    Res = ParseContinueStatement(attrs);
    SemiError = "continue";
    break;
  case tok::kw_break:               // C99 6.8.6.3: break-statement
    Res = ParseBreakStatement(attrs);
    SemiError = "break";
    break;
  case tok::kw_return:              // C99 6.8.6.4: return-statement
    Res = ParseReturnStatement(attrs);
    SemiError = "return";
    break;

  case tok::kw_asm: {
    ProhibitAttributes(attrs);
    bool msAsm = false;
    Res = ParseAsmStatement(msAsm);
    Res = Actions.ActOnFinishFullStmt(Res.get());
    if (msAsm) return move(Res);
    SemiError = "asm";
    break;
  }

  case tok::kw_try:                 // C++ 15: try-block
    return ParseCXXTryBlock(attrs);
  }

  // If we reached this code, the statement must end in a semicolon.
  if (Tok.is(tok::semi)) {
    ConsumeToken();
  } else if (!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, true, true);
  }

  return move(Res);
}

/// ParseLabeledStatement - We have an identifier and a ':' after it.
///
///       labeled-statement:
///         identifier ':' statement
/// [GNU]   identifier ':' attributes[opt] statement
///
StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) {
  assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() &&
         "Not an identifier!");

  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.
  MaybeParseGNUAttributes(attrs);

  StmtResult SubStmt(ParseStatement());

  // 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());
  if (AttributeList *Attrs = attrs.getList())
    Actions.ProcessDeclAttributeList(Actions.CurScope, LD, Attrs);
  
  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(ParsedAttributes &attrs, bool MissingCase,
                                      ExprResult Expr) {
  assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!");
  // FIXME: Use attributes?

  // It is very very common for code to contain many case statements recursively
  // nested, as in (but usually without indentation):
{'fraction_non_alphanumeric': 0.16591110416340993, 'fraction_numerical': 0.009170965556771403, 'mean_word_length': 2.265611706653054, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 18, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '320244', 'n_tokens_mistral': 5703, 'n_tokens_neox': 5539, 'n_words': 1363}