Fix handling of pointers-to-members and comma expressions when
lifetime-extending temporaries in reference bindings.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@183089 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index f587dfa..2a9b9eb 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -50,9 +50,9 @@
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 @@
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;
}
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 8ba5a1c..28eae50 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -295,8 +295,13 @@
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 @@
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.
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index 5f92cff..8e446f8 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -172,14 +172,19 @@
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();