From 3095f47a7bc47141d72cc62a221b5889b9fcfb02 Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Sat, 4 Jun 2016 22:55:55 +0200 Subject: [PATCH] Ticket #7137: Properly detect C++14 digit separators. (#802) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an optional extended description… --- lib/mathlib.cpp | 36 ++++++++++++++++++++++++++++++++++++ lib/mathlib.h | 7 +++++++ lib/preprocessor.cpp | 2 +- test/testmathlib.cpp | 18 ++++++++++++++++++ test/testpreprocessor.cpp | 5 +++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/lib/mathlib.cpp b/lib/mathlib.cpp index 8daddc0ff..7894acb5c 100644 --- a/lib/mathlib.cpp +++ b/lib/mathlib.cpp @@ -1249,6 +1249,42 @@ bool MathLib::isOctalDigit(char c) return (c >= '0' && c <= '7'); } +bool MathLib::isDigitSeparator(const std::string& iCode, std::string::size_type iPos) { + if (iPos == 0 || iPos >= iCode.size() || iCode[iPos] != '\'') + return false; + std::string::size_type i = iPos - 1; + while (std::isxdigit(iCode[i])) { + if (i == 0) + return true; // Only xdigits before ' + --i; + } + if (i == iPos - 1) { // No xdigit before ' + return false; + } else { + switch(iCode[i]) { + case ' ': + case '.': + case ',': + case 'x': + case '(': + case '{': + case '+': + case '-': + case '*': + case '%': + case '/': + case '&': + case '|': + case '^': + case '~': + case '=': + return true; + default: + return false; + } + } +} + MathLib::value operator+(const MathLib::value &v1, const MathLib::value &v2) { return MathLib::value::calc('+',v1,v2); diff --git a/lib/mathlib.h b/lib/mathlib.h index 067eb639c..5fc10f7eb 100644 --- a/lib/mathlib.h +++ b/lib/mathlib.h @@ -122,6 +122,13 @@ public: * */ static MathLib::bigint characterLiteralToLongNumber(const std::string& str); + /** + * \param iCode Code being considered + * \param iPos A posision within iCode + * \return Whether iCode[iPos] is a C++14 digit separator + */ + static bool isDigitSeparator(const std::string& iCode, std::string::size_type iPos); + private: /* * \param iLiteral A character literal diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 737c717c6..d9082e4d8 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -697,7 +697,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } // C++14 digit separators - if (ch == '\'' && std::isxdigit(previous)) + if (MathLib::isDigitSeparator(str, i)) ; // Just skip it. // String or char constants.. diff --git a/test/testmathlib.cpp b/test/testmathlib.cpp index ca569e103..d47600f9f 100644 --- a/test/testmathlib.cpp +++ b/test/testmathlib.cpp @@ -59,6 +59,7 @@ private: TEST_CASE(abs); TEST_CASE(toString); TEST_CASE(characterLiteralsNormalization); + TEST_CASE(CPP14DigitSeparators); } void isGreater() const { @@ -1143,6 +1144,23 @@ private: // Unsupported single escape sequence ASSERT_THROW(MathLib::normalizeCharacterLiteral("\\c"), InternalError); } + + void CPP14DigitSeparators() { // Ticket #7137 + ASSERT(MathLib::isDigitSeparator("'", 0) == false); + ASSERT(MathLib::isDigitSeparator("123'0;", 3)); + ASSERT(MathLib::isDigitSeparator("foo(1'2);", 5)); + ASSERT(MathLib::isDigitSeparator("foo(1,1'2);", 7)); + ASSERT(MathLib::isDigitSeparator("int a=1'234-1'2-'0';", 7)); + ASSERT(MathLib::isDigitSeparator("int a=1'234-1'2-'0';", 13)); + ASSERT(MathLib::isDigitSeparator("int a=1'234-1'2-'0';", 16) == false); + ASSERT(MathLib::isDigitSeparator("int b=1+9'8;", 9)); + ASSERT(MathLib::isDigitSeparator("if (1'2) { char c = 'c'; }", 5)); + ASSERT(MathLib::isDigitSeparator("if (120%1'2) { char c = 'c'; }", 9)); + ASSERT(MathLib::isDigitSeparator("if (120&1'2) { char c = 'c'; }", 9)); + ASSERT(MathLib::isDigitSeparator("if (120|1'2) { char c = 'c'; }", 9)); + ASSERT(MathLib::isDigitSeparator("if (120%1'2) { char c = 'c'; }", 24) == false); + ASSERT(MathLib::isDigitSeparator("if (120%1'2) { char c = 'c'; }", 26) == false); + } }; REGISTER_TEST(TestMathLib) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index ee062dc51..9a74bde1d 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -352,6 +352,11 @@ private: ASSERT_EQUALS("int i = 0x0F0FFFFF;", preprocessorRead("int i = 0x0F0F'FFFF;")); ASSERT_EQUALS("", errout.str()); + + // Ticket #7137 + const char code[] = "void t(char c) { switch (c) { case'M': break; } }"; + ASSERT_EQUALS(code, preprocessorRead(code)); + ASSERT_EQUALS("", errout.str()); }