Fix #11167 FP virtual call in destructor even though class is final / Delete 'final' from specializations (#4383)

* Add 'final' keyword

* Delete 'final' from specializations

* Fix #11167 FP virtual call in destructor even though class is final

* Fix test
This commit is contained in:
chrchr-github 2022-08-19 18:26:00 +02:00 committed by GitHub
parent 1b4141cbe5
commit 80a486dda0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 47 additions and 6 deletions

View File

@ -2588,11 +2588,13 @@ void CheckClass::checkVirtualFunctionCallInConstructor()
getFirstVirtualFunctionCallStack(virtualFunctionCallsMap, callToken, callstack);
if (callstack.empty())
continue;
if (!(callstack.back()->function()->hasVirtualSpecifier() || callstack.back()->function()->hasOverrideSpecifier()))
const Function* const func = callstack.back()->function();
if (!(func->hasVirtualSpecifier() || func->hasOverrideSpecifier()))
continue;
if (callstack.back()->function()->isPure())
if (func->isPure())
pureVirtualFunctionCallInConstructorError(scope->function, callstack, callstack.back()->str());
else if (!callstack.back()->function()->hasFinalSpecifier())
else if (!func->hasFinalSpecifier() &&
!(func->nestedIn && func->nestedIn->classDef && func->nestedIn->classDef->isFinalType()))
virtualFunctionCallInConstructorError(scope->function, callstack, callstack.back()->str());
}
}

View File

@ -680,6 +680,13 @@ public:
setFlag(fIsSimplifedScope, b);
}
bool isFinalType() const {
return getFlag(fIsFinalType);
}
void isFinalType(bool b) {
setFlag(fIsFinalType, b);
}
bool isBitfield() const {
return mImpl->mBits > 0;
}
@ -1287,6 +1294,7 @@ private:
fIsIncompleteConstant = (1ULL << 36),
fIsRestrict = (1ULL << 37), // Is this a restrict pointer type
fIsSimplifiedTypedef = (1ULL << 38),
fIsFinalType = (1ULL << 39), // Is this a type with final specifier
};
Token::Type mTokType;

View File

@ -8427,8 +8427,17 @@ void Tokenizer::simplifyKeyword()
// final:
// 1) struct name final { }; <- struct is final
if (Token::Match(tok->previous(), "struct|class|union %type% final [:{]")) {
tok->deleteNext();
if (Token::Match(tok->previous(), "struct|class|union %type%")) {
Token* finalTok = tok->next();
if (Token::simpleMatch(finalTok, "<")) { // specialization
finalTok = finalTok->findClosingBracket();
if (finalTok)
finalTok = finalTok->next();
}
if (Token::Match(finalTok, "final [:{]")) {
finalTok->deleteThis();
tok->previous()->isFinalType(true);
}
}
// noexcept -> noexcept(true)

View File

@ -7439,6 +7439,14 @@ private:
"}\n"
"S::~S() = default;\n");
ASSERT_EQUALS("", errout.str());
checkVirtualFunctionCall("struct Base: { virtual void wibble() = 0; virtual ~Base() {} };\n" // #11167
"struct D final : public Base {\n"
" void wibble() override;\n"
" D() {}\n"
" virtual ~D() { wibble(); }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
}
void pureVirtualFunctionCall() {

View File

@ -5531,7 +5531,7 @@ private:
"private:\n"
" std::basic_ostream<unsigned char> &outputStream_;\n"
"};";
const char expected[] = "struct OutputU16<unsignedchar> final { "
const char expected[] = "struct OutputU16<unsignedchar> { "
"explicit OutputU16<unsignedchar> ( std :: basic_ostream < unsigned char > & t ) : outputStream_ ( t ) { } "
"void operator() ( unsigned short ) const ; "
"private: "

View File

@ -156,6 +156,7 @@ private:
TEST_CASE(varid_templateParameter); // #7046 set varid for "X": std::array<int,X> Y;
TEST_CASE(varid_templateParameterFunctionPointer); // #11050
TEST_CASE(varid_templateUsing); // #5781 #7273
TEST_CASE(varid_templateSpecializationFinal);
TEST_CASE(varid_not_template_in_condition); // #7988
TEST_CASE(varid_cppcast); // #6190
TEST_CASE(varid_variadicFunc);
@ -2379,6 +2380,19 @@ private:
tokenize(code));
}
void varid_templateSpecializationFinal() {
const char code[] = "template <typename T>\n"
"struct S;\n"
"template <>\n"
"struct S<void> final {};\n";
ASSERT_EQUALS("4: struct S<void> ;\n"
"1: template < typename T >\n"
"2: struct S ;\n"
"3:\n"
"4: struct S<void> { } ;\n",
tokenize(code));
}
void varid_not_template_in_condition() {
const char code1[] = "void f() { if (x<a||x>b); }";
ASSERT_EQUALS("1: void f ( ) { if ( x < a || x > b ) { ; } }\n", tokenize(code1));