Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 80420a6

Browse files
committedMay 6, 2024
Auto merge of #124747 - MasterAwesome:master, r=davidtwco
Support Result<T, E> across FFI when niche optimization can be used (v2) This PR is identical to #122253, which was approved and merged but then removed from master by a force-push due to a [CI bug](https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra/topic/ci.20broken.3F). r? ghost Original PR description: --- Allow allow enums like `Result<T, E>` to be used across FFI if the T/E can be niche optimized and the non-niche-optimized type is FFI safe. Implementation of rust-lang/rfcs#3391 Tracking issue: #110503 Additional ABI and codegen tests were added in #115372
2 parents 3170bd9 + ed532cc commit 80420a6

File tree

8 files changed

+826
-73
lines changed

8 files changed

+826
-73
lines changed
 

‎compiler/rustc_feature/src/unstable.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,9 @@ declare_features! (
579579
(incomplete, repr128, "1.16.0", Some(56071)),
580580
/// Allows `repr(simd)` and importing the various simd intrinsics.
581581
(unstable, repr_simd, "1.4.0", Some(27731)),
582+
/// Allows enums like Result<T, E> to be used across FFI, if T's niche value can
583+
/// be used to describe E or vise-versa.
584+
(unstable, result_ffi_guarantees, "CURRENT_RUSTC_VERSION", Some(110503)),
582585
/// Allows bounding the return type of AFIT/RPITIT.
583586
(incomplete, return_type_notation, "1.70.0", Some(109417)),
584587
/// Allows `extern "rust-cold"`.

‎compiler/rustc_lint/src/types.rs

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,6 +1101,32 @@ fn get_nullable_type<'tcx>(
11011101
})
11021102
}
11031103

1104+
/// A type is niche-optimization candidate iff:
1105+
/// - Is a zero-sized type with alignment 1 (a “1-ZST”).
1106+
/// - Has no fields.
1107+
/// - Does not have the `#[non_exhaustive]` attribute.
1108+
fn is_niche_optimization_candidate<'tcx>(
1109+
tcx: TyCtxt<'tcx>,
1110+
param_env: ty::ParamEnv<'tcx>,
1111+
ty: Ty<'tcx>,
1112+
) -> bool {
1113+
if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| !layout.is_1zst()) {
1114+
return false;
1115+
}
1116+
1117+
match ty.kind() {
1118+
ty::Adt(ty_def, _) => {
1119+
let non_exhaustive = ty_def.is_variant_list_non_exhaustive();
1120+
let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none())
1121+
|| (ty_def.is_enum() && ty_def.variants().is_empty());
1122+
1123+
!non_exhaustive && empty
1124+
}
1125+
ty::Tuple(tys) => tys.is_empty(),
1126+
_ => false,
1127+
}
1128+
}
1129+
11041130
/// Check if this enum can be safely exported based on the "nullable pointer optimization". If it
11051131
/// can, return the type that `ty` can be safely converted to, otherwise return `None`.
11061132
/// Currently restricted to function pointers, boxes, references, `core::num::NonZero`,
@@ -1117,6 +1143,22 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
11171143
let field_ty = match &ty_def.variants().raw[..] {
11181144
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
11191145
([], [field]) | ([field], []) => field.ty(tcx, args),
1146+
([field1], [field2]) => {
1147+
if !tcx.features().result_ffi_guarantees {
1148+
return None;
1149+
}
1150+
1151+
let ty1 = field1.ty(tcx, args);
1152+
let ty2 = field2.ty(tcx, args);
1153+
1154+
if is_niche_optimization_candidate(tcx, param_env, ty1) {
1155+
ty2
1156+
} else if is_niche_optimization_candidate(tcx, param_env, ty2) {
1157+
ty1
1158+
} else {
1159+
return None;
1160+
}
1161+
}
11201162
_ => return None,
11211163
},
11221164
_ => return None,
@@ -1202,7 +1244,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12021244
args: GenericArgsRef<'tcx>,
12031245
) -> FfiResult<'tcx> {
12041246
use FfiResult::*;
1205-
12061247
let transparent_with_all_zst_fields = if def.repr().transparent() {
12071248
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
12081249
// Transparent newtypes have at most one non-ZST field which needs to be checked..
@@ -1329,27 +1370,29 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13291370
return FfiSafe;
13301371
}
13311372

1373+
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
1374+
return FfiUnsafe {
1375+
ty,
1376+
reason: fluent::lint_improper_ctypes_non_exhaustive,
1377+
help: None,
1378+
};
1379+
}
1380+
13321381
// Check for a repr() attribute to specify the size of the
13331382
// discriminant.
13341383
if !def.repr().c() && !def.repr().transparent() && def.repr().int.is_none()
13351384
{
1336-
// Special-case types like `Option<extern fn()>`.
1337-
if repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
1338-
.is_none()
1385+
// Special-case types like `Option<extern fn()>` and `Result<extern fn(), ()>`
1386+
if let Some(ty) =
1387+
repr_nullable_ptr(self.cx.tcx, self.cx.param_env, ty, self.mode)
13391388
{
1340-
return FfiUnsafe {
1341-
ty,
1342-
reason: fluent::lint_improper_ctypes_enum_repr_reason,
1343-
help: Some(fluent::lint_improper_ctypes_enum_repr_help),
1344-
};
1389+
return self.check_type_for_ffi(cache, ty);
13451390
}
1346-
}
13471391

1348-
if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
13491392
return FfiUnsafe {
13501393
ty,
1351-
reason: fluent::lint_improper_ctypes_non_exhaustive,
1352-
help: None,
1394+
reason: fluent::lint_improper_ctypes_enum_repr_reason,
1395+
help: Some(fluent::lint_improper_ctypes_enum_repr_help),
13531396
};
13541397
}
13551398

‎compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,7 @@ symbols! {
15111511
require,
15121512
residual,
15131513
result,
1514+
result_ffi_guarantees,
15141515
resume,
15151516
return_position_impl_trait_in_trait,
15161517
return_type_notation,
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# `result_ffi_guarantees`
2+
3+
The tracking issue for this feature is: [#110503]
4+
5+
[#110503]: https://github.com/rust-lang/rust/issues/110503
6+
7+
------------------------
8+
9+
This feature adds the possibility of using `Result<T, E>` in FFI if T's niche
10+
value can be used to describe E or vise-versa.
11+
12+
See [RFC 3391] for more information.
13+
14+
[RFC 3391]: https://github.com/rust-lang/rfcs/blob/master/text/3391-result_ffi_guarantees.md
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#![allow(dead_code)]
2+
#![deny(improper_ctypes)]
3+
#![feature(ptr_internals)]
4+
5+
use std::num;
6+
7+
enum Z {}
8+
9+
#[repr(transparent)]
10+
struct TransparentStruct<T>(T, std::marker::PhantomData<Z>);
11+
12+
#[repr(transparent)]
13+
enum TransparentEnum<T> {
14+
Variant(T, std::marker::PhantomData<Z>),
15+
}
16+
17+
struct NoField;
18+
19+
extern "C" {
20+
fn result_ref_t(x: Result<&'static u8, ()>);
21+
//~^ ERROR `extern` block uses type `Result
22+
fn result_fn_t(x: Result<extern "C" fn(), ()>);
23+
//~^ ERROR `extern` block uses type `Result
24+
fn result_nonnull_t(x: Result<std::ptr::NonNull<u8>, ()>);
25+
//~^ ERROR `extern` block uses type `Result
26+
fn result_unique_t(x: Result<std::ptr::Unique<u8>, ()>);
27+
//~^ ERROR `extern` block uses type `Result
28+
fn result_nonzero_u8_t(x: Result<num::NonZero<u8>, ()>);
29+
//~^ ERROR `extern` block uses type `Result
30+
fn result_nonzero_u16_t(x: Result<num::NonZero<u16>, ()>);
31+
//~^ ERROR `extern` block uses type `Result
32+
fn result_nonzero_u32_t(x: Result<num::NonZero<u32>, ()>);
33+
//~^ ERROR `extern` block uses type `Result
34+
fn result_nonzero_u64_t(x: Result<num::NonZero<u64>, ()>);
35+
//~^ ERROR `extern` block uses type `Result
36+
fn result_nonzero_usize_t(x: Result<num::NonZero<usize>, ()>);
37+
//~^ ERROR `extern` block uses type `Result
38+
fn result_nonzero_i8_t(x: Result<num::NonZero<i8>, ()>);
39+
//~^ ERROR `extern` block uses type `Result
40+
fn result_nonzero_i16_t(x: Result<num::NonZero<i16>, ()>);
41+
//~^ ERROR `extern` block uses type `Result
42+
fn result_nonzero_i32_t(x: Result<num::NonZero<i32>, ()>);
43+
//~^ ERROR `extern` block uses type `Result
44+
fn result_nonzero_i64_t(x: Result<num::NonZero<i64>, ()>);
45+
//~^ ERROR `extern` block uses type `Result
46+
fn result_nonzero_isize_t(x: Result<num::NonZero<isize>, ()>);
47+
//~^ ERROR `extern` block uses type `Result
48+
fn result_transparent_struct_t(x: Result<TransparentStruct<num::NonZero<u8>>, ()>);
49+
//~^ ERROR `extern` block uses type `Result
50+
fn result_transparent_enum_t(x: Result<TransparentEnum<num::NonZero<u8>>, ()>);
51+
//~^ ERROR `extern` block uses type `Result
52+
fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
53+
//~^ ERROR `extern` block uses type `Result
54+
fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
55+
//~^ ERROR `extern` block uses type `Result
56+
fn result_1zst_exhaustive_no_field_t(x: Result<num::NonZero<u8>, NoField>);
57+
//~^ ERROR `extern` block uses type `Result
58+
59+
fn result_ref_e(x: Result<(), &'static u8>);
60+
//~^ ERROR `extern` block uses type `Result
61+
fn result_fn_e(x: Result<(), extern "C" fn()>);
62+
//~^ ERROR `extern` block uses type `Result
63+
fn result_nonnull_e(x: Result<(), std::ptr::NonNull<u8>>);
64+
//~^ ERROR `extern` block uses type `Result
65+
fn result_unique_e(x: Result<(), std::ptr::Unique<u8>>);
66+
//~^ ERROR `extern` block uses type `Result
67+
fn result_nonzero_u8_e(x: Result<(), num::NonZero<u8>>);
68+
//~^ ERROR `extern` block uses type `Result
69+
fn result_nonzero_u16_e(x: Result<(), num::NonZero<u16>>);
70+
//~^ ERROR `extern` block uses type `Result
71+
fn result_nonzero_u32_e(x: Result<(), num::NonZero<u32>>);
72+
//~^ ERROR `extern` block uses type `Result
73+
fn result_nonzero_u64_e(x: Result<(), num::NonZero<u64>>);
74+
//~^ ERROR `extern` block uses type `Result
75+
fn result_nonzero_usize_e(x: Result<(), num::NonZero<usize>>);
76+
//~^ ERROR `extern` block uses type `Result
77+
fn result_nonzero_i8_e(x: Result<(), num::NonZero<i8>>);
78+
//~^ ERROR `extern` block uses type `Result
79+
fn result_nonzero_i16_e(x: Result<(), num::NonZero<i16>>);
80+
//~^ ERROR `extern` block uses type `Result
81+
fn result_nonzero_i32_e(x: Result<(), num::NonZero<i32>>);
82+
//~^ ERROR `extern` block uses type `Result
83+
fn result_nonzero_i64_e(x: Result<(), num::NonZero<i64>>);
84+
//~^ ERROR `extern` block uses type `Result
85+
fn result_nonzero_isize_e(x: Result<(), num::NonZero<isize>>);
86+
//~^ ERROR `extern` block uses type `Result
87+
fn result_transparent_struct_e(x: Result<(), TransparentStruct<num::NonZero<u8>>>);
88+
//~^ ERROR `extern` block uses type `Result
89+
fn result_transparent_enum_e(x: Result<(), TransparentEnum<num::NonZero<u8>>>);
90+
//~^ ERROR `extern` block uses type `Result
91+
fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
92+
//~^ ERROR `extern` block uses type `Result
93+
fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
94+
//~^ ERROR `extern` block uses type `Result
95+
fn result_1zst_exhaustive_no_field_e(x: Result<NoField, num::NonZero<u8>>);
96+
//~^ ERROR `extern` block uses type `Result
97+
}
98+
99+
pub fn main() {}

‎tests/ui/feature-gates/feature-gate-result_ffi_guarantees.stderr

Lines changed: 349 additions & 0 deletions
Large diffs are not rendered by default.

‎tests/ui/lint/lint-ctypes-enum.rs

Lines changed: 117 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![deny(improper_ctypes)]
33
#![feature(ptr_internals)]
44
#![feature(transparent_unions)]
5+
#![feature(result_ffi_guarantees)]
56

67
use std::num;
78

@@ -55,38 +56,123 @@ union TransparentUnion<T: Copy> {
5556

5657
struct Rust<T>(T);
5758

59+
struct NoField;
60+
61+
#[repr(transparent)]
62+
struct Field(());
63+
64+
#[non_exhaustive]
65+
enum NonExhaustive {}
66+
5867
extern "C" {
59-
fn zf(x: Z);
60-
fn uf(x: U); //~ ERROR `extern` block uses type `U`
61-
fn bf(x: B); //~ ERROR `extern` block uses type `B`
62-
fn tf(x: T); //~ ERROR `extern` block uses type `T`
63-
fn repr_c(x: ReprC);
64-
fn repr_u8(x: U8);
65-
fn repr_isize(x: Isize);
66-
fn option_ref(x: Option<&'static u8>);
67-
fn option_fn(x: Option<extern "C" fn()>);
68-
fn nonnull(x: Option<std::ptr::NonNull<u8>>);
69-
fn unique(x: Option<std::ptr::Unique<u8>>);
70-
fn nonzero_u8(x: Option<num::NonZero<u8>>);
71-
fn nonzero_u16(x: Option<num::NonZero<u16>>);
72-
fn nonzero_u32(x: Option<num::NonZero<u32>>);
73-
fn nonzero_u64(x: Option<num::NonZero<u64>>);
74-
fn nonzero_u128(x: Option<num::NonZero<u128>>);
75-
//~^ ERROR `extern` block uses type `u128`
76-
fn nonzero_usize(x: Option<num::NonZero<usize>>);
77-
fn nonzero_i8(x: Option<num::NonZero<i8>>);
78-
fn nonzero_i16(x: Option<num::NonZero<i16>>);
79-
fn nonzero_i32(x: Option<num::NonZero<i32>>);
80-
fn nonzero_i64(x: Option<num::NonZero<i64>>);
81-
fn nonzero_i128(x: Option<num::NonZero<i128>>);
82-
//~^ ERROR `extern` block uses type `i128`
83-
fn nonzero_isize(x: Option<num::NonZero<isize>>);
84-
fn transparent_struct(x: Option<TransparentStruct<num::NonZero<u8>>>);
85-
fn transparent_enum(x: Option<TransparentEnum<num::NonZero<u8>>>);
86-
fn transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
87-
//~^ ERROR `extern` block uses type
88-
fn repr_rust(x: Option<Rust<num::NonZero<u8>>>); //~ ERROR `extern` block uses type
89-
fn no_result(x: Result<(), num::NonZero<i32>>); //~ ERROR `extern` block uses type
68+
fn zf(x: Z);
69+
fn uf(x: U); //~ ERROR `extern` block uses type `U`
70+
fn bf(x: B); //~ ERROR `extern` block uses type `B`
71+
fn tf(x: T); //~ ERROR `extern` block uses type `T`
72+
fn repr_c(x: ReprC);
73+
fn repr_u8(x: U8);
74+
fn repr_isize(x: Isize);
75+
fn option_ref(x: Option<&'static u8>);
76+
fn option_fn(x: Option<extern "C" fn()>);
77+
fn option_nonnull(x: Option<std::ptr::NonNull<u8>>);
78+
fn option_unique(x: Option<std::ptr::Unique<u8>>);
79+
fn option_nonzero_u8(x: Option<num::NonZero<u8>>);
80+
fn option_nonzero_u16(x: Option<num::NonZero<u16>>);
81+
fn option_nonzero_u32(x: Option<num::NonZero<u32>>);
82+
fn option_nonzero_u64(x: Option<num::NonZero<u64>>);
83+
fn option_nonzero_u128(x: Option<num::NonZero<u128>>);
84+
//~^ ERROR `extern` block uses type `u128`
85+
fn option_nonzero_usize(x: Option<num::NonZero<usize>>);
86+
fn option_nonzero_i8(x: Option<num::NonZero<i8>>);
87+
fn option_nonzero_i16(x: Option<num::NonZero<i16>>);
88+
fn option_nonzero_i32(x: Option<num::NonZero<i32>>);
89+
fn option_nonzero_i64(x: Option<num::NonZero<i64>>);
90+
fn option_nonzero_i128(x: Option<num::NonZero<i128>>);
91+
//~^ ERROR `extern` block uses type `i128`
92+
fn option_nonzero_isize(x: Option<num::NonZero<isize>>);
93+
fn option_transparent_struct(x: Option<TransparentStruct<num::NonZero<u8>>>);
94+
fn option_transparent_enum(x: Option<TransparentEnum<num::NonZero<u8>>>);
95+
fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
96+
//~^ ERROR `extern` block uses type
97+
fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>); //~ ERROR `extern` block uses type
98+
99+
fn result_ref_t(x: Result<&'static u8, ()>);
100+
fn result_fn_t(x: Result<extern "C" fn(), ()>);
101+
fn result_nonnull_t(x: Result<std::ptr::NonNull<u8>, ()>);
102+
fn result_unique_t(x: Result<std::ptr::Unique<u8>, ()>);
103+
fn result_nonzero_u8_t(x: Result<num::NonZero<u8>, ()>);
104+
fn result_nonzero_u16_t(x: Result<num::NonZero<u16>, ()>);
105+
fn result_nonzero_u32_t(x: Result<num::NonZero<u32>, ()>);
106+
fn result_nonzero_u64_t(x: Result<num::NonZero<u64>, ()>);
107+
fn result_nonzero_u128_t(x: Result<num::NonZero<u128>, ()>);
108+
//~^ ERROR `extern` block uses type `u128`
109+
fn result_nonzero_usize_t(x: Result<num::NonZero<usize>, ()>);
110+
fn result_nonzero_i8_t(x: Result<num::NonZero<i8>, ()>);
111+
fn result_nonzero_i16_t(x: Result<num::NonZero<i16>, ()>);
112+
fn result_nonzero_i32_t(x: Result<num::NonZero<i32>, ()>);
113+
fn result_nonzero_i64_t(x: Result<num::NonZero<i64>, ()>);
114+
fn result_nonzero_i128_t(x: Result<num::NonZero<i128>, ()>);
115+
//~^ ERROR `extern` block uses type `i128`
116+
fn result_nonzero_isize_t(x: Result<num::NonZero<isize>, ()>);
117+
fn result_transparent_struct_t(x: Result<TransparentStruct<num::NonZero<u8>>, ()>);
118+
fn result_transparent_enum_t(x: Result<TransparentEnum<num::NonZero<u8>>, ()>);
119+
fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
120+
//~^ ERROR `extern` block uses type
121+
fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
122+
//~^ ERROR `extern` block uses type
123+
fn result_phantom_t(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
124+
fn result_1zst_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, Z>);
125+
fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
126+
//~^ ERROR `extern` block uses type
127+
fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
128+
//~^ ERROR `extern` block uses type
129+
fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
130+
//~^ ERROR `extern` block uses type
131+
fn result_1zst_exhaustive_no_field_t(x: Result<num::NonZero<u8>, NoField>);
132+
fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
133+
//~^ ERROR `extern` block uses type
134+
fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
135+
//~^ ERROR `extern` block uses type
136+
137+
fn result_ref_e(x: Result<(), &'static u8>);
138+
fn result_fn_e(x: Result<(), extern "C" fn()>);
139+
fn result_nonnull_e(x: Result<(), std::ptr::NonNull<u8>>);
140+
fn result_unique_e(x: Result<(), std::ptr::Unique<u8>>);
141+
fn result_nonzero_u8_e(x: Result<(), num::NonZero<u8>>);
142+
fn result_nonzero_u16_e(x: Result<(), num::NonZero<u16>>);
143+
fn result_nonzero_u32_e(x: Result<(), num::NonZero<u32>>);
144+
fn result_nonzero_u64_e(x: Result<(), num::NonZero<u64>>);
145+
fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
146+
//~^ ERROR `extern` block uses type `u128`
147+
fn result_nonzero_usize_e(x: Result<(), num::NonZero<usize>>);
148+
fn result_nonzero_i8_e(x: Result<(), num::NonZero<i8>>);
149+
fn result_nonzero_i16_e(x: Result<(), num::NonZero<i16>>);
150+
fn result_nonzero_i32_e(x: Result<(), num::NonZero<i32>>);
151+
fn result_nonzero_i64_e(x: Result<(), num::NonZero<i64>>);
152+
fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
153+
//~^ ERROR `extern` block uses type `i128`
154+
fn result_nonzero_isize_e(x: Result<(), num::NonZero<isize>>);
155+
fn result_transparent_struct_e(x: Result<(), TransparentStruct<num::NonZero<u8>>>);
156+
fn result_transparent_enum_e(x: Result<(), TransparentEnum<num::NonZero<u8>>>);
157+
fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
158+
//~^ ERROR `extern` block uses type
159+
fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
160+
//~^ ERROR `extern` block uses type
161+
fn result_phantom_e(x: Result<num::NonZero<u8>, std::marker::PhantomData<()>>);
162+
fn result_1zst_exhaustive_no_variant_e(x: Result<Z, num::NonZero<u8>>);
163+
fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
164+
//~^ ERROR `extern` block uses type
165+
fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
166+
//~^ ERROR `extern` block uses type
167+
fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
168+
//~^ ERROR `extern` block uses type
169+
fn result_1zst_exhaustive_no_field_e(x: Result<NoField, num::NonZero<u8>>);
170+
fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
171+
//~^ ERROR `extern` block uses type
172+
fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
173+
//~^ ERROR `extern` block uses type
174+
fn result_unit_t_e(x: Result<(), ()>);
175+
//~^ ERROR `extern` block uses type
90176
}
91177

92178
pub fn main() {}

‎tests/ui/lint/lint-ctypes-enum.stderr

Lines changed: 187 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
error: `extern` block uses type `U`, which is not FFI-safe
2-
--> $DIR/lint-ctypes-enum.rs:60:13
2+
--> $DIR/lint-ctypes-enum.rs:69:14
33
|
4-
LL | fn uf(x: U);
5-
| ^ not FFI-safe
4+
LL | fn uf(x: U);
5+
| ^ not FFI-safe
66
|
77
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
88
= note: enum has no representation hint
99
note: the type is defined here
10-
--> $DIR/lint-ctypes-enum.rs:9:1
10+
--> $DIR/lint-ctypes-enum.rs:10:1
1111
|
1212
LL | enum U {
1313
| ^^^^^^
@@ -18,75 +18,233 @@ LL | #![deny(improper_ctypes)]
1818
| ^^^^^^^^^^^^^^^
1919

2020
error: `extern` block uses type `B`, which is not FFI-safe
21-
--> $DIR/lint-ctypes-enum.rs:61:13
21+
--> $DIR/lint-ctypes-enum.rs:70:14
2222
|
23-
LL | fn bf(x: B);
24-
| ^ not FFI-safe
23+
LL | fn bf(x: B);
24+
| ^ not FFI-safe
2525
|
2626
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
2727
= note: enum has no representation hint
2828
note: the type is defined here
29-
--> $DIR/lint-ctypes-enum.rs:12:1
29+
--> $DIR/lint-ctypes-enum.rs:13:1
3030
|
3131
LL | enum B {
3232
| ^^^^^^
3333

3434
error: `extern` block uses type `T`, which is not FFI-safe
35-
--> $DIR/lint-ctypes-enum.rs:62:13
35+
--> $DIR/lint-ctypes-enum.rs:71:14
3636
|
37-
LL | fn tf(x: T);
38-
| ^ not FFI-safe
37+
LL | fn tf(x: T);
38+
| ^ not FFI-safe
3939
|
4040
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
4141
= note: enum has no representation hint
4242
note: the type is defined here
43-
--> $DIR/lint-ctypes-enum.rs:16:1
43+
--> $DIR/lint-ctypes-enum.rs:17:1
4444
|
4545
LL | enum T {
4646
| ^^^^^^
4747

4848
error: `extern` block uses type `u128`, which is not FFI-safe
49-
--> $DIR/lint-ctypes-enum.rs:74:23
49+
--> $DIR/lint-ctypes-enum.rs:83:31
5050
|
51-
LL | fn nonzero_u128(x: Option<num::NonZero<u128>>);
52-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
51+
LL | fn option_nonzero_u128(x: Option<num::NonZero<u128>>);
52+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
5353
|
5454
= note: 128-bit integers don't currently have a known stable ABI
5555

5656
error: `extern` block uses type `i128`, which is not FFI-safe
57-
--> $DIR/lint-ctypes-enum.rs:81:23
57+
--> $DIR/lint-ctypes-enum.rs:90:31
5858
|
59-
LL | fn nonzero_i128(x: Option<num::NonZero<i128>>);
60-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
59+
LL | fn option_nonzero_i128(x: Option<num::NonZero<i128>>);
60+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
6161
|
6262
= note: 128-bit integers don't currently have a known stable ABI
6363

6464
error: `extern` block uses type `Option<TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
65-
--> $DIR/lint-ctypes-enum.rs:86:28
65+
--> $DIR/lint-ctypes-enum.rs:95:36
6666
|
67-
LL | fn transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
68-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
67+
LL | fn option_transparent_union(x: Option<TransparentUnion<num::NonZero<u8>>>);
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
6969
|
7070
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
7171
= note: enum has no representation hint
7272

7373
error: `extern` block uses type `Option<Rust<NonZero<u8>>>`, which is not FFI-safe
74-
--> $DIR/lint-ctypes-enum.rs:88:20
74+
--> $DIR/lint-ctypes-enum.rs:97:28
7575
|
76-
LL | fn repr_rust(x: Option<Rust<num::NonZero<u8>>>);
77-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
76+
LL | fn option_repr_rust(x: Option<Rust<num::NonZero<u8>>>);
77+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
7878
|
7979
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
8080
= note: enum has no representation hint
8181

82-
error: `extern` block uses type `Result<(), NonZero<i32>>`, which is not FFI-safe
83-
--> $DIR/lint-ctypes-enum.rs:89:20
82+
error: `extern` block uses type `u128`, which is not FFI-safe
83+
--> $DIR/lint-ctypes-enum.rs:107:33
84+
|
85+
LL | fn result_nonzero_u128_t(x: Result<num::NonZero<u128>, ()>);
86+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
87+
|
88+
= note: 128-bit integers don't currently have a known stable ABI
89+
90+
error: `extern` block uses type `i128`, which is not FFI-safe
91+
--> $DIR/lint-ctypes-enum.rs:114:33
92+
|
93+
LL | fn result_nonzero_i128_t(x: Result<num::NonZero<i128>, ()>);
94+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
95+
|
96+
= note: 128-bit integers don't currently have a known stable ABI
97+
98+
error: `extern` block uses type `Result<TransparentUnion<NonZero<u8>>, ()>`, which is not FFI-safe
99+
--> $DIR/lint-ctypes-enum.rs:119:38
100+
|
101+
LL | fn result_transparent_union_t(x: Result<TransparentUnion<num::NonZero<u8>>, ()>);
102+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
103+
|
104+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
105+
= note: enum has no representation hint
106+
107+
error: `extern` block uses type `Result<Rust<NonZero<u8>>, ()>`, which is not FFI-safe
108+
--> $DIR/lint-ctypes-enum.rs:121:30
109+
|
110+
LL | fn result_repr_rust_t(x: Result<Rust<num::NonZero<u8>>, ()>);
111+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
112+
|
113+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
114+
= note: enum has no representation hint
115+
116+
error: `extern` block uses type `Result<NonZero<u8>, U>`, which is not FFI-safe
117+
--> $DIR/lint-ctypes-enum.rs:125:51
118+
|
119+
LL | fn result_1zst_exhaustive_single_variant_t(x: Result<num::NonZero<u8>, U>);
120+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
121+
|
122+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
123+
= note: enum has no representation hint
124+
125+
error: `extern` block uses type `Result<NonZero<u8>, B>`, which is not FFI-safe
126+
--> $DIR/lint-ctypes-enum.rs:127:53
127+
|
128+
LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result<num::NonZero<u8>, B>);
129+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
130+
|
131+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
132+
= note: enum has no representation hint
133+
134+
error: `extern` block uses type `Result<NonZero<u8>, NonExhaustive>`, which is not FFI-safe
135+
--> $DIR/lint-ctypes-enum.rs:129:51
136+
|
137+
LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result<num::NonZero<u8>, NonExhaustive>);
138+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
139+
|
140+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
141+
= note: enum has no representation hint
142+
143+
error: `extern` block uses type `Result<NonZero<u8>, Field>`, which is not FFI-safe
144+
--> $DIR/lint-ctypes-enum.rs:132:49
145+
|
146+
LL | fn result_1zst_exhaustive_single_field_t(x: Result<num::NonZero<u8>, Field>);
147+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
148+
|
149+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
150+
= note: enum has no representation hint
151+
152+
error: `extern` block uses type `Result<Result<(), NonZero<u8>>, ()>`, which is not FFI-safe
153+
--> $DIR/lint-ctypes-enum.rs:134:30
154+
|
155+
LL | fn result_cascading_t(x: Result<Result<(), num::NonZero<u8>>, ()>);
156+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
157+
|
158+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
159+
= note: enum has no representation hint
160+
161+
error: `extern` block uses type `u128`, which is not FFI-safe
162+
--> $DIR/lint-ctypes-enum.rs:145:33
163+
|
164+
LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero<u128>>);
165+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
166+
|
167+
= note: 128-bit integers don't currently have a known stable ABI
168+
169+
error: `extern` block uses type `i128`, which is not FFI-safe
170+
--> $DIR/lint-ctypes-enum.rs:152:33
171+
|
172+
LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero<i128>>);
173+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
174+
|
175+
= note: 128-bit integers don't currently have a known stable ABI
176+
177+
error: `extern` block uses type `Result<(), TransparentUnion<NonZero<u8>>>`, which is not FFI-safe
178+
--> $DIR/lint-ctypes-enum.rs:157:38
179+
|
180+
LL | fn result_transparent_union_e(x: Result<(), TransparentUnion<num::NonZero<u8>>>);
181+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
182+
|
183+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
184+
= note: enum has no representation hint
185+
186+
error: `extern` block uses type `Result<(), Rust<NonZero<u8>>>`, which is not FFI-safe
187+
--> $DIR/lint-ctypes-enum.rs:159:30
188+
|
189+
LL | fn result_repr_rust_e(x: Result<(), Rust<num::NonZero<u8>>>);
190+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
191+
|
192+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
193+
= note: enum has no representation hint
194+
195+
error: `extern` block uses type `Result<U, NonZero<u8>>`, which is not FFI-safe
196+
--> $DIR/lint-ctypes-enum.rs:163:51
197+
|
198+
LL | fn result_1zst_exhaustive_single_variant_e(x: Result<U, num::NonZero<u8>>);
199+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
200+
|
201+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
202+
= note: enum has no representation hint
203+
204+
error: `extern` block uses type `Result<B, NonZero<u8>>`, which is not FFI-safe
205+
--> $DIR/lint-ctypes-enum.rs:165:53
206+
|
207+
LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result<B, num::NonZero<u8>>);
208+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
209+
|
210+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
211+
= note: enum has no representation hint
212+
213+
error: `extern` block uses type `Result<NonExhaustive, NonZero<u8>>`, which is not FFI-safe
214+
--> $DIR/lint-ctypes-enum.rs:167:51
215+
|
216+
LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result<NonExhaustive, num::NonZero<u8>>);
217+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
218+
|
219+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
220+
= note: enum has no representation hint
221+
222+
error: `extern` block uses type `Result<Field, NonZero<u8>>`, which is not FFI-safe
223+
--> $DIR/lint-ctypes-enum.rs:170:49
224+
|
225+
LL | fn result_1zst_exhaustive_single_field_e(x: Result<Field, num::NonZero<u8>>);
226+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
227+
|
228+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
229+
= note: enum has no representation hint
230+
231+
error: `extern` block uses type `Result<(), Result<(), NonZero<u8>>>`, which is not FFI-safe
232+
--> $DIR/lint-ctypes-enum.rs:172:30
233+
|
234+
LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero<u8>>>);
235+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
236+
|
237+
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
238+
= note: enum has no representation hint
239+
240+
error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe
241+
--> $DIR/lint-ctypes-enum.rs:174:27
84242
|
85-
LL | fn no_result(x: Result<(), num::NonZero<i32>>);
86-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
243+
LL | fn result_unit_t_e(x: Result<(), ()>);
244+
| ^^^^^^^^^^^^^^ not FFI-safe
87245
|
88246
= help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
89247
= note: enum has no representation hint
90248

91-
error: aborting due to 8 previous errors
249+
error: aborting due to 26 previous errors
92250

0 commit comments

Comments
 (0)
Please sign in to comment.