Skip to content

Commit

Permalink
Map int to core::ffi::c_int (also for most other builtin C++ types).
Browse files Browse the repository at this point in the history
This CL provides mappings for most types under `core::ffi`, except for:
* Types like `core::ffi::ptrdiff_t`, because they depend on an
  experimental feature: rust-lang/rust#88345
* `core::ffi::c_char` because of b/276931370 and because continuing
  translating `char` to `u8` reduces the amount of cascading changes in
  this CL (e.g. changes to `crubit/support/cc_std/string_view.rs`).

Note that some other `clang/AST/BuiltinTypes.def` types like `char16_t`
don't have an equivelent under `core::ffi`. This CL doesn't change how
such types are handled (some of them are already covered by
`rs_bindings_from_cc/type_map.cc`).

PiperOrigin-RevId: 533279988
  • Loading branch information
anforowicz authored and Copybara-Service committed May 18, 2023
1 parent f164e03 commit 460e427
Show file tree
Hide file tree
Showing 31 changed files with 498 additions and 418 deletions.
55 changes: 26 additions & 29 deletions docs/bindings/reference/primitive_scalar_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,35 +30,32 @@ The C++ types below are mapped one-way into the corresponding Rust types.
("one-way" means that the type doesn't round-trip - for example `size_t` maps to
`usize`, but `usize` maps to `uintptr_t`.)

C++ | Rust
----------- | -------
`ptrdiff_t` | `isize`
`size_t` | `usize`
`char16_t` | `u16`
`char32_t` | `u32`
`wchar_t` | `i32`

### Platform-specific map

TODO(b/276790180): These will eventually become `ffi::c_char`, `ffi::c_int`,
etc.

The following C++ types are mapped in a platform-dependent way to the
corresponding Rust type of the same width and signedness:

C++ | Rust
-------------------- | -----------------------
`char` | `i8` or `u8`, or higher
`signed char` | `i8` or higher
`unsigned char` | `u8` or higher
`short` | `i16` or higher
`unsigned short` | `u16` or higher
`int` | `i16` or higher
`unsigned int` | `u16` or higher
`long` | `i32` or higher
`unsigned long` | `u32` or higher
`long long` | `i64`
`unsigned long long` | `u64`
TODO(b/283258442): `::core::ffi::*` should eventually be a bidirectional mapping

| C++ | Rust | Notes |
| -------------------- | -------------------------- | ------------------------ |
| `ptrdiff_t` | `isize` | |
| `size_t` | `usize` | |
| `char16_t` | `u16` | |
| `char32_t` | `u32` | Unlike `rs_std::rs_char` |
: : : above, `char32_t` may :
: : : contain invalid Unicode :
: : : characters :
| `wchar_t` | `i32` | TODO(b/283268558): This |
: : : is wrong on Windows. :
| `char` | `u8` or `i8` depending on | TODO(b/276790180): This |
: : whether `char` is signed : may eventually become :
: : on the target platform : `c_char` :
| `signed char` | `::core::ffi::c_schar` | |
| `unsigned char` | `::core::ffi::c_uchar` | |
| `short` | `::core::ffi::c_short` | |
| `unsigned short` | `::core::ffi::c_ushort` | |
| `int` | `::core::ffi::c_int` | |
| `unsigned int` | `::core::ffi::c_uint` | |
| `long` | `::core::ffi::c_long` | |
| `unsigned long` | `::core::ffi::c_ulong` | |
| `long long` | `::core::ffi::c_longlong` | |
| `unsigned long long` | `::core::ffi::c_ulonglong` | |

## Unsupported types

