From e946fc833d8592aa2890bfd9839f1ad839b3d284 Mon Sep 17 00:00:00 2001
From: Fariborz Jahanian <fjahanian@apple.com>
Date: Mon, 25 Oct 2010 23:27:26 +0000
Subject: [PATCH] Patch for mis-compile of statement expressions with
 non-trivial copy constructors. // rdar: //8540501. A test will be added to
 llvm nightly tests.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117324 91177308-0d34-0410-b5e6-96231b3b80d8
---
 clang.xcodeproj/project.pbxproj |  1 -
 include/clang/AST/Stmt.h        |  3 ++
 lib/Sema/SemaExpr.cpp           | 34 ++++++++++++++---
 test/CodeGenCXX/stmtexpr.cpp    | 65 +++++++++++++++++++++++++++++++++
 4 files changed, 96 insertions(+), 7 deletions(-)
 create mode 100644 test/CodeGenCXX/stmtexpr.cpp

diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj
index fa1e24574e..9c95d0a3de 100644
--- a/clang.xcodeproj/project.pbxproj
+++ b/clang.xcodeproj/project.pbxproj
@@ -2039,7 +2039,6 @@
 			isa = PBXProject;
 			buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
 			compatibilityVersion = "Xcode 2.4";
-			developmentRegion = English;
 			hasScannedForEncodings = 1;
 			knownRegions = (
 				English,
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 508bedacd7..d665d47133 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -383,6 +383,9 @@ public:
   body_iterator body_begin() { return Body; }
   body_iterator body_end() { return Body + NumStmts; }
   Stmt *body_back() { return NumStmts ? Body[NumStmts-1] : 0; }
+  
+  void setLastStmt(Stmt *S)
+  { assert(NumStmts && "setLastStmt"); Body[NumStmts-1] = S; }
 
   typedef Stmt* const * const_body_iterator;
   const_body_iterator body_begin() const { return Body; }
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index e329ada932..0510bd2ed8 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7067,21 +7067,43 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
   // If there are sub stmts in the compound stmt, take the type of the last one
   // as the type of the stmtexpr.
   QualType Ty = Context.VoidTy;
-
+  bool StmtExprMayBindToTemp = false;
   if (!Compound->body_empty()) {
     Stmt *LastStmt = Compound->body_back();
+    LabelStmt *LastLabelStmt = 0;
     // If LastStmt is a label, skip down through into the body.
-    while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt))
+    while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) {
+      LastLabelStmt = Label;
       LastStmt = Label->getSubStmt();
-
-    if (Expr *LastExpr = dyn_cast<Expr>(LastStmt))
+    }
+    if (Expr *LastExpr = dyn_cast<Expr>(LastStmt)) {
       Ty = LastExpr->getType();
+      if (!Ty->isDependentType() && !LastExpr->isTypeDependent()) {
+        ExprResult Res = PerformCopyInitialization(
+                            InitializedEntity::InitializeResult(LPLoc, 
+                                                                Ty,
+                                                                false),
+                                                   SourceLocation(),
+                                                   Owned(LastExpr));
+        if (Res.isInvalid())
+          return ExprError();
+        if ((LastExpr = Res.takeAs<Expr>())) {
+          if (!LastLabelStmt)
+            Compound->setLastStmt(LastExpr);
+          else
+            LastLabelStmt->setSubStmt(LastExpr);
+          StmtExprMayBindToTemp = true;
+        }
+      }
+    }
   }
 
   // FIXME: Check that expression type is complete/non-abstract; statement
   // expressions are not lvalues.
-
-  return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc));
+  Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc);
+  if (StmtExprMayBindToTemp)
+    return MaybeBindToTemporary(ResStmtExpr);
+  return Owned(ResStmtExpr);
 }
 
 ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
diff --git a/test/CodeGenCXX/stmtexpr.cpp b/test/CodeGenCXX/stmtexpr.cpp
new file mode 100644
index 0000000000..2b64747fa0
--- /dev/null
+++ b/test/CodeGenCXX/stmtexpr.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -Wno-unused-value -emit-llvm -o - %s | FileCheck %s
+// rdar: //8540501
+extern "C" int printf(...);
+extern "C" void abort();
+
+struct A
+{
+  int i;
+  A (int j) : i(j) {printf("this = %p A(%d)\n", this, j);}
+  A (const A &j) : i(j.i) {printf("this = %p const A&(%d)\n", this, i);}
+  A& operator= (const A &j) { i = j.i; abort(); return *this; }
+  ~A() { printf("this = %p ~A(%d)\n", this, i); }
+};
+
+struct B
+{
+  int i;
+  B (const A& a) { i = a.i; }
+  B() {printf("this = %p B()\n", this);}
+  B (const B &j) : i(j.i) {printf("this = %p const B&(%d)\n", this, i);}
+  ~B() { printf("this = %p ~B(%d)\n", this, i); }
+};
+
+A foo(int j)
+{
+  return ({ j ? A(1) : A(0); });
+}
+
+
+void foo2()
+{
+  A b = ({ A a(1); A a1(2); A a2(3); a1; a2; a; });
+  if (b.i != 1)
+    abort(); 
+  A c = ({ A a(1); A a1(2); A a2(3); a1; a2; a; A a3(4); a2; a3; });
+  if (c.i != 4)
+    abort(); 
+}
+
+void foo3()
+{
+  const A &b = ({ A a(1); a; });
+  if (b.i != 1)
+    abort();
+}
+
+void foo4()
+{
+// CHECK: call void @_ZN1AC1Ei
+// CHECK: call void @_ZN1AC1ERKS_
+// CHECK: call void @_ZN1AD1Ev
+// CHECK: call void @_ZN1BC1ERK1A
+// CHECK: call void @_ZN1AD1Ev
+  const B &b = ({ A a(1); a; });
+  if (b.i != 1)
+    abort();
+}
+
+int main()
+{
+  foo2();
+  foo3();
+  foo4();
+  return foo(1).i-1;
+}
-- 
2.40.0