Skip to content

Commit e993e29

Browse files
IOBYTEdanmar
authored andcommitted
Fixed danmar#5831 (FP in 1.65: call of pure virtual function 'throw' in destructor)
1 parent d3d3803 commit e993e29

File tree

5 files changed

+127
-37
lines changed

5 files changed

+127
-37
lines changed

lib/checkexceptionsafety.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,19 @@ void CheckExceptionSafety::destructors()
4343
if (j) {
4444
// only looking for destructors
4545
if (j->type == Function::eDestructor) {
46-
// Inspect this destructor..
46+
// Inspect this destructor.
4747
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
4848
// Skip try blocks
4949
if (Token::simpleMatch(tok, "try {")) {
5050
tok = tok->next()->link();
5151
}
5252

53+
// Skip uncaught execptions
54+
if (Token::simpleMatch(tok, "if ( ! std :: uncaught_exception ( ) ) {")) {
55+
tok = tok->next()->link(); // end of if ( ... )
56+
tok = tok->next()->link(); // end of { ... }
57+
}
58+
5359
// throw found within a destructor
5460
if (tok->str() == "throw") {
5561
destructorsError(tok);

lib/symboldatabase.cpp

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -454,56 +454,54 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
454454
}
455455

456456
// noexcept;
457+
// noexcept = 0;
457458
// const noexcept;
458-
else if (Token::Match(end, ") const| noexcept ;")) {
459+
// const noexcept = 0;
460+
else if (Token::Match(end, ") const| noexcept ;|=")) {
459461
function.isNoExcept = true;
460462

461463
if (end->next()->str() == "const")
462464
tok = end->tokAt(3);
463465
else
464466
tok = end->tokAt(2);
465467

466-
scope->functionList.push_back(function);
467-
}
468-
469-
// noexcept const;
470-
else if (Token::simpleMatch(end, ") noexcept const ;")) {
471-
function.isNoExcept = true;
472-
473-
tok = end->tokAt(3);
468+
if (Token::Match(tok, "= %any% ;")) {
469+
function.isPure = true;
470+
tok = tok->tokAt(2);
471+
}
474472

475473
scope->functionList.push_back(function);
476474
}
477475

478476
// noexcept(...);
479-
// noexcept(...) const;
480-
else if (Token::simpleMatch(end, ") noexcept (") &&
481-
Token::Match(end->linkAt(2), ") const| ;")) {
477+
// noexcept(...) = 0;
478+
// const noexcept(...);
479+
// const noexcept(...) = 0;
480+
else if (Token::Match(end, ") const| noexcept (") &&
481+
(end->next()->str() == "const" ? Token::Match(end->linkAt(3), ") ;|=") :
482+
Token::Match(end->linkAt(2), ") ;|="))) {
482483
function.isNoExcept = true;
483484

484-
if (end->linkAt(2)->strAt(1) == "const")
485-
tok = end->linkAt(2)->tokAt(2);
485+
if (end->next()->str() == "const")
486+
tok = end->tokAt(3);
486487
else
487-
tok = end->linkAt(2)->next();
488-
489-
scope->functionList.push_back(function);
490-
}
491-
492-
// const noexcept(...);
493-
else if (Token::simpleMatch(end, ") const noexcept (") &&
494-
Token::simpleMatch(end->linkAt(3), ") ;")) {
495-
function.isNoExcept = true;
488+
tok = end->tokAt(2);
496489

497-
tok = end->linkAt(3)->next();
490+
if (Token::Match(tok, "= %any% ;")) {
491+
function.isPure = true;
492+
tok = tok->tokAt(2);
493+
}
498494

499495
scope->functionList.push_back(function);
500496
}
501497

502-
// throw()
503-
// const throw()
498+
// throw();
499+
// throw() = 0;
500+
// const throw();
501+
// const throw() = 0;
504502
else if (Token::Match(end, ") const| throw (") &&
505-
(end->next()->str() == "const" ? Token::simpleMatch(end->linkAt(3), ") ;") :
506-
Token::simpleMatch(end->linkAt(2), ") ;"))) {
503+
(end->next()->str() == "const" ? Token::Match(end->linkAt(3), ") ;|=") :
504+
Token::Match(end->linkAt(2), ") ;|="))) {
507505
function.isThrow = true;
508506

509507
if (end->next()->str() == "const") {
@@ -516,6 +514,11 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
516514
tok = end->linkAt(2)->next();
517515
}
518516

517+
if (Token::Match(tok, "= %any% ;")) {
518+
function.isPure = true;
519+
tok = tok->tokAt(2);
520+
}
521+
519522
scope->functionList.push_back(function);
520523
}
521524

@@ -1097,10 +1100,10 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
10971100
(Token::Match(tok2, "%var% (") && tok2->isUpperCaseName() && tok2->next()->link()->strAt(1) == "{") ||
10981101
Token::Match(tok2, ": ::| %var% (|::|<|{") ||
10991102
Token::Match(tok2, "= delete|default ;") ||
1100-
Token::Match(tok2, "const| noexcept const| {|:|;") ||
1103+
Token::Match(tok2, "const| noexcept {|:|;|=") ||
11011104
(Token::Match(tok2, "const| noexcept|throw (") &&
1102-
tok2->str() == "const" ? (tok2->tokAt(2) && Token::Match(tok2->linkAt(2), ") const| {|:|;")) :
1103-
(tok2->next() && Token::Match(tok2->next()->link(), ") const| {|:|;"))))) {
1105+
tok2->str() == "const" ? (tok2->tokAt(2) && Token::Match(tok2->linkAt(2), ") const| {|:|;|=")) :
1106+
(tok2->next() && Token::Match(tok2->next()->link(), ") {|:|;|="))))) {
11041107
*funcStart = tok;
11051108
*argStart = tok->next();
11061109
return true;

test/testclass.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5903,6 +5903,14 @@ class TestClass : public TestFixture {
59035903
"{if (b) pure();}\n");
59045904
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
59055905

5906+
// ticket # 5831
5907+
checkPureVirtualFunctionCall("class abc {\n"
5908+
"public:\n"
5909+
" virtual ~abc() throw() {}\n"
5910+
" virtual void def(void* g) throw () = 0;\n"
5911+
"};\n");
5912+
ASSERT_EQUALS("", errout.str());
5913+
59065914
}
59075915

