Skip to content

Commit c414d41

Browse files
committed
lint ImproperCTypes: misc. changes due to review
- relaxed the uninhabited types allowed on function return
1 parent 939a97e commit c414d41

File tree

5 files changed

+29
-100
lines changed

5 files changed

+29
-100
lines changed

compiler/rustc_lint/messages.ftl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,10 +432,7 @@ lint_improper_ctypes_tuple_help = consider using a struct instead
432432
lint_improper_ctypes_tuple_reason = tuples have unspecified layout
433433
434434
lint_improper_ctypes_uninhabited_enum = zero-variant enums and other uninhabited types are not allowed in function arguments and static variables
435-
lint_improper_ctypes_uninhabited_enum_deep = zero-variant enums and other uninhabited types are only allowed in function returns if used directly
436435
lint_improper_ctypes_uninhabited_never = the never type (`!`) and other uninhabited types are not allowed in function arguments and static variables
437-
lint_improper_ctypes_uninhabited_never_deep = the never type (`!`) and other uninhabited types are only allowed in function returns if used directly
438-
lint_improper_ctypes_uninhabited_use_direct = if you meant to have a function that never returns, consider setting its return type to the never type (`!`) or a zero-variant enum
439436
440437
lint_improper_ctypes_union_consider_transparent = `{$ty}` has exactly one non-zero-sized field, consider making it `#[repr(transparent)]` instead
441438
lint_improper_ctypes_union_fieldless_help = consider adding a member to this union

compiler/rustc_lint/src/types/improper_ctypes.rs

Lines changed: 22 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -581,40 +581,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
581581
}
582582