Expand Down
60 changes: 41 additions & 19 deletions rs_bindings_from_cc/importer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -837,30 +837,52 @@ absl::StatusOr<MappedType> Importer::ConvertType(
switch (builtin_type->getKind()) {
case clang::BuiltinType::Bool:
return MappedType::Simple("bool", "bool");
break;
case clang::BuiltinType::Void:
return MappedType::Void();

// Floating-point numbers
//
// TODO(b/255768062): Generated bindings should explicitly check if
// `math.h` defines the `__STDC_IEC_559__` macro.
case clang::BuiltinType::Float:
// TODO(b/255768062): Generated bindings should explicitly check if
// `math.h` defines the `__STDC_IEC_559__` macro.
return MappedType::Simple("f32", "float");
break;
case clang::BuiltinType::Double:
// TODO(b/255768062): Generated bindings should explicitly check if
// `math.h` defines the `__STDC_IEC_559__` macro.
return MappedType::Simple("f64", "double");
break;
case clang::BuiltinType::Void:
return MappedType::Void();
break;

// `char`
case clang::BuiltinType::Char_S: // 'char' in targets where it's signed
// TODO(b/276790180, b/276931370): use `::core::ffi::c_char` instead.
return MappedType::Simple("i8", "char");
case clang::BuiltinType::Char_U: // 'char' in targets where it's unsigned
// TODO(b/276790180, b/276931370): use `::core::ffi::c_char` instead.
return MappedType::Simple("u8", "char");
case clang::BuiltinType::SChar: // 'signed char', explicitly qualified
return MappedType::Simple("::core::ffi::c_schar", "signed char");
case clang::BuiltinType::UChar: // 'unsigned char', explicitly qualified
return MappedType::Simple("::core::ffi::c_uchar", "unsigned char");

// Signed integers
case clang::BuiltinType::Short:
return MappedType::Simple("::core::ffi::c_short", "short");
case clang::BuiltinType::Int:
return MappedType::Simple("::core::ffi::c_int", "int");
case clang::BuiltinType::Long:
return MappedType::Simple("::core::ffi::c_long", "long");
case clang::BuiltinType::LongLong:
return MappedType::Simple("::core::ffi::c_longlong", "long long");

// Unsigned integers
case clang::BuiltinType::UShort:
return MappedType::Simple("::core::ffi::c_ushort", "unsigned short");
case clang::BuiltinType::UInt:
return MappedType::Simple("::core::ffi::c_uint", "unsigned int");
case clang::BuiltinType::ULong:
return MappedType::Simple("::core::ffi::c_ulong", "unsigned long");
case clang::BuiltinType::ULongLong:
return MappedType::Simple("::core::ffi::c_ulonglong",
"unsigned long long");
default:
if (builtin_type->isIntegerType()) {
auto size = ctx_.getTypeSize(builtin_type);
if (size == 8 || size == 16 || size == 32 || size == 64) {
return MappedType::Simple(
absl::Substitute(
"$0$1", builtin_type->isSignedInteger() ? 'i' : 'u', size),
type_string);
}
}
break;
}
} else if (const auto* tag_type = type->getAsAdjusted<clang::TagType>()) {
return ConvertTypeDecl(tag_type->getDecl());
Expand Down
4 changes: 3 additions & 1 deletion rs_bindings_from_cc/importer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ auto CcTypeParamsAre(const Args&... matchers) {

auto IsCcInt() { return AllOf(NameIs("int"), CcTypeParamsAre()); }

auto IsRsInt() { return AllOf(NameIs("i32"), RsTypeParamsAre()); }
auto IsRsInt() {
return AllOf(NameIs("::core::ffi::c_int"), RsTypeParamsAre());
}

// Matches a CcType that is a pointer to a type matching `matcher`.
template <typename Matcher>
Expand Down
2 changes: 1 addition & 1 deletion rs_bindings_from_cc/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ struct RsType {
llvm::json::Value ToJson() const;

// The name of the type. Examples:
// - "i32" or "bool"
// - "i32" or "bool" or "::core::ffi::c_int"
// - "()" (the unit type, equivalent of "void" in CcType)
// - "&", "&mut", "*const", "*mut" (pointee stored in `type_args[0]`)
// - "Option" (e.g. representing nullable, lifetime-annotated C++ pointer as
Expand Down
75 changes: 37 additions & 38 deletions rs_bindings_from_cc/ir_from_cc_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn test_function() {
doc_comment: None,
return_type: MappedType {
rs_type: RsType {
name: Some("i32"),
name: Some("::core::ffi::c_int"),
lifetime_args: [],
type_args: [],
decl_id: None,
Expand All @@ -49,7 +49,7 @@ fn test_function() {
FuncParam {
type_: MappedType {
rs_type: RsType {
name: Some("i32"),
name: Some("::core::ffi::c_int"),
lifetime_args: [],
type_args: [],
decl_id: None,
Expand All @@ -66,7 +66,7 @@ fn test_function() {
FuncParam {
type_: MappedType {
rs_type: RsType {
name: Some("i32"),
name: Some("::core::ffi::c_int"),
lifetime_args: [],
type_args: [],
decl_id: None,
Expand Down Expand Up @@ -399,7 +399,7 @@ fn test_bitfields() {
Field {
identifier: Some("b1"), ...
type_: Ok(MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
}), ...
offset: 0,
Expand All @@ -409,7 +409,7 @@ fn test_bitfields() {
Field {
identifier: Some("b2"), ...
type_: Ok(MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
}), ...
offset: 1,
Expand All @@ -419,7 +419,7 @@ fn test_bitfields() {
Field {
identifier: Some("b3"), ...
type_: Ok(MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
}), ...
offset: 3,
Expand All @@ -429,7 +429,7 @@ fn test_bitfields() {
Field {
identifier: Some("b4"), ...
type_: Ok(MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
}), ...
offset: 16,
Expand Down Expand Up @@ -909,37 +909,36 @@ fn test_type_conversion() -> Result<()> {

assert_eq!(type_mapping["bool"], "bool");

// TODO(b/276790180, b/276931370): use c_char instead.
// TODO(b/276790180, b/276931370): use `::core::ffi::c_char` instead.
if multiplatform_testing::test_platform() == multiplatform_testing::Platform::X86Linux {
assert_eq!(type_mapping["char"], "i8");
} else {
assert_eq!(type_mapping["char"], "u8");
}
assert_eq!(type_mapping["unsigned char"], "::core::ffi::c_uchar");
assert_eq!(type_mapping["signed char"], "::core::ffi::c_schar");

assert_eq!(type_mapping["unsigned char"], "u8");
assert_eq!(type_mapping["signed char"], "i8");
assert_eq!(type_mapping["char16_t"], "u16");

// We cannot map C++ char32_t or wchar_t to Rust char,
// because Rust requires that chars are valid UTF scalar values.
assert_eq!(type_mapping["char32_t"], "u32");
assert_eq!(type_mapping["wchar_t"], "i32");

assert_eq!(type_mapping["short"], "i16");
assert_eq!(type_mapping["int"], "i32");
assert_eq!(type_mapping["long"], "i64");
assert_eq!(type_mapping["long long"], "i64");
// TODO(b/283268558): Per https://en.cppreference.com/w/cpp/language/types#Character_types
// maybe `wchar_t` should translate to`i16` on Windows?
assert_eq!(type_mapping["wchar_t"], "i32");

assert_eq!(type_mapping["unsigned short"], "u16");
assert_eq!(type_mapping["unsigned int"], "u32");
assert_eq!(type_mapping["unsigned long"], "u64");
assert_eq!(type_mapping["unsigned long long"], "u64");
assert_eq!(type_mapping["short"], "::core::ffi::c_short");
assert_eq!(type_mapping["int"], "::core::ffi::c_int");
assert_eq!(type_mapping["long"], "::core::ffi::c_long");
assert_eq!(type_mapping["long long"], "::core::ffi::c_longlong");

assert_eq!(type_mapping["short"], "i16");
assert_eq!(type_mapping["int"], "i32");
assert_eq!(type_mapping["long"], "i64");
assert_eq!(type_mapping["long long"], "i64");
assert_eq!(type_mapping["unsigned short"], "::core::ffi::c_ushort");
assert_eq!(type_mapping["unsigned int"], "::core::ffi::c_uint");
assert_eq!(type_mapping["unsigned long"], "::core::ffi::c_ulong");
assert_eq!(type_mapping["unsigned long long"], "::core::ffi::c_ulonglong");

/* TOOD(b/275876867): Reenable assertions below after fix the `#include` problem.
/* TOOD(b/275876867): Reenable assertions below after fixing the `#include` problem.
assert_eq!(type_mapping["int8_t"], "i8");
assert_eq!(type_mapping["int16_t"], "i16");
assert_eq!(type_mapping["int32_t"], "i32");
Expand Down Expand Up @@ -989,7 +988,7 @@ fn test_typedef() -> Result<()> {
let int = quote! {
MappedType {
rs_type: RsType {
name: Some("i32"),
name: Some("::core::ffi::c_int"),
lifetime_args: [],
type_args: [],
decl_id: None,
Expand Down Expand Up @@ -1117,7 +1116,7 @@ fn test_typedef_of_full_template_specialization() -> Result<()> {
identifier: Some("value"), ...
doc_comment: Some("Doc comment of `value` field."), ...
type_: Ok(MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
}),
access: Public,
Expand Down Expand Up @@ -1226,7 +1225,7 @@ fn test_typedef_for_explicit_template_specialization() -> Result<()> {
identifier: Some("value"), ...
doc_comment: Some("Doc comment of the `value` field specialization for T=int."), ...
type_: Ok(MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
}),
access: Public,
Expand Down Expand Up @@ -1503,14 +1502,14 @@ fn test_subst_template_type_parm_pack_type() -> Result<()> {
params: [
FuncParam {
type_: MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
},
identifier: "__my_args_0",
},
FuncParam {
type_: MappedType {
rs_type: RsType { name: Some("i32"), ... },
rs_type: RsType { name: Some("::core::ffi::c_int"), ... },
cc_type: CcType { name: Some("int"), ... },
},
identifier: "__my_args_1",
Expand Down Expand Up @@ -1759,7 +1758,7 @@ fn test_template_with_decltype_and_with_auto() -> Result<()> {
Func {
name: "TemplatedAdd", ...
return_type: MappedType {
rs_type: RsType { name: Some("i64"), ... },
rs_type: RsType { name: Some("::core::ffi::c_longlong"), ... },
cc_type: CcType { name: Some("long long"), ... },
}, ...
}
Expand Down Expand Up @@ -1798,7 +1797,7 @@ fn test_subst_template_type_parm_type_vs_const_when_non_const_template_param() -
return_type: MappedType {
rs_type: RsType {
name: Some("&"), ...
type_args: [RsType { name: Some("i32"), ... }], ...
type_args: [RsType { name: Some("::core::ffi::c_int"), ... }], ...
},
cc_type: CcType {
name: Some("&"),
Expand All @@ -1820,7 +1819,7 @@ fn test_subst_template_type_parm_type_vs_const_when_non_const_template_param() -
return_type: MappedType {
rs_type: RsType {
name: Some("&mut"), ...
type_args: [RsType { name: Some("i32"), ... }], ...
type_args: [RsType { name: Some("::core::ffi::c_int"), ... }], ...
},
cc_type: CcType {
name: Some("&"),
Expand Down Expand Up @@ -1867,7 +1866,7 @@ fn test_subst_template_type_parm_type_vs_const_when_const_template_param() -> Re
return_type: MappedType {
rs_type: RsType {
name: Some("&"), ...
type_args: [RsType { name: Some("i32"), ... }], ...
type_args: [RsType { name: Some("::core::ffi::c_int"), ... }], ...
},
cc_type: CcType {
name: Some("&"),
Expand All @@ -1889,7 +1888,7 @@ fn test_subst_template_type_parm_type_vs_const_when_const_template_param() -> Re
return_type: MappedType {
rs_type: RsType {
name: Some("&"), ...
type_args: [RsType { name: Some("i32"), ... }], ...
type_args: [RsType { name: Some("::core::ffi::c_int"), ... }], ...
},
cc_type: CcType {
name: Some("&"),
Expand Down Expand Up @@ -2528,7 +2527,7 @@ fn test_struct() {
Field {
identifier: Some("first_field"), ...
type_: Ok(MappedType {
rs_type : RsType { name : Some ("i32"), ...},
rs_type : RsType { name : Some("::core::ffi::c_int"), ...},
cc_type : CcType { name : Some ("int"), ...},
}), ...
offset: 0, ...
Expand All @@ -2538,7 +2537,7 @@ fn test_struct() {
Field {
identifier: Some("second_field"), ...
type_: Ok(MappedType {
rs_type : RsType { name : Some ("i32"), ...},
rs_type : RsType { name : Some("::core::ffi::c_int"), ...},
cc_type : CcType { name : Some ("int"), ...},
}), ...
offset: 32, ...
Expand Down Expand Up @@ -2631,7 +2630,7 @@ fn test_union() {
Field {
identifier: Some("first_field"), ...
type_: Ok(MappedType {
rs_type : RsType { name : Some ("i32"), ...},
rs_type : RsType { name : Some("::core::ffi::c_int"), ...},
cc_type : CcType { name : Some ("int"), ...},
}), ...
offset: 0, ...
Expand All @@ -2641,7 +2640,7 @@ fn test_union() {
Field {
identifier: Some("second_field"), ...
type_: Ok(MappedType {
rs_type : RsType { name : Some ("i32"), ...},
rs_type : RsType { name : Some("::core::ffi::c_int"), ...},
cc_type : CcType { name : Some ("int"), ...},
}), ...
offset: 0, ...
Expand Down

0 comments on commit 460e427

Please sign in to comment.