Fixed #5756 (declspec(nothrow) not supported)

This commit is contained in:
Robert Reif 2014-05-04 20:47:20 +02:00 committed by Daniel Marjamäki
parent 7d583e639c
commit ae96491d6c
10 changed files with 74 additions and 9 deletions

View File

@ -253,6 +253,13 @@ void CheckExceptionSafety::nothrowThrows()
if (throws)
nothrowAttributeThrowError(throws);
}
// check __declspec(nothrow) functions
else if (scope->function && scope->function->isDeclspecNothrow()) {
const Token *throws = functionThrows(scope->function);
if (throws)
nothrowDeclspecThrowError(throws);
}
}
}

View File

@ -123,6 +123,11 @@ private:
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 */
void unhandledExceptionSpecificationError(const Token * const tok1, const Token * const tok2, const std::string & funcname) {
std::string str1(tok1 ? tok1->str() : "foo");
@ -145,6 +150,7 @@ private:
c.noexceptThrowError(0);
c.nothrowThrowError(0);
c.nothrowAttributeThrowError(0);
c.nothrowDeclspecThrowError(0);
c.unhandledExceptionSpecificationError(0, 0, "funcname");
}
@ -163,6 +169,7 @@ private:
"* Throwing exception in noexcept function\n"
"* Throwing exception in 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";
}
};

View File

@ -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)->isAttributeConst(i->tokenDef->isAttributeConst());
const_cast<Token *>(tok)->isAttributeNothrow(i->tokenDef->isAttributeNothrow());
const_cast<Token *>(tok)->isDeclspecNothrow(i->tokenDef->isDeclspecNothrow());
break;
}
}
@ -1916,6 +1917,7 @@ void SymbolDatabase::printOut(const char *title) const
std::cerr << " isAttributeConst: " << (func->isAttributeConst() ? "true" : "false") << std::endl;
std::cerr << " isAttributePure: " << (func->isAttributePure() ? "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 << " throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
std::cout << " tokenDef: " << func->tokenDef->str() << " " <<_tokenizer->list.fileLine(func->tokenDef) << std::endl;

View File

@ -593,6 +593,9 @@ public:
bool isAttributeNothrow() const {
return tokenDef->isAttributeNothrow();
}
bool isDeclspecNothrow() const {
return tokenDef->isDeclspecNothrow();
}
const Token *tokenDef; // function name token in class definition
const Token *argDef; // function argument start '(' in class definition

View File

@ -57,6 +57,7 @@ Token::Token(Token **t) :
_isAttributePure(false),
_isAttributeConst(false),
_isAttributeNothrow(false),
_isDeclspecNothrow(false),
_astOperand1(nullptr),
_astOperand2(nullptr),
_astParent(nullptr)
@ -189,6 +190,7 @@ void Token::deleteThis()
_isAttributePure = _next->_isAttributePure;
_isAttributeConst = _next->_isAttributeConst;
_isAttributeNothrow = _next->_isAttributeNothrow;
_isDeclspecNothrow = _next->_isDeclspecNothrow;
_varId = _next->_varId;
_fileIndex = _next->_fileIndex;
_linenr = _next->_linenr;
@ -217,6 +219,7 @@ void Token::deleteThis()
_isAttributePure = _previous->_isAttributePure;
_isAttributeConst = _previous->_isAttributeConst;
_isAttributeNothrow = _previous->_isAttributeNothrow;
_isDeclspecNothrow = _previous->_isDeclspecNothrow;
_varId = _previous->_varId;
_fileIndex = _previous->_fileIndex;
_linenr = _previous->_linenr;

View File

@ -322,6 +322,12 @@ public:
void isAttributeNothrow(bool 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[], const Token *end);
@ -706,6 +712,7 @@ private:
bool _isAttributePure; // __attribute__((pure))
bool _isAttributeConst; // __attribute__((const))
bool _isAttributeNothrow; // __attribute__((nothrow))
bool _isDeclspecNothrow; // __declspec(nothrow)
/** Updates internal property cache like _isName or _isBoolean.
Called after any _str() modification. */

View File

@ -121,6 +121,7 @@ Token *Tokenizer::copyTokens(Token *dest, const Token *first, const Token *last,
tok2->isAttributePure(tok->isAttributePure());
tok2->isAttributeConst(tok->isAttributeConst());
tok2->isAttributeNothrow(tok->isAttributeNothrow());
tok2->isDeclspecNothrow(tok->isDeclspecNothrow());
tok2->varId(tok->varId());
// Check for links and fix them up
@ -3215,15 +3216,15 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
if (_settings->terminated())
return false;
// remove calling conventions __cdecl, __stdcall..
simplifyCallingConvention();
// Remove __declspec()
simplifyDeclspec();
// remove some unhandled macros in global scope
removeMacrosInGlobalScope();
// remove calling conventions __cdecl, __stdcall..
simplifyCallingConvention();
// remove __attribute__((?))
simplifyAttribute();
@ -9147,6 +9148,15 @@ void Tokenizer::simplifyDeclspec()
{
for (Token *tok = list.front(); tok; tok = tok->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());
tok->deleteThis();
}

View File

@ -154,6 +154,7 @@ void TokenList::addtoken(const Token * tok, const unsigned int lineno, const uns
_back->isAttributePure(tok->isAttributePure());
_back->isAttributeConst(tok->isAttributeConst());
_back->isAttributeNothrow(tok->isAttributeNothrow());
_back->isDeclspecNothrow(tok->isDeclspecNothrow());
}
//---------------------------------------------------------------------------
// 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->isAttributeConst(src->isAttributeConst());
dest->isAttributeNothrow(src->isAttributeNothrow());
dest->isDeclspecNothrow(src->isDeclspecNothrow());
src = src->next();
--n;
}

View File

@ -48,6 +48,7 @@ private:
TEST_CASE(unhandledExceptionSpecification2);
TEST_CASE(nothrowAttributeThrow);
TEST_CASE(nothrowAttributeThrow2); // #5703
TEST_CASE(nothrowDeclspecThrow);
}
void check(const char code[], bool inconclusive = false) {
@ -371,12 +372,10 @@ private:
void nothrowAttributeThrow() {
check("void func1() throw(int) { throw 1; }\n"
"void func2() __attribute((nothrow)); void func1() { throw 1; }\n"
"void func3() __attribute((nothrow)); void func1() { func1(); }\n");
TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Exception thrown in __attribute__((nothrow)) function.\n"
"[test.cpp:3]: (error) Exception thrown in __attribute__((nothrow)) function.\n",
"",
errout.str());
"void func2() __attribute((nothrow)); void func2() { throw 1; }\n"
"void func3() __attribute((nothrow)); void func3() { func1(); }\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", errout.str());
// avoid false positives
check("const char *func() __attribute((nothrow)); void func1() { return 0; }\n");
@ -392,6 +391,17 @@ private:
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)

View File

@ -236,6 +236,7 @@ private:
TEST_CASE(noexceptFunction4);
TEST_CASE(nothrowAttributeFunction);
TEST_CASE(nothrowDeclspecFunction);
}
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)