583583
/// Checks whether an uninhabited type (one without valid values) is safe-ish to have here
584-
fn visit_uninhabited(
585-
&self,
586-
state: CTypesVisitorState,
587-
outer_ty: Option<Ty<'tcx>>,
588-
ty: Ty<'tcx>,
589-
) -> FfiResult<'tcx> {
590-
if state.is_in_function_return()
591-
&& matches!(outer_ty.map(|ty| ty.kind()), None | Some(ty::FnPtr(..)))
592-
{
584+
fn visit_uninhabited(&self, state: CTypesVisitorState, ty: Ty<'tcx>) -> FfiResult<'tcx> {
585+
if state.is_in_function_return() {
593586
FfiResult::FfiSafe
594587
} else {
595-
let help = if state.is_in_function_return() {
596-
Some(fluent::lint_improper_ctypes_uninhabited_use_direct)
597-
} else {
598-
None
599-
};
600588
let desc = match ty.kind() {
601-
ty::Adt(..) => {
602-
if state.is_in_function_return() {
603-
fluent::lint_improper_ctypes_uninhabited_enum_deep
604-
} else {
605-
fluent::lint_improper_ctypes_uninhabited_enum
606-
}
607-
}
608-
ty::Never => {
609-
if state.is_in_function_return() {
610-
fluent::lint_improper_ctypes_uninhabited_never_deep
611-
} else {
612-
fluent::lint_improper_ctypes_uninhabited_never
613-
}
614-
}
589+
ty::Adt(..) => fluent::lint_improper_ctypes_uninhabited_enum,
590+
ty::Never => fluent::lint_improper_ctypes_uninhabited_never,
615591
r @ _ => bug!("unexpected ty_kind in uninhabited type handling: {:?}", r),
616592
};
617-
FfiResult::new_with_reason(ty, desc, help)
593+
FfiResult::new_with_reason(ty, desc, None)
618594
}
619595
}
620596

@@ -623,14 +599,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
623599
fn visit_numeric(&self, ty: Ty<'tcx>) -> FfiResult<'tcx> {
624600
// FIXME: for now, this is very incomplete, and seems to assume a x86_64 target
625601
match ty.kind() {
602+
// note: before rust 1.77, 128-bit ints were not FFI-safe on x86_64
603+
// ...they probably are still unsafe on i686 and other x86_32 architectures
626604
ty::Int(..) | ty::Uint(..) | ty::Float(..) => FfiResult::FfiSafe,
627605

628606
ty::Char => FfiResult::new_with_reason(
629607
ty,
630608
fluent::lint_improper_ctypes_char_reason,
631609
Some(fluent::lint_improper_ctypes_char_help),
632610
),
633-
_ => bug!("visit_numeric is to be called with numeric (int, float) types"),
611+
_ => bug!("visit_numeric is to be called with numeric (char, int, float) types"),
634612
}
635613
}
636614

@@ -767,7 +745,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
767745
// determine if there is 0 or 1 non-1ZST field, and which it is.
768746
// (note: for enums, "transparent" means 1-variant)
769747
if ty.is_privately_uninhabited(self.cx.tcx, self.cx.typing_env()) {
770-
// let's consider transparent structs are considered unsafe if uninhabited,
748+
// let's consider transparent structs to be maybe unsafe if uninhabited,
771749
// even if that is because of fields otherwise ignored in FFI-safety checks
772750
// FIXME: and also maybe this should be "!is_inhabited_from" but from where?
773751
ffires_accumulator += variant
@@ -778,9 +756,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
778756
let mut field_res = self.visit_type(state, Some(ty), field_ty);
779757
field_res.take_with_core_note(&[
780758
fluent::lint_improper_ctypes_uninhabited_enum,
781-
fluent::lint_improper_ctypes_uninhabited_enum_deep,
782759
fluent::lint_improper_ctypes_uninhabited_never,
783-
fluent::lint_improper_ctypes_uninhabited_never_deep,
784760
])
785761
})
786762
.reduce(|r1, r2| r1 + r2)
@@ -872,19 +848,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
872848
let help = if non_1zst_count == 1
873849
&& last_non_1zst.map(|field_i| fields_ok_list[field_i]) == Some(true)
874850
{
875-
if ty.is_privately_uninhabited(self.cx.tcx, self.cx.typing_env()) {
876-
// uninhabited types can't be helped by being turned transparent
877-
None
878-
} else {
879-
match def.adt_kind() {
880-
AdtKind::Struct => {
881-
Some(fluent::lint_improper_ctypes_struct_consider_transparent)
882-
}
883-
AdtKind::Union => {
884-
Some(fluent::lint_improper_ctypes_union_consider_transparent)
885-
}
886-
AdtKind::Enum => bug!("cannot suggest an enum to be repr(transparent)"),
851+
match def.adt_kind() {
852+
AdtKind::Struct => {
853+
Some(fluent::lint_improper_ctypes_struct_consider_transparent)
854+
}
855+
AdtKind::Union => {
856+
Some(fluent::lint_improper_ctypes_union_consider_transparent)
887857
}
858+
AdtKind::Enum => bug!("cannot suggest an enum to be repr(transparent)"),
888859
}
889860
} else {
890861
None
@@ -978,7 +949,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
978949
fn visit_enum(
979950
&self,
980951
state: CTypesVisitorState,
981-
outer_ty: Option<Ty<'tcx>>,
982952
ty: Ty<'tcx>,
983953
def: AdtDef<'tcx>,
984954
args: GenericArgsRef<'tcx>,
@@ -988,7 +958,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
988958

989959
if def.variants().is_empty() {
990960
// Empty enums are implicitely handled as the never type:
991-
return self.visit_uninhabited(state, outer_ty, ty);
961+
return self.visit_uninhabited(state, ty);
992962
}
993963
// Check for a repr() attribute to specify the size of the
994964
// discriminant.
@@ -1008,6 +978,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
1008978
);
1009979
}
1010980

981+
// FIXME: connect `def.repr().int` to visit_numeric
982+
// (for now it's OK, `repr(char)` doesn't exist and visit_numeric doesn't warn on anything else)
983+
1011984
let non_exhaustive = def.variant_list_has_applicable_non_exhaustive();
1012985
// Check the contained variants.
1013986

@@ -1042,9 +1015,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
10421015
let mut variant_res = self.visit_variant_fields(state, ty, def, variant, args);
10431016
variants_uninhabited_ffires[variant_i] = variant_res.take_with_core_note(&[
10441017
fluent::lint_improper_ctypes_uninhabited_enum,
1045-
fluent::lint_improper_ctypes_uninhabited_enum_deep,
10461018
fluent::lint_improper_ctypes_uninhabited_never,
1047-
fluent::lint_improper_ctypes_uninhabited_never_deep,
10481019
]);
10491020
// FIXME: check that enums allow any (up to all) variants to be phantoms?
10501021
// (previous code says no, but I don't know why? the problem with phantoms is that they're ZSTs, right?)
@@ -1102,7 +1073,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
11021073
}
11031074
self.visit_struct_or_union(state, ty, def, args)
11041075
}
1105-
AdtKind::Enum => self.visit_enum(state, outer_ty, ty, def, args),
1076+
AdtKind::Enum => self.visit_enum(state, ty, def, args),
11061077
}
11071078
}
11081079

