Fix assertion failure on unmatched function or macro

The fix in commit v3.2.3~3^2 (Fix assertion failure on unmatched foreach
in function, 2015-05-18) broke handling of unmatched non-loop blocks
because it assumed all function blockers removed during error unwinding
were for loops, essentially switching the set of mishandled cases.

The purpose of the loop block push/pop operations is to define a scope
matching the lifetime of the loop function blockers.  Since our function
blockers already have the proper lifetime, simply move the push/pop
operations to their constructor/destructor.

Extend the RunCMake.Syntax test with a case covering this.
This commit is contained in:
Brad King 2015-06-22 11:31:04 -04:00
parent 3a65606591
commit 5d85fb4f40
13 changed files with 52 additions and 27 deletions

View File

@ -13,6 +13,17 @@
#include <cmsys/auto_ptr.hxx>
cmForEachFunctionBlocker::cmForEachFunctionBlocker(cmMakefile* mf):
Makefile(mf), Depth(0)
{
this->Makefile->PushLoopBlock();
}
cmForEachFunctionBlocker::~cmForEachFunctionBlocker()
{
this->Makefile->PopLoopBlock();
}
bool cmForEachFunctionBlocker::
IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
cmExecutionStatus &inStatus)
@ -27,8 +38,6 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
// if this is the endofreach for this statement
if (!this->Depth)
{
cmMakefile::LoopBlockPop loopBlockPop(&mf);
// Remove the function blocker for this scope or bail.
cmsys::auto_ptr<cmFunctionBlocker>
fb(mf.RemoveFunctionBlocker(this, lff));
@ -130,7 +139,7 @@ bool cmForEachCommand
}
// create a function blocker
cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker();
cmForEachFunctionBlocker *f = new cmForEachFunctionBlocker(this->Makefile);
if ( args.size() > 1 )
{
if ( args[1] == "RANGE" )
@ -206,15 +215,14 @@ bool cmForEachCommand
}
this->Makefile->AddFunctionBlocker(f);
this->Makefile->PushLoopBlock();
return true;
}
//----------------------------------------------------------------------------
bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args)
{
cmsys::auto_ptr<cmForEachFunctionBlocker> f(new cmForEachFunctionBlocker());
cmsys::auto_ptr<cmForEachFunctionBlocker>
f(new cmForEachFunctionBlocker(this->Makefile));
f->Args.push_back(args[0]);
enum Doing { DoingNone, DoingLists, DoingItems };
@ -252,7 +260,5 @@ bool cmForEachCommand::HandleInMode(std::vector<std::string> const& args)
this->Makefile->AddFunctionBlocker(f.release()); // TODO: pass auto_ptr
this->Makefile->PushLoopBlock();
return true;
}

View File

@ -19,8 +19,8 @@
class cmForEachFunctionBlocker : public cmFunctionBlocker
{
public:
cmForEachFunctionBlocker() {this->Depth = 0;}
virtual ~cmForEachFunctionBlocker() {}
cmForEachFunctionBlocker(cmMakefile* mf);
~cmForEachFunctionBlocker();
virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
cmMakefile &mf,
cmExecutionStatus &);
@ -29,6 +29,7 @@ public:
std::vector<std::string> Args;
std::vector<cmListFileFunction> Functions;
private:
cmMakefile* Makefile;
int Depth;
};

View File

@ -3284,7 +3284,6 @@ void cmMakefile::PopFunctionBlockerBarrier(bool reportError)
this->FunctionBlockerBarriers.back();
while(this->FunctionBlockers.size() > barrier)
{
cmMakefile::LoopBlockPop loopBlockPop(this);
cmsys::auto_ptr<cmFunctionBlocker> fb(this->FunctionBlockers.back());
this->FunctionBlockers.pop_back();
if(reportError)

View File

@ -125,15 +125,6 @@ public:
};
friend class LexicalPushPop;
class LoopBlockPop
{
public:
LoopBlockPop(cmMakefile* mf) { this->Makefile = mf; }
~LoopBlockPop() { this->Makefile->PopLoopBlock(); }
private:
cmMakefile* Makefile;
};
/**
* Try running cmake and building a file. This is used for dynalically
* loaded commands, not as part of the usual build process.

View File

@ -12,6 +12,17 @@
#include "cmWhileCommand.h"
#include "cmConditionEvaluator.h"
cmWhileFunctionBlocker::cmWhileFunctionBlocker(cmMakefile* mf):
Makefile(mf), Depth(0)
{
this->Makefile->PushLoopBlock();
}
cmWhileFunctionBlocker::~cmWhileFunctionBlocker()
{
this->Makefile->PopLoopBlock();
}
bool cmWhileFunctionBlocker::
IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
cmExecutionStatus &inStatus)
@ -27,8 +38,6 @@ IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &mf,
// if this is the endwhile for this while loop then execute
if (!this->Depth)
{
cmMakefile::LoopBlockPop loopBlockPop(&mf);
// Remove the function blocker for this scope or bail.
cmsys::auto_ptr<cmFunctionBlocker>
fb(mf.RemoveFunctionBlocker(this, lff));
@ -140,12 +149,10 @@ bool cmWhileCommand
}
// create a function blocker
cmWhileFunctionBlocker *f = new cmWhileFunctionBlocker();
cmWhileFunctionBlocker *f = new cmWhileFunctionBlocker(this->Makefile);
f->Args = args;
this->Makefile->AddFunctionBlocker(f);
this->Makefile->PushLoopBlock();
return true;
}

View File

@ -19,8 +19,8 @@
class cmWhileFunctionBlocker : public cmFunctionBlocker
{
public:
cmWhileFunctionBlocker() {this->Depth=0;}
virtual ~cmWhileFunctionBlocker() {}
cmWhileFunctionBlocker(cmMakefile* mf);
~cmWhileFunctionBlocker();
virtual bool IsFunctionBlocked(const cmListFileFunction& lff,
cmMakefile &mf,
cmExecutionStatus &);
@ -29,6 +29,7 @@ public:
std::vector<cmListFileArgument> Args;
std::vector<cmListFileFunction> Functions;
private:
cmMakefile* Makefile;
int Depth;
};

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
^CMake Error at CMakeLists.txt:[0-9]+ \(include\):
A logical block opening on the line
.*/Tests/RunCMake/Syntax/FunctionUnmatched.cmake:[0-9]+ \(function\)
is not closed.$

View File

@ -0,0 +1,2 @@
function(f)
#endfunction() # missing

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,6 @@
^CMake Error at CMakeLists.txt:[0-9]+ \(include\):
A logical block opening on the line
.*/Tests/RunCMake/Syntax/MacroUnmatched.cmake:[0-9]+ \(macro\)
is not closed.$

View File

@ -0,0 +1,2 @@
macro(m)
#endmacro() # missing

View File

@ -110,5 +110,7 @@ run_cmake(CMP0053-NameWithEscapedSpacesQuoted)
run_cmake(CMP0053-NameWithEscapedTabsQuoted)
# Function and macro tests.
run_cmake(FunctionUnmatched)
run_cmake(FunctionUnmatchedForeach)
run_cmake(MacroUnmatched)
run_cmake(MacroUnmatchedForeach)