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) {
|
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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in New Issue