@@ -1237,7 +1208,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12371208

12381209
ty::Foreign(..) => FfiSafe,
12391210

1240-
ty::Never => self.visit_uninhabited(state, outer_ty, ty),
1211+
ty::Never => self.visit_uninhabited(state, ty),
12411212

12421213
// This is only half of the checking-for-opaque-aliases story:
12431214
// since they are liable to vanish on normalisation, we need a specific to find them through

src/tools/clippy/tests/ui/ptr_arg.stderr

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,13 @@ LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str {
220220
| ^^^^^^^^^^^^^^^^ help: change this to: `&str`
221221

222222
error: writing `&String` instead of `&str` involves a new object where a slice will do
223-
--> tests/ui/ptr_arg.rs:348:17
223+
--> tests/ui/ptr_arg.rs:347:17
224224
|
225225
LL | fn good(v1: &String, v2: &String) {
226226
| ^^^^^^^ help: change this to: `&str`
227227

228228
error: writing `&String` instead of `&str` involves a new object where a slice will do
229-
--> tests/ui/ptr_arg.rs:348:30
229+
--> tests/ui/ptr_arg.rs:347:30
230230
|
231231
LL | fn good(v1: &String, v2: &String) {
232232
| ^^^^^^^ help: change this to: `&str`
@@ -285,4 +285,3 @@ LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &'a str {
285285
| ++
286286

287287
error: aborting due to 33 previous errors
288-

tests/ui/lint/improper_ctypes/lint_uninhabited.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct HalfHiddenUninhabited {
3232
extern "C" {
3333

3434
fn bad_entry(e: AlsoUninhabited); //~ ERROR: uses type `AlsoUninhabited`
35-
fn bad_exit()->AlsoUninhabited; //~ ERROR: uses type `AlsoUninhabited`
35+
fn bad_exit()->AlsoUninhabited;
3636

3737
fn bad0_entry(e: Uninhabited); //~ ERROR: uses type `Uninhabited`
3838
fn bad0_exit()->Uninhabited;
@@ -46,7 +46,7 @@ fn never_exit()->!;
4646
}
4747

4848
extern "C" fn impl_bad_entry(e: AlsoUninhabited) {} //~ ERROR: uses type `AlsoUninhabited`
49-
extern "C" fn impl_bad_exit()->AlsoUninhabited { //~ ERROR: uses type `AlsoUninhabited`
49+
extern "C" fn impl_bad_exit()->AlsoUninhabited {
5050
AlsoUninhabited{
5151
a: impl_bad0_exit(),
5252
b: 0,

tests/ui/lint/improper_ctypes/lint_uninhabited.stderr

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ error: `extern` block uses type `AlsoUninhabited`, which is not FFI-safe
44
LL | fn bad_entry(e: AlsoUninhabited);
55
| ^^^^^^^^^^^^^^^ not FFI-safe
66
|
7+
= help: `AlsoUninhabited` has exactly one non-zero-sized field, consider making it `#[repr(transparent)]` instead
78
= note: this struct/enum/union (`AlsoUninhabited`) is FFI-unsafe due to a `Uninhabited` field
89
note: the type is defined here
910
--> $DIR/lint_uninhabited.rs:12:1
@@ -22,26 +23,6 @@ note: the lint level is defined here
2223
LL | #![deny(improper_ctypes)]
2324
| ^^^^^^^^^^^^^^^
2425

25-
error: `extern` block uses type `AlsoUninhabited`, which is not FFI-safe
26-
--> $DIR/lint_uninhabited.rs:35:16
27-
|
28-
LL | fn bad_exit()->AlsoUninhabited;
29-
| ^^^^^^^^^^^^^^^ not FFI-safe
30-
|
31-
= note: this struct/enum/union (`AlsoUninhabited`) is FFI-unsafe due to a `Uninhabited` field
32-
note: the type is defined here
33-
--> $DIR/lint_uninhabited.rs:12:1
34-
|
35-
LL | struct AlsoUninhabited{
36-
| ^^^^^^^^^^^^^^^^^^^^^^
37-
= help: if you meant to have a function that never returns, consider setting its return type to the never type (`!`) or a zero-variant enum
38-
= note: zero-variant enums and other uninhabited types are only allowed in function returns if used directly
39-
note: the type is defined here
40-
--> $DIR/lint_uninhabited.rs:9:1
41-
|
42-
LL | enum Uninhabited{}
43-
| ^^^^^^^^^^^^^^^^
44-
4526
error: `extern` block uses type `Uninhabited`, which is not FFI-safe
4627
--> $DIR/lint_uninhabited.rs:37:18
4728
|
@@ -69,6 +50,7 @@ error: `extern` fn uses type `AlsoUninhabited`, which is not FFI-safe
6950
LL | extern "C" fn impl_bad_entry(e: AlsoUninhabited) {}
7051
| ^^^^^^^^^^^^^^^ not FFI-safe
7152
|
53+
= help: `AlsoUninhabited` has exactly one non-zero-sized field, consider making it `#[repr(transparent)]` instead
7254
= note: this struct/enum/union (`AlsoUninhabited`) is FFI-unsafe due to a `Uninhabited` field
7355
note: the type is defined here
7456
--> $DIR/lint_uninhabited.rs:12:1
@@ -87,26 +69,6 @@ note: the lint level is defined here
8769
LL | #![deny(improper_c_fn_definitions, improper_c_callbacks)]
8870
| ^^^^^^^^^^^^^^^^^^^^^^^^^
8971

90-
error: `extern` fn uses type `AlsoUninhabited`, which is not FFI-safe
91-
--> $DIR/lint_uninhabited.rs:49:32
92-
|
93-
LL | extern "C" fn impl_bad_exit()->AlsoUninhabited {
94-
| ^^^^^^^^^^^^^^^ not FFI-safe
95-
|
96-
= note: this struct/enum/union (`AlsoUninhabited`) is FFI-unsafe due to a `Uninhabited` field
97-
note: the type is defined here
98-
--> $DIR/lint_uninhabited.rs:12:1
99-
|
100-
LL | struct AlsoUninhabited{
101-
| ^^^^^^^^^^^^^^^^^^^^^^
102-
= help: if you meant to have a function that never returns, consider setting its return type to the never type (`!`) or a zero-variant enum
103-
= note: zero-variant enums and other uninhabited types are only allowed in function returns if used directly
104-
note: the type is defined here
105-
--> $DIR/lint_uninhabited.rs:9:1
106-
|
107-
LL | enum Uninhabited{}
108-
| ^^^^^^^^^^^^^^^^
109-
11072
error: `extern` fn uses type `Uninhabited`, which is not FFI-safe
11173
--> $DIR/lint_uninhabited.rs:56:34
11274
|
@@ -155,5 +117,5 @@ LL | struct HalfHiddenUninhabited {
155117
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
156118
= note: the never type (`!`) and other uninhabited types are not allowed in function arguments and static variables
157119

158-
error: aborting due to 9 previous errors; 1 warning emitted
120+
error: aborting due to 7 previous errors; 1 warning emitted
159121

0 commit comments

Comments
 (0)