59085916
void pureVirtualFunctionCallOtherClass() {

test/testexceptionsafety.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,15 @@ class TestExceptionSafety : public TestFixture {
100100
" }\n"
101101
"}");
102102
ASSERT_EQUALS("", errout.str());
103+
104+
check("class x {\n"
105+
" ~x() {\n"
106+
" if(!std::uncaught_exception()) {\n"
107+
" throw e;\n"
108+
" }\n"
109+
" }\n"
110+
"}");
111+
ASSERT_EQUALS("", errout.str());
103112
}
104113

105114
void deallocThrow1() {

test/testsymboldatabase.cpp

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,9 @@ class TestSymbolDatabase: public TestFixture {
235235
TEST_CASE(noexceptFunction3);
236236
TEST_CASE(noexceptFunction4);
237237

238+
TEST_CASE(throwFunction1);
239+
TEST_CASE(throwFunction2);
240+
238241
TEST_CASE(nothrowAttributeFunction);
239242
TEST_CASE(nothrowDeclspecFunction);
240243
}
@@ -2051,7 +2054,7 @@ class TestSymbolDatabase: public TestFixture {
20512054
}
20522055

20532056
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
2054-
ASSERT_EQUALS(true, x != nullptr); \
2057+
ASSERT_EQUALS(true, x != nullptr); \
20552058
if (x) ASSERT_EQUALS(true, x->isNoExcept);
20562059

20572060
void noexceptFunction1() {
@@ -2095,10 +2098,10 @@ class TestSymbolDatabase: public TestFixture {
20952098
" void func6() const noexcept { }\n"
20962099
" void func7() const noexcept(true);\n"
20972100
" void func8() const noexcept(true) { }\n"
2098-
" void func9() noexcept const;\n"
2099-
" void func10() noexcept const { }\n"
2100-
" void func11() noexcept(true) const;\n"
2101-
" void func12() noexcept(true) const { }\n"
2101+
" void func9() noexcept = 0;\n"
2102+
" void func10() noexcept = 0;\n"
2103+
" void func11() const noexcept(true) = 0;\n"
2104+
" void func12() const noexcept(true) = 0;\n"
21022105
"};");
21032106
ASSERT_EQUALS("", errout.str());
21042107
ASSERT_EQUALS(true, db != nullptr); // not null
@@ -2147,6 +2150,67 @@ class TestSymbolDatabase: public TestFixture {
21472150
}
21482151
}
21492152

2153+
#define FUNC_THROW(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
2154+
ASSERT_EQUALS(true, x != nullptr); \
2155+
if (x) ASSERT_EQUALS(true, x->isThrow);
2156+
2157+
void throwFunction1() {
2158+
GET_SYMBOL_DB("void func1() throw();\n"
2159+
"void func2() throw() { }\n"
2160+
"void func3() throw(int);\n"
2161+
"void func4() throw(int) { }\n");
2162+
ASSERT_EQUALS("", errout.str());
2163+
ASSERT_EQUALS(true, db != nullptr); // not null
2164+
2165+
if (db) {
2166+
FUNC_THROW(func1);
2167+
FUNC_THROW(func2);
2168+
FUNC_THROW(func3);
2169+
FUNC_THROW(func4);
2170+
}
2171+
}
2172+
2173+
#define CLASS_FUNC_THROW(x, y) const Function *x = findFunctionByName(#x, y); \
2174+
ASSERT_EQUALS(true, x != nullptr); \
2175+
if (x) ASSERT_EQUALS(true, x->isThrow);
2176+
void throwFunction2() {
2177+
GET_SYMBOL_DB("struct Fred {\n"
2178+
" void func1() throw();\n"
2179+
" void func2() throw() { }\n"
2180+
" void func3() throw(int);\n"
2181+
" void func4() throw(int) { }\n"
2182+
" void func5() const throw();\n"
2183+
" void func6() const throw() { }\n"
2184+
" void func7() const throw(int);\n"
2185+
" void func8() const throw(int) { }\n"
2186+
" void func9() throw() = 0;\n"
2187+
" void func10() throw(int) = 0;\n"
2188+
" void func11() const throw() = 0;\n"
2189+
" void func12() const throw(int) = 0;\n"
2190+
"};");
2191+
ASSERT_EQUALS("", errout.str());
2192+
ASSERT_EQUALS(true, db != nullptr); // not null
2193+
2194+
if (db) {
2195+
const Scope *fred = db->findScopeByName("Fred");
2196+
ASSERT_EQUALS(true, fred != nullptr);
2197+
if (fred) {
2198+
CLASS_FUNC_THROW(func1, fred);
2199+
CLASS_FUNC_THROW(func2, fred);
2200+
CLASS_FUNC_THROW(func3, fred);
2201+
CLASS_FUNC_THROW(func4, fred);
2202+
CLASS_FUNC_THROW(func5, fred);
2203+
CLASS_FUNC_THROW(func6, fred);
2204+
CLASS_FUNC_THROW(func7, fred);
2205+
CLASS_FUNC_THROW(func8, fred);
2206+
CLASS_FUNC_THROW(func9, fred);
2207+
CLASS_FUNC_THROW(func10, fred);
2208+
CLASS_FUNC_THROW(func11, fred);
2209+
CLASS_FUNC_THROW(func12, fred);
2210+
}
2211+
}
2212+
}
2213+
21502214
void nothrowAttributeFunction() {
21512215
GET_SYMBOL_DB("void func() __attribute__((nothrow));\n"
21522216
"void func() { }\n");

0 commit comments

Comments
 (0)