r183089 - Fix handling of pointers-to-members and comma expressions when
Richard Smith
richard-llvm at metafoo.co.uk
Sun Jun 2 17:17:12 PDT 2013
Author: rsmith
Date: Sun Jun 2 19:17:11 2013
New Revision: 183089
URL: http://llvm.org/viewvc/llvm-project?rev=183089&view=rev
Log:
Fix handling of pointers-to-members and comma expressions when
lifetime-extending temporaries in reference bindings.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/Sema/JumpDiagnostics.cpp
cfe/trunk/test/CodeGenCXX/temporaries.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=183089&r1=183088&r2=183089&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Sun Jun 2 19:17:11 2013
@@ -760,10 +760,10 @@ public:
/// Walk outwards from an expression we want to bind a reference to and
/// find the expression whose lifetime needs to be extended. Record
- /// the adjustments needed along the path.
- const Expr *
- skipRValueSubobjectAdjustments(
- SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
+ /// the LHSs of comma expressions and adjustments needed along the path.
+ const Expr *skipRValueSubobjectAdjustments(
+ SmallVectorImpl<const Expr *> &CommaLHS,
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const;
/// Skip irrelevant expressions to find what should be materialize for
/// binding with a reference.
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=183089&r1=183088&r2=183089&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Sun Jun 2 19:17:11 2013
@@ -50,9 +50,9 @@ const CXXRecordDecl *Expr::getBestDynami
return cast<CXXRecordDecl>(D);
}
-const Expr *
-Expr::skipRValueSubobjectAdjustments(
- SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
+const Expr *Expr::skipRValueSubobjectAdjustments(
+ SmallVectorImpl<const Expr *> &CommaLHSs,
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
const Expr *E = this;
while (true) {
E = E->IgnoreParens();
@@ -88,6 +88,11 @@ Expr::skipRValueSubobjectAdjustments(
const MemberPointerType *MPT =
BO->getRHS()->getType()->getAs<MemberPointerType>();
Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
+ continue;
+ } else if (BO->getOpcode() == BO_Comma) {
+ CommaLHSs.push_back(BO->getLHS());
+ E = BO->getRHS();
+ continue;
}
}
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=183089&r1=183088&r2=183089&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Jun 2 19:17:11 2013
@@ -295,8 +295,13 @@ EmitExprForReferenceBinding(CodeGenFunct
return ReferenceTemporary;
}
+ SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- E = E->skipRValueSubobjectAdjustments(Adjustments);
+ E = E->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+
+ for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
+ CGF.EmitIgnoredExpr(CommaLHSs[I]);
+
if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E))
if (opaque->getType()->isRecordType())
return CGF.EmitOpaqueValueLValue(opaque).getAddress();
@@ -332,6 +337,10 @@ EmitExprForReferenceBinding(CodeGenFunct
RValue RV = CGF.EmitAnyExpr(E, AggSlot);
+ // FIXME: This is wrong. We need to register the destructor for the temporary
+ // now, *before* we perform the adjustments, because in the case of a
+ // pointer-to-member adjustment, the adjustment might throw.
+
// Check if need to perform derived-to-base casts and/or field accesses, to
// get from the temporary object we created (and, potentially, for which we
// extended the lifetime) to the subobject we're binding the reference to.
Modified: cfe/trunk/lib/Sema/JumpDiagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/JumpDiagnostics.cpp?rev=183089&r1=183088&r2=183089&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/JumpDiagnostics.cpp (original)
+++ cfe/trunk/lib/Sema/JumpDiagnostics.cpp Sun Jun 2 19:17:11 2013
@@ -172,14 +172,19 @@ static ScopePair GetDiagForGotoScopeDecl
if (EWC)
Init = EWC->getSubExpr();
+ // FIXME: Why are we looking through reference initialization?
+ // This causes us to incorrectly accept invalid code such as:
+ // struct S { int n; };
+ // int f() { goto x; S &&s = S(); x: return x.n; }
const MaterializeTemporaryExpr *M = NULL;
Init = Init->findMaterializedTemporary(M);
+ SmallVector<const Expr *, 2> CommaLHSs;
SmallVector<SubobjectAdjustment, 2> Adjustments;
- Init = Init->skipRValueSubobjectAdjustments(Adjustments);
+ Init = Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
QualType QT = Init->getType();
- if (QT.isNull())
+ if (QT.isNull() || !CommaLHSs.empty())
return ScopePair(diag::note_protected_by_variable_init, 0);
const Type *T = QT.getTypePtr();
Modified: cfe/trunk/test/CodeGenCXX/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=183089&r1=183088&r2=183089&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/temporaries.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/temporaries.cpp Sun Jun 2 19:17:11 2013
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++11 | FileCheck %s
struct A {
A();
~A();
@@ -558,3 +558,49 @@ namespace AssignmentOp {
// CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS
// CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev(
}
+
+namespace BindToSubobject {
+ struct A {
+ A();
+ ~A();
+ int a;
+ };
+
+ void f(), g();
+
+ // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1aE)
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1aE to i8*), i8* @__dso_handle)
+ // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1aE, i32 0, i32 0), i32** @_ZN15BindToSubobject1aE, align 8
+ int &&a = A().a;
+
+ // CHECK: call void @_ZN15BindToSubobject1fEv()
+ // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1bE)
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1bE to i8*), i8* @__dso_handle)
+ // CHECK: store i32* getelementptr inbounds ({{.*}} @_ZGRN15BindToSubobject1bE, i32 0, i32 0), i32** @_ZN15BindToSubobject1bE, align 8
+ int &&b = (f(), A().a);
+
+ int A::*h();
+
+ // CHECK: call void @_ZN15BindToSubobject1fEv()
+ // CHECK: call void @_ZN15BindToSubobject1gEv()
+ // CHECK: call void @_ZN15BindToSubobject1AC1Ev({{.*}} @_ZGRN15BindToSubobject1cE)
+ // FIXME: This is wrong. We should emit the call to __cxa_atexit prior to
+ // calling h(), in case h() throws.
+ // CHECK: call {{.*}} @_ZN15BindToSubobject1hE
+ // CHECK: getelementptr
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1AD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1cE to i8*), i8* @__dso_handle)
+ // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1cE, align 8
+ int &&c = (f(), (g(), A().*h()));
+
+ struct B {
+ int padding;
+ A a;
+ };
+
+ // CHECK: call void @_ZN15BindToSubobject1BC1Ev({{.*}} @_ZGRN15BindToSubobject1dE)
+ // CHECK: call {{.*}} @_ZN15BindToSubobject1hE
+ // CHECK: getelementptr {{.*}} getelementptr
+ // CHECK: call i32 @__cxa_atexit({{.*}} bitcast ({{.*}} @_ZN15BindToSubobject1BD1Ev to void (i8*)*), i8* bitcast ({{.*}} @_ZGRN15BindToSubobject1dE to i8*), i8* @__dso_handle)
+ // CHECK: store i32* {{.*}}, i32** @_ZN15BindToSubobject1dE, align 8
+ int &&d = (B().a).*h();
+}
More information about the cfe-commits
mailing list