diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h index d314858c8dca..7d01ebb9a002 100644 --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -49,17 +49,26 @@ typedef AnalysisManager CGSCCAnalysisManager; /// never use a CGSCC analysis manager from within (transitively) a module /// pass manager unless your parent module pass has received a proxy result /// object for it. +/// +/// Note that the proxy's result is a move-only object and represents ownership +/// of the validity of the analyses in the \c CGSCCAnalysisManager it provides. class CGSCCAnalysisManagerModuleProxy { public: class Result { public: explicit Result(CGSCCAnalysisManager &CGAM) : CGAM(&CGAM) {} - // We have to explicitly define all the special member functions because - // MSVC refuses to generate them. - Result(const Result &Arg) : CGAM(Arg.CGAM) {} - Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) {} - Result &operator=(Result RHS) { - std::swap(CGAM, RHS.CGAM); + Result(Result &&Arg) : CGAM(std::move(Arg.CGAM)) { + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of its responsibilty to clear the + // analysis state. + Arg.CGAM = nullptr; + } + Result &operator=(Result &&RHS) { + CGAM = RHS.CGAM; + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of its responsibilty to clear the + // analysis state. + RHS.CGAM = nullptr; return *this; } ~Result(); @@ -275,17 +284,27 @@ createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass) { /// never use a function analysis manager from within (transitively) a CGSCC /// pass manager unless your parent CGSCC pass has received a proxy result /// object for it. +/// +/// Note that the proxy's result is a move-only object and represents ownership +/// of the validity of the analyses in the \c FunctionAnalysisManager it +/// provides. class FunctionAnalysisManagerCGSCCProxy { public: class Result { public: explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} - // We have to explicitly define all the special member functions because - // MSVC refuses to generate them. - Result(const Result &Arg) : FAM(Arg.FAM) {} - Result(Result &&Arg) : FAM(std::move(Arg.FAM)) {} - Result &operator=(Result RHS) { - std::swap(FAM, RHS.FAM); + Result(Result &&Arg) : FAM(std::move(Arg.FAM)) { + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of the responsibilty to clear the + // analysis state. + Arg.FAM = nullptr; + } + Result &operator=(Result &&RHS) { + FAM = RHS.FAM; + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of the responsibilty to clear the + // analysis state. + RHS.FAM = nullptr; return *this; } ~Result(); diff --git a/llvm/include/llvm/IR/PassManager.h b/llvm/include/llvm/IR/PassManager.h index 9b0301b4a663..56ddfeb97a53 100644 --- a/llvm/include/llvm/IR/PassManager.h +++ b/llvm/include/llvm/IR/PassManager.h @@ -618,6 +618,10 @@ typedef AnalysisManager FunctionAnalysisManager; /// never use a function analysis manager from within (transitively) a module /// pass manager unless your parent module pass has received a proxy result /// object for it. +/// +/// Note that the proxy's result is a move-only object and represents ownership +/// of the validity of the analyses in the \c FunctionAnalysisManager it +/// provides. class FunctionAnalysisManagerModuleProxy { public: class Result; @@ -665,12 +669,18 @@ private: class FunctionAnalysisManagerModuleProxy::Result { public: explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} - // We have to explicitly define all the special member functions because MSVC - // refuses to generate them. - Result(const Result &Arg) : FAM(Arg.FAM) {} - Result(Result &&Arg) : FAM(std::move(Arg.FAM)) {} - Result &operator=(Result RHS) { - std::swap(FAM, RHS.FAM); + Result(Result &&Arg) : FAM(std::move(Arg.FAM)) { + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of the responsibilty to clear the + // analysis state. + Arg.FAM = nullptr; + } + Result &operator=(Result &&RHS) { + FAM = RHS.FAM; + // We have to null out the analysis manager in the moved-from state + // because we are taking ownership of the responsibilty to clear the + // analysis state. + RHS.FAM = nullptr; return *this; } ~Result(); diff --git a/llvm/lib/Analysis/CGSCCPassManager.cpp b/llvm/lib/Analysis/CGSCCPassManager.cpp index 4a03002e510b..9cceed4ba875 100644 --- a/llvm/lib/Analysis/CGSCCPassManager.cpp +++ b/llvm/lib/Analysis/CGSCCPassManager.cpp @@ -22,6 +22,10 @@ CGSCCAnalysisManagerModuleProxy::run(Module &M) { } CGSCCAnalysisManagerModuleProxy::Result::~Result() { + // CGAM is cleared in a moved from state where there is nothing to do. + if (!CGAM) + return; + // Clear out the analysis manager if we're being destroyed -- it means we // didn't even see an invalidate call when we got invalidated. CGAM->clear(); @@ -51,6 +55,10 @@ FunctionAnalysisManagerCGSCCProxy::run(LazyCallGraph::SCC &C) { } FunctionAnalysisManagerCGSCCProxy::Result::~Result() { + // FAM is cleared in a moved from state where there is nothing to do. + if (!FAM) + return; + // Clear out the analysis manager if we're being destroyed -- it means we // didn't even see an invalidate call when we got invalidated. FAM->clear(); diff --git a/llvm/lib/IR/PassManager.cpp b/llvm/lib/IR/PassManager.cpp index a5f407c00e8e..f55db9c1e649 100644 --- a/llvm/lib/IR/PassManager.cpp +++ b/llvm/lib/IR/PassManager.cpp @@ -22,6 +22,10 @@ FunctionAnalysisManagerModuleProxy::run(Module &M) { } FunctionAnalysisManagerModuleProxy::Result::~Result() { + // FAM is cleared in a moved from state where there is nothing to do. + if (!FAM) + return; + // Clear out the analysis manager if we're being destroyed -- it means we // didn't even see an invalidate call when we got invalidated. FAM->clear();