================ @@ -948,6 +950,165 @@ void CIRGenFunction::emitIgnoredExpr(const Expr *e) { emitLValue(e); } +// Handle the case where the condition is a constant evaluatable simple integer, +// which means we don't have to separately handle the true/false blocks. +static std::optional<LValue> handleConditionalOperatorLValueSimpleCase( + CIRGenFunction &cgf, const AbstractConditionalOperator *e) { + const Expr *condExpr = e->getCond(); + bool condExprBool = false; + if (cgf.constantFoldsToSimpleInteger(condExpr, condExprBool)) { + const Expr *live = e->getTrueExpr(), *dead = e->getFalseExpr(); + if (!condExprBool) + std::swap(live, dead); + + if (!cgf.containsLabel(dead)) { + // If the true case is live, we need to track its region. + if (condExprBool) { + assert(!cir::MissingFeatures::incrementProfileCounter()); + } + // If a throw expression we emit it and return an undefined lvalue + // because it can't be used. + if (isa<CXXThrowExpr>(live->IgnoreParens())) { + assert(!cir::MissingFeatures::throwOp()); + cgf.cgm.errorNYI(live->getSourceRange(), + "throw expressions in conditional operator"); + return std::nullopt; + } + return cgf.emitLValue(live); + } + } + return std::nullopt; +} + +/// Emit the operand of a glvalue conditional operator. This is either a glvalue +/// or a (possibly-parenthesized) throw-expression. If this is a throw, no +/// LValue is returned and the current block has been terminated. +static std::optional<LValue> emitLValueOrThrowExpression(CIRGenFunction &cgf, + const Expr *operand) { + if (isa<CXXThrowExpr>(operand->IgnoreParens())) { + assert(!cir::MissingFeatures::throwOp()); + cgf.cgm.errorNYI(operand->getSourceRange(), + "throw expressions in conditional operator"); + return std::nullopt; + } + + return cgf.emitLValue(operand); +} + +// Create and generate the 3 blocks for a conditional operator. +// Leaves the 'current block' in the continuation basic block. +template <typename FuncTy> +CIRGenFunction::ConditionalInfo +CIRGenFunction::emitConditionalBlocks(const AbstractConditionalOperator *e, + const FuncTy &branchGenFunc) { + ConditionalInfo info; + CIRGenFunction &cgf = *this; + ConditionalEvaluation eval(cgf); + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + CIRGenBuilderTy &builder = cgf.getBuilder(); + Expr *trueExpr = e->getTrueExpr(); + Expr *falseExpr = e->getFalseExpr(); + + mlir::Value condV = cgf.emitOpOnBoolExpr(loc, e->getCond()); + SmallVector<mlir::OpBuilder::InsertPoint, 2> insertPoints{}; + mlir::Type yieldTy{}; + + auto emitBranch = [&](mlir::OpBuilder &b, mlir::Location loc, Expr *expr, + std::optional<LValue> &branchInfo) { + CIRGenFunction::LexicalScope lexScope{cgf, loc, b.getInsertionBlock()}; + cgf.curLexScope->setAsTernary(); + + assert(!cir::MissingFeatures::incrementProfileCounter()); + eval.begin(cgf); + branchInfo = branchGenFunc(cgf, expr); + mlir::Value branch = branchInfo->getPointer(); + eval.end(cgf); + + if (branch) { + yieldTy = branch.getType(); + b.create<cir::YieldOp>(loc, branch); + } else { + // If LHS or RHS is a throw or void expression we need to patch + // arms as to properly match yield types. + insertPoints.push_back(b.saveInsertionPoint()); + } + }; + + info.result = builder + .create<cir::TernaryOp>( + loc, condV, /*trueBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + emitBranch(b, loc, trueExpr, info.lhs); + }, + /*falseBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + emitBranch(b, loc, falseExpr, info.rhs); + }) + .getResult(); + + if (!insertPoints.empty()) { + // If both arms are void, so be it. + if (!yieldTy) + yieldTy = cgf.VoidTy; + + // Insert required yields. + for (mlir::OpBuilder::InsertPoint &toInsert : insertPoints) { + mlir::OpBuilder::InsertionGuard guard(builder); + builder.restoreInsertionPoint(toInsert); + + // Block does not return: build empty yield. + if (mlir::isa<cir::VoidType>(yieldTy)) { + builder.create<cir::YieldOp>(loc); + } else { // Block returns: set null yield value. + mlir::Value op0 = builder.getNullValue(yieldTy, loc); ---------------- andykaylor wrote:
I don't think this is right. If a block contains a throw, the incubator generates a `cir.throw` followed by a `cir.unreachable` and then inserts a null constant and a `cir.yield`. This causes verification to fail because `cir.unreachable` isn't the last operation in the block. https://github.com/llvm/llvm-project/pull/138156 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits