Exemple #1
0
C2::StmtResult C2Sema::ActOnIfStmt(SourceLocation ifLoc,
                                   Stmt* condition, StmtResult thenStmt,
                                   SourceLocation elseLoc, StmtResult elseStmt) {
#ifdef SEMA_DEBUG
    std::cerr << COL_SEMA"SEMA: if statement at ";
    ifLoc.dump(SourceMgr);
    std::cerr << ANSI_NORMAL"\n";
#endif
    return StmtResult(new IfStmt(ifLoc, condition, thenStmt.get(), elseLoc, elseStmt.get()));
}
Exemple #2
0
static bool actOnCoroutineBodyStart(Sema &S, Scope *SC, SourceLocation KWLoc,
                                    StringRef Keyword) {
  if (!checkCoroutineContext(S, KWLoc, Keyword))
    return false;
  auto *ScopeInfo = S.getCurFunction();
  assert(ScopeInfo->CoroutinePromise);

  // If we have existing coroutine statements then we have already built
  // the initial and final suspend points.
  if (!ScopeInfo->NeedsCoroutineSuspends)
    return true;

  ScopeInfo->setNeedsCoroutineSuspends(false);

  auto *Fn = cast<FunctionDecl>(S.CurContext);
  SourceLocation Loc = Fn->getLocation();
  // Build the initial suspend point
  auto buildSuspends = [&](StringRef Name) mutable -> StmtResult {
    ExprResult Suspend =
        buildPromiseCall(S, ScopeInfo->CoroutinePromise, Loc, Name, None);
    if (Suspend.isInvalid())
      return StmtError();
    Suspend = buildOperatorCoawaitCall(S, SC, Loc, Suspend.get());
    if (Suspend.isInvalid())
      return StmtError();
    Suspend = S.BuildResolvedCoawaitExpr(Loc, Suspend.get(),
                                         /*IsImplicit*/ true);
    Suspend = S.ActOnFinishFullExpr(Suspend.get());
    if (Suspend.isInvalid()) {
      S.Diag(Loc, diag::note_coroutine_promise_suspend_implicitly_required)
          << ((Name == "initial_suspend") ? 0 : 1);
      S.Diag(KWLoc, diag::note_declared_coroutine_here) << Keyword;
      return StmtError();
    }
    return cast<Stmt>(Suspend.get());
  };

  StmtResult InitSuspend = buildSuspends("initial_suspend");
  if (InitSuspend.isInvalid())
    return true;

  StmtResult FinalSuspend = buildSuspends("final_suspend");
  if (FinalSuspend.isInvalid())
    return true;

  ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());

  return true;
}
Exemple #3
0
bool CoroutineStmtBuilder::makeOnFallthrough() {
  assert(!IsPromiseDependentType &&
         "cannot make statement while the promise type is dependent");

  // [dcl.fct.def.coroutine]/4
  // The unqualified-ids 'return_void' and 'return_value' are looked up in
  // the scope of class P. If both are found, the program is ill-formed.
  bool HasRVoid, HasRValue;
  LookupResult LRVoid =
      lookupMember(S, "return_void", PromiseRecordDecl, Loc, HasRVoid);
  LookupResult LRValue =
      lookupMember(S, "return_value", PromiseRecordDecl, Loc, HasRValue);

  StmtResult Fallthrough;
  if (HasRVoid && HasRValue) {
    // FIXME Improve this diagnostic
    S.Diag(FD.getLocation(),
           diag::err_coroutine_promise_incompatible_return_functions)
        << PromiseRecordDecl;
    S.Diag(LRVoid.getRepresentativeDecl()->getLocation(),
           diag::note_member_first_declared_here)
        << LRVoid.getLookupName();
    S.Diag(LRValue.getRepresentativeDecl()->getLocation(),
           diag::note_member_first_declared_here)
        << LRValue.getLookupName();
    return false;
  } else if (!HasRVoid && !HasRValue) {
    // FIXME: The PDTS currently specifies this case as UB, not ill-formed.
    // However we still diagnose this as an error since until the PDTS is fixed.
    S.Diag(FD.getLocation(),
           diag::err_coroutine_promise_requires_return_function)
        << PromiseRecordDecl;
    S.Diag(PromiseRecordDecl->getLocation(), diag::note_defined_here)
        << PromiseRecordDecl;
    return false;
  } else if (HasRVoid) {
    // If the unqualified-id return_void is found, flowing off the end of a
    // coroutine is equivalent to a co_return with no operand. Otherwise,
    // flowing off the end of a coroutine results in undefined behavior.
    Fallthrough = S.BuildCoreturnStmt(FD.getLocation(), nullptr,
                                      /*IsImplicit*/false);
    Fallthrough = S.ActOnFinishFullStmt(Fallthrough.get());
    if (Fallthrough.isInvalid())
      return false;
  }

  this->OnFallthrough = Fallthrough.get();
  return true;
}
Exemple #4
0
StmtResult Parser::HandlePragmaCaptured()
{
  assert(Tok.is(tok::annot_pragma_captured));
  ConsumeToken();

  if (Tok.isNot(tok::l_brace)) {
    PP.Diag(Tok, diag::err_expected_lbrace);
    return StmtError();
  }

  SourceLocation Loc = Tok.getLocation();

  ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope);
  Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default);

  StmtResult R = ParseCompoundStatement();
  CapturedRegionScope.Exit();

  if (R.isInvalid()) {
    Actions.ActOnCapturedRegionError();
    return StmtError();
  }

  return Actions.ActOnCapturedRegionEnd(R.get());
}
Exemple #5
0
C2::StmtResult C2Sema::ActOnDoStmt(SourceLocation loc, ExprResult Cond, StmtResult Then) {
#ifdef SEMA_DEBUG
    std::cerr << COL_SEMA"SEMA: do statement at ";
    loc.dump(SourceMgr);
    std::cerr << ANSI_NORMAL"\n";
#endif
    return StmtResult(new DoStmt(loc, Cond.get(), Then.get()));
}
StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) {
  auto *Context = checkCoroutineContext(*this, Loc, "co_return");
  StmtResult Res = StmtError();

  if (Context && !Res.isInvalid())
    Context->CoroutineStmts.push_back(Res.get());
  return Res;
}
Exemple #7
0
bool CoroutineStmtBuilder::makePromiseStmt() {
  // Form a declaration statement for the promise declaration, so that AST
  // visitors can more easily find it.
  StmtResult PromiseStmt =
      S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(Fn.CoroutinePromise), Loc, Loc);
  if (PromiseStmt.isInvalid())
    return false;

  this->Promise = PromiseStmt.get();
  return true;
}
Exemple #8
0
bool CoroutineStmtBuilder::makeReturnOnAllocFailure() {
  assert(!IsPromiseDependentType &&
         "cannot make statement while the promise type is dependent");

  // [dcl.fct.def.coroutine]/8
  // The unqualified-id get_return_object_on_allocation_failure is looked up in
  // the scope of class P by class member access lookup (3.4.5). ...
  // If an allocation function returns nullptr, ... the coroutine return value
  // is obtained by a call to ... get_return_object_on_allocation_failure().

  DeclarationName DN =
      S.PP.getIdentifierInfo("get_return_object_on_allocation_failure");
  LookupResult Found(S, DN, Loc, Sema::LookupMemberName);
  if (!S.LookupQualifiedName(Found, PromiseRecordDecl))
    return true;

  CXXScopeSpec SS;
  ExprResult DeclNameExpr =
      S.BuildDeclarationNameExpr(SS, Found, /*NeedsADL=*/false);
  if (DeclNameExpr.isInvalid())
    return false;

  if (!diagReturnOnAllocFailure(S, DeclNameExpr.get(), PromiseRecordDecl, Fn))
    return false;

  ExprResult ReturnObjectOnAllocationFailure =
      S.ActOnCallExpr(nullptr, DeclNameExpr.get(), Loc, {}, Loc);
  if (ReturnObjectOnAllocationFailure.isInvalid())
    return false;

  StmtResult ReturnStmt =
      S.BuildReturnStmt(Loc, ReturnObjectOnAllocationFailure.get());
  if (ReturnStmt.isInvalid()) {
    S.Diag(Found.getFoundDecl()->getLocation(), diag::note_member_declared_here)
        << DN;
    S.Diag(Fn.FirstCoroutineStmtLoc, diag::note_declared_coroutine_here)
        << Fn.getFirstCoroutineStmtKeyword();
    return false;
  }

  this->ReturnStmtOnAllocFailure = ReturnStmt.get();
  return true;
}
Exemple #9
0
void Parser::CheckStmtOrder(SourceLocation Loc, StmtResult SR) {
  auto S = SR.get();
  if(SR.isUsable()) {
    if(Actions.InsideWhereConstruct(S))
      Actions.CheckValidWhereStmtPart(S);
  }

  if(PrevStmtWasSelectCase) {
    PrevStmtWasSelectCase = false;
    if(SR.isUsable() && (isa<SelectionCase>(S) ||
       (isa<ConstructPartStmt>(S) &&
        cast<ConstructPartStmt>(S)->getConstructStmtClass() == ConstructPartStmt::EndSelectStmtClass)))
      return;
    Diag.Report(SR.isUsable()? S->getLocation() : Loc,
                diag::err_expected_case_or_end_select);
  }
  if(SR.isUsable() && isa<SelectCaseStmt>(S))
    PrevStmtWasSelectCase = true;
}
Exemple #10
0
 void Fix(CompoundStmt* CS) {
   if (!CS->size())
     return;
   typedef llvm::SmallVector<Stmt*, 32> Statements;
   Statements Stmts;
   Stmts.append(CS->body_begin(), CS->body_end());
   for (Statements::iterator I = Stmts.begin(); I != Stmts.end(); ++I) {
     if (!TraverseStmt(*I) && !m_HandledDecls.count(m_FoundDRE->getDecl())) {
       Sema::DeclGroupPtrTy VDPtrTy
         = m_Sema->ConvertDeclToDeclGroup(m_FoundDRE->getDecl());
       StmtResult DS = m_Sema->ActOnDeclStmt(VDPtrTy,
                                             m_FoundDRE->getLocStart(),
                                             m_FoundDRE->getLocEnd());
       assert(!DS.isInvalid() && "Invalid DeclStmt.");
       I = Stmts.insert(I, DS.get());
       m_HandledDecls.insert(m_FoundDRE->getDecl());
     }
   }
   CS->setStmts(m_Sema->getASTContext(), Stmts.data(), Stmts.size());
 }
