Browse Source

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.
Matthew Woehlke 4 months ago
parent
commit
b3873b8272

+ 2 - 2
Source/cmFindPackageCommand.cxx

@@ -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

+ 9 - 2
Source/cmFindPackageStack.cxx

@@ -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();
+}

+ 37 - 3
Source/cmFindPackageStack.h

@@ -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

+ 16 - 3
Source/cmMakefile.cxx

@@ -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();

+ 1 - 11
Source/cmMakefile.h

@@ -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
   {