From 3a36c436543484e386e35305e44ca9be2ef96161 Mon Sep 17 00:00:00 2001 From: zengzengran Date: Thu, 4 Sep 2025 11:27:42 +0800 Subject: [PATCH] Fix Incompatible numeric type conversion Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICVJKS Description: If the value exceeds the range of long, an error should be reported. If it exceeds the range of int, it should be converted to long, not to a negative number. Tested-by: ninja tests (passed) ets_testrunner (passed) Signed-off-by: zengzengran # --- ets2panda/lexer/ETSLexer.h | 4 +- ets2panda/lexer/lexer.h | 30 +++--- .../ast/compiler/ets/integer_literals.ets | 60 ++++++++++++ .../test/runtime/ets/integer_literals.ets | 95 +++++++++++++++++++ 4 files changed, 173 insertions(+), 16 deletions(-) create mode 100644 ets2panda/test/ast/compiler/ets/integer_literals.ets create mode 100644 ets2panda/test/runtime/ets/integer_literals.ets diff --git a/ets2panda/lexer/ETSLexer.h b/ets2panda/lexer/ETSLexer.h index 6d63d300cb..e72163158b 100644 --- a/ets2panda/lexer/ETSLexer.h +++ b/ets2panda/lexer/ETSLexer.h @@ -47,9 +47,9 @@ public: allowBigint = true; } - if (!ScanNumberLeadingZeroImpl(leadingMinus)) { + if (!ScanNumberLeadingZeroImpl(leadingMinus)) { Rewind(savedLexerPosition); - if (!ScanNumberLeadingZeroImpl(leadingMinus)) { + if (!ScanNumberLeadingZeroImpl(leadingMinus)) { LogError(diagnostic::TOO_LARGE_NUM); } } diff --git a/ets2panda/lexer/lexer.h b/ets2panda/lexer/lexer.h index 4f50319122..aa85ea5849 100644 --- a/ets2panda/lexer/lexer.h +++ b/ets2panda/lexer/lexer.h @@ -362,6 +362,7 @@ protected: void CheckOctal(); inline static uint32_t HexValue(char32_t ch); + inline static int32_t SignedHexValue(char32_t ch); inline static bool IsDecimalDigit(uint32_t cp); inline static bool IsHexDigit(char32_t ch); inline static bool IsBinaryDigit(char32_t ch); @@ -548,12 +549,14 @@ bool Lexer::ScanNumberLeadingZeroImpl(bool const leadingMinus) } template -bool ScanTooLargeNumber([[maybe_unused]] RadixType const number, [[maybe_unused]] std::uint32_t const digit) +bool ScanTooLargeNumber(RadixType const number, std::int32_t const digit, bool leadingMinus = false) { // NOTE (DZ): probably more sophisticates check will be required for general usage if constexpr (std::is_integral_v) { - if (static_cast(std::numeric_limits::max()) / RADIX < number || - static_cast(std::numeric_limits::max()) - number * RADIX < digit) { + RadixType const Limit = static_cast(leadingMinus ? std::numeric_limits::min() + : std::numeric_limits::max()); + if ((leadingMinus ? number < (Limit / RADIX) : number > (Limit / RADIX)) || + (number == (Limit / RADIX) && digit > Limit % RADIX)) { return false; } } @@ -575,12 +578,12 @@ bool Lexer::ScanNumberRadix(bool leadingMinus, bool allowNumericSeparator) do { cp = Iterator().Peek(); if (RANGE_CHECK(cp)) { - auto const digit = HexValue(cp); - if (!ScanTooLargeNumber(number, digit)) { + auto const digit = SignedHexValue(cp); + if (!ScanTooLargeNumber(number, digit, leadingMinus)) { GetToken().number_ = lexer::Number(); return false; } - number = number * RADIX + digit; + number = number * RADIX + (leadingMinus ? (-digit) : digit); Iterator().Forward(1); allowNumericOnNext = true; @@ -606,14 +609,6 @@ bool Lexer::ScanNumberRadix(bool leadingMinus, bool allowNumericSeparator) break; } while (true); - if (leadingMinus) { - if constexpr (std::is_integral_v) { - number = ~number + static_cast(1); - } else { - number = -number; - } - } - GetToken().number_ = lexer::Number(number); GetToken().number_.SetStr(SourceView(GetToken().Start().index, Iterator().Index())); return true; @@ -626,6 +621,13 @@ inline uint32_t Lexer::HexValue(char32_t ch) return ch < LEX_CHAR_UPPERCASE_A ? ch - LEX_CHAR_0 : ((ch - LEX_CHAR_UPPERCASE_A + DEC_OFFSET) & HEX_MASK); } +inline int32_t Lexer::SignedHexValue(char32_t ch) +{ + constexpr int32_t HEX_MASK = 0xF; + constexpr int32_t DEC_OFFSET = 10; + return ch < LEX_CHAR_UPPERCASE_A ? ch - LEX_CHAR_0 : ((ch - LEX_CHAR_UPPERCASE_A + DEC_OFFSET) & HEX_MASK); +} + inline bool Lexer::IsDecimalDigit(uint32_t cp) { return (cp >= LEX_CHAR_0 && cp <= LEX_CHAR_9); diff --git a/ets2panda/test/ast/compiler/ets/integer_literals.ets b/ets2panda/test/ast/compiler/ets/integer_literals.ets new file mode 100644 index 0000000000..a57308cf54 --- /dev/null +++ b/ets2panda/test/ast/compiler/ets/integer_literals.ets @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function main(){ + let n1 = 0x8000000000000000; + let n2 = 9223372036854775808; + let n3 = 0o1000000000000000000000; + let n4 = 0b1000000000000000000000000000000000000000000000000000000000000000; + + let n5 = -0x8000000000000001; + let n6 = -9223372036854775809; + let n7 = -0o1000000000000000000001; + let n8 = -0b1000000000000000000000000000000000000000000000000000000000000001; + + let n9 = -0x8000010000000001; + let n10 = -9223373036854775809; + let n11 = -0o1000100000000000000001; + let n12 = -0b1000100000000000000000000000000000000000000000000000000000000001; + + let xint1:int = 0x80000000 + let xint2:int = -0x80000001 +} + +/* @@? 17:14 Error SyntaxError: Number is too large. */ +/* @@? 17:31 Error SyntaxError: Unexpected token '0'. */ +/* @@? 18:14 Error SyntaxError: Invalid number. */ +/* @@? 19:14 Error SyntaxError: Number is too large. */ +/* @@? 19:37 Error SyntaxError: Unexpected token '0'. */ +/* @@? 20:14 Error SyntaxError: Number is too large. */ +/* @@? 20:79 Error SyntaxError: Unexpected token '0'. */ +/* @@? 22:15 Error SyntaxError: Number is too large. */ +/* @@? 22:32 Error SyntaxError: Unexpected token '1'. */ +/* @@? 23:15 Error SyntaxError: Invalid number. */ +/* @@? 24:15 Error SyntaxError: Number is too large. */ +/* @@? 24:38 Error SyntaxError: Unexpected token '1'. */ +/* @@? 25:15 Error SyntaxError: Number is too large. */ +/* @@? 25:80 Error SyntaxError: Unexpected token '1'. */ +/* @@? 27:15 Error SyntaxError: Number is too large. */ +/* @@? 27:32 Error SyntaxError: Unexpected token '1'. */ +/* @@? 28:16 Error SyntaxError: Invalid number. */ +/* @@? 29:16 Error SyntaxError: Number is too large. */ +/* @@? 29:39 Error SyntaxError: Unexpected token '1'. */ +/* @@? 30:16 Error SyntaxError: Number is too large. */ +/* @@? 30:81 Error SyntaxError: Unexpected token '1'. */ +/* @@? 32:15 Error TypeError: Value is out of range */ +/* @@? 32:21 Error TypeError: Type 'Long' cannot be assigned to type 'Int' */ +/* @@? 33:15 Error TypeError: Value is out of range */ +/* @@? 33:21 Error TypeError: Type 'Long' cannot be assigned to type 'Int' */ diff --git a/ets2panda/test/runtime/ets/integer_literals.ets b/ets2panda/test/runtime/ets/integer_literals.ets new file mode 100644 index 0000000000..05716d7a9b --- /dev/null +++ b/ets2panda/test/runtime/ets/integer_literals.ets @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function main(){ + testHex(); + testDec(); + testOct(); + testBin(); +} + +function testHex() { + let n = 0x7fffffff; + arktest.assertEQ(n,2147483647); + + let n2 = 0x80000000; + arktest.assertEQ(n2,2147483648); + + let n3 = 0xcccccccc; + arktest.assertEQ(n3,3435973836); + + let n4 = 0x7fffffffffffffff; + arktest.assertEQ(n4,9223372036854775807); + + let n5 = -0x7fffffff; + arktest.assertEQ(n5,-2147483647); + + let n6 = -0x80000000; + arktest.assertEQ(n6,-2147483648); + + let n7 = -0xcccccccc; + arktest.assertEQ(n7,-3435973836); + + let n8 = -0x7fffffffffffffff; + arktest.assertEQ(n8,-9223372036854775807); + + let n9 = -0x8000000000000000; + arktest.assertEQ(n9,-9223372036854775808); +} + +function testDec() { + let n = 2147483647; + arktest.assertEQ(n,2147483647); + + let n2 = 2147483648; + arktest.assertEQ(n2,2147483648); + + let n3 = 9223372036854775807; + arktest.assertEQ(n3,9223372036854775807); + + let n4 = -2147483647; + arktest.assertEQ(n4,-2147483647); + + let n5 = -2147483648; + arktest.assertEQ(n5,-2147483648); + + let n6 = -9223372036854775807; + arktest.assertEQ(n6,-9223372036854775807); + + let n7 = -9223372036854775808; + arktest.assertEQ(n7,-9223372036854775808); +} + +function testOct() { + let n = 0o17777777777; + arktest.assertEQ(n,2147483647); + + let n2 = 0o20000000000; + arktest.assertEQ(n2,2147483648); + + let n3 = 0o777777777777777777777; + arktest.assertEQ(n3,9223372036854775807); +} + +function testBin() { + let n = 0b01111111111111111111111111111111; + arktest.assertEQ(n,2147483647); + + let n2 = 0b10000000000000000000000000000000; + arktest.assertEQ(n2,2147483648); + + let n3 = 0b0111111111111111111111111111111111111111111111111111111111111111; + arktest.assertEQ(n3,9223372036854775807); +} -- Gitee