cmFindPackageStack: Allow controlled mutation

As mentioned in the previous commit, we would like to record additional
information in the find-package stack, but we don't have the information
at the point a stack entry is created. This necessitates making the
stack mutable. However, in order to restrict mutation, do not directly
expose the mutable value, and instead arrange for it to be accessible
only via cmFindPackageStackRAII (renamed and extracted from cmMakefile).
This ensures that mutation can only happen while the stack is being
built.
This commit is contained in:
Matthew Woehlke
2025-07-29 10:55:38 -04:00
parent f2bdc2176f
commit b3873b8272
5 changed files with 65 additions and 21 deletions

View File

@@ -28,6 +28,7 @@
#include "cmDependencyProvider.h"
#include "cmExecutionStatus.h"
#include "cmExperimental.h"
#include "cmFindPackageStack.h"
#include "cmList.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
@@ -1221,8 +1222,7 @@ bool cmFindPackageCommand::FindPackage(
FlushDebugBufferOnExit flushDebugBufferOnExit(*this);
PushPopRootPathStack pushPopRootPathStack(*this);
SetRestoreFindDefinitions setRestoreFindDefinitions(*this);
cmMakefile::FindPackageStackRAII findPackageStackRAII(this->Makefile,
this->Name);
cmFindPackageStackRAII findPackageStackRAII(this->Makefile, this->Name);
// See if we have been told to delegate to FetchContent or some other
// redirected config package first. We have to check all names that

View File

@@ -4,5 +4,12 @@
#include "cmFindPackageStack.h"
#include "cmStack.tcc" // IWYU pragma: keep
template class cmStack<cmFindPackageCall const, cmFindPackageStack,
cmStackType::Const>;
template class cmStack<cmFindPackageCall, cmFindPackageStack>;
template cmFindPackageCall&
cmStack<cmFindPackageCall, cmFindPackageStack>::Top<true>();
cmFindPackageCall const& cmFindPackageStack::Top() const
{
return this->cmStack::Top();
}

View File

@@ -9,6 +9,8 @@
#include "cmStack.h"
class cmMakefile;
/**
* Represents one call to find_package.
*/
@@ -19,16 +21,48 @@ public:
unsigned int Index;
};
/**
* RAII type to manage the find_package call stack.
*/
// Note: implemented in cmMakefile.cxx
class cmFindPackageStackRAII
{
cmMakefile* Makefile;
cmFindPackageCall** Value = nullptr;
public:
cmFindPackageStackRAII(cmMakefile* mf, std::string const& pkg);
~cmFindPackageStackRAII();
cmFindPackageStackRAII(cmFindPackageStackRAII const&) = delete;
cmFindPackageStackRAII& operator=(cmFindPackageStackRAII const&) = delete;
/** Get a mutable pointer to the top of the stack.
The pointer is invalidated if BindTop is called again or when the
cmFindPackageStackRAII goes out of scope. */
void BindTop(cmFindPackageCall*& value);
};
/**
* Represents a stack of find_package calls with efficient value semantics.
*/
class cmFindPackageStack
: public cmConstStack<cmFindPackageCall, cmFindPackageStack>
: protected cmStack<cmFindPackageCall, cmFindPackageStack>
{
using cmStack::cmStack;
friend cmFindPackageStack::Base;
friend class cmFindPackageStackRAII;
public:
using cmStack::Push;
using cmStack::Pop;
using cmStack::Empty;
cmFindPackageCall const& Top() const;
};
#ifndef cmFindPackageStack_cxx
extern template class cmStack<cmFindPackageCall const, cmFindPackageStack,
cmStackType::Const>;
extern template class cmStack<cmFindPackageCall, cmFindPackageStack>;
extern template cmFindPackageCall&
cmStack<cmFindPackageCall, cmFindPackageStack>::Top<true>();
#endif

View File

@@ -4231,8 +4231,8 @@ cmMakefile::MacroPushPop::~MacroPushPop()
this->Makefile->PopMacroScope(this->ReportError);
}
cmMakefile::FindPackageStackRAII::FindPackageStackRAII(cmMakefile* mf,
std::string const& name)
cmFindPackageStackRAII::cmFindPackageStackRAII(cmMakefile* mf,
std::string const& name)
: Makefile(mf)
{
this->Makefile->FindPackageStack =
@@ -4243,8 +4243,21 @@ cmMakefile::FindPackageStackRAII::FindPackageStackRAII(cmMakefile* mf,
this->Makefile->FindPackageStackNextIndex++;
}
cmMakefile::FindPackageStackRAII::~FindPackageStackRAII()
void cmFindPackageStackRAII::BindTop(cmFindPackageCall*& value)
{
if (this->Value) {
*this->Value = nullptr;
}
this->Value = &value;
value = &this->Makefile->FindPackageStack.cmStack::Top();
}
cmFindPackageStackRAII::~cmFindPackageStackRAII()
{
if (this->Value) {
*this->Value = nullptr;
}
this->Makefile->FindPackageStackNextIndex =
this->Makefile->FindPackageStack.Top().Index + 1;
this->Makefile->FindPackageStack = this->Makefile->FindPackageStack.Pop();

View File

@@ -1034,17 +1034,7 @@ public:
// searches
std::deque<std::vector<std::string>> FindPackageRootPathStack;
class FindPackageStackRAII
{
cmMakefile* Makefile;
public:
FindPackageStackRAII(cmMakefile* mf, std::string const& pkg);
~FindPackageStackRAII();
FindPackageStackRAII(FindPackageStackRAII const&) = delete;
FindPackageStackRAII& operator=(FindPackageStackRAII const&) = delete;
};
friend class cmFindPackageStackRAII;
class DebugFindPkgRAII
{