From: Richard Smith Date: Fri, 20 Jun 2014 18:43:47 +0000 (+0000) Subject: Don't crash when emitting a glvalue conditional where one arm is a X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f3076ff2fd325d7ea74ced48f2e741baceef6460;p=platform%2Fupstream%2Fllvm.git Don't crash when emitting a glvalue conditional where one arm is a throw-expression. Based on a patch by Marius Wachtler! llvm-svn: 211388 --- diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index fda0410..62ecc73 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2684,6 +2684,19 @@ LValue CodeGenFunction::EmitInitListLValue(const InitListExpr *E) { return EmitLValue(E->getInit(0)); } +/// 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 Optional EmitLValueOrThrowExpression(CodeGenFunction &CGF, + const Expr *Operand) { + if (auto *ThrowExpr = dyn_cast(Operand->IgnoreParens())) { + CGF.EmitCXXThrowExpr(ThrowExpr, /*KeepInsertionPoint*/false); + return None; + } + + return CGF.EmitLValue(Operand); +} + LValue CodeGenFunction:: EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { if (!expr->isGLValue()) { @@ -2721,31 +2734,40 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { EmitBlock(lhsBlock); Cnt.beginRegion(Builder); eval.begin(*this); - LValue lhs = EmitLValue(expr->getTrueExpr()); + Optional lhs = + EmitLValueOrThrowExpression(*this, expr->getTrueExpr()); eval.end(*this); - if (!lhs.isSimple()) + if (lhs && !lhs->isSimple()) return EmitUnsupportedLValue(expr, "conditional operator"); lhsBlock = Builder.GetInsertBlock(); - Builder.CreateBr(contBlock); + if (lhs) + Builder.CreateBr(contBlock); // Any temporaries created here are conditional. EmitBlock(rhsBlock); eval.begin(*this); - LValue rhs = EmitLValue(expr->getFalseExpr()); + Optional rhs = + EmitLValueOrThrowExpression(*this, expr->getFalseExpr()); eval.end(*this); - if (!rhs.isSimple()) + if (rhs && !rhs->isSimple()) return EmitUnsupportedLValue(expr, "conditional operator"); rhsBlock = Builder.GetInsertBlock(); EmitBlock(contBlock); - llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(), 2, - "cond-lvalue"); - phi->addIncoming(lhs.getAddress(), lhsBlock); - phi->addIncoming(rhs.getAddress(), rhsBlock); - return MakeAddrLValue(phi, expr->getType()); + if (lhs && rhs) { + llvm::PHINode *phi = Builder.CreatePHI(lhs->getAddress()->getType(), + 2, "cond-lvalue"); + phi->addIncoming(lhs->getAddress(), lhsBlock); + phi->addIncoming(rhs->getAddress(), rhsBlock); + return MakeAddrLValue(phi, expr->getType()); + } else { + assert((lhs || rhs) && + "both operands of glvalue conditional are throw-expressions?"); + return lhs ? *lhs : *rhs; + } } /// EmitCastLValue - Casts are never lvalues unless that cast is to a reference diff --git a/clang/test/CodeGenCXX/throw-expressions.cpp b/clang/test/CodeGenCXX/throw-expressions.cpp index 7e81141..549aef0 100644 --- a/clang/test/CodeGenCXX/throw-expressions.cpp +++ b/clang/test/CodeGenCXX/throw-expressions.cpp @@ -80,3 +80,35 @@ namespace DR1560 { // CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN6DR15601AD1Ev {{.*}} @_ZGRN6DR15601rE // CHECK-NOT: call {{.*}}@_ZN6DR15601AD1Ev } + +// CHECK-LABEL: define void @_Z5test7b( +void test7(bool cond) { + // CHECK: br i1 + // + // x.true: + // CHECK: call void @__cxa_throw( + // CHECK-NEXT: unreachable + // + // x.false: + // CHECK: br label + // + // end: + // CHECK: ret void + cond ? throw test7 : val; +} + +// CHECK-LABEL: define nonnull i32* @_Z5test8b( +int &test8(bool cond) { + // CHECK: br i1 + // + // x.true: + // CHECK: br label + // + // x.false: + // CHECK: call void @__cxa_throw( + // CHECK-NEXT: unreachable + // + // end: + // CHECK: ret i32* @val + return cond ? val : ((throw "foo")); +}