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<LValue> EmitLValueOrThrowExpression(CodeGenFunction &CGF,
+ const Expr *Operand) {
+ if (auto *ThrowExpr = dyn_cast<CXXThrowExpr>(Operand->IgnoreParens())) {
+ CGF.EmitCXXThrowExpr(ThrowExpr, /*KeepInsertionPoint*/false);
+ return None;
+ }
+
+ return CGF.EmitLValue(Operand);
+}
+
LValue CodeGenFunction::
EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
if (!expr->isGLValue()) {
EmitBlock(lhsBlock);
Cnt.beginRegion(Builder);
eval.begin(*this);
- LValue lhs = EmitLValue(expr->getTrueExpr());
+ Optional<LValue> 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<LValue> 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
// 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"));
+}