summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTContext.cpp13
-rw-r--r--clang/lib/AST/ASTDumper.cpp10
-rw-r--r--clang/lib/AST/ExprConstant.cpp74
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp9
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp57
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h10
-rw-r--r--clang/lib/Sema/SemaExpr.cpp2
-rw-r--r--clang/lib/Sema/SemaInit.cpp192
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp1
10 files changed, 351 insertions, 18 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 1f89e3f1f69..44ff94e3584 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -8029,6 +8029,19 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const {
return I->second;
}
+APValue *
+ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
+ bool MayCreate) {
+ assert(E && E->getStorageDuration() == SD_Static &&
+ "don't need to cache the computed value for this temporary");
+ if (MayCreate)
+ return &MaterializedTemporaryValues[E];
+
+ llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I =
+ MaterializedTemporaryValues.find(E);
+ return I == MaterializedTemporaryValues.end() ? 0 : &I->second;
+}
+
bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const {
const llvm::Triple &T = getTargetInfo().getTriple();
if (!T.isOSDarwin())
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 2ed36455bb1..c7809e06acc 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -274,6 +274,7 @@ namespace {
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(const CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
void dumpCXXTemporary(const CXXTemporary *Temporary);
@@ -1682,6 +1683,15 @@ void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
dumpCXXTemporary(Node->getTemporary());
}
+void
+ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) {
+ VisitExpr(Node);
+ if (const ValueDecl *VD = Node->getExtendingDecl()) {
+ OS << " extended by ";
+ dumpBareDeclRef(VD);
+ }
+}
+
void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
VisitExpr(Node);
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 467fb82b8d0..19eaf55ba43 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1001,6 +1001,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
return CLE->isFileScope() && CLE->isLValue();
}
+ case Expr::MaterializeTemporaryExprClass:
+ // A materialized temporary might have been lifetime-extended to static
+ // storage duration.
+ return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static;
// A string literal has static storage duration.
case Expr::StringLiteralClass:
case Expr::PredefinedExprClass:
@@ -1182,7 +1186,10 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
}
static bool IsLiteralLValue(const LValue &Value) {
- return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;
+ if (Value.CallIndex)
+ return false;
+ const Expr *E = Value.Base.dyn_cast<const Expr*>();
+ return E && !isa<MaterializeTemporaryExpr>(E);
}
static bool IsWeakLValue(const LValue &Value) {
@@ -2279,11 +2286,44 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
if (!Frame) {
- Info.Diag(E);
- return CompleteObject();
- }
+ if (const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ assert(MTE->getStorageDuration() == SD_Static &&
+ "should have a frame for a non-global materialized temporary");
+
+ // Per C++1y [expr.const]p2:
+ // an lvalue-to-rvalue conversion [is not allowed unless it applies to]
+ // - a [...] glvalue of integral or enumeration type that refers to
+ // a non-volatile const object [...]
+ // [...]
+ // - a [...] glvalue of literal type that refers to a non-volatile
+ // object whose lifetime began within the evaluation of e.
+ //
+ // C++11 misses the 'began within the evaluation of e' check and
+ // instead allows all temporaries, including things like:
+ // int &&r = 1;
+ // int x = ++r;
+ // constexpr int k = r;
+ // Therefore we use the C++1y rules in C++11 too.
+ const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();
+ const ValueDecl *ED = MTE->getExtendingDecl();
+ if (!(BaseType.isConstQualified() &&
+ BaseType->isIntegralOrEnumerationType()) &&
+ !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
+ Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
+ Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here);
+ return CompleteObject();
+ }
- BaseVal = &Frame->Temporaries[Base];
+ BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ assert(BaseVal && "got reference to unevaluated temporary");
+ } else {
+ Info.Diag(E);
+ return CompleteObject();
+ }
+ } else {
+ BaseVal = &Frame->Temporaries[Base];
+ }
// Volatile temporary objects cannot be accessed in constant expressions.
if (BaseType.isVolatileQualified()) {
@@ -3940,6 +3980,8 @@ public:
// * Any Expr, with a CallIndex indicating the function in which the temporary
// was evaluated, for cases where the MaterializeTemporaryExpr is missing
// from the AST (FIXME).
+// * A MaterializeTemporaryExpr that has static storage duration, with no
+// CallIndex, for a lifetime-extended temporary.
// plus an offset in bytes.
//===----------------------------------------------------------------------===//
namespace {
@@ -4045,9 +4087,19 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
if (!EvaluateIgnoredValue(Info, CommaLHSs[I]))
return false;
+ // A materialized temporary with static storage duration can appear within the
+ // result of a constant expression evaluation, so we need to preserve its
+ // value for use outside this evaluation.
+ APValue *Value;
+ if (E->getStorageDuration() == SD_Static) {
+ Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
+ Result.set(E);
+ } else {
+ Value = &Info.CurrentCall->Temporaries[E];
+ Result.set(E, Info.CurrentCall->Index);
+ }
+
// Materialize the temporary itself.
- APValue *Value = &Info.CurrentCall->Temporaries[E];
- Result.set(E, Info.CurrentCall->Index);
if (!EvaluateInPlace(*Value, Info, Result, Inner))
return false;
@@ -7608,10 +7660,10 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx,
}
}
- bool Expr::EvalResult::isGlobalLValue() const {
- assert(Val.isLValue());
- return IsGlobalLValue(Val.getLValueBase());
- }
+bool Expr::EvalResult::isGlobalLValue() const {
+ assert(Val.isLValue());
+ return IsGlobalLValue(Val.getLValueBase());
+}
/// isIntegerConstantExpr - this recursive routine will test if an expression is
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index f5c8187c26f..ca331cc92be 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1003,6 +1003,15 @@ public:
case Expr::CXXUuidofExprClass: {
return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E));
}
+ case Expr::MaterializeTemporaryExprClass: {
+ MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E);
+ assert(MTE->getStorageDuration() == SD_Static);
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Inner = MTE->GetTemporaryExpr()
+ ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+ return CGM.GetAddrOfGlobalTemporary(MTE, Inner);
+ }
}
return 0;
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 3675e849aa7..4d64624dbcb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2735,6 +2735,63 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str,
return GetAddrOfConstantString(StrWithNull, GlobalName, Alignment);
}
+llvm::Constant *CodeGenModule::GetAddrOfGlobalTemporary(
+ const MaterializeTemporaryExpr *E, const Expr *Inner) {
+ assert((E->getStorageDuration() == SD_Static ||
+ E->getStorageDuration() == SD_Thread) && "not a global temporary");
+ const VarDecl *VD = cast<VarDecl>(E->getExtendingDecl());
+
+ // If we're not materializing a subobject of the temporary, keep the
+ // cv-qualifiers from the type of the MaterializeTemporaryExpr.
+ if (Inner == E->GetTemporaryExpr())
+ Inner = E;
+
+ llvm::Constant *&Slot = MaterializedGlobalTemporaryMap[E];
+ if (Slot)
+ return Slot;
+
+ // FIXME: If an externally-visible declaration extends multiple temporaries,
+ // we need to give each temporary the same name in every translation unit (and
+ // we also need to make the temporaries externally-visible).
+ SmallString<256> Name;
+ llvm::raw_svector_ostream Out(Name);
+ getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Out);
+ Out.flush();
+
+ llvm::Constant *InitialValue = 0;
+ APValue *Value = 0;
+ if (E->getStorageDuration() == SD_Static) {
+ // We might have a constant initializer for this temporary.
+ Value = getContext().getMaterializedTemporaryValue(E, false);
+ if (Value && Value->isUninit())
+ Value = 0;
+ }
+
+ bool Constant;
+ if (Value) {
+ // The temporary has a constant initializer, use it.
+ InitialValue = EmitConstantValue(*Value, Inner->getType(), 0);
+ Constant = isTypeConstant(Inner->getType(), /*ExcludeCtor*/Value);
+ } else {
+ // No constant initializer, the initialization will be provided when we
+ // initialize the declaration which performed lifetime extension.
+ InitialValue = EmitNullConstant(Inner->getType());
+ Constant = false;
+ }
+
+ // Create a global variable for this lifetime-extended temporary.
+ llvm::GlobalVariable *GV =
+ new llvm::GlobalVariable(getModule(), InitialValue->getType(), Constant,
+ llvm::GlobalValue::PrivateLinkage, InitialValue,
+ Name.c_str());
+ GV->setAlignment(
+ getContext().getTypeAlignInChars(Inner->getType()).getQuantity());
+ if (VD->getTLSKind())
+ setTLSMode(GV, *VD);
+ Slot = GV;
+ return GV;
+}
+
/// EmitObjCPropertyImplementations - Emit information for synthesized
/// properties for an implementation.
void CodeGenModule::EmitObjCPropertyImplementations(const
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 2777f959228..aa48cce08b8 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -307,7 +307,8 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::StringMap<llvm::GlobalVariable*> ConstantStringMap;
llvm::DenseMap<const Decl*, llvm::Constant *> StaticLocalDeclMap;
llvm::DenseMap<const Decl*, llvm::GlobalVariable*> StaticLocalDeclGuardMap;
-
+ llvm::DenseMap<const Expr*, llvm::Constant *> MaterializedGlobalTemporaryMap;
+
llvm::DenseMap<QualType, llvm::Constant *> AtomicSetterHelperFnMap;
llvm::DenseMap<QualType, llvm::Constant *> AtomicGetterHelperFnMap;
@@ -731,7 +732,12 @@ public:
/// GetAddrOfConstantCompoundLiteral - Returns a pointer to a constant global
/// variable for the given file-scope compound literal expression.
llvm::Constant *GetAddrOfConstantCompoundLiteral(const CompoundLiteralExpr*E);
-
+
+ /// \brief Returns a pointer to a global variable representing a temporary
+ /// with static or thread storage duration.
+ llvm::Constant *GetAddrOfGlobalTemporary(const MaterializeTemporaryExpr *E,
+ const Expr *Inner);
+
/// \brief Retrieve the record type that describes the state of an
/// Objective-C fast enumeration loop (for..in).
QualType getObjCFastEnumerationStateType();
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a70e3917214..2a3482238d8 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -8353,7 +8353,7 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
return QualType();
// Materialize the temporary as an lvalue so that we can take its address.
OrigOp = op = new (S.Context)
- MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true);
+ MaterializeTemporaryExpr(op->getType(), OrigOp.take(), true, 0);
} else if (isa<ObjCSelectorExpr>(op)) {
return S.Context.getPointerType(op->getType());
} else if (lval == Expr::LV_MemberFunction) {
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 2e11bc98acb..ab400cd11b4 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -2502,6 +2502,46 @@ bool InitializedEntity::allowsNRVO() const {
return false;
}
+unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
+ unsigned Depth = getParent() ? getParent()->dumpImpl(OS) : 0;
+ for (unsigned I = 0; I != Depth; ++I)
+ OS << "`-";
+
+ switch (getKind()) {
+ case EK_Variable: OS << "Variable"; break;
+ case EK_Parameter: OS << "Parameter"; break;
+ case EK_Result: OS << "Result"; break;
+ case EK_Exception: OS << "Exception"; break;
+ case EK_Member: OS << "Member"; break;
+ case EK_New: OS << "New"; break;
+ case EK_Temporary: OS << "Temporary"; break;
+ case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;
+ case EK_Base: OS << "Base"; break;
+ case EK_Delegating: OS << "Delegating"; break;
+ case EK_ArrayElement: OS << "ArrayElement " << Index; break;
+ case EK_VectorElement: OS << "VectorElement " << Index; break;
+ case EK_ComplexElement: OS << "ComplexElement " << Index; break;
+ case EK_BlockElement: OS << "Block"; break;
+ case EK_LambdaCapture:
+ OS << "LambdaCapture ";
+ getCapturedVar()->printName(OS);
+ break;
+ }
+
+ if (Decl *D = getDecl()) {
+ OS << " ";
+ cast<NamedDecl>(D)->printQualifiedName(OS);
+ }
+
+ OS << " '" << getType().getAsString() << "'\n";
+
+ return Depth + 1;
+}
+
+void InitializedEntity::dump() const {
+ dumpImpl(llvm::errs());
+}
+
//===----------------------------------------------------------------------===//
// Initialization sequence
//===----------------------------------------------------------------------===//
@@ -5089,6 +5129,143 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
llvm_unreachable("unknown entity kind");
}
+/// Determine the declaration which an initialized entity ultimately refers to,
+/// for the purpose of lifetime-extending a temporary bound to a reference in
+/// the initialization of \p Entity.
+static const ValueDecl *
+getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
+ const ValueDecl *FallbackDecl = 0) {
+ // C++11 [class.temporary]p5:
+ switch (Entity.getKind()) {
+ case InitializedEntity::EK_Variable:
+ // The temporary [...] persists for the lifetime of the reference
+ return Entity.getDecl();
+
+ case InitializedEntity::EK_Member:
+ // For subobjects, we look at the complete object.
+ if (Entity.getParent())
+ return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
+ Entity.getDecl());
+
+ // except:
+ // -- A temporary bound to a reference member in a constructor's
+ // ctor-initializer persists until the constructor exits.
+ return Entity.getDecl();
+
+ case InitializedEntity::EK_Parameter:
+ // -- A temporary bound to a reference parameter in a function call
+ // persists until the completion of the full-expression containing
+ // the call.
+ case InitializedEntity::EK_Result:
+ // -- The lifetime of a temporary bound to the returned value in a
+ // function return statement is not extended; the temporary is
+ // destroyed at the end of the full-expression in the return statement.
+ case InitializedEntity::EK_New:
+ // -- A temporary bound to a reference in a new-initializer persists
+ // until the completion of the full-expression containing the
+ // new-initializer.
+ return 0;
+
+ case InitializedEntity::EK_Temporary:
+ case InitializedEntity::EK_CompoundLiteralInit:
+ // We don't yet know the storage duration of the surrounding temporary.
+ // Assume it's got full-expression duration for now, it will patch up our
+ // storage duration if that's not correct.
+ return 0;
+
+ case InitializedEntity::EK_ArrayElement:
+ // For subobjects, we look at the complete object.
+ return getDeclForTemporaryLifetimeExtension(*Entity.getParent(),
+ FallbackDecl);
+
+ case InitializedEntity::EK_Base:
+ case InitializedEntity::EK_Delegating:
+ // We can reach this case for aggregate initialization in a constructor:
+ // struct A { int &&r; };
+ // struct B : A { B() : A{0} {} };
+ // In this case, use the innermost field decl as the context.
+ return FallbackDecl;
+
+ case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_LambdaCapture:
+ case InitializedEntity::EK_Exception:
+ case InitializedEntity::EK_VectorElement:
+ case InitializedEntity::EK_ComplexElement:
+ llvm_unreachable("should not materialize a temporary to initialize this");
+ }
+}
+
+static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD);
+
+/// Update a glvalue expression that is used as the initializer of a reference
+/// to note that its lifetime is extended.
+static void performReferenceExtension(Expr *Init, const ValueDecl *ExtendingD) {
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
+ // This is just redundant braces around an initializer. Step over it.
+ Init = ILE->getInit(0);
+ }
+ }
+
+ if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) {
+ // Update the storage duration of the materialized temporary.
+ // FIXME: Rebuild the expression instead of mutating it.
+ ME->setExtendingDecl(ExtendingD);
+ performLifetimeExtension(ME->GetTemporaryExpr(), ExtendingD);
+ }
+}
+
+/// Update a prvalue expression that is going to be materialized as a
+/// lifetime-extended temporary.
+static void performLifetimeExtension(Expr *Init, const ValueDecl *ExtendingD) {
+ // Dig out the expression which constructs the extended temporary.
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ Init = const_cast<Expr *>(
+ Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments));
+
+ if (InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
+ if (ILE->initializesStdInitializerList()) {
+ // FIXME: If this is an InitListExpr which creates a std::initializer_list
+ // object, we also need to lifetime-extend the underlying array
+ // itself. Fix the representation to explicitly materialize an
+ // array temporary so we can model this properly.
+ for (unsigned I = 0, N = ILE->getNumInits(); I != N; ++I)
+ performLifetimeExtension(ILE->getInit(I), ExtendingD);
+ return;
+ }
+
+ CXXRecordDecl *RD = Init->getType()->getAsCXXRecordDecl();
+ if (RD) {
+ assert(RD->isAggregate() && "aggregate init on non-aggregate");
+
+ // If we lifetime-extend a braced initializer which is initializing an
+ // aggregate, and that aggregate contains reference members which are
+ // bound to temporaries, those temporaries are also lifetime-extended.
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() &&
+ ILE->getInitializedFieldInUnion()->getType()->isReferenceType())
+ performReferenceExtension(ILE->getInit(0), ExtendingD);
+ else {
+ unsigned Index = 0;
+ for (RecordDecl::field_iterator I = RD->field_begin(),
+ E = RD->field_end();
+ I != E; ++I) {
+ if (I->isUnnamedBitfield())
+ continue;
+ if (I->getType()->isReferenceType())
+ performReferenceExtension(ILE->getInit(Index), ExtendingD);
+ else if (isa<InitListExpr>(ILE->getInit(Index)))
+ // This may be either aggregate-initialization of a member or
+ // initialization of a std::initializer_list object. Either way,
+ // we should recursively lifetime-extend that initializer.
+ performLifetimeExtension(ILE->getInit(Index), ExtendingD);
+ ++Index;
+ }
+ }
+ }
+ }
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -5326,7 +5503,7 @@ InitializationSequence::Perform(Sema &S,
break;
- case SK_BindReferenceToTemporary:
+ case SK_BindReferenceToTemporary: {
// Make sure the "temporary" is actually an rvalue.
assert(CurInit.get()->isRValue() && "not a temporary");
@@ -5334,11 +5511,17 @@ InitializationSequence::Perform(Sema &S,
if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType))
return ExprError();
+ // Maybe lifetime-extend the temporary's subobjects to match the
+ // entity's lifetime.
+ const ValueDecl *ExtendingDecl =
+ getDeclForTemporaryLifetimeExtension(Entity);
+ if (ExtendingDecl)
+ performLifetimeExtension(CurInit.get(), ExtendingDecl);
+
// Materialize the temporary into memory.
CurInit = new (S.Context) MaterializeTemporaryExpr(
- Entity.getType().getNonReferenceType(),
- CurInit.get(),
- Entity.getType()->isLValueReferenceType());
+ Entity.getType().getNonReferenceType(), CurInit.get(),
+ Entity.getType()->isLValueReferenceType(), ExtendingDecl);
// If we're binding to an Objective-C object that has lifetime, we
// need cleanups.
@@ -5347,6 +5530,7 @@ InitializationSequence::Perform(Sema &S,
S.ExprNeedsCleanups = true;
break;
+ }
case SK_ExtraneousCopyToTemporary:
CurInit = CopyObject(S, Step->Type, Entity, CurInit,
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 04fc2bde2ec..9e0157d7afb 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1576,6 +1576,7 @@ void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
E->Temporary = Reader.ReadSubExpr();
+ E->ExtendingDecl = ReadDeclAs<ValueDecl>(Record, Idx);
}
void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 5f7ac01bae9..5a8baa9d88a 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1572,6 +1572,7 @@ void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) {
void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->Temporary);
+ Writer.AddDeclRef(E->ExtendingDecl, Record);
Code = serialization::EXPR_MATERIALIZE_TEMPORARY;
}
OpenPOWER on IntegriCloud