ENH: Create policy scope barriers

This creates a barrier mechanism to prevent user code from using
cmake_policy(POP) to pop a scope it didn't push with cmake_policy(PUSH).
This commit is contained in:
Brad King 2009-01-22 10:57:16 -05:00
parent ac14b5d2eb
commit dfc181a1dc
3 changed files with 83 additions and 55 deletions

View File

@ -43,7 +43,8 @@ bool cmCMakePolicyCommand
this->SetError("PUSH may not be given additional arguments."); this->SetError("PUSH may not be given additional arguments.");
return false; return false;
} }
return this->Makefile->PushPolicy(); this->Makefile->PushPolicy();
return true;
} }
else if(args[0] == "POP") else if(args[0] == "POP")
{ {
@ -52,15 +53,8 @@ bool cmCMakePolicyCommand
this->SetError("POP may not be given additional arguments."); this->SetError("POP may not be given additional arguments.");
return false; return false;
} }
if(this->Makefile->PopPolicy(false)) this->Makefile->PopPolicy();
{ return true;
return true;
}
else
{
this->SetError("POP without matching PUSH");
return false;
}
} }
else if(args[0] == "VERSION") else if(args[0] == "VERSION")
{ {

View File

@ -150,6 +150,9 @@ void cmMakefile::Initialize()
// Enter a policy level for this directory. // Enter a policy level for this directory.
this->PushPolicy(); this->PushPolicy();
// Protect the directory-level policies.
this->PushPolicyBarrier();
// By default the check is not done. It is enabled by // By default the check is not done. It is enabled by
// cmListFileCache in the top level if necessary. // cmListFileCache in the top level if necessary.
this->CheckCMP0000 = false; this->CheckCMP0000 = false;
@ -441,6 +444,34 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff,
return result; return result;
} }
//----------------------------------------------------------------------------
class cmMakefile::IncludeScope
{
public:
IncludeScope(cmMakefile* mf);
~IncludeScope();
void Quiet() { this->ReportError = false; }
private:
cmMakefile* Makefile;
bool ReportError;
};
//----------------------------------------------------------------------------
cmMakefile::IncludeScope::IncludeScope(cmMakefile* mf):
Makefile(mf), ReportError(true)
{
// The included file cannot pop our policy scope.
this->Makefile->PushPolicyBarrier();
}
//----------------------------------------------------------------------------
cmMakefile::IncludeScope::~IncludeScope()
{
// Enforce matching policy scopes inside the included file.
this->Makefile->PopPolicyBarrier(this->ReportError);
}
//----------------------------------------------------------------------------
// Parse the given CMakeLists.txt file executing all commands // Parse the given CMakeLists.txt file executing all commands
// //
bool cmMakefile::ReadListFile(const char* filename_in, bool cmMakefile::ReadListFile(const char* filename_in,
@ -533,10 +564,7 @@ bool cmMakefile::ReadListFile(const char* filename_in,
// Enforce balanced blocks (if/endif, function/endfunction, etc.). // Enforce balanced blocks (if/endif, function/endfunction, etc.).
{ {
LexicalPushPop lexScope(this); LexicalPushPop lexScope(this);
bool endScopeNicely = true; IncludeScope incScope(this);
// Save the current policy stack depth.
size_t const policy_depth = this->PolicyStack.size();
// Run the parsed commands. // Run the parsed commands.
const size_t numberFunctions = cacheFile.Functions.size(); const size_t numberFunctions = cacheFile.Functions.size();
@ -547,8 +575,8 @@ bool cmMakefile::ReadListFile(const char* filename_in,
if(cmSystemTools::GetFatalErrorOccured()) if(cmSystemTools::GetFatalErrorOccured())
{ {
// Exit early due to error. // Exit early due to error.
endScopeNicely = false;
lexScope.Quiet(); lexScope.Quiet();
incScope.Quiet();
break; break;
} }
if(status.GetReturnInvoked()) if(status.GetReturnInvoked())
@ -557,17 +585,6 @@ bool cmMakefile::ReadListFile(const char* filename_in,
break; break;
} }
} }
// Restore policy stack depth.
while(this->PolicyStack.size() > policy_depth)
{
if(endScopeNicely)
{
this->IssueMessage(cmake::FATAL_ERROR,
"cmake_policy PUSH without matching POP");
}
this->PopPolicy(false);
}
} }
// If this is the directory-level CMakeLists.txt file then perform // If this is the directory-level CMakeLists.txt file then perform
@ -3675,54 +3692,65 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id,
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m): Makefile(m) cmMakefile::PolicyPushPop::PolicyPushPop(cmMakefile* m):
Makefile(m), ReportError(true)
{ {
this->Makefile->PushPolicy(); this->Makefile->PushPolicy();
this->PolicyDepth = this->Makefile->PolicyStack.size(); this->Makefile->PushPolicyBarrier();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
cmMakefile::PolicyPushPop::~PolicyPushPop() cmMakefile::PolicyPushPop::~PolicyPushPop()
{ {
// Enforce matching PUSH/POP pairs. this->Makefile->PopPolicyBarrier(this->ReportError);
if(this->Makefile->PolicyStack.size() < this->PolicyDepth)
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
"cmake_policy POP without matching PUSH");
return;
}
while(this->Makefile->PolicyStack.size() > this->PolicyDepth)
{
this->Makefile->IssueMessage(cmake::FATAL_ERROR,
"cmake_policy PUSH without matching POP");
this->Makefile->PopPolicy(false);
}
// Pop our scope.
this->Makefile->PopPolicy(); this->Makefile->PopPolicy();
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmMakefile::PushPolicy() void cmMakefile::PushPolicy()
{ {
// Allocate a new stack entry. // Allocate a new stack entry.
this->PolicyStack.push_back(PolicyStackEntry()); this->PolicyStack.push_back(PolicyStackEntry());
return true;
} }
bool cmMakefile::PopPolicy(bool reportError) //----------------------------------------------------------------------------
void cmMakefile::PopPolicy()
{ {
if(this->PolicyStack.size() == 1) if(this->PolicyStack.size() > this->PolicyBarriers.back())
{
this->PolicyStack.pop_back();
}
else
{
this->IssueMessage(cmake::FATAL_ERROR,
"cmake_policy POP without matching PUSH");
}
}
//----------------------------------------------------------------------------
void cmMakefile::PushPolicyBarrier()
{
this->PolicyBarriers.push_back(this->PolicyStack.size());
}
//----------------------------------------------------------------------------
void cmMakefile::PopPolicyBarrier(bool reportError)
{
// Remove any extra entries pushed on the barrier.
PolicyStackType::size_type barrier = this->PolicyBarriers.back();
while(this->PolicyStack.size() > barrier)
{ {
if(reportError) if(reportError)
{ {
cmSystemTools::Error("Attempt to pop the policy stack past " this->IssueMessage(cmake::FATAL_ERROR,
"it's beginning."); "cmake_policy PUSH without matching POP");
reportError = false;
} }
return false; this->PopPolicy();
} }
this->PolicyStack.pop_back();
return true; // Remove the barrier.
this->PolicyBarriers.pop_back();
} }
bool cmMakefile::SetPolicyVersion(const char *version) bool cmMakefile::SetPolicyVersion(const char *version)

View File

@ -351,9 +351,10 @@ public:
public: public:
PolicyPushPop(cmMakefile* m); PolicyPushPop(cmMakefile* m);
~PolicyPushPop(); ~PolicyPushPop();
void Quiet() { this->ReportError = false; }
private: private:
cmMakefile* Makefile; cmMakefile* Makefile;
size_t PolicyDepth; bool ReportError;
}; };
friend class PolicyPushPop; friend class PolicyPushPop;
@ -942,9 +943,13 @@ private:
std::map<cmStdString, cmTarget*> ImportedTargets; std::map<cmStdString, cmTarget*> ImportedTargets;
// Internal policy stack management. // Internal policy stack management.
bool PushPolicy(); void PushPolicy();
bool PopPolicy(bool reportError = true); void PopPolicy();
void PushPolicyBarrier();
void PopPolicyBarrier(bool reportError = true);
friend class cmCMakePolicyCommand; friend class cmCMakePolicyCommand;
class IncludeScope;
friend class IncludeScope;
// stack of policy settings // stack of policy settings
struct PolicyStackEntry: public cmPolicies::PolicyMap struct PolicyStackEntry: public cmPolicies::PolicyMap
@ -956,6 +961,7 @@ private:
}; };
typedef std::vector<PolicyStackEntry> PolicyStackType; typedef std::vector<PolicyStackEntry> PolicyStackType;
PolicyStackType PolicyStack; PolicyStackType PolicyStack;
std::vector<PolicyStackType::size_type> PolicyBarriers;
cmPolicies::PolicyStatus GetPolicyStatusInternal(cmPolicies::PolicyID id); cmPolicies::PolicyStatus GetPolicyStatusInternal(cmPolicies::PolicyID id);
bool CheckCMP0000; bool CheckCMP0000;