mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Fix big integer literals type (#6234)
Following the C++ standard rules for assigning a type to a decimal integer literal, when a Carbon integer literal is passed as a call argument to a C++ function and it is too big to fit to `int`, `long` or `long long`, it is assigned an extended integer type (`_int128`). Discussed in the [interop meeting](https://docs.google.com/document/d/1YlxEOJ0r-o19o19TCJbFl4Ln1U88yn_Vj23y1Hr5vTk/edit?tab=t.0#heading=h.zdrwb1soj9ms) and documented in this [design doc](https://docs.google.com/document/d/18u8z9UEuGH73XzXlDynTgyNK76q1Efl8YYWbpM5LX7o/edit?tab=t.0#heading=h.vxmw1gfg49f2). Part of #5915
This commit is contained in:
@@ -28,9 +28,13 @@
|
||||
|
||||
namespace Carbon::Check {
|
||||
|
||||
// Find the bit width of an integer literal.
|
||||
// The default bit width is 32. If the literal's bit width is greater than 32,
|
||||
// the bit width is increased to 64.
|
||||
// Find the bit width of an integer literal. Following the C++ standard rules
|
||||
// for assigning a type to a decimal integer literal, the first signed integer
|
||||
// in which the value could fit among bit widths of 32, 64 and 128 is selected.
|
||||
// If the value can't fit into a signed integer with width of 128-bits, then a
|
||||
// diagnostic is emitted and the function returns IntId::None. Returns
|
||||
// IntId::None also if the argument is not a constant integer, if it is an
|
||||
// error constant, or if it is a symbolic constant.
|
||||
static auto FindIntLiteralBitWidth(Context& context, SemIR::InstId arg_id)
|
||||
-> IntId {
|
||||
auto arg_const_id = context.constant_values().Get(arg_id);
|
||||
@@ -42,13 +46,24 @@ static auto FindIntLiteralBitWidth(Context& context, SemIR::InstId arg_id)
|
||||
}
|
||||
auto arg = context.insts().GetAs<SemIR::IntValue>(
|
||||
context.constant_values().GetInstId(arg_const_id));
|
||||
unsigned arg_non_sign_bits =
|
||||
context.ints().Get(arg.int_id).getSignificantBits() - 1;
|
||||
llvm::APInt arg_val = context.ints().Get(arg.int_id);
|
||||
int arg_non_sign_bits = arg_val.getSignificantBits() - 1;
|
||||
|
||||
// TODO: What if the literal is larger than 64 bits? Currently an error is
|
||||
// reported that the int value is too large for type `i64`. Maybe try to fit
|
||||
// in i128/i256? Try unsigned?
|
||||
return (arg_non_sign_bits <= 32) ? IntId::MakeRaw(32) : IntId::MakeRaw(64);
|
||||
if (arg_non_sign_bits >= 128) {
|
||||
CARBON_DIAGNOSTIC(IntTooLargeForCppType, Error,
|
||||
"integer value {0} too large to fit in a signed C++ "
|
||||
"integer type; requires {1} bits, but max is 128",
|
||||
TypedInt, int);
|
||||
context.emitter().Emit(arg_id, IntTooLargeForCppType,
|
||||
{.type = arg.type_id, .value = arg_val},
|
||||
arg_non_sign_bits + 1);
|
||||
return IntId::None;
|
||||
}
|
||||
|
||||
return (arg_non_sign_bits < 32)
|
||||
? IntId::MakeRaw(32)
|
||||
: ((arg_non_sign_bits < 64) ? IntId::MakeRaw(64)
|
||||
: IntId::MakeRaw(128));
|
||||
}
|
||||
|
||||
// Attempts to look up a type by name, and returns the corresponding `QualType`,
|
||||
|
||||
Reference in New Issue
Block a user