Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions toolchain/check/cpp/type_mapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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`,
Expand Down
Loading
Loading