diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 10f988426..0d55bbd52 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -57,11 +57,6 @@ void CheckType::checkTooBigBitwiseShift() if (mSettings->platformType == Settings::Unspecified) return; - const bool cpp14 = mSettings->standards.cpp >= Standards::CPP14; - - if (cpp14 && !mSettings->isEnabled(Settings::PORTABILITY)) - return; - for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) { // C++ and macro: OUT(x<isCPP() && Token::Match(tok, "[;{}] %name% (") && Token::simpleMatch(tok->linkAt(2), ") ;") && tok->next()->isUpperCaseName() && !tok->next()->function()) @@ -96,7 +91,7 @@ void CheckType::checkTooBigBitwiseShift() // Get biggest rhs value. preferably a value which doesn't have 'condition'. const ValueFlow::Value * value = tok->astOperand2()->getValueGE(lhsbits, mSettings); - if (value && mSettings->isEnabled(value, false) && !cpp14) + if (value && mSettings->isEnabled(value, false)) tooBigBitwiseShiftError(tok, lhsbits, *value); else if (lhstype->sign == ValueType::Sign::SIGNED) { value = tok->astOperand2()->getValueGE(lhsbits-1, mSettings); @@ -150,6 +145,8 @@ void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, con if (cpp14) severity = Severity::portability; + if ((severity == Severity::portability) && !mSettings->isEnabled(Settings::PORTABILITY)) + return; reportError(errorPath, severity, id, errmsg.str(), CWE758, rhsbits.isInconclusive()); } diff --git a/test/testtype.cpp b/test/testtype.cpp index 0ac40e945..956feadec 100644 --- a/test/testtype.cpp +++ b/test/testtype.cpp @@ -41,7 +41,7 @@ private: TEST_CASE(checkFloatToIntegerOverflow); } - void check(const char code[], Settings* settings = nullptr, const char filename[] = "test.cpp") { + void check(const char code[], Settings* settings = nullptr, const char filename[] = "test.cpp", const std::string& standard = "c++11") { // Clear the error buffer.. errout.str(""); @@ -50,7 +50,8 @@ private: settings = &_settings; } settings->addEnabled("warning"); - settings->standards.setCPP("c++11"); + settings->addEnabled("portability"); + settings->standards.setCPP(standard); // Tokenize.. Tokenizer tokenizer(settings, this); @@ -71,6 +72,8 @@ private: { const std::string types[] = {"unsigned char", /*[unsigned]*/"char", "bool", "unsigned short", "unsigned int", "unsigned long"}; for (const std::string& type : types) { + check((type + " f(" + type +" x) { return x << 31; }").c_str(), &settings); + ASSERT_EQUALS("", errout.str()); check((type + " f(" + type +" x) { return x << 33; }").c_str(), &settings); ASSERT_EQUALS("[test.cpp:1]: (error) Shifting 32-bit value by 33 bits is undefined behaviour\n", errout.str()); check((type + " f(int x) { return (x = (" + type + ")x << 32); }").c_str(), &settings); @@ -84,6 +87,7 @@ private: { const std::string types[] = {"signed char", "signed short", /*[signed]*/"short", "wchar_t", /*[signed]*/"int", "signed int", /*[signed]*/"long", "signed long"}; for (const std::string& type : types) { + // c++11 check((type + " f(" + type +" x) { return x << 33; }").c_str(), &settings); ASSERT_EQUALS("[test.cpp:1]: (error) Shifting 32-bit value by 33 bits is undefined behaviour\n", errout.str()); check((type + " f(int x) { return (x = (" + type + ")x << 32); }").c_str(), &settings); @@ -92,6 +96,12 @@ private: ASSERT_EQUALS("[test.cpp:1]: (error) Shifting signed 32-bit value by 31 bits is undefined behaviour\n", errout.str()); check((type + " foo(" + type + " x) { return x << 30; }").c_str(), &settings); ASSERT_EQUALS("", errout.str()); + + // c++14 + check((type + " foo(" + type + " x) { return x << 31; }").c_str(), &settings, "test.cpp", "c++14"); + ASSERT_EQUALS("[test.cpp:1]: (portability) Shifting signed 32-bit value by 31 bits is implementation-defined behaviour\n", errout.str()); + check((type + " f(int x) { return (x = (" + type + ")x << 32); }").c_str(), &settings, "test.cpp", "c++14"); + ASSERT_EQUALS("[test.cpp:1]: (error) Shifting 32-bit value by 32 bits is undefined behaviour\n", errout.str()); } } // 64 bit width types @@ -121,6 +131,16 @@ private: ASSERT_EQUALS("[test.cpp:1]: (error) Shifting signed 64-bit value by 63 bits is undefined behaviour\n", errout.str()); check("signed long long f(signed long long x) { return x << 62; }",&settings); ASSERT_EQUALS("", errout.str()); + + // c++14 + check("signed long long foo(signed long long x) { return x << 64; }",&settings, "test.cpp", "c++14"); + ASSERT_EQUALS("[test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour\n", errout.str()); + check("signed long long f(long long x) { return (x = (signed long long)x << 64); }",&settings, "test.cpp", "c++14"); + ASSERT_EQUALS("[test.cpp:1]: (error) Shifting 64-bit value by 64 bits is undefined behaviour\n", errout.str()); + check("signed long long f(signed long long x) { return x << 63; }",&settings, "test.cpp", "c++14"); + ASSERT_EQUALS("[test.cpp:1]: (portability) Shifting signed 64-bit value by 63 bits is implementation-defined behaviour\n", errout.str()); + check("signed long long f(signed long long x) { return x << 62; }",&settings); + ASSERT_EQUALS("", errout.str()); } check("void foo() {\n"