From 87d4c2dfc6e9b8e57472cf58edcbe9b8f737450f Mon Sep 17 00:00:00 2001 From: Jon Ross-Perkins Date: Thu, 7 Sep 2023 11:53:38 -0700 Subject: [PATCH] Improve testing and handling of unsigned APInt values (#3202) --- toolchain/check/handle_array.cpp | 2 +- .../check/testdata/array/nine_elements.carbon | 6 +- .../testdata/basics/numeric_literals.carbon | 233 ++++++++++++++++++ .../index/fail_array_large_index.carbon | 2 +- .../index/fail_tuple_large_index.carbon | 2 +- .../testdata/operators/assignment.carbon | 2 +- .../lex/testdata/numeric_literals.carbon | 84 +++++++ toolchain/lex/tokenized_buffer.h | 4 +- toolchain/lower/handle.cpp | 2 +- .../testdata/basics/numeric_literals.carbon | 97 ++++++++ .../testdata/basics/numeric_literals.carbon | 84 +++++++ toolchain/sem_ir/file.cpp | 19 +- toolchain/sem_ir/file.h | 5 +- toolchain/sem_ir/formatter.cpp | 3 +- toolchain/testing/BUILD | 5 + 15 files changed, 532 insertions(+), 18 deletions(-) create mode 100644 toolchain/check/testdata/basics/numeric_literals.carbon create mode 100644 toolchain/lex/testdata/numeric_literals.carbon create mode 100644 toolchain/lower/testdata/basics/numeric_literals.carbon create mode 100644 toolchain/parse/testdata/basics/numeric_literals.carbon create mode 100644 toolchain/testing/BUILD diff --git a/toolchain/check/handle_array.cpp b/toolchain/check/handle_array.cpp index 0039ad01bbcc..31560dd19bd5 100644 --- a/toolchain/check/handle_array.cpp +++ b/toolchain/check/handle_array.cpp @@ -38,7 +38,7 @@ auto HandleArrayExpression(Context& context, Parse::Node parse_node) -> bool { auto bound_value = context.semantics_ir().GetIntegerLiteral( bound_node.GetAsIntegerLiteral()); // TODO: Produce an error if the array type is too large. - if (bound_value.getBitWidth() <= 64) { + if (bound_value.getActiveBits() <= 64) { context.AddNodeAndPush( parse_node, SemIR::Node::ArrayType::Make( diff --git a/toolchain/check/testdata/array/nine_elements.carbon b/toolchain/check/testdata/array/nine_elements.carbon index 2578a6d17e18..80e7c92d49a0 100644 --- a/toolchain/check/testdata/array/nine_elements.carbon +++ b/toolchain/check/testdata/array/nine_elements.carbon @@ -10,7 +10,7 @@ var a: [i32; 9] = (1, 2, 3, 4, 5, 6, 7, 8, 9); // CHECK:STDOUT: functions: [ // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ -// CHECK:STDOUT: -7, +// CHECK:STDOUT: 9, // CHECK:STDOUT: 1, // CHECK:STDOUT: 2, // CHECK:STDOUT: 3, @@ -18,8 +18,8 @@ var a: [i32; 9] = (1, 2, 3, 4, 5, 6, 7, 8, 9); // CHECK:STDOUT: 5, // CHECK:STDOUT: 6, // CHECK:STDOUT: 7, -// CHECK:STDOUT: -8, -// CHECK:STDOUT: -7, +// CHECK:STDOUT: 8, +// CHECK:STDOUT: 9, // CHECK:STDOUT: ] // CHECK:STDOUT: real_literals: [ // CHECK:STDOUT: ] diff --git a/toolchain/check/testdata/basics/numeric_literals.carbon b/toolchain/check/testdata/basics/numeric_literals.carbon new file mode 100644 index 000000000000..cdc15cf673c1 --- /dev/null +++ b/toolchain/check/testdata/basics/numeric_literals.carbon @@ -0,0 +1,233 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +fn F() { + // 8 and 9 trigger special behavior in APInt when mishandling signed versus + // unsigned, so we pay extra attention to those. + var ints: [i32; 5] = ( + 8, + 9, + 0x8, + 0b1000, + 39999999999999999993, + ); + var floats: [f64; 7] = ( + 0.9, + 8.0, + 80.0, + 1.0e7, + 1.0e8, + 1.0e-8, + 39999999999999999993.0e39999999999999999993, + ); +} + +// CHECK:STDOUT: cross_reference_irs_size: 1 +// CHECK:STDOUT: functions: [ +// CHECK:STDOUT: {name: str0, param_refs: block0, body: [block2]}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: integer_literals: [ +// CHECK:STDOUT: 5, +// CHECK:STDOUT: 8, +// CHECK:STDOUT: 9, +// CHECK:STDOUT: 8, +// CHECK:STDOUT: 8, +// CHECK:STDOUT: 39999999999999999993, +// CHECK:STDOUT: 7, +// CHECK:STDOUT: ] +// CHECK:STDOUT: real_literals: [ +// CHECK:STDOUT: {mantissa: 9, exponent: -1, is_decimal: 1}, +// CHECK:STDOUT: {mantissa: 80, exponent: -1, is_decimal: 1}, +// CHECK:STDOUT: {mantissa: 800, exponent: -1, is_decimal: 1}, +// CHECK:STDOUT: {mantissa: 10, exponent: 6, is_decimal: 1}, +// CHECK:STDOUT: {mantissa: 10, exponent: 7, is_decimal: 1}, +// CHECK:STDOUT: {mantissa: 10, exponent: -9, is_decimal: 1}, +// CHECK:STDOUT: {mantissa: 399999999999999999930, exponent: 39999999999999999992, is_decimal: 1}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: strings: [ +// CHECK:STDOUT: F, +// CHECK:STDOUT: ints, +// CHECK:STDOUT: floats, +// CHECK:STDOUT: ] +// CHECK:STDOUT: types: [ +// CHECK:STDOUT: nodeIntegerType, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+14, +// CHECK:STDOUT: nodeFloatingPointType, +// CHECK:STDOUT: node+19, +// CHECK:STDOUT: node+35, +// CHECK:STDOUT: ] +// CHECK:STDOUT: type_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: type0, +// CHECK:STDOUT: type0, +// CHECK:STDOUT: type0, +// CHECK:STDOUT: type0, +// CHECK:STDOUT: type0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: type3, +// CHECK:STDOUT: type3, +// CHECK:STDOUT: type3, +// CHECK:STDOUT: type3, +// CHECK:STDOUT: type3, +// CHECK:STDOUT: type3, +// CHECK:STDOUT: type3, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] +// CHECK:STDOUT: nodes: [ +// CHECK:STDOUT: {kind: FunctionDeclaration, arg0: function0}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int0, type: type0}, +// CHECK:STDOUT: {kind: ArrayType, arg0: node+1, arg1: type0, type: typeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, arg0: str1, type: type1}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int1, type: type0}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+4, type: type0}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int2, type: type0}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+6, type: type0}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int3, type: type0}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+8, type: type0}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int4, type: type0}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+10, type: type0}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int5, type: type0}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+12, type: type0}, +// CHECK:STDOUT: {kind: TupleType, arg0: typeBlock0, type: typeTypeType}, +// CHECK:STDOUT: {kind: TupleValue, arg0: block3, type: type2}, +// CHECK:STDOUT: {kind: ArrayValue, arg0: node+15, type: type1}, +// CHECK:STDOUT: {kind: Assign, arg0: node+3, arg1: node+16}, +// CHECK:STDOUT: {kind: IntegerLiteral, arg0: int6, type: type0}, +// CHECK:STDOUT: {kind: ArrayType, arg0: node+18, arg1: type3, type: typeTypeType}, +// CHECK:STDOUT: {kind: VarStorage, arg0: str2, type: type4}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real0, type: type3}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+21, type: type3}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real1, type: type3}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+23, type: type3}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real2, type: type3}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+25, type: type3}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real3, type: type3}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+27, type: type3}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real4, type: type3}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+29, type: type3}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real5, type: type3}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+31, type: type3}, +// CHECK:STDOUT: {kind: RealLiteral, arg0: real6, type: type3}, +// CHECK:STDOUT: {kind: StubReference, arg0: node+33, type: type3}, +// CHECK:STDOUT: {kind: TupleType, arg0: typeBlock1, type: typeTypeType}, +// CHECK:STDOUT: {kind: TupleValue, arg0: block4, type: type5}, +// CHECK:STDOUT: {kind: ArrayValue, arg0: node+36, type: type4}, +// CHECK:STDOUT: {kind: Assign, arg0: node+20, arg1: node+37}, +// CHECK:STDOUT: {kind: Return}, +// CHECK:STDOUT: ] +// CHECK:STDOUT: node_blocks: [ +// CHECK:STDOUT: [ +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+0, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+1, +// CHECK:STDOUT: node+2, +// CHECK:STDOUT: node+3, +// CHECK:STDOUT: node+4, +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+6, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+8, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+10, +// CHECK:STDOUT: node+11, +// CHECK:STDOUT: node+12, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: node+14, +// CHECK:STDOUT: node+15, +// CHECK:STDOUT: node+16, +// CHECK:STDOUT: node+17, +// CHECK:STDOUT: node+18, +// CHECK:STDOUT: node+19, +// CHECK:STDOUT: node+20, +// CHECK:STDOUT: node+21, +// CHECK:STDOUT: node+22, +// CHECK:STDOUT: node+23, +// CHECK:STDOUT: node+24, +// CHECK:STDOUT: node+25, +// CHECK:STDOUT: node+26, +// CHECK:STDOUT: node+27, +// CHECK:STDOUT: node+28, +// CHECK:STDOUT: node+29, +// CHECK:STDOUT: node+30, +// CHECK:STDOUT: node+31, +// CHECK:STDOUT: node+32, +// CHECK:STDOUT: node+33, +// CHECK:STDOUT: node+34, +// CHECK:STDOUT: node+35, +// CHECK:STDOUT: node+36, +// CHECK:STDOUT: node+37, +// CHECK:STDOUT: node+38, +// CHECK:STDOUT: node+39, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+5, +// CHECK:STDOUT: node+7, +// CHECK:STDOUT: node+9, +// CHECK:STDOUT: node+11, +// CHECK:STDOUT: node+13, +// CHECK:STDOUT: ], +// CHECK:STDOUT: [ +// CHECK:STDOUT: node+22, +// CHECK:STDOUT: node+24, +// CHECK:STDOUT: node+26, +// CHECK:STDOUT: node+28, +// CHECK:STDOUT: node+30, +// CHECK:STDOUT: node+32, +// CHECK:STDOUT: node+34, +// CHECK:STDOUT: ], +// CHECK:STDOUT: ] +// CHECK:STDOUT: +// CHECK:STDOUT: package { +// CHECK:STDOUT: %.loc7 = fn_decl @F +// CHECK:STDOUT: } +// CHECK:STDOUT: +// CHECK:STDOUT: fn @F() { +// CHECK:STDOUT: !entry: +// CHECK:STDOUT: %.loc10_19: i32 = int_literal 5 +// CHECK:STDOUT: %.loc10_20: type = array_type %.loc10_19, i32 +// CHECK:STDOUT: %ints: ref [i32; 5] = var "ints" +// CHECK:STDOUT: %.loc11_5.1: i32 = int_literal 8 +// CHECK:STDOUT: %.loc11_5.2: i32 = stub_reference %.loc11_5.1 +// CHECK:STDOUT: %.loc12_5.1: i32 = int_literal 9 +// CHECK:STDOUT: %.loc12_5.2: i32 = stub_reference %.loc12_5.1 +// CHECK:STDOUT: %.loc13_5.1: i32 = int_literal 8 +// CHECK:STDOUT: %.loc13_5.2: i32 = stub_reference %.loc13_5.1 +// CHECK:STDOUT: %.loc14_5.1: i32 = int_literal 8 +// CHECK:STDOUT: %.loc14_5.2: i32 = stub_reference %.loc14_5.1 +// CHECK:STDOUT: %.loc15_5.1: i32 = int_literal 39999999999999999993 +// CHECK:STDOUT: %.loc15_5.2: i32 = stub_reference %.loc15_5.1 +// CHECK:STDOUT: %.loc16_3.1: type = tuple_type (i32, i32, i32, i32, i32) +// CHECK:STDOUT: %.loc16_3.2: (i32, i32, i32, i32, i32) = tuple_value (%.loc11_5.2, %.loc12_5.2, %.loc13_5.2, %.loc14_5.2, %.loc15_5.2) +// CHECK:STDOUT: %.loc16_3.3: [i32; 5] = array_value %.loc16_3.2 +// CHECK:STDOUT: assign %ints, %.loc16_3.3 +// CHECK:STDOUT: %.loc17_21: i32 = int_literal 7 +// CHECK:STDOUT: %.loc17_22: type = array_type %.loc17_21, f64 +// CHECK:STDOUT: %floats: ref [f64; 7] = var "floats" +// CHECK:STDOUT: %.loc18_5.1: f64 = real_literal 9e-1 +// CHECK:STDOUT: %.loc18_5.2: f64 = stub_reference %.loc18_5.1 +// CHECK:STDOUT: %.loc19_5.1: f64 = real_literal 80e-1 +// CHECK:STDOUT: %.loc19_5.2: f64 = stub_reference %.loc19_5.1 +// CHECK:STDOUT: %.loc20_5.1: f64 = real_literal 800e-1 +// CHECK:STDOUT: %.loc20_5.2: f64 = stub_reference %.loc20_5.1 +// CHECK:STDOUT: %.loc21_5.1: f64 = real_literal 10e6 +// CHECK:STDOUT: %.loc21_5.2: f64 = stub_reference %.loc21_5.1 +// CHECK:STDOUT: %.loc22_5.1: f64 = real_literal 10e7 +// CHECK:STDOUT: %.loc22_5.2: f64 = stub_reference %.loc22_5.1 +// CHECK:STDOUT: %.loc23_5.1: f64 = real_literal 10e-9 +// CHECK:STDOUT: %.loc23_5.2: f64 = stub_reference %.loc23_5.1 +// CHECK:STDOUT: %.loc24_5.1: f64 = real_literal 399999999999999999930e39999999999999999992 +// CHECK:STDOUT: %.loc24_5.2: f64 = stub_reference %.loc24_5.1 +// CHECK:STDOUT: %.loc25_3.1: type = tuple_type (f64, f64, f64, f64, f64, f64, f64) +// CHECK:STDOUT: %.loc25_3.2: (f64, f64, f64, f64, f64, f64, f64) = tuple_value (%.loc18_5.2, %.loc19_5.2, %.loc20_5.2, %.loc21_5.2, %.loc22_5.2, %.loc23_5.2, %.loc24_5.2) +// CHECK:STDOUT: %.loc25_3.3: [f64; 7] = array_value %.loc25_3.2 +// CHECK:STDOUT: assign %floats, %.loc25_3.3 +// CHECK:STDOUT: return +// CHECK:STDOUT: } diff --git a/toolchain/check/testdata/index/fail_array_large_index.carbon b/toolchain/check/testdata/index/fail_array_large_index.carbon index 4298e7a00e12..f044fd6c0810 100644 --- a/toolchain/check/testdata/index/fail_array_large_index.carbon +++ b/toolchain/check/testdata/index/fail_array_large_index.carbon @@ -16,7 +16,7 @@ var b: i32 = a[0xFFFFFFFFFFFFFFFFF]; // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 1, // CHECK:STDOUT: 12, -// CHECK:STDOUT: -1, +// CHECK:STDOUT: 295147905179352825855, // CHECK:STDOUT: ] // CHECK:STDOUT: real_literals: [ // CHECK:STDOUT: ] diff --git a/toolchain/check/testdata/index/fail_tuple_large_index.carbon b/toolchain/check/testdata/index/fail_tuple_large_index.carbon index 909062432009..520f7404a2b0 100644 --- a/toolchain/check/testdata/index/fail_tuple_large_index.carbon +++ b/toolchain/check/testdata/index/fail_tuple_large_index.carbon @@ -16,7 +16,7 @@ var c: i32 = b[0xFFFFFFFFFFFFFFFFF]; // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 12, -// CHECK:STDOUT: -1, +// CHECK:STDOUT: 295147905179352825855, // CHECK:STDOUT: ] // CHECK:STDOUT: real_literals: [ // CHECK:STDOUT: ] diff --git a/toolchain/check/testdata/operators/assignment.carbon b/toolchain/check/testdata/operators/assignment.carbon index 147e082bf658..295f976d2317 100644 --- a/toolchain/check/testdata/operators/assignment.carbon +++ b/toolchain/check/testdata/operators/assignment.carbon @@ -28,7 +28,7 @@ fn Main() { // CHECK:STDOUT: ] // CHECK:STDOUT: integer_literals: [ // CHECK:STDOUT: 12, -// CHECK:STDOUT: -7, +// CHECK:STDOUT: 9, // CHECK:STDOUT: 1, // CHECK:STDOUT: 2, // CHECK:STDOUT: 0, diff --git a/toolchain/lex/testdata/numeric_literals.carbon b/toolchain/lex/testdata/numeric_literals.carbon new file mode 100644 index 000000000000..97899466487d --- /dev/null +++ b/toolchain/lex/testdata/numeric_literals.carbon @@ -0,0 +1,84 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// CHECK:STDOUT: [ + +fn F() { +// CHECK:STDOUT: { index: 0, kind: 'Fn', line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: 'fn', has_trailing_space: true }, +// CHECK:STDOUT: { index: 1, kind: 'Identifier', line: {{ *}}[[@LINE-2]], column: 4, indent: 1, spelling: 'F', identifier: 0 }, +// CHECK:STDOUT: { index: 2, kind: 'OpenParen', line: {{ *}}[[@LINE-3]], column: 5, indent: 1, spelling: '(', closing_token: 3 }, +// CHECK:STDOUT: { index: 3, kind: 'CloseParen', line: {{ *}}[[@LINE-4]], column: 6, indent: 1, spelling: ')', opening_token: 2, has_trailing_space: true }, +// CHECK:STDOUT: { index: 4, kind: 'OpenCurlyBrace', line: {{ *}}[[@LINE-5]], column: 8, indent: 1, spelling: '{', closing_token: 53, has_trailing_space: true }, + // 8 and 9 trigger special behavior in APInt when mishandling signed versus + // unsigned, so we pay extra attention to those. + var ints: [i32; 5] = ( + // CHECK:STDOUT: { index: 5, kind: 'Var', line: {{ *}}[[@LINE-1]], column: 3, indent: 3, spelling: 'var', has_trailing_space: true }, + // CHECK:STDOUT: { index: 6, kind: 'Identifier', line: {{ *}}[[@LINE-2]], column: 7, indent: 3, spelling: 'ints', identifier: 1 }, + // CHECK:STDOUT: { index: 7, kind: 'Colon', line: {{ *}}[[@LINE-3]], column: 11, indent: 3, spelling: ':', has_trailing_space: true }, + // CHECK:STDOUT: { index: 8, kind: 'OpenSquareBracket', line: {{ *}}[[@LINE-4]], column: 13, indent: 3, spelling: '[', closing_token: 12 }, + // CHECK:STDOUT: { index: 9, kind: 'IntegerTypeLiteral', line: {{ *}}[[@LINE-5]], column: 14, indent: 3, spelling: 'i32' }, + // CHECK:STDOUT: { index: 10, kind: 'Semi', line: {{ *}}[[@LINE-6]], column: 17, indent: 3, spelling: ';', has_trailing_space: true }, + // CHECK:STDOUT: { index: 11, kind: 'IntegerLiteral', line: {{ *}}[[@LINE-7]], column: 19, indent: 3, spelling: '5', value: `5` }, + // CHECK:STDOUT: { index: 12, kind: 'CloseSquareBracket', line: {{ *}}[[@LINE-8]], column: 20, indent: 3, spelling: ']', opening_token: 8, has_trailing_space: true }, + // CHECK:STDOUT: { index: 13, kind: 'Equal', line: {{ *}}[[@LINE-9]], column: 22, indent: 3, spelling: '=', has_trailing_space: true }, + // CHECK:STDOUT: { index: 14, kind: 'OpenParen', line: {{ *}}[[@LINE-10]], column: 24, indent: 3, spelling: '(', closing_token: 25, has_trailing_space: true }, + 8, + // CHECK:STDOUT: { index: 15, kind: 'IntegerLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '8', value: `8` }, + // CHECK:STDOUT: { index: 16, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 6, indent: 5, spelling: ',', has_trailing_space: true }, + 9, + // CHECK:STDOUT: { index: 17, kind: 'IntegerLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '9', value: `9` }, + // CHECK:STDOUT: { index: 18, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 6, indent: 5, spelling: ',', has_trailing_space: true }, + 0x8, + // CHECK:STDOUT: { index: 19, kind: 'IntegerLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '0x8', value: `8` }, + // CHECK:STDOUT: { index: 20, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 8, indent: 5, spelling: ',', has_trailing_space: true }, + 0b1000, + // CHECK:STDOUT: { index: 21, kind: 'IntegerLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '0b1000', value: `8` }, + // CHECK:STDOUT: { index: 22, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 11, indent: 5, spelling: ',', has_trailing_space: true }, + 39999999999999999993, + // CHECK:STDOUT: { index: 23, kind: 'IntegerLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '39999999999999999993', value: `39999999999999999993` }, + // CHECK:STDOUT: { index: 24, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 25, indent: 5, spelling: ',', has_trailing_space: true }, + ); + // CHECK:STDOUT: { index: 25, kind: 'CloseParen', line: {{ *}}[[@LINE-1]], column: 3, indent: 3, spelling: ')', opening_token: 14 }, + // CHECK:STDOUT: { index: 26, kind: 'Semi', line: {{ *}}[[@LINE-2]], column: 4, indent: 3, spelling: ';', has_trailing_space: true }, + var floats: [f64; 7] = ( + // CHECK:STDOUT: { index: 27, kind: 'Var', line: {{ *}}[[@LINE-1]], column: 3, indent: 3, spelling: 'var', has_trailing_space: true }, + // CHECK:STDOUT: { index: 28, kind: 'Identifier', line: {{ *}}[[@LINE-2]], column: 7, indent: 3, spelling: 'floats', identifier: 2 }, + // CHECK:STDOUT: { index: 29, kind: 'Colon', line: {{ *}}[[@LINE-3]], column: 13, indent: 3, spelling: ':', has_trailing_space: true }, + // CHECK:STDOUT: { index: 30, kind: 'OpenSquareBracket', line: {{ *}}[[@LINE-4]], column: 15, indent: 3, spelling: '[', closing_token: 34 }, + // CHECK:STDOUT: { index: 31, kind: 'FloatingPointTypeLiteral', line: {{ *}}[[@LINE-5]], column: 16, indent: 3, spelling: 'f64' }, + // CHECK:STDOUT: { index: 32, kind: 'Semi', line: {{ *}}[[@LINE-6]], column: 19, indent: 3, spelling: ';', has_trailing_space: true }, + // CHECK:STDOUT: { index: 33, kind: 'IntegerLiteral', line: {{ *}}[[@LINE-7]], column: 21, indent: 3, spelling: '7', value: `7` }, + // CHECK:STDOUT: { index: 34, kind: 'CloseSquareBracket', line: {{ *}}[[@LINE-8]], column: 22, indent: 3, spelling: ']', opening_token: 30, has_trailing_space: true }, + // CHECK:STDOUT: { index: 35, kind: 'Equal', line: {{ *}}[[@LINE-9]], column: 24, indent: 3, spelling: '=', has_trailing_space: true }, + // CHECK:STDOUT: { index: 36, kind: 'OpenParen', line: {{ *}}[[@LINE-10]], column: 26, indent: 3, spelling: '(', closing_token: 51, has_trailing_space: true }, + 0.9, + // CHECK:STDOUT: { index: 37, kind: 'RealLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '0.9', value: `9*10^-1` }, + // CHECK:STDOUT: { index: 38, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 8, indent: 5, spelling: ',', has_trailing_space: true }, + 8.0, + // CHECK:STDOUT: { index: 39, kind: 'RealLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '8.0', value: `80*10^-1` }, + // CHECK:STDOUT: { index: 40, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 8, indent: 5, spelling: ',', has_trailing_space: true }, + 80.0, + // CHECK:STDOUT: { index: 41, kind: 'RealLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '80.0', value: `800*10^-1` }, + // CHECK:STDOUT: { index: 42, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 9, indent: 5, spelling: ',', has_trailing_space: true }, + 1.0e7, + // CHECK:STDOUT: { index: 43, kind: 'RealLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '1.0e7', value: `10*10^6` }, + // CHECK:STDOUT: { index: 44, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 10, indent: 5, spelling: ',', has_trailing_space: true }, + 1.0e8, + // CHECK:STDOUT: { index: 45, kind: 'RealLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '1.0e8', value: `10*10^7` }, + // CHECK:STDOUT: { index: 46, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 10, indent: 5, spelling: ',', has_trailing_space: true }, + 1.0e-8, + // CHECK:STDOUT: { index: 47, kind: 'RealLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '1.0e-8', value: `10*10^-9` }, + // CHECK:STDOUT: { index: 48, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 11, indent: 5, spelling: ',', has_trailing_space: true }, + 39999999999999999993.0e39999999999999999993, + // CHECK:STDOUT: { index: 49, kind: 'RealLiteral', line: {{ *}}[[@LINE-1]], column: 5, indent: 5, spelling: '39999999999999999993.0e39999999999999999993', value: `399999999999999999930*10^39999999999999999992` }, + // CHECK:STDOUT: { index: 50, kind: 'Comma', line: {{ *}}[[@LINE-2]], column: 48, indent: 5, spelling: ',', has_trailing_space: true }, + ); + // CHECK:STDOUT: { index: 51, kind: 'CloseParen', line: {{ *}}[[@LINE-1]], column: 3, indent: 3, spelling: ')', opening_token: 36 }, + // CHECK:STDOUT: { index: 52, kind: 'Semi', line: {{ *}}[[@LINE-2]], column: 4, indent: 3, spelling: ';', has_trailing_space: true }, +} +// CHECK:STDOUT: { index: 53, kind: 'CloseCurlyBrace', line: {{ *}}[[@LINE-1]], column: 1, indent: 1, spelling: '}', opening_token: 4, has_trailing_space: true }, + +// CHECK:STDOUT: { index: 54, kind: 'EndOfFile', line: {{ *}}[[@LINE+1]], column: {{ *\d+}}, indent: 1, spelling: '' }, +// CHECK:STDOUT: ] diff --git a/toolchain/lex/tokenized_buffer.h b/toolchain/lex/tokenized_buffer.h index 2819e7e2e350..f1853b84aa74 100644 --- a/toolchain/lex/tokenized_buffer.h +++ b/toolchain/lex/tokenized_buffer.h @@ -128,8 +128,8 @@ class TokenIterator class RealLiteralValue : public Printable { public: auto Print(llvm::raw_ostream& output_stream) const -> void { - output_stream << mantissa << "*" << (is_decimal ? "10" : "2") << "^" - << exponent; + mantissa.print(output_stream, /*isSigned=*/false); + output_stream << "*" << (is_decimal ? "10" : "2") << "^" << exponent; } // The mantissa, represented as an unsigned integer. diff --git a/toolchain/lower/handle.cpp b/toolchain/lower/handle.cpp index b3b3ed50c822..b57772a02ed6 100644 --- a/toolchain/lower/handle.cpp +++ b/toolchain/lower/handle.cpp @@ -251,7 +251,7 @@ auto HandleRealLiteral(FunctionContext& context, SemIR::NodeId node_id, context.semantics_ir().GetRealLiteral(node.GetAsRealLiteral()); // TODO: This will probably have overflow issues, and should be fixed. double val = - real.mantissa.getSExtValue() * + real.mantissa.getZExtValue() * std::pow((real.is_decimal ? 10 : 2), real.exponent.getSExtValue()); llvm::APFloat llvm_val(val); context.SetLocal(node_id, llvm::ConstantFP::get( diff --git a/toolchain/lower/testdata/basics/numeric_literals.carbon b/toolchain/lower/testdata/basics/numeric_literals.carbon new file mode 100644 index 000000000000..ce89100de345 --- /dev/null +++ b/toolchain/lower/testdata/basics/numeric_literals.carbon @@ -0,0 +1,97 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +fn F() { + // 8 and 9 trigger special behavior in APInt when mishandling signed versus + // unsigned, so we pay extra attention to those. + var ints: [i32; 4] = ( + 8, + 9, + 0x8, + 0b1000, + ); + var floats: [f64; 6] = ( + 0.9, + 8.0, + 80.0, + 1.0e7, + 1.0e8, + 1.0e-8, + ); +} + +// CHECK:STDOUT: ; ModuleID = 'numeric_literals.carbon' +// CHECK:STDOUT: source_filename = "numeric_literals.carbon" +// CHECK:STDOUT: +// CHECK:STDOUT: define void @F() { +// CHECK:STDOUT: %ints = alloca [4 x i32], align 4 +// CHECK:STDOUT: %tuple = alloca { i32, i32, i32, i32 }, align 8 +// CHECK:STDOUT: %1 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 0 +// CHECK:STDOUT: store i32 8, ptr %1, align 4 +// CHECK:STDOUT: %2 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 1 +// CHECK:STDOUT: store i32 9, ptr %2, align 4 +// CHECK:STDOUT: %3 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 2 +// CHECK:STDOUT: store i32 8, ptr %3, align 4 +// CHECK:STDOUT: %4 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 3 +// CHECK:STDOUT: store i32 8, ptr %4, align 4 +// CHECK:STDOUT: %array = alloca [4 x i32], align 4 +// CHECK:STDOUT: %array.element = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 0 +// CHECK:STDOUT: %5 = load i32, ptr %array.element, align 4 +// CHECK:STDOUT: %6 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 0 +// CHECK:STDOUT: store i32 %5, ptr %6, align 4 +// CHECK:STDOUT: %array.element1 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 1 +// CHECK:STDOUT: %7 = load i32, ptr %array.element1, align 4 +// CHECK:STDOUT: %8 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 1 +// CHECK:STDOUT: store i32 %7, ptr %8, align 4 +// CHECK:STDOUT: %array.element2 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 2 +// CHECK:STDOUT: %9 = load i32, ptr %array.element2, align 4 +// CHECK:STDOUT: %10 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 2 +// CHECK:STDOUT: store i32 %9, ptr %10, align 4 +// CHECK:STDOUT: %array.element3 = getelementptr inbounds { i32, i32, i32, i32 }, ptr %tuple, i32 0, i32 3 +// CHECK:STDOUT: %11 = load i32, ptr %array.element3, align 4 +// CHECK:STDOUT: %12 = getelementptr inbounds [4 x i32], ptr %array, i32 0, i32 3 +// CHECK:STDOUT: store i32 %11, ptr %12, align 4 +// CHECK:STDOUT: %floats = alloca [6 x double], align 8 +// CHECK:STDOUT: %tuple4 = alloca { double, double, double, double, double, double }, align 8 +// CHECK:STDOUT: %13 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 0 +// CHECK:STDOUT: store double 9.000000e-01, ptr %13, align 8 +// CHECK:STDOUT: %14 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 1 +// CHECK:STDOUT: store double 8.000000e+00, ptr %14, align 8 +// CHECK:STDOUT: %15 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 2 +// CHECK:STDOUT: store double 8.000000e+01, ptr %15, align 8 +// CHECK:STDOUT: %16 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 3 +// CHECK:STDOUT: store double 1.000000e+07, ptr %16, align 8 +// CHECK:STDOUT: %17 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 4 +// CHECK:STDOUT: store double 1.000000e+08, ptr %17, align 8 +// CHECK:STDOUT: %18 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 5 +// CHECK:STDOUT: store double 1.000000e-08, ptr %18, align 8 +// CHECK:STDOUT: %array5 = alloca [6 x double], align 8 +// CHECK:STDOUT: %array.element6 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 0 +// CHECK:STDOUT: %19 = load double, ptr %array.element6, align 8 +// CHECK:STDOUT: %20 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 0 +// CHECK:STDOUT: store double %19, ptr %20, align 8 +// CHECK:STDOUT: %array.element7 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 1 +// CHECK:STDOUT: %21 = load double, ptr %array.element7, align 8 +// CHECK:STDOUT: %22 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 1 +// CHECK:STDOUT: store double %21, ptr %22, align 8 +// CHECK:STDOUT: %array.element8 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 2 +// CHECK:STDOUT: %23 = load double, ptr %array.element8, align 8 +// CHECK:STDOUT: %24 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 2 +// CHECK:STDOUT: store double %23, ptr %24, align 8 +// CHECK:STDOUT: %array.element9 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 3 +// CHECK:STDOUT: %25 = load double, ptr %array.element9, align 8 +// CHECK:STDOUT: %26 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 3 +// CHECK:STDOUT: store double %25, ptr %26, align 8 +// CHECK:STDOUT: %array.element10 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 4 +// CHECK:STDOUT: %27 = load double, ptr %array.element10, align 8 +// CHECK:STDOUT: %28 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 4 +// CHECK:STDOUT: store double %27, ptr %28, align 8 +// CHECK:STDOUT: %array.element11 = getelementptr inbounds { double, double, double, double, double, double }, ptr %tuple4, i32 0, i32 5 +// CHECK:STDOUT: %29 = load double, ptr %array.element11, align 8 +// CHECK:STDOUT: %30 = getelementptr inbounds [6 x double], ptr %array5, i32 0, i32 5 +// CHECK:STDOUT: store double %29, ptr %30, align 8 +// CHECK:STDOUT: ret void +// CHECK:STDOUT: } diff --git a/toolchain/parse/testdata/basics/numeric_literals.carbon b/toolchain/parse/testdata/basics/numeric_literals.carbon new file mode 100644 index 000000000000..66d65f9d4ca3 --- /dev/null +++ b/toolchain/parse/testdata/basics/numeric_literals.carbon @@ -0,0 +1,84 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE + +fn F() { + // 8 and 9 trigger special behavior in APInt when mishandling signed versus + // unsigned, so we pay extra attention to those. + var ints: [i32; 5] = ( + 8, + 9, + 0x8, + 0b1000, + 39999999999999999993, + ); + var floats: [f64; 7] = ( + 0.9, + 8.0, + 80.0, + 1.0e7, + 1.0e8, + 1.0e-8, + 39999999999999999993.0e39999999999999999993, + ); +} + +// CHECK:STDOUT: [ +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'Name', text: 'F'}, +// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('}, +// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDefinitionStart', text: '{', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'Name', text: 'ints'}, +// CHECK:STDOUT: {kind: 'ArrayExpressionStart', text: '['}, +// CHECK:STDOUT: {kind: 'Literal', text: 'i32'}, +// CHECK:STDOUT: {kind: 'ArrayExpressionSemi', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'Literal', text: '5'}, +// CHECK:STDOUT: {kind: 'ArrayExpression', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'ParenExpressionOrTupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'Literal', text: '8'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '9'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '0x8'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '0b1000'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '39999999999999999993'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 22}, +// CHECK:STDOUT: {kind: 'VariableIntroducer', text: 'var'}, +// CHECK:STDOUT: {kind: 'Name', text: 'floats'}, +// CHECK:STDOUT: {kind: 'ArrayExpressionStart', text: '['}, +// CHECK:STDOUT: {kind: 'Literal', text: 'f64'}, +// CHECK:STDOUT: {kind: 'ArrayExpressionSemi', text: ';', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'Literal', text: '7'}, +// CHECK:STDOUT: {kind: 'ArrayExpression', text: ']', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'PatternBinding', text: ':', subtree_size: 7}, +// CHECK:STDOUT: {kind: 'VariableInitializer', text: '='}, +// CHECK:STDOUT: {kind: 'ParenExpressionOrTupleLiteralStart', text: '('}, +// CHECK:STDOUT: {kind: 'Literal', text: '0.9'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '8.0'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '80.0'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '1.0e7'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '1.0e8'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '1.0e-8'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'Literal', text: '39999999999999999993.0e39999999999999999993'}, +// CHECK:STDOUT: {kind: 'TupleLiteralComma', text: ','}, +// CHECK:STDOUT: {kind: 'TupleLiteral', text: ')', subtree_size: 16}, +// CHECK:STDOUT: {kind: 'VariableDeclaration', text: ';', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 54}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/sem_ir/file.cpp b/toolchain/sem_ir/file.cpp index 1209eb8b373b..9b7b74a1a400 100644 --- a/toolchain/sem_ir/file.cpp +++ b/toolchain/sem_ir/file.cpp @@ -92,13 +92,17 @@ auto File::Verify() const -> ErrorOr { static constexpr int Indent = 2; -template -static auto PrintList(llvm::raw_ostream& out, llvm::StringLiteral name, - const llvm::SmallVector& list) { +template > +static auto PrintList( + llvm::raw_ostream& out, llvm::StringLiteral name, + const llvm::SmallVector& list, + PrintT print = [](llvm::raw_ostream& out, const T& val) { out << val; }) { out << name << ": [\n"; for (const auto& element : list) { out.indent(Indent); - out << element << ",\n"; + print(out, element); + out << ",\n"; } out << "]\n"; } @@ -125,7 +129,12 @@ auto File::Print(llvm::raw_ostream& out, bool include_builtins) const -> void { out << "cross_reference_irs_size: " << cross_reference_irs_.size() << "\n"; PrintList(out, "functions", functions_); - PrintList(out, "integer_literals", integer_literals_); + // Integer literals are an APInt, and default to a signed print, but the + // ZExtValue print is correct. + PrintList(out, "integer_literals", integer_literals_, + [](llvm::raw_ostream& out, const llvm::APInt& val) { + val.print(out, /*isSigned=*/false); + }); PrintList(out, "real_literals", real_literals_); PrintList(out, "strings", strings_); PrintList(out, "types", types_); diff --git a/toolchain/sem_ir/file.h b/toolchain/sem_ir/file.h index 49c97f25a06f..e408b7e884a4 100644 --- a/toolchain/sem_ir/file.h +++ b/toolchain/sem_ir/file.h @@ -52,8 +52,9 @@ struct Function : public Printable { struct RealLiteral : public Printable { auto Print(llvm::raw_ostream& out) const -> void { - out << "{mantissa: " << mantissa << ", exponent: " << exponent - << ", is_decimal: " << is_decimal << "}"; + out << "{mantissa: "; + mantissa.print(out, /*isSigned=*/false); + out << ", exponent: " << exponent << ", is_decimal: " << is_decimal << "}"; } llvm::APInt mantissa; diff --git a/toolchain/sem_ir/formatter.cpp b/toolchain/sem_ir/formatter.cpp index 6e86771427a1..5bfad9706973 100644 --- a/toolchain/sem_ir/formatter.cpp +++ b/toolchain/sem_ir/formatter.cpp @@ -717,7 +717,8 @@ class Formatter { auto FormatArg(RealLiteralId id) -> void { // TODO: Format with a `.` when the exponent is near zero. const auto& real = semantics_ir_.GetRealLiteral(id); - out_ << real.mantissa << (real.is_decimal ? 'e' : 'p') << real.exponent; + real.mantissa.print(out_, /*isSigned=*/false); + out_ << (real.is_decimal ? 'e' : 'p') << real.exponent; } auto FormatArg(StringId id) -> void { diff --git a/toolchain/testing/BUILD b/toolchain/testing/BUILD new file mode 100644 index 000000000000..a3c08fae30b9 --- /dev/null +++ b/toolchain/testing/BUILD @@ -0,0 +1,5 @@ +# Part of the Carbon Language project, under the Apache License v2.0 with LLVM +# Exceptions. See /LICENSE for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +package(default_visibility = ["//visibility:public"])