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) { if (j) {
// only looking for destructors // only looking for destructors
if (j->type == Function::eDestructor) { if (j->type == Function::eDestructor) {
// Inspect this destructor.. // Inspect this destructor.
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
// Skip try blocks // Skip try blocks
if (Token::simpleMatch(tok, "try {")) { if (Token::simpleMatch(tok, "try {")) {
tok = tok->next()->link(); 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 // throw found within a destructor
if (tok->str() == "throw") { if (tok->str() == "throw") {
destructorsError(tok); destructorsError(tok);

View File

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

View File

@ -5903,6 +5903,14 @@ private:
"{if (b) pure();}\n"); "{if (b) pure();}\n");
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str()); 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() { void pureVirtualFunctionCallOtherClass() {

View File

@ -100,6 +100,15 @@ private:
" }\n" " }\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); 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() { void deallocThrow1() {

View File

@ -235,6 +235,9 @@ private:
TEST_CASE(noexceptFunction3); TEST_CASE(noexceptFunction3);
TEST_CASE(noexceptFunction4); TEST_CASE(noexceptFunction4);
TEST_CASE(throwFunction1);
TEST_CASE(throwFunction2);
TEST_CASE(nothrowAttributeFunction); TEST_CASE(nothrowAttributeFunction);
TEST_CASE(nothrowDeclspecFunction); TEST_CASE(nothrowDeclspecFunction);
} }
@ -2051,7 +2054,7 @@ private:
} }
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \ #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); if (x) ASSERT_EQUALS(true, x->isNoExcept);
void noexceptFunction1() { void noexceptFunction1() {
@ -2095,10 +2098,10 @@ private:
" void func6() const noexcept { }\n" " void func6() const noexcept { }\n"
" void func7() const noexcept(true);\n" " void func7() const noexcept(true);\n"
" void func8() const noexcept(true) { }\n" " void func8() const noexcept(true) { }\n"
" void func9() noexcept const;\n" " void func9() noexcept = 0;\n"
" void func10() noexcept const { }\n" " void func10() noexcept = 0;\n"
" void func11() noexcept(true) const;\n" " void func11() const noexcept(true) = 0;\n"
" void func12() noexcept(true) const { }\n" " void func12() const noexcept(true) = 0;\n"
"};"); "};");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null 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() { void nothrowAttributeFunction() {
GET_SYMBOL_DB("void func() __attribute__((nothrow));\n" GET_SYMBOL_DB("void func() __attribute__((nothrow));\n"
"void func() { }\n"); "void func() { }\n");