Fixed #5831 (FP in 1.65: call of pure virtual function 'throw' in destructor)

This commit is contained in:
Robert Reif 2014-05-20 06:10:34 +02:00 committed by Daniel Marjamäki
parent d3d3803ae4
commit e993e2927c
5 changed files with 128 additions and 38 deletions

View File

@ -43,13 +43,19 @@ void CheckExceptionSafety::destructors()
if (j) {
// only looking for destructors
if (j->type == Function::eDestructor) {
// Inspect this destructor..
// Inspect this destructor.
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
// Skip try blocks
if (Token::simpleMatch(tok, "try {")) {
tok = tok->next()->link();
}
// Skip uncaught execptions
if (Token::simpleMatch(tok, "if ( ! std :: uncaught_exception ( ) ) {")) {
tok = tok->next()->link(); // end of if ( ... )
tok = tok->next()->link(); // end of { ... }
}
// throw found within a destructor
if (tok->str() == "throw") {
destructorsError(tok);

View File

@ -454,8 +454,10 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
}
// noexcept;
// noexcept = 0;
// const noexcept;
else if (Token::Match(end, ") const| noexcept ;")) {
// const noexcept = 0;
else if (Token::Match(end, ") const| noexcept ;|=")) {
function.isNoExcept = true;
if (end->next()->str() == "const")
@ -463,47 +465,43 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
else
tok = end->tokAt(2);
scope->functionList.push_back(function);
}
// noexcept const;
else if (Token::simpleMatch(end, ") noexcept const ;")) {
function.isNoExcept = true;
tok = end->tokAt(3);
if (Token::Match(tok, "= %any% ;")) {
function.isPure = true;
tok = tok->tokAt(2);
}
scope->functionList.push_back(function);
}
// noexcept(...);
// noexcept(...) const;
else if (Token::simpleMatch(end, ") noexcept (") &&
Token::Match(end->linkAt(2), ") const| ;")) {
function.isNoExcept = true;
if (end->linkAt(2)->strAt(1) == "const")
tok = end->linkAt(2)->tokAt(2);
else
tok = end->linkAt(2)->next();
scope->functionList.push_back(function);
}
// noexcept(...) = 0;
// const noexcept(...);
else if (Token::simpleMatch(end, ") const noexcept (") &&
Token::simpleMatch(end->linkAt(3), ") ;")) {
// const noexcept(...) = 0;
else if (Token::Match(end, ") const| noexcept (") &&
(end->next()->str() == "const" ? Token::Match(end->linkAt(3), ") ;|=") :
Token::Match(end->linkAt(2), ") ;|="))) {
function.isNoExcept = true;
tok = end->linkAt(3)->next();
if (end->next()->str() == "const")
tok = end->tokAt(3);
else
tok = end->tokAt(2);
if (Token::Match(tok, "= %any% ;")) {
function.isPure = true;
tok = tok->tokAt(2);
}
scope->functionList.push_back(function);
}
// throw()
// const throw()
// throw();
// throw() = 0;
// const throw();
// const throw() = 0;
else if (Token::Match(end, ") const| throw (") &&
(end->next()->str() == "const" ? Token::simpleMatch(end->linkAt(3), ") ;") :
Token::simpleMatch(end->linkAt(2), ") ;"))) {
(end->next()->str() == "const" ? Token::Match(end->linkAt(3), ") ;|=") :
Token::Match(end->linkAt(2), ") ;|="))) {
function.isThrow = true;
if (end->next()->str() == "const") {
@ -516,6 +514,11 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
tok = end->linkAt(2)->next();
}
if (Token::Match(tok, "= %any% ;")) {
function.isPure = true;
tok = tok->tokAt(2);
}
scope->functionList.push_back(function);
}
@ -1097,10 +1100,10 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
(Token::Match(tok2, "%var% (") && tok2->isUpperCaseName() && tok2->next()->link()->strAt(1) == "{") ||
Token::Match(tok2, ": ::| %var% (|::|<|{") ||
Token::Match(tok2, "= delete|default ;") ||
Token::Match(tok2, "const| noexcept const| {|:|;") ||
Token::Match(tok2, "const| noexcept {|:|;|=") ||
(Token::Match(tok2, "const| noexcept|throw (") &&
tok2->str() == "const" ? (tok2->tokAt(2) && Token::Match(tok2->linkAt(2), ") const| {|:|;")) :
(tok2->next() && Token::Match(tok2->next()->link(), ") const| {|:|;"))))) {
tok2->str() == "const" ? (tok2->tokAt(2) && Token::Match(tok2->linkAt(2), ") const| {|:|;|=")) :
(tok2->next() && Token::Match(tok2->next()->link(), ") {|:|;|="))))) {
*funcStart = tok;
*argStart = tok->next();
return true;

View File

@ -5903,6 +5903,14 @@ private:
"{if (b) pure();}\n");
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
// ticket # 5831
checkPureVirtualFunctionCall("class abc {\n"
"public:\n"
" virtual ~abc() throw() {}\n"
" virtual void def(void* g) throw () = 0;\n"
"};\n");
ASSERT_EQUALS("", errout.str());
}
void pureVirtualFunctionCallOtherClass() {

View File

@ -100,6 +100,15 @@ private:
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("class x {\n"
" ~x() {\n"
" if(!std::uncaught_exception()) {\n"
" throw e;\n"
" }\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void deallocThrow1() {

View File

@ -235,6 +235,9 @@ private:
TEST_CASE(noexceptFunction3);
TEST_CASE(noexceptFunction4);
TEST_CASE(throwFunction1);
TEST_CASE(throwFunction2);
TEST_CASE(nothrowAttributeFunction);
TEST_CASE(nothrowDeclspecFunction);
}
@ -2051,7 +2054,7 @@ private:
}
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
ASSERT_EQUALS(true, x != nullptr); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(true, x->isNoExcept);
void noexceptFunction1() {
@ -2095,10 +2098,10 @@ private:
" void func6() const noexcept { }\n"
" void func7() const noexcept(true);\n"
" void func8() const noexcept(true) { }\n"
" void func9() noexcept const;\n"
" void func10() noexcept const { }\n"
" void func11() noexcept(true) const;\n"
" void func12() noexcept(true) const { }\n"
" void func9() noexcept = 0;\n"
" void func10() noexcept = 0;\n"
" void func11() const noexcept(true) = 0;\n"
" void func12() const noexcept(true) = 0;\n"
"};");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
@ -2147,6 +2150,67 @@ private:
}
}
#define FUNC_THROW(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(true, x->isThrow);
void throwFunction1() {
GET_SYMBOL_DB("void func1() throw();\n"
"void func2() throw() { }\n"
"void func3() throw(int);\n"
"void func4() throw(int) { }\n");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
if (db) {
FUNC_THROW(func1);
FUNC_THROW(func2);
FUNC_THROW(func3);
FUNC_THROW(func4);
}
}
#define CLASS_FUNC_THROW(x, y) const Function *x = findFunctionByName(#x, y); \
ASSERT_EQUALS(true, x != nullptr); \
if (x) ASSERT_EQUALS(true, x->isThrow);
void throwFunction2() {
GET_SYMBOL_DB("struct Fred {\n"
" void func1() throw();\n"
" void func2() throw() { }\n"
" void func3() throw(int);\n"
" void func4() throw(int) { }\n"
" void func5() const throw();\n"
" void func6() const throw() { }\n"
" void func7() const throw(int);\n"
" void func8() const throw(int) { }\n"
" void func9() throw() = 0;\n"
" void func10() throw(int) = 0;\n"
" void func11() const throw() = 0;\n"
" void func12() const throw(int) = 0;\n"
"};");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
if (db) {
const Scope *fred = db->findScopeByName("Fred");
ASSERT_EQUALS(true, fred != nullptr);
if (fred) {
CLASS_FUNC_THROW(func1, fred);
CLASS_FUNC_THROW(func2, fred);
CLASS_FUNC_THROW(func3, fred);
CLASS_FUNC_THROW(func4, fred);
CLASS_FUNC_THROW(func5, fred);
CLASS_FUNC_THROW(func6, fred);
CLASS_FUNC_THROW(func7, fred);
CLASS_FUNC_THROW(func8, fred);
CLASS_FUNC_THROW(func9, fred);
CLASS_FUNC_THROW(func10, fred);
CLASS_FUNC_THROW(func11, fred);
CLASS_FUNC_THROW(func12, fred);
}
}
}
void nothrowAttributeFunction() {
GET_SYMBOL_DB("void func() __attribute__((nothrow));\n"
"void func() { }\n");