Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -272,12 +272,6 @@ /// Mapping from __block VarDecls to BlockVarCopyInit. llvm::DenseMap BlockVarCopyInits; - /// Mapping from materialized temporaries with static storage duration - /// that appear in constant initializers to their evaluated values. These are - /// allocated in a std::map because their address must be stable. - llvm::DenseMap - MaterializedTemporaryValues; - /// Used to cleanups APValues stored in the AST. mutable llvm::SmallVector APValueCleanups; @@ -2827,11 +2821,6 @@ /// index of the parameter when it exceeds the size of the normal bitfield. unsigned getParameterIndex(const ParmVarDecl *D) const; - /// Get the storage for the constant value of a materialized temporary - /// of static storage duration. - APValue *getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, - bool MayCreate); - /// Return a string representing the human readable name for the specified /// function declaration or file name. Used by SourceLocExpr and /// PredefinedExpr to cache evaluated results. Index: clang/include/clang/AST/DeclCXX.h =================================================================== --- clang/include/clang/AST/DeclCXX.h +++ clang/include/clang/AST/DeclCXX.h @@ -3052,6 +3052,73 @@ static bool classofKind(Kind K) { return K == NamespaceAlias; } }; +/// Implicit declartion of a temporary that was materialized by +/// MaterializeTemporaryExpr +class MaterializeTemporaryDecl final : public Decl { + friend class MaterializeTemporaryExpr; + friend class ASTDeclReader; + friend class ASTDeclWriter; + + /// The temporary-generating expression whose value will be + /// materialized. + Stmt *StmtWithTemporary; + + /// The declaration which lifetime-extended this reference, if any. + /// Either a VarDecl, or (for a ctor-initializer) a FieldDecl. + ValueDecl *ExtendingDecl = nullptr; + unsigned ManglingNumber; + + mutable APValue* Value = nullptr; + + virtual void anchor(); + + MaterializeTemporaryDecl(Stmt *Temp, ValueDecl *EDecl, unsigned Mangling) + : Decl(Decl::MaterializeTemporary, EDecl->getDeclContext(), + EDecl->getLocation()), + StmtWithTemporary(Temp), ExtendingDecl(EDecl), + ManglingNumber(Mangling) {} + + MaterializeTemporaryDecl(EmptyShell) + : Decl(Decl::MaterializeTemporary, EmptyShell{}) {} + +public: + static MaterializeTemporaryDecl *Create(Stmt *Temp, ValueDecl *EDec, + unsigned Mangling) { + return new (EDec->getASTContext(), EDec->getDeclContext()) + MaterializeTemporaryDecl(Temp, EDec, Mangling); + } + static MaterializeTemporaryDecl *CreateDeserialized(ASTContext &C, + unsigned ID) { + return new (C, ID) MaterializeTemporaryDecl(EmptyShell{}); + } + + ValueDecl* getExtendingDecl() { + return ExtendingDecl; + } + const ValueDecl* getExtendingDecl() const { + return ExtendingDecl; + } + Stmt* getStmtWithTemporary() { + return StmtWithTemporary; + } + const Stmt* getStmtWithTemporary() const { + return StmtWithTemporary; + } + + APValue* getValue() const { + return Value; + } + + unsigned getManglingNumber() const { + return ManglingNumber; + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == Decl::MaterializeTemporary; + } +}; + /// Represents a shadow declaration introduced into a scope by a /// (resolved) using declaration. /// Index: clang/include/clang/AST/ExprCXX.h =================================================================== --- clang/include/clang/AST/ExprCXX.h +++ clang/include/clang/AST/ExprCXX.h @@ -4421,35 +4421,20 @@ friend class ASTStmtReader; friend class ASTStmtWriter; - struct ExtraState { - /// The temporary-generating expression whose value will be - /// materialized. - Stmt *Temporary; - - /// The declaration which lifetime-extended this reference, if any. - /// Either a VarDecl, or (for a ctor-initializer) a FieldDecl. - const ValueDecl *ExtendingDecl; - - unsigned ManglingNumber; - }; - llvm::PointerUnion State; + llvm::PointerUnion State; public: MaterializeTemporaryExpr(QualType T, Expr *Temporary, - bool BoundToLvalueReference) - : Expr(MaterializeTemporaryExprClass, T, - BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary, - Temporary->isTypeDependent(), Temporary->isValueDependent(), - Temporary->isInstantiationDependent(), - Temporary->containsUnexpandedParameterPack()), - State(Temporary) {} + bool BoundToLvalueReference, + MaterializeTemporaryDecl *MTD = nullptr); MaterializeTemporaryExpr(EmptyShell Empty) : Expr(MaterializeTemporaryExprClass, Empty) {} Stmt *getTemporary() const { return State.is() ? State.get() - : State.get()->Temporary; + : State.get() + ->getStmtWithTemporary(); } /// Retrieve the temporary-generating subexpression whose value will @@ -4474,17 +4459,34 @@ return cast(ExtendingDecl)->getStorageDuration(); } + MaterializeTemporaryDecl* getMaterializeTemporaryDecl() { + return State.dyn_cast(); + } + const MaterializeTemporaryDecl* getMaterializeTemporaryDecl() const { + return State.dyn_cast(); + } + + /// Get the storage for the constant value of a materialized temporary + /// of static storage duration. + APValue *getOrCreateValue(ASTContext &Ctx, bool MayCreate) const; + /// Get the declaration which triggered the lifetime-extension of this /// temporary, if any. - const ValueDecl *getExtendingDecl() const { - return State.is() ? nullptr - : State.get()->ExtendingDecl; + ValueDecl *getExtendingDecl() { + return State.is() + ? nullptr + : State.get()->getExtendingDecl(); + } + const ValueDecl* getExtendingDecl() const { + return const_cast(this)->getExtendingDecl(); } - void setExtendingDecl(const ValueDecl *ExtendedBy, unsigned ManglingNumber); + void setExtendingDecl(ValueDecl *ExtendedBy, unsigned ManglingNumber); unsigned getManglingNumber() const { - return State.is() ? 0 : State.get()->ManglingNumber; + return State.is() + ? 0 + : State.get()->getManglingNumber(); } /// Determine whether this materialized temporary is bound to an @@ -4510,8 +4512,8 @@ if (State.is()) return child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1); - auto ES = State.get(); - return child_range(&ES->Temporary, &ES->Temporary + 1); + auto ES = State.get(); + return child_range(&ES->StmtWithTemporary, &ES->StmtWithTemporary + 1); } const_child_range children() const { @@ -4519,8 +4521,8 @@ return const_child_range(State.getAddrOfPtr1(), State.getAddrOfPtr1() + 1); - auto ES = State.get(); - return const_child_range(&ES->Temporary, &ES->Temporary + 1); + auto ES = State.get(); + return const_child_range(&ES->StmtWithTemporary, &ES->StmtWithTemporary + 1); } }; Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -2121,6 +2121,11 @@ TRY_TO(TraverseStmt(D->getDefaultArg())); }) +DEF_TRAVERSE_DECL(MaterializeTemporaryDecl, { + TRY_TO(TraverseDecl(D->getExtendingDecl())); + TRY_TO(TraverseStmt(D->getStmtWithTemporary())); +}) + #undef DEF_TRAVERSE_DECL // ----------------- Stmt traversal ----------------- Index: clang/include/clang/Basic/DeclNodes.td =================================================================== --- clang/include/clang/Basic/DeclNodes.td +++ clang/include/clang/Basic/DeclNodes.td @@ -102,4 +102,5 @@ def OMPAllocate : Decl; def OMPRequires : Decl; def Empty : Decl; +def MaterializeTemporary : Decl; Index: clang/include/clang/Sema/Template.h =================================================================== --- clang/include/clang/Sema/Template.h +++ clang/include/clang/Sema/Template.h @@ -464,6 +464,7 @@ #define OBJCPROPERTY(DERIVED, BASE) #define OBJCPROPERTYIMPL(DERIVED, BASE) #define EMPTY(DERIVED, BASE) +#define MATERIALIZETEMPORARY(DERIVED, BASE) // Decls which use special-case instantiation code. #define BLOCK(DERIVED, BASE) Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -1537,6 +1537,9 @@ /// An EmptyDecl record. DECL_EMPTY, + /// An MaterializeTemporaryDecl record. + DECL_MATERIALIZE_TEMPORARY, + /// An ObjCTypeParamDecl record. DECL_OBJC_TYPE_PARAM, Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -875,10 +875,6 @@ A != AEnd; ++A) A->second->~AttrVec(); - for (std::pair &MTVPair : - MaterializedTemporaryValues) - MTVPair.second->~APValue(); - for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); @@ -10324,21 +10320,6 @@ 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) { - APValue *&MTVI = MaterializedTemporaryValues[E]; - if (!MTVI) - MTVI = new (*this) APValue; - return MTVI; - } - - return MaterializedTemporaryValues.lookup(E); -} - QualType ASTContext::getStringLiteralArrayType(QualType EltTy, unsigned Length) const { // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -483,6 +483,7 @@ ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D); ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); ExpectedDecl VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + ExpectedDecl VisitMaterializeTemporaryDecl(MaterializeTemporaryDecl *D); Expected ImportObjCTypeParamList(ObjCTypeParamList *list); @@ -6989,23 +6990,42 @@ E->requiresZeroInitialization()); } +ExpectedDecl +ASTNodeImporter::VisitMaterializeTemporaryDecl(MaterializeTemporaryDecl *D) { + auto Imp = importSeq(D->getStmtWithTemporary(), D->getExtendingDecl()); + // FIXME: the APValue should be imported as well if present. + if (!Imp) + return Imp.takeError(); + + Stmt *Temporary; + ValueDecl *ExtendingDecl; + std::tie(Temporary, ExtendingDecl) = *Imp; + // FIXME: Should ManglingNumber get numbers associated with 'to' context? + auto* To = MaterializeTemporaryDecl::Create(Temporary, ExtendingDecl, + D->getManglingNumber()); + Importer.MapImported(D, To); + return To; +} + ExpectedStmt ASTNodeImporter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { - auto Imp = importSeq( - E->getType(), E->GetTemporaryExpr(), E->getExtendingDecl()); + auto Imp = + importSeq(E->getType(), + E->getMaterializeTemporaryDecl() ? nullptr : E->GetTemporaryExpr(), + E->getMaterializeTemporaryDecl()); if (!Imp) return Imp.takeError(); QualType ToType; Expr *ToTemporaryExpr; - const ValueDecl *ToExtendingDecl; - std::tie(ToType, ToTemporaryExpr, ToExtendingDecl) = *Imp; + MaterializeTemporaryDecl *MaterialzedDecl; + std::tie(ToType, ToTemporaryExpr, MaterialzedDecl) = *Imp; + if (!ToTemporaryExpr) + ToTemporaryExpr = cast(MaterialzedDecl->getStmtWithTemporary()); - auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr( - ToType, ToTemporaryExpr, E->isBoundToLvalueReference()); + auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr( + ToType, ToTemporaryExpr, E->isBoundToLvalueReference(), MaterialzedDecl); - // FIXME: Should ManglingNumber get numbers associated with 'to' context? - ToMTE->setExtendingDecl(ToExtendingDecl, E->getManglingNumber()); return ToMTE; } Index: clang/lib/AST/DeclBase.cpp =================================================================== --- clang/lib/AST/DeclBase.cpp +++ clang/lib/AST/DeclBase.cpp @@ -803,6 +803,7 @@ case OMPRequires: case OMPCapturedExpr: case Empty: + case MaterializeTemporary: // Never looked up by name. return 0; } Index: clang/lib/AST/DeclCXX.cpp =================================================================== --- clang/lib/AST/DeclCXX.cpp +++ clang/lib/AST/DeclCXX.cpp @@ -2796,6 +2796,8 @@ SourceLocation(), nullptr); } +void MaterializeTemporaryDecl::anchor() {} + void UsingShadowDecl::anchor() {} UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, Index: clang/lib/AST/ExprCXX.cpp =================================================================== --- clang/lib/AST/ExprCXX.cpp +++ clang/lib/AST/ExprCXX.cpp @@ -1653,7 +1653,35 @@ FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr); } -void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy, +MaterializeTemporaryExpr::MaterializeTemporaryExpr( + QualType T, Expr *Temporary, bool BoundToLvalueReference, + MaterializeTemporaryDecl *MTD) + : Expr(MaterializeTemporaryExprClass, T, + BoundToLvalueReference ? VK_LValue : VK_XValue, OK_Ordinary, + Temporary->isTypeDependent(), Temporary->isValueDependent(), + Temporary->isInstantiationDependent(), + Temporary->containsUnexpandedParameterPack()) { + if (MTD) { + State = MTD; + MTD->StmtWithTemporary = Temporary; + return; + } + State = Temporary; +} + +APValue *MaterializeTemporaryExpr::getOrCreateValue(ASTContext &Ctx, + bool MayCreate) const { + assert(getStorageDuration() == SD_Static && + "don't need to cache the computed value for this temporary"); + const MaterializeTemporaryDecl* D = getMaterializeTemporaryDecl(); + assert(D && "must not be null"); + if (MayCreate && !D->getValue()) + D->Value = new (Ctx) APValue; + assert(D->getValue() && "may not be null"); + return D->getValue(); +} + +void MaterializeTemporaryExpr::setExtendingDecl(ValueDecl *ExtendedBy, unsigned ManglingNumber) { // We only need extra state if we have to remember more than just the Stmt. if (!ExtendedBy) @@ -1661,13 +1689,11 @@ // We may need to allocate extra storage for the mangling number and the // extended-by ValueDecl. - if (!State.is()) { - auto *ES = new (ExtendedBy->getASTContext()) ExtraState; - ES->Temporary = State.get(); - State = ES; - } + if (!State.is()) + State = MaterializeTemporaryDecl::Create(State.get(), ExtendedBy, + ManglingNumber); - auto ES = State.get(); + auto ES = State.get(); ES->ExtendingDecl = ExtendedBy; ES->ManglingNumber = ManglingNumber; } Index: clang/lib/AST/ExprConstant.cpp =================================================================== --- clang/lib/AST/ExprConstant.cpp +++ clang/lib/AST/ExprConstant.cpp @@ -2072,7 +2072,7 @@ return false; } - APValue *V = Info.Ctx.getMaterializedTemporaryValue(MTE, false); + APValue *V = MTE->getOrCreateValue(Info.Ctx, false); assert(V && "evasluation result refers to uninitialised temporary"); if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression, Info, MTE->getExprLoc(), TempType, *V, @@ -3676,7 +3676,7 @@ return CompleteObject(); } - BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); + BaseVal = MTE->getOrCreateValue(Info.Ctx, false); assert(BaseVal && "got reference to unevaluated temporary"); } else { if (!IsAccess) @@ -7473,7 +7473,7 @@ // value for use outside this evaluation. APValue *Value; if (E->getStorageDuration() == SD_Static) { - Value = Info.Ctx.getMaterializedTemporaryValue(E, true); + Value = E->getOrCreateValue(Info.Ctx, true); *Value = APValue(); Result.set(E); } else { Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -109,6 +109,7 @@ case Decl::OMPRequires: case Decl::Empty: case Decl::Concept: + case Decl::MaterializeTemporary: // None of these decls require codegen support. return; Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -5022,7 +5022,7 @@ // temporary. Note that this might have a different value from the value // computed by evaluating the initializer if the surrounding constant // expression modifies the temporary. - Value = getContext().getMaterializedTemporaryValue(E, false); + Value = E->getOrCreateValue(getContext(), false); } // Try evaluating it now, it might have a constant initializer. Index: clang/lib/Serialization/ASTCommon.cpp =================================================================== --- clang/lib/Serialization/ASTCommon.cpp +++ clang/lib/Serialization/ASTCommon.cpp @@ -401,6 +401,7 @@ case Decl::Decomposition: case Decl::Binding: case Decl::Concept: + case Decl::MaterializeTemporary: return false; // These indirectly derive from Redeclarable but are not actually Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -405,6 +405,7 @@ void VisitBlockDecl(BlockDecl *BD); void VisitCapturedDecl(CapturedDecl *CD); void VisitEmptyDecl(EmptyDecl *D); + void VisitMaterializeTemporaryDecl(MaterializeTemporaryDecl* D); std::pair VisitDeclContext(DeclContext *DC); @@ -2346,6 +2347,15 @@ VisitDecl(D); } +void ASTDeclReader::VisitMaterializeTemporaryDecl(MaterializeTemporaryDecl* D) { + VisitDecl(D); + D->ExtendingDecl = ReadDeclAs(); + D->StmtWithTemporary = Record.readStmt(); + if (Record.readInt()) + D->Value = new (D->getASTContext()) APValue(Record.readAPValue()); + D->ManglingNumber = Record.readInt(); +} + std::pair ASTDeclReader::VisitDeclContext(DeclContext *DC) { uint64_t LexicalOffset = ReadLocalOffset(); @@ -3836,6 +3846,9 @@ case DECL_BLOCK: D = BlockDecl::CreateDeserialized(Context, ID); break; + case DECL_MATERIALIZE_TEMPORARY: + D = MaterializeTemporaryDecl::CreateDeserialized(Context, ID); + break; case DECL_MS_PROPERTY: D = MSPropertyDecl::CreateDeserialized(Context, ID); break; Index: clang/lib/Serialization/ASTReaderStmt.cpp =================================================================== --- clang/lib/Serialization/ASTReaderStmt.cpp +++ clang/lib/Serialization/ASTReaderStmt.cpp @@ -1900,10 +1900,11 @@ void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); - E->State = Record.readSubExpr(); - auto *VD = ReadDeclAs(); - unsigned ManglingNumber = Record.readInt(); - E->setExtendingDecl(VD, ManglingNumber); + bool HasMaterialzedDecl = Record.readInt(); + if (HasMaterialzedDecl) + E->State = ReadDeclAs(); + else + E->State = Record.readSubExpr(); } void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) { Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -124,6 +124,7 @@ void VisitBlockDecl(BlockDecl *D); void VisitCapturedDecl(CapturedDecl *D); void VisitEmptyDecl(EmptyDecl *D); + void VisitMaterializeTemporaryDecl(MaterializeTemporaryDecl* D); void VisitDeclContext(DeclContext *DC); template void VisitRedeclarable(Redeclarable *D); @@ -1131,6 +1132,17 @@ Code = serialization::DECL_EMPTY; } +void ASTDeclWriter::VisitMaterializeTemporaryDecl(MaterializeTemporaryDecl *D) { + VisitDecl(D); + Record.AddDeclRef(D->getExtendingDecl()); + Record.AddStmt(D->getStmtWithTemporary()); + Record.push_back(static_cast(D->getValue())); + if (D->getValue()) + Record.AddAPValue(*D->getValue()); + Record.push_back(D->getManglingNumber()); + Code = serialization::DECL_MATERIALIZE_TEMPORARY; +} + void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { VisitDecl(D); Record.AddStmt(D->getBody()); Index: clang/lib/Serialization/ASTWriterStmt.cpp =================================================================== --- clang/lib/Serialization/ASTWriterStmt.cpp +++ clang/lib/Serialization/ASTWriterStmt.cpp @@ -1835,9 +1835,11 @@ void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); - Record.AddStmt(E->getTemporary()); - Record.AddDeclRef(E->getExtendingDecl()); - Record.push_back(E->getManglingNumber()); + Record.push_back(static_cast(E->getMaterializeTemporaryDecl())); + if (E->getMaterializeTemporaryDecl()) + Record.AddDeclRef(E->getMaterializeTemporaryDecl()); + else + Record.AddStmt(E->getTemporary()); Code = serialization::EXPR_MATERIALIZE_TEMPORARY; } Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -6299,6 +6299,7 @@ case Decl::PragmaDetectMismatch: case Decl::UsingPack: case Decl::Concept: + case Decl::MaterializeTemporary: return C; // Declaration kinds that don't make any sense here, but are