Fixed #5831 (FP in 1.65: call of pure virtual function 'throw' in destructor)
This commit is contained in:
parent
d3d3803ae4
commit
e993e2927c
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue