Don't crash when emitting a glvalue conditional where one arm is a
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 20 Jun 2014 18:43:47 +0000 (18:43 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 20 Jun 2014 18:43:47 +0000 (18:43 +0000)
throw-expression. Based on a patch by Marius Wachtler!

llvm-svn: 211388

clang/lib/CodeGen/CGExpr.cpp
clang/test/CodeGenCXX/throw-expressions.cpp

index fda0410..62ecc73 100644 (file)
@@ -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<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()) {
@@ -2721,31 +2734,40 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
   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
index 7e81141..549aef0 100644 (file)
@@ -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"));
+}