diff options
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenStmt.cpp')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 121 |
1 files changed, 78 insertions, 43 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index ad8c4d0..f486c46 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -446,54 +446,89 @@ mlir::LogicalResult CIRGenFunction::emitReturnStmt(const ReturnStmt &s) { mlir::Location loc = getLoc(s.getSourceRange()); const Expr *rv = s.getRetValue(); - if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() && - s.getNRVOCandidate()->isNRVOVariable()) { - assert(!cir::MissingFeatures::openMP()); - assert(!cir::MissingFeatures::nrvo()); - } else if (!rv) { - // No return expression. Do nothing. - } else if (rv->getType()->isVoidType()) { - // Make sure not to return anything, but evaluate the expression - // for side effects. - if (rv) { - emitAnyExpr(rv); + RunCleanupsScope cleanupScope(*this); + bool createNewScope = false; + if (const auto *ewc = dyn_cast_or_null<ExprWithCleanups>(rv)) { + rv = ewc->getSubExpr(); + createNewScope = true; + } + + auto handleReturnVal = [&]() { + if (getContext().getLangOpts().ElideConstructors && s.getNRVOCandidate() && + s.getNRVOCandidate()->isNRVOVariable()) { + assert(!cir::MissingFeatures::openMP()); + assert(!cir::MissingFeatures::nrvo()); + } else if (!rv) { + // No return expression. Do nothing. + } else if (rv->getType()->isVoidType()) { + // Make sure not to return anything, but evaluate the expression + // for side effects. + if (rv) { + emitAnyExpr(rv); + } + } else if (cast<FunctionDecl>(curGD.getDecl()) + ->getReturnType() + ->isReferenceType()) { + // If this function returns a reference, take the address of the + // expression rather than the value. + RValue result = emitReferenceBindingToExpr(rv); + builder.CIRBaseBuilderTy::createStore(loc, result.getValue(), + *fnRetAlloca); + } else { + mlir::Value value = nullptr; + switch (CIRGenFunction::getEvaluationKind(rv->getType())) { + case cir::TEK_Scalar: + value = emitScalarExpr(rv); + if (value) { // Change this to an assert once emitScalarExpr is complete + builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca); + } + break; + case cir::TEK_Complex: + emitComplexExprIntoLValue(rv, + makeAddrLValue(returnValue, rv->getType()), + /*isInit=*/true); + break; + case cir::TEK_Aggregate: + assert(!cir::MissingFeatures::aggValueSlotGC()); + emitAggExpr(rv, AggValueSlot::forAddr(returnValue, Qualifiers(), + AggValueSlot::IsDestructed, + AggValueSlot::IsNotAliased, + getOverlapForReturnValue())); + break; + } } - } else if (cast<FunctionDecl>(curGD.getDecl()) - ->getReturnType() - ->isReferenceType()) { - // If this function returns a reference, take the address of the - // expression rather than the value. - RValue result = emitReferenceBindingToExpr(rv); - builder.CIRBaseBuilderTy::createStore(loc, result.getValue(), *fnRetAlloca); + }; + + if (!createNewScope) { + handleReturnVal(); } else { - mlir::Value value = nullptr; - switch (CIRGenFunction::getEvaluationKind(rv->getType())) { - case cir::TEK_Scalar: - value = emitScalarExpr(rv); - if (value) { // Change this to an assert once emitScalarExpr is complete - builder.CIRBaseBuilderTy::createStore(loc, value, *fnRetAlloca); - } - break; - case cir::TEK_Complex: - emitComplexExprIntoLValue(rv, makeAddrLValue(returnValue, rv->getType()), - /*isInit=*/true); - break; - case cir::TEK_Aggregate: - assert(!cir::MissingFeatures::aggValueSlotGC()); - emitAggExpr(rv, AggValueSlot::forAddr(returnValue, Qualifiers(), - AggValueSlot::IsDestructed, - AggValueSlot::IsNotAliased, - getOverlapForReturnValue())); - break; + mlir::Location scopeLoc = + getLoc(rv ? rv->getSourceRange() : s.getSourceRange()); + // First create cir.scope and later emit it's body. Otherwise all CIRGen + // dispatched by `handleReturnVal()` might needs to manipulate blocks and + // look into parents, which are all unlinked. + mlir::OpBuilder::InsertPoint scopeBody; + cir::ScopeOp::create(builder, scopeLoc, /*scopeBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + scopeBody = b.saveInsertionPoint(); + }); + { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.restoreInsertionPoint(scopeBody); + CIRGenFunction::LexicalScope lexScope{*this, scopeLoc, + builder.getInsertionBlock()}; + handleReturnVal(); } } + cleanupScope.forceCleanup(); + + // In CIR we might have returns in different scopes. + // FIXME(cir): cleanup code is handling actual return emission, the logic + // should try to match traditional codegen more closely (to the extent which + // is possible). auto *retBlock = curLexScope->getOrCreateRetBlock(*this, loc); - // This should emit a branch through the cleanup block if one exists. - builder.create<cir::BrOp>(loc, retBlock); - assert(!cir::MissingFeatures::emitBranchThroughCleanup()); - if (ehStack.stable_begin() != currentCleanupStackDepth) - cgm.errorNYI(s.getSourceRange(), "return with cleanup stack"); + emitBranchThroughCleanup(loc, returnBlock(retBlock)); // Insert the new block to continue codegen after branch to ret block. builder.createBlock(builder.getBlock()->getParent()); @@ -1063,5 +1098,5 @@ void CIRGenFunction::emitReturnOfRValue(mlir::Location loc, RValue rv, assert(!cir::MissingFeatures::emitBranchThroughCleanup()); builder.create<cir::BrOp>(loc, retBlock); if (ehStack.stable_begin() != currentCleanupStackDepth) - cgm.errorNYI(loc, "return with cleanup stack"); + cgm.errorNYI(loc, "return of r-value with cleanup stack"); } |