From 250da35c3b3cb089f071334836025b6fbe002f14 Mon Sep 17 00:00:00 2001 From: mstr-six <169169413+mstr-six@users.noreply.github.com> Date: Fri, 12 Jun 2026 17:19:57 -0400 Subject: [PATCH] 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 --- toolchain/check/eval.cpp | 18 ++++-- .../int/fail_convert_oversized_type.carbon | 57 +++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 toolchain/check/testdata/builtins/int/fail_convert_oversized_type.carbon diff --git a/toolchain/check/eval.cpp b/toolchain/check/eval.cpp index 0c6e33c30d26..f218330f894e 100644 --- a/toolchain/check/eval.cpp +++ b/toolchain/check/eval.cpp @@ -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(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(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(); diff --git a/toolchain/check/testdata/builtins/int/fail_convert_oversized_type.carbon b/toolchain/check/testdata/builtins/int/fail_convert_oversized_type.carbon new file mode 100644 index 000000000000..4023ab21c878 --- /dev/null +++ b/toolchain/check/testdata/builtins/int/fail_convert_oversized_type.carbon @@ -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;