]> granicus.if.org Git - clang/commitdiff
Patch for mis-compile of statement expressions with
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 25 Oct 2010 23:27:26 +0000 (23:27 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 25 Oct 2010 23:27:26 +0000 (23:27 +0000)
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
include/clang/AST/Stmt.h
lib/Sema/SemaExpr.cpp
test/CodeGenCXX/stmtexpr.cpp [new file with mode: 0644]

index fa1e24574e8f6ff71d0892d96891c27ec9d1669e..9c95d0a3dee5c0ed6924daa5c0242b6448d219d0 100644 (file)
                        isa = PBXProject;
                        buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
                        compatibilityVersion = "Xcode 2.4";
-                       developmentRegion = English;
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                English,
index 508bedacd73ff7c9795e272f81957e4e986c99c0..d665d47133b6be2236967d44b9c08e2ea40af3af 100644 (file)
@@ -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; }
index e329ada93221dee230a8840ee6d8c2842102389c..0510bd2ed86b3a694170a721e967552edcf070ab 100644 (file)
@@ -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 (file)
index 0000000..2b64747
--- /dev/null
@@ -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;
+}