mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:50:14 +01:00
Recover when converting to an invalid integer type (#7342)
Converting an integer value to a destination type that is not a valid integer type -- such as `i8388609` or `i16777216`, whose bit widths are diagnosed as invalid -- hit a CHECK failure in `TypeStore::GetIntTypeInfo` during constant evaluation of `int.convert` / `int.convert_checked`: ``` CHECK failure at toolchain/sem_ir/type.cpp:189: int_info: Type type(...) is not an integer type ``` The width error is already diagnosed when forming the type (`IntWidthNotMultipleOf8` / `IntWidthTooLarge`), so `PerformIntConvert` and `PerformCheckedIntConvert` now use `TryGetIntTypeInfo` and produce an error value instead of crashing, following the existing `SemIR::ErrorInst::ConstantId` convention in `eval.cpp`. Added a file test covering all three reproducers from the issue (`i8388609`, `i16777216`, `Core.Int(8388609)`); it crashes without this change. The full `//toolchain/testing:file_test` suite (1578 tests) passes. Fixes #7278. I have reviewed this change and take responsibility for it. Assisted-by: Claude
This commit is contained in:
@@ -1327,8 +1327,14 @@ static auto PerformIntConvert(Context& context, SemIR::InstId arg_id,
|
||||
SemIR::TypeId dest_type_id) -> SemIR::ConstantId {
|
||||
auto arg_val =
|
||||
context.ints().Get(context.insts().GetAs<SemIR::IntValue>(arg_id).int_id);
|
||||
auto [dest_is_signed, bit_width_id] =
|
||||
context.sem_ir().types().GetIntTypeInfo(dest_type_id);
|
||||
auto dest_int_info = context.sem_ir().types().TryGetIntTypeInfo(dest_type_id);
|
||||
if (!dest_int_info) {
|
||||
// The destination is not a valid integer type, such as when its bit width
|
||||
// was diagnosed as invalid. The error was already diagnosed when forming
|
||||
// the type, so just produce an error value.
|
||||
return SemIR::ErrorInst::ConstantId;
|
||||
}
|
||||
auto [dest_is_signed, bit_width_id] = *dest_int_info;
|
||||
if (bit_width_id.has_value()) {
|
||||
// TODO: If the value fits in the destination type, reuse the existing
|
||||
// int_id rather than recomputing it. This is probably the most common case.
|
||||
@@ -1351,8 +1357,12 @@ static auto PerformCheckedIntConvert(Context& context, SemIR::LocId loc_id,
|
||||
auto arg = context.insts().GetAs<SemIR::IntValue>(arg_id);
|
||||
auto arg_val = context.ints().Get(arg.int_id);
|
||||
|
||||
auto [is_signed, bit_width_id] =
|
||||
context.sem_ir().types().GetIntTypeInfo(dest_type_id);
|
||||
auto dest_int_info = context.sem_ir().types().TryGetIntTypeInfo(dest_type_id);
|
||||
if (!dest_int_info) {
|
||||
// The destination is not a valid integer type; see PerformIntConvert.
|
||||
return SemIR::ErrorInst::ConstantId;
|
||||
}
|
||||
auto [is_signed, bit_width_id] = *dest_int_info;
|
||||
auto width = bit_width_id.has_value()
|
||||
? context.ints().Get(bit_width_id).getZExtValue()
|
||||
: arg_val.getBitWidth();
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// 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
|
||||
//
|
||||
// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/full.carbon
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// TIP: To test this file alone, run:
|
||||
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/builtins/int/fail_convert_oversized_type.carbon
|
||||
// TIP: To dump output, run:
|
||||
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/builtins/int/fail_convert_oversized_type.carbon
|
||||
|
||||
// --- fail_width_not_multiple_of_8.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// Initializing a binding whose type is an invalid integer type must not crash
|
||||
// constant evaluation (#7278). The type is diagnosed; the conversion of the
|
||||
// initializer should then produce an error value, not a CHECK failure.
|
||||
// CHECK:STDERR: fail_width_not_multiple_of_8.carbon:[[@LINE+11]]:10: error: bit width of integer type literal must be a multiple of 8; use `Core.Int(8388609)` instead [IntWidthNotMultipleOf8]
|
||||
// CHECK:STDERR: let bad: i8388609 = 0;
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
// CHECK:STDERR: fail_width_not_multiple_of_8.carbon:[[@LINE+7]]:10: error: binding pattern has incomplete type `i8388609` in name binding declaration [IncompleteTypeInBindingDecl]
|
||||
// CHECK:STDERR: let bad: i8388609 = 0;
|
||||
// CHECK:STDERR: ^~~~~~~~
|
||||
// CHECK:STDERR: {{.*}}/prelude/types/int.carbon:18:9: note: integer type width of 8388609 is greater than the maximum supported width of 8388608 [IntWidthTooLarge]
|
||||
// CHECK:STDERR: adapt MakeInt(N);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let bad: i8388609 = 0;
|
||||
|
||||
// --- fail_width_too_large.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// CHECK:STDERR: fail_width_too_large.carbon:[[@LINE+7]]:10: error: binding pattern has incomplete type `i16777216` in name binding declaration [IncompleteTypeInBindingDecl]
|
||||
// CHECK:STDERR: let bad: i16777216 = 0;
|
||||
// CHECK:STDERR: ^~~~~~~~~
|
||||
// CHECK:STDERR: {{.*}}/prelude/types/int.carbon:18:9: note: integer type width of 16777216 is greater than the maximum supported width of 8388608 [IntWidthTooLarge]
|
||||
// CHECK:STDERR: adapt MakeInt(N);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let bad: i16777216 = 0;
|
||||
|
||||
// --- fail_width_too_large_core_int.carbon
|
||||
|
||||
library "[[@TEST_NAME]]";
|
||||
|
||||
// CHECK:STDERR: fail_width_too_large_core_int.carbon:[[@LINE+7]]:10: error: binding pattern has incomplete type `i8388609` in name binding declaration [IncompleteTypeInBindingDecl]
|
||||
// CHECK:STDERR: let bad: Core.Int(8388609) = 0;
|
||||
// CHECK:STDERR: ^~~~~~~~~~~~~~~~~
|
||||
// CHECK:STDERR: {{.*}}/prelude/types/int.carbon:18:9: note: integer type width of 8388609 is greater than the maximum supported width of 8388608 [IntWidthTooLarge]
|
||||
// CHECK:STDERR: adapt MakeInt(N);
|
||||
// CHECK:STDERR: ^~~~~~~~~~
|
||||
// CHECK:STDERR:
|
||||
let bad: Core.Int(8388609) = 0;
|
||||
Reference in New Issue
Block a user