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:
parent
1b4141cbe5
commit
80a486dda0
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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: "
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue