Skip to content

Commit 4637d79

Browse files
committed
improper_ctypes lint: allow 128 bit integers for the sysv64 ABI
For the sysv64 ABI, 128 bit integers are well defined. Fixes rust-lang#78473.
1 parent 4d247ad commit 4637d79

File tree

5 files changed

+73
-37
lines changed

5 files changed

+73
-37
lines changed

compiler/rustc_lint/src/types.rs

+42-25
Original file line numberDiff line numberDiff line change
@@ -808,22 +808,24 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
808808
fn check_field_type_for_ffi(
809809
&self,
810810
cache: &mut FxHashSet<Ty<'tcx>>,
811+
abi: SpecAbi,
811812
field: &ty::FieldDef,
812813
substs: SubstsRef<'tcx>,
813814
) -> FfiResult<'tcx> {
814815
let field_ty = field.ty(self.cx.tcx, substs);
815816
if field_ty.has_opaque_types() {
816-
self.check_type_for_ffi(cache, field_ty)
817+
self.check_type_for_ffi(cache, abi, field_ty)
817818
} else {
818819
let field_ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, field_ty);
819-
self.check_type_for_ffi(cache, field_ty)
820+
self.check_type_for_ffi(cache, abi, field_ty)
820821
}
821822
}
822823

823824
/// Checks if the given `VariantDef`'s field types are "ffi-safe".
824825
fn check_variant_for_ffi(
825826
&self,
826827
cache: &mut FxHashSet<Ty<'tcx>>,
828+
abi: SpecAbi,
827829
ty: Ty<'tcx>,
828830
def: &ty::AdtDef,
829831
variant: &ty::VariantDef,
@@ -835,7 +837,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
835837
// Can assume that only one field is not a ZST, so only check
836838
// that field's type for FFI-safety.
837839
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
838-
self.check_field_type_for_ffi(cache, field, substs)
840+
self.check_field_type_for_ffi(cache, abi, field, substs)
839841
} else {
840842
bug!("malformed transparent type");
841843
}
@@ -844,7 +846,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
844846
// actually safe.
845847
let mut all_phantom = !variant.fields.is_empty();
846848
for field in &variant.fields {
847-
match self.check_field_type_for_ffi(cache, &field, substs) {
849+
match self.check_field_type_for_ffi(cache, abi, &field, substs) {
848850
FfiSafe => {
849851
all_phantom = false;
850852
}
@@ -866,7 +868,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
866868

867869
/// Checks if the given type is "ffi-safe" (has a stable, well-defined
868870
/// representation which can be exported to C code).
869-
fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult<'tcx> {
871+
fn check_type_for_ffi(
872+
&self,
873+
cache: &mut FxHashSet<Ty<'tcx>>,
874+
abi: SpecAbi,
875+
ty: Ty<'tcx>,
876+
) -> FfiResult<'tcx> {
870877
use FfiResult::*;
871878

872879
let tcx = self.cx.tcx;
@@ -922,7 +929,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
922929
};
923930
}
924931

925-
self.check_variant_for_ffi(cache, ty, def, def.non_enum_variant(), substs)
932+
self.check_variant_for_ffi(
933+
cache,
934+
abi,
935+
ty,
936+
def,
937+
def.non_enum_variant(),
938+
substs,
939+
)
926940
}
927941
AdtKind::Enum => {
928942
if def.variants.is_empty() {
@@ -967,7 +981,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
967981
};
968982
}
969983

970-
match self.check_variant_for_ffi(cache, ty, def, variant, substs) {
984+
match self.check_variant_for_ffi(cache, abi, ty, def, variant, substs) {
971985
FfiSafe => (),
972986
r => return r,
973987
}
@@ -984,11 +998,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
984998
help: Some("consider using `u32` or `libc::wchar_t` instead".into()),
985999
},
9861000

