Fixed #5756 (declspec(nothrow) not supported)
This commit is contained in:
parent
7d583e639c
commit
ae96491d6c
|
@ -253,6 +253,13 @@ void CheckExceptionSafety::nothrowThrows()
|
||||||
if (throws)
|
if (throws)
|
||||||
nothrowAttributeThrowError(throws);
|
nothrowAttributeThrowError(throws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check __declspec(nothrow) functions
|
||||||
|
else if (scope->function && scope->function->isDeclspecNothrow()) {
|
||||||
|
const Token *throws = functionThrows(scope->function);
|
||||||
|
if (throws)
|
||||||
|
nothrowDeclspecThrowError(throws);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,11 @@ private:
|
||||||
reportError(tok, Severity::error, "exceptThrowInAttributeNoThrowFunction", "Exception thrown in __attribute__((nothrow)) function.");
|
reportError(tok, Severity::error, "exceptThrowInAttributeNoThrowFunction", "Exception thrown in __attribute__((nothrow)) function.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Don't throw exceptions in __declspec(nothrow) functions */
|
||||||
|
void nothrowDeclspecThrowError(const Token * const tok) {
|
||||||
|
reportError(tok, Severity::error, "exceptThrowInDeclspecNoThrowFunction", "Exception thrown in __declspec(nothrow) function.");
|
||||||
|
}
|
||||||
|
|
||||||
/** Missing exception specification */
|
/** Missing exception specification */
|
||||||
void unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname) {
|
void unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname) {
|
||||||
std::string str1(tok1 ? tok1->str() : "foo");
|
std::string str1(tok1 ? tok1->str() : "foo");
|
||||||
|
@ -145,6 +150,7 @@ private:
|
||||||
c.noexceptThrowError(0);
|
c.noexceptThrowError(0);
|
||||||
c.nothrowThrowError(0);
|
c.nothrowThrowError(0);
|
||||||
c.nothrowAttributeThrowError(0);
|
c.nothrowAttributeThrowError(0);
|
||||||
|
c.nothrowDeclspecThrowError(0);
|
||||||
c.unhandledExceptionSpecificationError(0, 0, "funcname");
|
c.unhandledExceptionSpecificationError(0, 0, "funcname");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +169,7 @@ private:
|
||||||
"* Throwing exception in noexcept function\n"
|
"* Throwing exception in noexcept function\n"
|
||||||
"* Throwing exception in nothrow() function\n"
|
"* Throwing exception in nothrow() function\n"
|
||||||
"* Throwing exception in __attribute__((nothrow)) function\n"
|
"* Throwing exception in __attribute__((nothrow)) function\n"
|
||||||
|
"* Throwing exception in __declspec(nothrow) function\n"
|
||||||
"* Unhandled exception specification when calling function foo()\n";
|
"* Unhandled exception specification when calling function foo()\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1365,6 +1365,7 @@ Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, co
|
||||||
const_cast<Token *>(tok)->isAttributePure(i->tokenDef->isAttributePure());
|
const_cast<Token *>(tok)->isAttributePure(i->tokenDef->isAttributePure());
|
||||||
const_cast<Token *>(tok)->isAttributeConst(i->tokenDef->isAttributeConst());
|
const_cast<Token *>(tok)->isAttributeConst(i->tokenDef->isAttributeConst());
|
||||||
const_cast<Token *>(tok)->isAttributeNothrow(i->tokenDef->isAttributeNothrow());
|
const_cast<Token *>(tok)->isAttributeNothrow(i->tokenDef->isAttributeNothrow());
|
||||||
|
const_cast<Token *>(tok)->isDeclspecNothrow(i->tokenDef->isDeclspecNothrow());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1916,6 +1917,7 @@ void SymbolDatabase::printOut(const char *title) const
|
||||||
std::cerr << " isAttributeConst: " << (func->isAttributeConst() ? "true" : "false") << std::endl;
|
std::cerr << " isAttributeConst: " << (func->isAttributeConst() ? "true" : "false") << std::endl;
|
||||||
std::cerr << " isAttributePure: " << (func->isAttributePure() ? "true" : "false") << std::endl;
|
std::cerr << " isAttributePure: " << (func->isAttributePure() ? "true" : "false") << std::endl;
|
||||||
std::cerr << " isAttributeNothrow: " << (func->isAttributeNothrow() ? "true" : "false") << std::endl;
|
std::cerr << " isAttributeNothrow: " << (func->isAttributeNothrow() ? "true" : "false") << std::endl;
|
||||||
|
std::cerr << " isDeclspecNothrow: " << (func->isDeclspecNothrow() ? "true" : "false") << std::endl;
|
||||||
std::cout << " noexceptArg: " << (func->noexceptArg ? func->noexceptArg->str() : "none") << std::endl;
|
std::cout << " noexceptArg: " << (func->noexceptArg ? func->noexceptArg->str() : "none") << std::endl;
|
||||||
std::cout << " throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
|
std::cout << " throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
|
||||||
std::cout << " tokenDef: " << func->tokenDef->str() << " " <<_tokenizer->list.fileLine(func->tokenDef) << std::endl;
|
std::cout << " tokenDef: " << func->tokenDef->str() << " " <<_tokenizer->list.fileLine(func->tokenDef) << std::endl;
|
||||||
|
|
|
@ -593,6 +593,9 @@ public:
|
||||||
bool isAttributeNothrow() const {
|
bool isAttributeNothrow() const {
|
||||||
return tokenDef->isAttributeNothrow();
|
return tokenDef->isAttributeNothrow();
|
||||||
}
|
}
|
||||||
|
bool isDeclspecNothrow() const {
|
||||||
|
return tokenDef->isDeclspecNothrow();
|
||||||
|
}
|
||||||
|
|
||||||
const Token *tokenDef; // function name token in class definition
|
const Token *tokenDef; // function name token in class definition
|
||||||
const Token *argDef; // function argument start '(' in class definition
|
const Token *argDef; // function argument start '(' in class definition
|
||||||
|
|
|
@ -57,6 +57,7 @@ Token::Token(Token **t) :
|
||||||
_isAttributePure(false),
|
_isAttributePure(false),
|
||||||
_isAttributeConst(false),
|
_isAttributeConst(false),
|
||||||
_isAttributeNothrow(false),
|
_isAttributeNothrow(false),
|
||||||
|
_isDeclspecNothrow(false),
|
||||||
_astOperand1(nullptr),
|
_astOperand1(nullptr),
|
||||||
_astOperand2(nullptr),
|
_astOperand2(nullptr),
|
||||||
_astParent(nullptr)
|
_astParent(nullptr)
|
||||||
|
@ -189,6 +190,7 @@ void Token::deleteThis()
|
||||||
_isAttributePure = _next->_isAttributePure;
|
_isAttributePure = _next->_isAttributePure;
|
||||||
_isAttributeConst = _next->_isAttributeConst;
|
_isAttributeConst = _next->_isAttributeConst;
|
||||||
_isAttributeNothrow = _next->_isAttributeNothrow;
|
_isAttributeNothrow = _next->_isAttributeNothrow;
|
||||||
|
_isDeclspecNothrow = _next->_isDeclspecNothrow;
|
||||||
_varId = _next->_varId;
|
_varId = _next->_varId;
|
||||||
_fileIndex = _next->_fileIndex;
|
_fileIndex = _next->_fileIndex;
|
||||||
_linenr = _next->_linenr;
|
_linenr = _next->_linenr;
|
||||||
|
@ -217,6 +219,7 @@ void Token::deleteThis()
|
||||||
_isAttributePure = _previous->_isAttributePure;
|
_isAttributePure = _previous->_isAttributePure;
|
||||||
_isAttributeConst = _previous->_isAttributeConst;
|
_isAttributeConst = _previous->_isAttributeConst;
|
||||||
_isAttributeNothrow = _previous->_isAttributeNothrow;
|
_isAttributeNothrow = _previous->_isAttributeNothrow;
|
||||||
|
_isDeclspecNothrow = _previous->_isDeclspecNothrow;
|
||||||
_varId = _previous->_varId;
|
_varId = _previous->_varId;
|
||||||
_fileIndex = _previous->_fileIndex;
|
_fileIndex = _previous->_fileIndex;
|
||||||
_linenr = _previous->_linenr;
|
_linenr = _previous->_linenr;
|
||||||
|
|
|
@ -322,6 +322,12 @@ public:
|
||||||
void isAttributeNothrow(bool value) {
|
void isAttributeNothrow(bool value) {
|
||||||
_isAttributeNothrow = value;
|
_isAttributeNothrow = value;
|
||||||
}
|
}
|
||||||
|
bool isDeclspecNothrow() const {
|
||||||
|
return _isDeclspecNothrow;
|
||||||
|
}
|
||||||
|
void isDeclspecNothrow(bool value) {
|
||||||
|
_isDeclspecNothrow = value;
|
||||||
|
}
|
||||||
|
|
||||||
static const Token *findsimplematch(const Token *tok, const char pattern[]);
|
static const Token *findsimplematch(const Token *tok, const char pattern[]);
|
||||||
static const Token *findsimplematch(const Token *tok, const char pattern[], const Token *end);
|
static const Token *findsimplematch(const Token *tok, const char pattern[], const Token *end);
|
||||||
|
@ -706,6 +712,7 @@ private:
|
||||||
bool _isAttributePure; // __attribute__((pure))
|
bool _isAttributePure; // __attribute__((pure))
|
||||||
bool _isAttributeConst; // __attribute__((const))
|
bool _isAttributeConst; // __attribute__((const))
|
||||||
bool _isAttributeNothrow; // __attribute__((nothrow))
|
bool _isAttributeNothrow; // __attribute__((nothrow))
|
||||||
|
bool _isDeclspecNothrow; // __declspec(nothrow)
|
||||||
|
|
||||||
/** Updates internal property cache like _isName or _isBoolean.
|
/** Updates internal property cache like _isName or _isBoolean.
|
||||||
Called after any _str() modification. */
|
Called after any _str() modification. */
|
||||||
|
|
|
@ -121,6 +121,7 @@ Token *Tokenizer::copyTokens(Token *dest, const Token *first, const Token *last,
|
||||||
tok2->isAttributePure(tok->isAttributePure());
|
tok2->isAttributePure(tok->isAttributePure());
|
||||||
tok2->isAttributeConst(tok->isAttributeConst());
|
tok2->isAttributeConst(tok->isAttributeConst());
|
||||||
tok2->isAttributeNothrow(tok->isAttributeNothrow());
|
tok2->isAttributeNothrow(tok->isAttributeNothrow());
|
||||||
|
tok2->isDeclspecNothrow(tok->isDeclspecNothrow());
|
||||||
tok2->varId(tok->varId());
|
tok2->varId(tok->varId());
|
||||||
|
|
||||||
// Check for links and fix them up
|
// Check for links and fix them up
|
||||||
|
@ -3215,15 +3216,15 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
||||||
if (_settings->terminated())
|
if (_settings->terminated())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// remove calling conventions __cdecl, __stdcall..
|
||||||
|
simplifyCallingConvention();
|
||||||
|
|
||||||
// Remove __declspec()
|
// Remove __declspec()
|
||||||
simplifyDeclspec();
|
simplifyDeclspec();
|
||||||
|
|
||||||
// remove some unhandled macros in global scope
|
// remove some unhandled macros in global scope
|
||||||
removeMacrosInGlobalScope();
|
removeMacrosInGlobalScope();
|
||||||
|
|
||||||
// remove calling conventions __cdecl, __stdcall..
|
|
||||||
simplifyCallingConvention();
|
|
||||||
|
|
||||||
// remove __attribute__((?))
|
// remove __attribute__((?))
|
||||||
simplifyAttribute();
|
simplifyAttribute();
|
||||||
|
|
||||||
|
@ -9147,6 +9148,15 @@ void Tokenizer::simplifyDeclspec()
|
||||||
{
|
{
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
while (Token::simpleMatch(tok, "__declspec (") && tok->next()->link() && tok->next()->link()->next()) {
|
while (Token::simpleMatch(tok, "__declspec (") && tok->next()->link() && tok->next()->link()->next()) {
|
||||||
|
if (tok->strAt(2) == "nothrow") {
|
||||||
|
Token *tok1 = tok->next()->link()->next();
|
||||||
|
while (tok1 && !Token::Match(tok1, "%var%")) {
|
||||||
|
tok1 = tok1->next();
|
||||||
|
}
|
||||||
|
if (tok1) {
|
||||||
|
tok1->isDeclspecNothrow(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
Token::eraseTokens(tok, tok->next()->link()->next());
|
Token::eraseTokens(tok, tok->next()->link()->next());
|
||||||
tok->deleteThis();
|
tok->deleteThis();
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,7 @@ void TokenList::addtoken(const Token * tok, const unsigned int lineno, const uns
|
||||||
_back->isAttributePure(tok->isAttributePure());
|
_back->isAttributePure(tok->isAttributePure());
|
||||||
_back->isAttributeConst(tok->isAttributeConst());
|
_back->isAttributeConst(tok->isAttributeConst());
|
||||||
_back->isAttributeNothrow(tok->isAttributeNothrow());
|
_back->isAttributeNothrow(tok->isAttributeNothrow());
|
||||||
|
_back->isDeclspecNothrow(tok->isDeclspecNothrow());
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// InsertTokens - Copy and insert tokens
|
// InsertTokens - Copy and insert tokens
|
||||||
|
@ -189,6 +190,7 @@ void TokenList::insertTokens(Token *dest, const Token *src, unsigned int n)
|
||||||
dest->isAttributePure(src->isAttributePure());
|
dest->isAttributePure(src->isAttributePure());
|
||||||
dest->isAttributeConst(src->isAttributeConst());
|
dest->isAttributeConst(src->isAttributeConst());
|
||||||
dest->isAttributeNothrow(src->isAttributeNothrow());
|
dest->isAttributeNothrow(src->isAttributeNothrow());
|
||||||
|
dest->isDeclspecNothrow(src->isDeclspecNothrow());
|
||||||
src = src->next();
|
src = src->next();
|
||||||
--n;
|
--n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ private:
|
||||||
TEST_CASE(unhandledExceptionSpecification2);
|
TEST_CASE(unhandledExceptionSpecification2);
|
||||||
TEST_CASE(nothrowAttributeThrow);
|
TEST_CASE(nothrowAttributeThrow);
|
||||||
TEST_CASE(nothrowAttributeThrow2); // #5703
|
TEST_CASE(nothrowAttributeThrow2); // #5703
|
||||||
|
TEST_CASE(nothrowDeclspecThrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], bool inconclusive = false) {
|
void check(const char code[], bool inconclusive = false) {
|
||||||
|
@ -371,12 +372,10 @@ private:
|
||||||
|
|
||||||
void nothrowAttributeThrow() {
|
void nothrowAttributeThrow() {
|
||||||
check("void func1() throw(int) { throw 1; }\n"
|
check("void func1() throw(int) { throw 1; }\n"
|
||||||
"void func2() __attribute((nothrow)); void func1() { throw 1; }\n"
|
"void func2() __attribute((nothrow)); void func2() { throw 1; }\n"
|
||||||
"void func3() __attribute((nothrow)); void func1() { func1(); }\n");
|
"void func3() __attribute((nothrow)); void func3() { func1(); }\n");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Exception thrown in __attribute__((nothrow)) function.\n"
|
ASSERT_EQUALS("[test.cpp:2]: (error) Exception thrown in __attribute__((nothrow)) function.\n"
|
||||||
"[test.cpp:3]: (error) Exception thrown in __attribute__((nothrow)) function.\n",
|
"[test.cpp:3]: (error) Exception thrown in __attribute__((nothrow)) function.\n", errout.str());
|
||||||
"",
|
|
||||||
errout.str());
|
|
||||||
|
|
||||||
// avoid false positives
|
// avoid false positives
|
||||||
check("const char *func() __attribute((nothrow)); void func1() { return 0; }\n");
|
check("const char *func() __attribute((nothrow)); void func1() { return 0; }\n");
|
||||||
|
@ -392,6 +391,17 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nothrowDeclspecThrow() {
|
||||||
|
check("void func1() throw(int) { throw 1; }\n"
|
||||||
|
"void __declspec(nothrow) func2() { throw 1; }\n"
|
||||||
|
"void __declspec(nothrow) func3() { func1(); }\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (error) Exception thrown in __declspec(nothrow) function.\n"
|
||||||
|
"[test.cpp:3]: (error) Exception thrown in __declspec(nothrow) function.\n", errout.str());
|
||||||
|
|
||||||
|
// avoid false positives
|
||||||
|
check("const char *func() __attribute((nothrow)); void func1() { return 0; }\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestExceptionSafety)
|
REGISTER_TEST(TestExceptionSafety)
|
||||||
|
|
|
@ -236,6 +236,7 @@ private:
|
||||||
TEST_CASE(noexceptFunction4);
|
TEST_CASE(noexceptFunction4);
|
||||||
|
|
||||||
TEST_CASE(nothrowAttributeFunction);
|
TEST_CASE(nothrowAttributeFunction);
|
||||||
|
TEST_CASE(nothrowDeclspecFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
void array() const {
|
void array() const {
|
||||||
|
@ -2160,6 +2161,19 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nothrowDeclspecFunction() {
|
||||||
|
GET_SYMBOL_DB("void __declspec(nothrow) func() { }\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
ASSERT_EQUALS(true, db != nullptr); // not null
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
const Function *func = findFunctionByName("func", &db->scopeList.front());
|
||||||
|
ASSERT_EQUALS(true, func != nullptr);
|
||||||
|
if (func)
|
||||||
|
ASSERT_EQUALS(true, func->isDeclspecNothrow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestSymbolDatabase)
|
REGISTER_TEST(TestSymbolDatabase)
|
||||||
|
|
Loading…
Reference in New Issue