Support LP64 platforms such as Darwin where int64_t is long long. (#7596)

Add `Core.CppCompat.[U]Long64` to represent a 64-bit long that is not
`i64`. Treat it as being "just slightly smaller than" `i64`, like we
treat `Core.CppCompat.LongLong64` as being "just slightly larger than"
`i64`, so that we get implicit conversions `Cpp.long` -> `i64` ->
`Cpp.long_long` on all targets.

This follows the direction of proposal #5448, and seems like the obvious
extension of the `[U]Long32` and `[U]LongLong64` types added in #6275
for targets of this "shape".

Assisted-by: Gemini via Antigravity
This commit is contained in:
Richard Smith
2026-08-07 16:10:01 +00:00
committed by GitHub
parent ee2b3888ef
commit c278bea3c5
16 changed files with 4904 additions and 3492 deletions
+80 -30
View File
@@ -15,6 +15,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -1109,17 +1110,48 @@ static auto MakeCppCompatType(Context& context, SemIR::LocId loc_id,
LookupNameInCore(context, loc_id, {CoreIdentifier::CppCompat, name}));
}
// Maps a C++ builtin integer type to a Carbon `Core.CppCompat` type.
static auto MapBuiltinCppCompatIntegerType(Context& context,
unsigned int cpp_width,
unsigned int carbon_width,
CoreIdentifier cpp_compat_name)
-> TypeExpr {
if (cpp_width != carbon_width) {
return TypeExpr::None;
auto GetIntNType(const clang::ASTContext& ast_context, unsigned width,
bool is_signed) -> clang::QualType {
const auto& target_info = ast_context.getTargetInfo();
// Work around Clang's getIntTypeForBitwidth being broken in various targets.
auto target_type = clang::TargetInfo::IntType::NoInt;
if (width == 64) {
target_type =
is_signed ? target_info.getInt64Type() : target_info.getUInt64Type();
} else if (width == 16) {
target_type =
is_signed ? target_info.getInt16Type() : target_info.getUInt16Type();
} else {
target_type = target_info.getIntTypeByWidth(width, is_signed);
}
return MakeCppCompatType(context, Parse::NodeId::None, cpp_compat_name);
switch (target_type) {
case clang::TargetInfo::NoInt:
// Call getIntTypeForBitwidth to pick up its i128 handling.
return ast_context.getIntTypeForBitwidth(width, is_signed);
case clang::TargetInfo::SignedChar:
return ast_context.SignedCharTy;
case clang::TargetInfo::UnsignedChar:
return ast_context.UnsignedCharTy;
case clang::TargetInfo::SignedShort:
return ast_context.ShortTy;
case clang::TargetInfo::UnsignedShort:
return ast_context.UnsignedShortTy;
case clang::TargetInfo::SignedInt:
return ast_context.IntTy;
case clang::TargetInfo::UnsignedInt:
return ast_context.UnsignedIntTy;
case clang::TargetInfo::SignedLong:
return ast_context.LongTy;
case clang::TargetInfo::UnsignedLong:
return ast_context.UnsignedLongTy;
case clang::TargetInfo::SignedLongLong:
return ast_context.LongLongTy;
case clang::TargetInfo::UnsignedLongLong:
return ast_context.UnsignedLongLongTy;
}
}
// Maps a C++ builtin integer type to a Carbon type.
@@ -1130,7 +1162,10 @@ static auto MapBuiltinIntegerType(Context& context, SemIR::LocId loc_id,
clang::ASTContext& ast_context = context.ast_context();
unsigned width = ast_context.getIntWidth(qual_type);
bool is_signed = type.isSignedInteger();
auto int_n_type = ast_context.getIntTypeForBitwidth(width, is_signed);
// Check whether the type is `intN_t` or `uintN_t`, and if so, map it to `iN`
// or `uN` respectively.
auto int_n_type = GetIntNType(ast_context, width, is_signed);
if (clang::ASTContext::hasSameType(qual_type, int_n_type)) {
TypeExpr type_expr =
MakeIntType(context, context.ints().Add(width), is_signed);
@@ -1144,26 +1179,41 @@ static auto MapBuiltinIntegerType(Context& context, SemIR::LocId loc_id,
}
return type_expr;
}
if (clang::ASTContext::hasSameType(qual_type, ast_context.CharTy)) {
return ExprAsType(context, Parse::NodeId::None,
MakeCharTypeLiteral(context, Parse::NodeId::None));
}
if (clang::ASTContext::hasSameType(qual_type, ast_context.LongTy)) {
return MapBuiltinCppCompatIntegerType(context, width, 32,
CoreIdentifier::Long32);
}
if (clang::ASTContext::hasSameType(qual_type, ast_context.UnsignedLongTy)) {
return MapBuiltinCppCompatIntegerType(context, width, 32,
CoreIdentifier::ULong32);
}
if (clang::ASTContext::hasSameType(qual_type, ast_context.LongLongTy)) {
return MapBuiltinCppCompatIntegerType(context, width, 64,
CoreIdentifier::LongLong64);
}
if (clang::ASTContext::hasSameType(qual_type,
ast_context.UnsignedLongLongTy)) {
return MapBuiltinCppCompatIntegerType(context, width, 64,
CoreIdentifier::ULongLong64);
// Handle special cases for types that don't map to `iN` or `uN`.
switch (type.getKind()) {
case clang::BuiltinType::Char_S:
case clang::BuiltinType::Char_U:
return ExprAsType(context, Parse::NodeId::None,
MakeCharTypeLiteral(context, Parse::NodeId::None));
case clang::BuiltinType::Long:
if (width == 32) {
return MakeCppCompatType(context, loc_id, CoreIdentifier::Long32);
}
if (width == 64) {
return MakeCppCompatType(context, loc_id, CoreIdentifier::Long64);
}
break;
case clang::BuiltinType::ULong:
if (width == 32) {
return MakeCppCompatType(context, loc_id, CoreIdentifier::ULong32);
}
if (width == 64) {
return MakeCppCompatType(context, loc_id, CoreIdentifier::ULong64);
}
break;
case clang::BuiltinType::LongLong:
if (width == 64) {
return MakeCppCompatType(context, loc_id, CoreIdentifier::LongLong64);
}
break;
case clang::BuiltinType::ULongLong:
if (width == 64) {
return MakeCppCompatType(context, loc_id, CoreIdentifier::ULongLong64);
}
break;
default:
break;
}
return TypeExpr::None;
}