987-
ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe {
988-
ty,
989-
reason: "128-bit integers don't currently have a known stable ABI".into(),
990-
help: None,
991-
},
1001+
ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) if abi != SpecAbi::SysV64 => {
1002+
FfiUnsafe {
1003+
ty,
1004+
reason: "128-bit integers don't currently have a known stable ABI".into(),
1005+
help: None,
1006+
}
1007+
}
9921008

9931009
// Primitive types with a stable representation.
9941010
ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
@@ -1025,10 +1041,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10251041
}
10261042

10271043
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
1028-
self.check_type_for_ffi(cache, ty)
1044+
self.check_type_for_ffi(cache, abi, ty)
10291045
}
10301046

1031-
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, inner_ty),
1047+
ty::Array(inner_ty, _) => self.check_type_for_ffi(cache, abi, inner_ty),
10321048

10331049
ty::FnPtr(sig) => {
10341050
if self.is_internal_abi(sig.abi()) {
@@ -1045,7 +1061,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10451061

10461062
let sig = tcx.erase_late_bound_regions(&sig);
10471063
if !sig.output().is_unit() {
1048-
let r = self.check_type_for_ffi(cache, sig.output());
1064+
let r = self.check_type_for_ffi(cache, abi, sig.output());
10491065
match r {
10501066
FfiSafe => {}
10511067
_ => {
@@ -1054,7 +1070,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10541070
}
10551071
}
10561072
for arg in sig.inputs() {
1057-
let r = self.check_type_for_ffi(cache, arg);
1073+
let r = self.check_type_for_ffi(cache, abi, arg);
10581074
match r {
10591075
FfiSafe => {}
10601076
_ => {
@@ -1166,6 +1182,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11661182

11671183
fn check_type_for_ffi_and_report_errors(
11681184
&mut self,
1185+
abi: SpecAbi,
11691186
sp: Span,
11701187
ty: Ty<'tcx>,
11711188
is_static: bool,
@@ -1196,7 +1213,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11961213
return;
11971214
}
11981215

1199-
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
1216+
match self.check_type_for_ffi(&mut FxHashSet::default(), abi, ty) {
12001217
FfiResult::FfiSafe => {}
12011218
FfiResult::FfiPhantom(ty) => {
12021219
self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None);
@@ -1210,25 +1227,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12101227
}
12111228
}
12121229

1213-
fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) {
1230+
fn check_foreign_fn(&mut self, abi: SpecAbi, id: hir::HirId, decl: &hir::FnDecl<'_>) {
12141231
let def_id = self.cx.tcx.hir().local_def_id(id);
12151232
let sig = self.cx.tcx.fn_sig(def_id);
12161233
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
12171234

12181235
for (input_ty, input_hir) in sig.inputs().iter().zip(decl.inputs) {
1219-
self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false);
1236+
self.check_type_for_ffi_and_report_errors(abi, input_hir.span, input_ty, false, false);
12201237
}
12211238

12221239
if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
12231240
let ret_ty = sig.output();
1224-
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false, true);
1241+
self.check_type_for_ffi_and_report_errors(abi, ret_hir.span, ret_ty, false, true);
12251242
}
12261243
}
12271244

1228-
fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
1245+
fn check_foreign_static(&mut self, abi: SpecAbi, id: hir::HirId, span: Span) {
12291246
let def_id = self.cx.tcx.hir().local_def_id(id);
12301247
let ty = self.cx.tcx.type_of(def_id);
1231-
self.check_type_for_ffi_and_report_errors(span, ty, true, false);
1248+
self.check_type_for_ffi_and_report_errors(abi, span, ty, true, false);
12321249
}
12331250

12341251
fn is_internal_abi(&self, abi: SpecAbi) -> bool {
@@ -1252,10 +1269,10 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
12521269
if !vis.is_internal_abi(abi) {
12531270
match it.kind {
12541271
hir::ForeignItemKind::Fn(ref decl, _, _) => {
1255-
vis.check_foreign_fn(it.hir_id, decl);
1272+
vis.check_foreign_fn(abi, it.hir_id, decl);
12561273
}
12571274
hir::ForeignItemKind::Static(ref ty, _) => {
1258-
vis.check_foreign_static(it.hir_id, ty.span);
1275+
vis.check_foreign_static(abi, it.hir_id, ty.span);
12591276
}
12601277
hir::ForeignItemKind::Type => (),
12611278
}
@@ -1283,7 +1300,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
12831300

12841301
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
12851302
if !vis.is_internal_abi(abi) {
1286-
vis.check_foreign_fn(hir_id, decl);
1303+
vis.check_foreign_fn(abi, hir_id, decl);
12871304
}
12881305
}
12891306
}

src/test/ui/lint/lint-ctypes-enum.rs

+6
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,10 @@ extern {
6969
fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR `extern` block uses type
7070
}
7171

72+
// The u128/i128 is well defined for the SystemV ABI
73+
extern "sysv64" {
74+
fn good_nonzero_u128(x: Option<num::NonZeroU128>);
75+
fn good_nonzero_i128(x: Option<num::NonZeroI128>);
76+
}
77+
7278
pub fn main() {}

src/test/ui/lint/lint-ctypes-fn.rs

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ pub extern "C" fn i128_type(p: i128) { }
8383
pub extern "C" fn u128_type(p: u128) { }
8484
//~^ ERROR uses type `u128`
8585

86+
pub extern "sysv64" fn good_i128_type(p: i128) { }
87+
88+
pub extern "sysv64" fn good_u128_type(p: u128) { }
89+
8690
pub extern "C" fn tuple_type(p: (i32, i32)) { }
8791
//~^ ERROR uses type `(i32, i32)`
8892

src/test/ui/lint/lint-ctypes-fn.stderr

+12-12
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ LL | pub extern "C" fn u128_type(p: u128) { }
4747
= note: 128-bit integers don't currently have a known stable ABI
4848

4949
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
50-
--> $DIR/lint-ctypes-fn.rs:86:33
50+
--> $DIR/lint-ctypes-fn.rs:90:33
5151
|
5252
LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
5353
| ^^^^^^^^^^ not FFI-safe
@@ -56,7 +56,7 @@ LL | pub extern "C" fn tuple_type(p: (i32, i32)) { }
5656
= note: tuples have unspecified layout
5757

5858
error: `extern` fn uses type `(i32, i32)`, which is not FFI-safe
59-
--> $DIR/lint-ctypes-fn.rs:89:34
59+
--> $DIR/lint-ctypes-fn.rs:93:34
6060
|
6161
LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
6262
| ^^^^^^^ not FFI-safe
@@ -65,7 +65,7 @@ LL | pub extern "C" fn tuple_type2(p: I32Pair) { }
6565
= note: tuples have unspecified layout
6666

6767
error: `extern` fn uses type `ZeroSize`, which is not FFI-safe
68-
--> $DIR/lint-ctypes-fn.rs:92:32
68+
--> $DIR/lint-ctypes-fn.rs:96:32
6969
|
7070
LL | pub extern "C" fn zero_size(p: ZeroSize) { }
7171
| ^^^^^^^^ not FFI-safe
@@ -79,7 +79,7 @@ LL | pub struct ZeroSize;
7979
| ^^^^^^^^^^^^^^^^^^^^
8080

8181
error: `extern` fn uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
82-
--> $DIR/lint-ctypes-fn.rs:95:40
82+
--> $DIR/lint-ctypes-fn.rs:99:40
8383
|
8484
LL | pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { }
8585
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -92,15 +92,15 @@ LL | pub struct ZeroSizeWithPhantomData(PhantomData<i32>);
9292
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9393

9494
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
95-
--> $DIR/lint-ctypes-fn.rs:98:51
95+
--> $DIR/lint-ctypes-fn.rs:102:51
9696
|
9797
LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData<bool> {
9898
| ^^^^^^^^^^^^^^^^^ not FFI-safe
9999
|
100100
= note: composed only of `PhantomData`
101101

102102
error: `extern` fn uses type `fn()`, which is not FFI-safe
103-
--> $DIR/lint-ctypes-fn.rs:103:30
103+
--> $DIR/lint-ctypes-fn.rs:107:30
104104
|
105105
LL | pub extern "C" fn fn_type(p: RustFn) { }
106106
| ^^^^^^ not FFI-safe
@@ -109,7 +109,7 @@ LL | pub extern "C" fn fn_type(p: RustFn) { }
109109
= note: this function pointer has Rust-specific calling convention
110110

111111
error: `extern` fn uses type `fn()`, which is not FFI-safe
112-
--> $DIR/lint-ctypes-fn.rs:106:31
112+
--> $DIR/lint-ctypes-fn.rs:110:31
113113
|
114114
LL | pub extern "C" fn fn_type2(p: fn()) { }
115115
| ^^^^ not FFI-safe
@@ -118,15 +118,15 @@ LL | pub extern "C" fn fn_type2(p: fn()) { }
118118
= note: this function pointer has Rust-specific calling convention
119119

120120
error: `extern` fn uses type `i128`, which is not FFI-safe
121-
--> $DIR/lint-ctypes-fn.rs:111:39
121+
--> $DIR/lint-ctypes-fn.rs:115:39
122122
|
123123
LL | pub extern "C" fn transparent_i128(p: TransparentI128) { }
124124
| ^^^^^^^^^^^^^^^ not FFI-safe
125125
|
126126
= note: 128-bit integers don't currently have a known stable ABI
127127

128128
error: `extern` fn uses type `str`, which is not FFI-safe
129-
--> $DIR/lint-ctypes-fn.rs:114:38
129+
--> $DIR/lint-ctypes-fn.rs:118:38
130130
|
131131
LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
132132
| ^^^^^^^^^^^^^^ not FFI-safe
@@ -135,15 +135,15 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { }
135135
= note: string slices have no C equivalent
136136

137137
error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe
138-
--> $DIR/lint-ctypes-fn.rs:160:43
138+
--> $DIR/lint-ctypes-fn.rs:164:43
139139
|
140140
LL | pub extern "C" fn unused_generic2<T>() -> PhantomData<bool> {
141141
| ^^^^^^^^^^^^^^^^^ not FFI-safe
142142
|
143143
= note: composed only of `PhantomData`
144144

145145
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
146-
--> $DIR/lint-ctypes-fn.rs:173:39
146+
--> $DIR/lint-ctypes-fn.rs:177:39
147147
|
148148
LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
149149
| ^^^^^^ not FFI-safe
@@ -152,7 +152,7 @@ LL | pub extern "C" fn used_generic4<T>(x: Vec<T>) { }
152152
= note: this struct has unspecified layout
153153

154154
error: `extern` fn uses type `Vec<T>`, which is not FFI-safe
155-
--> $DIR/lint-ctypes-fn.rs:176:41
155+
--> $DIR/lint-ctypes-fn.rs:180:41
156156
|
157157
LL | pub extern "C" fn used_generic5<T>() -> Vec<T> {
158158
| ^^^^^^ not FFI-safe

src/test/ui/lint/lint-ctypes.rs

+9
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ extern {
9595

9696
}
9797

98+
// The u128/i128 is well defined for the SystemV ABI
99+
extern "sysv64" {
100+
pub fn good_i128_type(p: i128);
101+
pub fn good_u128_type(p: u128);
102+
103+
pub static good_static_u128_type: u128;
104+
pub static good_static_u128_array_type: [u128; 16];
105+
}
106+
98107
#[allow(improper_ctypes)]
99108
extern {
100109
pub fn good19(_: &String);

0 commit comments

Comments
 (0)