Exemple #11
0
bool CoroutineStmtBuilder::makeParamMoves() {
  for (auto *paramDecl : FD.parameters()) {
    auto Ty = paramDecl->getType();
    if (Ty->isDependentType())
      continue;

    // No need to copy scalars, llvm will take care of them.
    if (Ty->getAsCXXRecordDecl()) {
      if (!paramDecl->getIdentifier())
        continue;

      ExprResult ParamRef =
          S.BuildDeclRefExpr(paramDecl, paramDecl->getType(),
                             ExprValueKind::VK_LValue, Loc); // FIXME: scope?
      if (ParamRef.isInvalid())
        return false;

      Expr *RCast = castForMoving(S, ParamRef.get());

      auto D = buildVarDecl(S, Loc, Ty, paramDecl->getIdentifier()->getName());

      S.AddInitializerToDecl(D, RCast, /*DirectInit=*/true);

      // Convert decl to a statement.
      StmtResult Stmt = S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(D), Loc, Loc);
      if (Stmt.isInvalid())
        return false;

      ParamMovesVector.push_back(Stmt.get());
    }
  }

  // Convert to ArrayRef in CtorArgs structure that builder inherits from.
  ParamMoves = ParamMovesVector;
  return true;
}
Exemple #12
0
/// \brief Parsing of declarative or executable OpenMP directives.
///
///       threadprivate-directive:
///         annot_pragma_openmp 'threadprivate' simple-variable-list
///         annot_pragma_openmp_end
///
///       executable-directive:
///         annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' |
///         'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] |
///         'parallel for' | 'parallel sections' | 'task' | 'taskyield' |
///         'barrier' | 'taskwait' | 'flush' {clause} annot_pragma_openmp_end
///
StmtResult
Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
    assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
    ParenBraceBracketBalancer BalancerRAIIObj(*this);
    SmallVector<Expr *, 5> Identifiers;
    SmallVector<OMPClause *, 5> Clauses;
    SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
    FirstClauses(OMPC_unknown + 1);
    unsigned ScopeFlags =
        Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
    SourceLocation Loc = ConsumeToken(), EndLoc;
    auto DKind = ParseOpenMPDirectiveKind(*this);
    // Name of critical directive.
    DeclarationNameInfo DirName;
    StmtResult Directive = StmtError();
    bool HasAssociatedStatement = true;
    bool FlushHasClause = false;

    switch (DKind) {
    case OMPD_threadprivate:
        ConsumeToken();
        if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
            // The last seen token is annot_pragma_openmp_end - need to check for
            // extra tokens.
            if (Tok.isNot(tok::annot_pragma_openmp_end)) {
                Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
                        << getOpenMPDirectiveName(OMPD_threadprivate);
                SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
            }
            DeclGroupPtrTy Res =
                Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers);
            Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
        }
        SkipUntil(tok::annot_pragma_openmp_end);
        break;
    case OMPD_flush:
        if (PP.LookAhead(0).is(tok::l_paren)) {
            FlushHasClause = true;
            // Push copy of the current token back to stream to properly parse
            // pseudo-clause OMPFlushClause.
            PP.EnterToken(Tok);
        }
    case OMPD_taskyield:
    case OMPD_barrier:
    case OMPD_taskwait:
        if (!StandAloneAllowed) {
            Diag(Tok, diag::err_omp_immediate_directive)
                    << getOpenMPDirectiveName(DKind);
        }
        HasAssociatedStatement = false;
    // Fall through for further analysis.
    case OMPD_parallel:
    case OMPD_simd:
    case OMPD_for:
    case OMPD_sections:
    case OMPD_single:
    case OMPD_section:
    case OMPD_master:
    case OMPD_critical:
    case OMPD_parallel_for:
    case OMPD_parallel_sections:
    case OMPD_task: {
        ConsumeToken();
        // Parse directive name of the 'critical' directive if any.
        if (DKind == OMPD_critical) {
            BalancedDelimiterTracker T(*this, tok::l_paren,
                                       tok::annot_pragma_openmp_end);
            if (!T.consumeOpen()) {
                if (Tok.isAnyIdentifier()) {
                    DirName =
                        DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation());
                    ConsumeAnyToken();
                } else {
                    Diag(Tok, diag::err_omp_expected_identifier_for_critical);
                }
                T.consumeClose();
            }
        }

        if (isOpenMPLoopDirective(DKind))
            ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
        if (isOpenMPSimdDirective(DKind))
            ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
        ParseScope OMPDirectiveScope(this, ScopeFlags);
        Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc);

        while (Tok.isNot(tok::annot_pragma_openmp_end)) {
            OpenMPClauseKind CKind =
                Tok.isAnnotation()
                ? OMPC_unknown
                : FlushHasClause ? OMPC_flush
                : getOpenMPClauseKind(PP.getSpelling(Tok));
            FlushHasClause = false;
            OMPClause *Clause =
                ParseOpenMPClause(DKind, CKind, !FirstClauses[CKind].getInt());
            FirstClauses[CKind].setInt(true);
            if (Clause) {
                FirstClauses[CKind].setPointer(Clause);
                Clauses.push_back(Clause);
            }

            // Skip ',' if any.
            if (Tok.is(tok::comma))
                ConsumeToken();
        }
        // End location of the directive.
        EndLoc = Tok.getLocation();
        // Consume final annot_pragma_openmp_end.
        ConsumeToken();

        StmtResult AssociatedStmt;
        bool CreateDirective = true;
        if (HasAssociatedStatement) {
            // The body is a block scope like in Lambdas and Blocks.
            Sema::CompoundScopeRAII CompoundScope(Actions);
            Actions.ActOnOpenMPRegionStart(DKind, getCurScope());
            Actions.ActOnStartOfCompoundStmt();
            // Parse statement
            AssociatedStmt = ParseStatement();
            Actions.ActOnFinishOfCompoundStmt();
            if (!AssociatedStmt.isUsable()) {
                Actions.ActOnCapturedRegionError();
                CreateDirective = false;
            } else {
                AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.get());
                CreateDirective = AssociatedStmt.isUsable();
            }
        }
        if (CreateDirective)
            Directive = Actions.ActOnOpenMPExecutableDirective(
                            DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc);

        // Exit scope.
        Actions.EndOpenMPDSABlock(Directive.get());
        OMPDirectiveScope.Exit();
        break;
    }
    case OMPD_unknown:
        Diag(Tok, diag::err_omp_unknown_directive);
        SkipUntil(tok::annot_pragma_openmp_end);
        break;
    }
    return Directive;
}
Exemple #13
0
/// \brief Parsing of declarative or executable OpenMP directives.
///
///       threadprivate-directive:
///         annot_pragma_openmp 'threadprivate' simple-variable-list
///         annot_pragma_openmp_end
///
///       parallel-directive:
///         annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end
///
StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
  assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
  ParenBraceBracketBalancer BalancerRAIIObj(*this);
  SmallVector<Expr *, 5> Identifiers;
  SmallVector<OMPClause *, 5> Clauses;
  SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, NUM_OPENMP_CLAUSES>
                                               FirstClauses(NUM_OPENMP_CLAUSES);
  const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
                              Scope::OpenMPDirectiveScope;
  SourceLocation Loc = ConsumeToken(), EndLoc;
  OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
                                  OMPD_unknown :
                                  getOpenMPDirectiveKind(PP.getSpelling(Tok));
  // Name of critical directive.
  DeclarationNameInfo DirName;
  StmtResult Directive = StmtError();

  switch (DKind) {
  case OMPD_threadprivate:
    ConsumeToken();
    if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
      // The last seen token is annot_pragma_openmp_end - need to check for
      // extra tokens.
      if (Tok.isNot(tok::annot_pragma_openmp_end)) {
        Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
          << getOpenMPDirectiveName(OMPD_threadprivate);
        SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
      }
      DeclGroupPtrTy Res =
        Actions.ActOnOpenMPThreadprivateDirective(Loc,
                                                  Identifiers);
      Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
    }
    SkipUntil(tok::annot_pragma_openmp_end);
    break;
  case OMPD_parallel: {
    ConsumeToken();

    Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope());

    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
      OpenMPClauseKind CKind = Tok.isAnnotation() ?
                                  OMPC_unknown :
                                  getOpenMPClauseKind(PP.getSpelling(Tok));
      OMPClause *Clause = ParseOpenMPClause(DKind, CKind,
                                            !FirstClauses[CKind].getInt());
      FirstClauses[CKind].setInt(true);
      if (Clause) {
        FirstClauses[CKind].setPointer(Clause);
        Clauses.push_back(Clause);
      }

      // Skip ',' if any.
      if (Tok.is(tok::comma))
        ConsumeToken();
    }
    // End location of the directive.
    EndLoc = Tok.getLocation();
    // Consume final annot_pragma_openmp_end.
    ConsumeToken();

    StmtResult AssociatedStmt;
    bool CreateDirective = true;
    ParseScope OMPDirectiveScope(this, ScopeFlags);
    {
      // The body is a block scope like in Lambdas and Blocks.
      Sema::CompoundScopeRAII CompoundScope(Actions);
      Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1);
      Actions.ActOnStartOfCompoundStmt();
      // Parse statement
      AssociatedStmt = ParseStatement();
      Actions.ActOnFinishOfCompoundStmt();
      if (!AssociatedStmt.isUsable()) {
        Actions.ActOnCapturedRegionError();
        CreateDirective = false;
      } else {
        AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take());
        CreateDirective = AssociatedStmt.isUsable();
      }
    }
    if (CreateDirective)
      Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses,
                                                         AssociatedStmt.take(),
                                                         Loc, EndLoc);

    // Exit scope.
    Actions.EndOpenMPDSABlock(Directive.get());
    OMPDirectiveScope.Exit();
    }
    break;
  case OMPD_unknown:
    Diag(Tok, diag::err_omp_unknown_directive);
    SkipUntil(tok::annot_pragma_openmp_end);
    break;
  case OMPD_task:
  case NUM_OPENMP_DIRECTIVES:
    Diag(Tok, diag::err_omp_unexpected_directive)
      << getOpenMPDirectiveName(DKind);
    SkipUntil(tok::annot_pragma_openmp_end);
    break;
  }
  return Directive;
}
Exemple #14
0
bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() {
  assert(!IsPromiseDependentType &&
         "cannot make statement while the promise type is dependent");
  assert(this->ReturnValue && "ReturnValue must be already formed");

  QualType const GroType = this->ReturnValue->getType();
  assert(!GroType->isDependentType() &&
         "get_return_object type must no longer be dependent");

  QualType const FnRetType = FD.getReturnType();
  assert(!FnRetType->isDependentType() &&
         "get_return_object type must no longer be dependent");

  if (FnRetType->isVoidType()) {
    ExprResult Res = S.ActOnFinishFullExpr(this->ReturnValue, Loc);
    if (Res.isInvalid())
      return false;

    this->ResultDecl = Res.get();
    return true;
  }

  if (GroType->isVoidType()) {
    // Trigger a nice error message.
    InitializedEntity Entity =
        InitializedEntity::InitializeResult(Loc, FnRetType, false);
    S.PerformMoveOrCopyInitialization(Entity, nullptr, FnRetType, ReturnValue);
    noteMemberDeclaredHere(S, ReturnValue, Fn);
    return false;
  }

  auto *GroDecl = VarDecl::Create(
      S.Context, &FD, FD.getLocation(), FD.getLocation(),
      &S.PP.getIdentifierTable().get("__coro_gro"), GroType,
      S.Context.getTrivialTypeSourceInfo(GroType, Loc), SC_None);

  S.CheckVariableDeclarationType(GroDecl);
  if (GroDecl->isInvalidDecl())
    return false;

  InitializedEntity Entity = InitializedEntity::InitializeVariable(GroDecl);
  ExprResult Res = S.PerformMoveOrCopyInitialization(Entity, nullptr, GroType,
                                                     this->ReturnValue);
  if (Res.isInvalid())
    return false;

  Res = S.ActOnFinishFullExpr(Res.get());
  if (Res.isInvalid())
    return false;

  if (GroType == FnRetType) {
    GroDecl->setNRVOVariable(true);
  }

  S.AddInitializerToDecl(GroDecl, Res.get(),
                         /*DirectInit=*/false);

  S.FinalizeDeclaration(GroDecl);

  // Form a declaration statement for the return declaration, so that AST
  // visitors can more easily find it.
  StmtResult GroDeclStmt =
      S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(GroDecl), Loc, Loc);
  if (GroDeclStmt.isInvalid())
    return false;

  this->ResultDecl = GroDeclStmt.get();

  ExprResult declRef = S.BuildDeclRefExpr(GroDecl, GroType, VK_LValue, Loc);
  if (declRef.isInvalid())
    return false;

  StmtResult ReturnStmt = S.BuildReturnStmt(Loc, declRef.get());
  if (ReturnStmt.isInvalid()) {
    noteMemberDeclaredHere(S, ReturnValue, Fn);
    return false;
  }

  this->ReturnStmt = ReturnStmt.get();
  return true;
}
Exemple #15
0
/// ParseSAVEStmt - Parse the SAVE statement.
///
///   [R543]:
///     save-stmt :=
///         SAVE [ [::] saved-entity-list ]
Parser::StmtResult Parser::ParseSAVEStmt() {
  // Check if this is an assignment.
  if (IsNextToken(tok::equal))
    return StmtResult();

  auto Loc = ConsumeToken();
  if(Tok.isAtStartOfStatement())
    return Actions.ActOnSAVE(Context, Loc, StmtLabel);

  bool IsSaveStmt = ConsumeIfPresent(tok::coloncolon);
  SmallVector<Stmt *,8> StmtList;
  bool ListParsedOk = true;

  auto IDLoc = Tok.getLocation();
  auto II = Tok.getIdentifierInfo();
  StmtResult Stmt;
  if(ConsumeIfPresent(tok::slash)) {
    IDLoc = Tok.getLocation();
    II = Tok.getIdentifierInfo();
    if(ExpectAndConsume(tok::identifier)) {
      if(!ExpectAndConsume(tok::slash))
        ListParsedOk = false;
      Stmt = Actions.ActOnSAVECommonBlock(Context, Loc, IDLoc, II);
    }
    else ListParsedOk = false;
  }
  else if(ExpectAndConsume(tok::identifier)) {
    if(!IsSaveStmt && Features.FixedForm && (IsPresent(tok::equal) || IsPresent(tok::l_paren)))
      return ReparseAmbiguousAssignmentStatement();
    Stmt = Actions.ActOnSAVE(Context, Loc, IDLoc, II, nullptr);
  } else ListParsedOk = false;

  if(Stmt.isUsable())
    StmtList.push_back(Stmt.get());
  if(ListParsedOk) {
    while(ConsumeIfPresent(tok::comma)) {
      IDLoc = Tok.getLocation();
      II = Tok.getIdentifierInfo();
      if(ConsumeIfPresent(tok::slash)) {
        IDLoc = Tok.getLocation();
        II = Tok.getIdentifierInfo();
        if(!ExpectAndConsume(tok::identifier)) {
          ListParsedOk = false;
          break;
        }
        if(!ExpectAndConsume(tok::slash)) {
          ListParsedOk = false;
          break;
        }
        Stmt = Actions.ActOnSAVECommonBlock(Context, Loc, IDLoc, II);
      }
      else if(ExpectAndConsume(tok::identifier))
        Stmt = Actions.ActOnSAVE(Context, Loc, IDLoc, II, nullptr);
      else {
        ListParsedOk = false;
        break;
      }

      if(Stmt.isUsable())
        StmtList.push_back(Stmt.get());
    }
  }

  if(ListParsedOk) ExpectStatementEnd();
  else SkipUntilNextStatement();

  return Actions.ActOnCompoundStmt(Context, Loc, StmtList, StmtLabel);
}