aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFariborz Jahanian <fjahanian@apple.com>2010-10-25 23:27:26 +0000
committerFariborz Jahanian <fjahanian@apple.com>2010-10-25 23:27:26 +0000
commite946fc833d8592aa2890bfd9839f1ad839b3d284 (patch)
tree1f9125aa9546447672670d24704ea7091be2576c
parentb31c289678a3fe0f062656015dbcd57272f60742 (diff)
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
-rw-r--r--clang.xcodeproj/project.pbxproj1
-rw-r--r--include/clang/AST/Stmt.h3
-rw-r--r--lib/Sema/SemaExpr.cpp34
-rw-r--r--test/CodeGenCXX/stmtexpr.cpp65
4 files changed, 96 insertions, 7 deletions
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;
+}