Skip to content

Commit eb48d6b

Browse files
committed
Auto merge of #64359 - varkor:opaque-ty-in-extern, r=estebank
Forbid opaque types in `extern "C"` blocks Fixes #64338.
2 parents 28e85d7 + 9d71217 commit eb48d6b

13 files changed

+268
-135
lines changed

src/librustc_lint/types.rs

+82-31
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
624624
AdtKind::Struct => {
625625
if !def.repr.c() && !def.repr.transparent() {
626626
return FfiUnsafe {
627-
ty: ty,
627+
ty,
628628
reason: "this struct has unspecified layout",
629629
help: Some("consider adding a `#[repr(C)]` or \
630630
`#[repr(transparent)]` attribute to this struct"),
@@ -633,7 +633,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
633633

634634
if def.non_enum_variant().fields.is_empty() {
635635
return FfiUnsafe {
636-
ty: ty,
636+
ty,
637637
reason: "this struct has no fields",
638638
help: Some("consider adding a member to this struct"),
639639
};
@@ -669,7 +669,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
669669
AdtKind::Union => {
670670
if !def.repr.c() && !def.repr.transparent() {
671671
return FfiUnsafe {
672-
ty: ty,
672+
ty,
673673
reason: "this union has unspecified layout",
674674
help: Some("consider adding a `#[repr(C)]` or \
675675
`#[repr(transparent)]` attribute to this union"),
@@ -678,7 +678,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
678678

679679
if def.non_enum_variant().fields.is_empty() {
680680
return FfiUnsafe {
681-
ty: ty,
681+
ty,
682682
reason: "this union has no fields",
683683
help: Some("consider adding a field to this union"),
684684
};
@@ -721,7 +721,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
721721
// Special-case types like `Option<extern fn()>`.
722722
if !is_repr_nullable_ptr(cx, ty, def, substs) {
723723
return FfiUnsafe {
724-
ty: ty,
724+
ty,
725725
reason: "enum has no representation hint",
726726
help: Some("consider adding a `#[repr(C)]`, \
727727
`#[repr(transparent)]`, or integer `#[repr(...)]` \
@@ -750,7 +750,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
750750
}
751751
FfiPhantom(..) => {
752752
return FfiUnsafe {
753-
ty: ty,
753+
ty,
754754
reason: "this enum contains a PhantomData field",
755755
help: None,
756756
};
@@ -764,13 +764,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
764764
}
765765

766766
ty::Char => FfiUnsafe {
767-
ty: ty,
767+
ty,
768768
reason: "the `char` type has no C equivalent",
769769
help: Some("consider using `u32` or `libc::wchar_t` instead"),
770770
},
771771

772772
ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe {
773-
ty: ty,
773+
ty,
774774
reason: "128-bit integers don't currently have a known stable ABI",
775775
help: None,
776776
},
@@ -779,25 +779,25 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
779779
ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
780780

781781
ty::Slice(_) => FfiUnsafe {
782-
ty: ty,
782+
ty,
783783
reason: "slices have no C equivalent",
784784
help: Some("consider using a raw pointer instead"),
785785
},
786786

787787
ty::Dynamic(..) => FfiUnsafe {
788-
ty: ty,
788+
ty,
789789
reason: "trait objects have no C equivalent",
790790
help: None,
791791
},
792792

793793
ty::Str => FfiUnsafe {
794-
ty: ty,
794+
ty,
795795
reason: "string slices have no C equivalent",
796796
help: Some("consider using `*const u8` and a length instead"),
797797
},
798798

799799
ty::Tuple(..) => FfiUnsafe {
800-
ty: ty,
800+
ty,
801801
reason: "tuples have unspecified layout",
802802
help: Some("consider using a struct instead"),
803803
},
@@ -811,7 +811,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
811811
match sig.abi() {
812812
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
813813
return FfiUnsafe {
814-
ty: ty,
814+
ty,
815815
reason: "this function pointer has Rust-specific calling convention",
816816
help: Some("consider using an `extern fn(...) -> ...` \
817817
function pointer instead"),
@@ -855,36 +855,87 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
855855
ty::UnnormalizedProjection(..) |
856856
ty::Projection(..) |
857857
ty::Opaque(..) |
858-
ty::FnDef(..) => bug!("Unexpected type in foreign function"),
858+
ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
859+
}
860+
}
861+
862+
fn emit_ffi_unsafe_type_lint(
863+
&mut self,
864+
ty: Ty<'tcx>,
865+
sp: Span,
866+
note: &str,
867+
help: Option<&str>,
868+
) {
869+
let mut diag = self.cx.struct_span_lint(
870+
IMPROPER_CTYPES,
871+
sp,
872+
&format!("`extern` block uses type `{}`, which is not FFI-safe", ty),
873+
);
874+
diag.span_label(sp, "not FFI-safe");
875+
if let Some(help) = help {
876+
diag.help(help);
877+
}
878+
diag.note(note);
879+
if let ty::Adt(def, _) = ty.sty {
880+
if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) {
881+
diag.span_note(sp, "type defined here");
882+
}
883+
}
884+
diag.emit();
885+
}
886+
887+
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
888+
use crate::rustc::ty::TypeFoldable;
889+
890+
struct ProhibitOpaqueTypes<'tcx> {
891+
ty: Option<Ty<'tcx>>,
892+
};
893+
894+
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
895+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
896+
if let ty::Opaque(..) = ty.sty {
897+
self.ty = Some(ty);
898+
true
899+
} else {
900+
ty.super_visit_with(self)
901+
}
902+
}
903+
}
904+
905+
let mut visitor = ProhibitOpaqueTypes { ty: None };
906+
ty.visit_with(&mut visitor);
907+
if let Some(ty) = visitor.ty {
908+
self.emit_ffi_unsafe_type_lint(
909+
ty,
910+
sp,
911+
"opaque types have no C equivalent",
912+
None,
913+
);
914+
true
915+
} else {
916+
false
859917
}
860918
}
861919

862920
fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
921+
// We have to check for opaque types before `normalize_erasing_regions`,
922+
// which will replace opaque types with their underlying concrete type.
923+
if self.check_for_opaque_ty(sp, ty) {
924+
// We've already emitted an error due to an opaque type.
925+
return;
926+
}
927+
863928
// it is only OK to use this function because extern fns cannot have
864929
// any generic types right now:
865930
let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
866931

867932
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
868933
FfiResult::FfiSafe => {}
869934
FfiResult::FfiPhantom(ty) => {
870-
self.cx.span_lint(IMPROPER_CTYPES,
871-
sp,
872-
&format!("`extern` block uses type `{}` which is not FFI-safe: \
873-
composed only of PhantomData", ty));
935+
self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None);
874936
}
875-
FfiResult::FfiUnsafe { ty: unsafe_ty, reason, help } => {
876-
let msg = format!("`extern` block uses type `{}` which is not FFI-safe: {}",
877-
unsafe_ty, reason);
878-
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
879-
if let Some(s) = help {
880-
diag.help(s);
881-
}
882-
if let ty::Adt(def, _) = unsafe_ty.sty {
883-
if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) {
884-
diag.span_note(sp, "type defined here");
885-
}
886-
}
887-
diag.emit();
937+
FfiResult::FfiUnsafe { ty, reason, help } => {
938+
self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
888939
}
889940
}
890941
}

src/test/ui/issues/issue-14309.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct D {
2727
}
2828

2929
extern "C" {
30-
fn foo(x: A); //~ ERROR type `A` which is not FFI-safe
30+
fn foo(x: A); //~ ERROR type `A`, which is not FFI-safe
3131
fn bar(x: B); //~ ERROR type `A`
3232
fn baz(x: C);
3333
fn qux(x: A2); //~ ERROR type `A`

src/test/ui/issues/issue-14309.stderr

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
1+
error: `extern` block uses type `A`, which is not FFI-safe
22
--> $DIR/issue-14309.rs:30:15
33
|
44
LL | fn foo(x: A);
5-
| ^
5+
| ^ not FFI-safe
66
|
77
note: lint level defined here
88
--> $DIR/issue-14309.rs:1:9
99
|
1010
LL | #![deny(improper_ctypes)]
1111
| ^^^^^^^^^^^^^^^
1212
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
13+
= note: this struct has unspecified layout
1314
note: type defined here
1415
--> $DIR/issue-14309.rs:4:1
1516
|
@@ -18,13 +19,14 @@ LL | | x: i32
1819
LL | | }
1920
| |_^
2021

21-
error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
22+
error: `extern` block uses type `A`, which is not FFI-safe
2223
--> $DIR/issue-14309.rs:31:15
2324
|
2425
LL | fn bar(x: B);
25-
| ^
26+
| ^ not FFI-safe
2627
|
2728
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
29+
= note: this struct has unspecified layout
2830
note: type defined here
2931
--> $DIR/issue-14309.rs:4:1
3032
|
@@ -33,13 +35,14 @@ LL | | x: i32
3335
LL | | }
3436
| |_^
3537

36-
error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
38+
error: `extern` block uses type `A`, which is not FFI-safe
3739
--> $DIR/issue-14309.rs:33:15
3840
|
3941
LL | fn qux(x: A2);
40-
| ^^
42+
| ^^ not FFI-safe
4143
|
4244
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
45+
= note: this struct has unspecified layout
4346
note: type defined here
4447
--> $DIR/issue-14309.rs:4:1
4548
|
@@ -48,13 +51,14 @@ LL | | x: i32
4851
LL | | }
4952
| |_^
5053

51-
error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
54+
error: `extern` block uses type `A`, which is not FFI-safe
5255
--> $DIR/issue-14309.rs:34:16
5356
|
5457
LL | fn quux(x: B2);
55-
| ^^
58+
| ^^ not FFI-safe
5659
|
5760
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
61+
= note: this struct has unspecified layout
5862
note: type defined here
5963
--> $DIR/issue-14309.rs:4:1
6064
|
@@ -63,13 +67,14 @@ LL | | x: i32
6367
LL | | }
6468
| |_^
6569

66-
error: `extern` block uses type `A` which is not FFI-safe: this struct has unspecified layout
70+
error: `extern` block uses type `A`, which is not FFI-safe
6771
--> $DIR/issue-14309.rs:36:16
6872
|
6973
LL | fn fred(x: D);
70-
| ^
74+
| ^ not FFI-safe
7175
|
7276
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
77+
= note: this struct has unspecified layout
7378
note: type defined here
7479
--> $DIR/issue-14309.rs:4:1
7580
|

src/test/ui/issues/issue-16250.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
pub struct Foo;
44

55
extern {
6-
pub fn foo(x: (Foo)); //~ ERROR unspecified layout
6+
pub fn foo(x: (Foo)); //~ ERROR `extern` block uses type `Foo`
77
}
88

99
fn main() {

src/test/ui/issues/issue-16250.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: `extern` block uses type `Foo` which is not FFI-safe: this struct has unspecified layout
1+
error: `extern` block uses type `Foo`, which is not FFI-safe
22
--> $DIR/issue-16250.rs:6:20
33
|
44
LL | pub fn foo(x: (Foo));
5-
| ^^^
5+
| ^^^ not FFI-safe
66
|
77
note: lint level defined here
88
--> $DIR/issue-16250.rs:1:9
@@ -11,6 +11,7 @@ LL | #![deny(warnings)]
1111
| ^^^^^^^^
1212
= note: `#[deny(improper_ctypes)]` implied by `#[deny(warnings)]`
1313
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
14+
= note: this struct has unspecified layout
1415
note: type defined here
1516
--> $DIR/issue-16250.rs:3:1
1617
|

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

+11-10
Original file line numberDiff line numberDiff line change
@@ -36,36 +36,37 @@ struct Rust<T>(T);
3636

3737
extern {
3838
fn zf(x: Z);
39-
fn uf(x: U); //~ ERROR enum has no representation hint
40-
fn bf(x: B); //~ ERROR enum has no representation hint
41-
fn tf(x: T); //~ ERROR enum has no representation hint
39+
fn uf(x: U); //~ ERROR `extern` block uses type `U`
40+
fn bf(x: B); //~ ERROR `extern` block uses type `B`
41+
fn tf(x: T); //~ ERROR `extern` block uses type `T`
4242
fn repr_c(x: ReprC);
4343
fn repr_u8(x: U8);
4444
fn repr_isize(x: Isize);
4545
fn option_ref(x: Option<&'static u8>);
4646
fn option_fn(x: Option<extern "C" fn()>);
4747
fn nonnull(x: Option<std::ptr::NonNull<u8>>);
48-
fn unique(x: Option<std::ptr::Unique<u8>>); //~ ERROR enum has no representation hint
48+
fn unique(x: Option<std::ptr::Unique<u8>>);
49+
//~^ ERROR `extern` block uses type `std::option::Option<std::ptr::Unique<u8>>`
4950
fn nonzero_u8(x: Option<num::NonZeroU8>);
5051
fn nonzero_u16(x: Option<num::NonZeroU16>);
5152
fn nonzero_u32(x: Option<num::NonZeroU32>);
5253
fn nonzero_u64(x: Option<num::NonZeroU64>);
5354
fn nonzero_u128(x: Option<num::NonZeroU128>);
54-
//~^ ERROR 128-bit integers don't currently have a known stable ABI
55+
//~^ ERROR `extern` block uses type `u128`
5556
fn nonzero_usize(x: Option<num::NonZeroUsize>);
5657
fn nonzero_i8(x: Option<num::NonZeroI8>);
5758
fn nonzero_i16(x: Option<num::NonZeroI16>);
5859
fn nonzero_i32(x: Option<num::NonZeroI32>);
5960
fn nonzero_i64(x: Option<num::NonZeroI64>);
6061
fn nonzero_i128(x: Option<num::NonZeroI128>);
61-
//~^ ERROR 128-bit integers don't currently have a known stable ABI
62+
//~^ ERROR `extern` block uses type `i128`
6263
fn nonzero_isize(x: Option<num::NonZeroIsize>);
6364
fn transparent_struct(x: Option<TransparentStruct<num::NonZeroU8>>);
6465
fn transparent_enum(x: Option<TransparentEnum<num::NonZeroU8>>);
6566
fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>);
66-
//~^ ERROR enum has no representation hint
67-
fn repr_rust(x: Option<Rust<num::NonZeroU8>>); //~ ERROR enum has no representation hint
68-
fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR enum has no representation hint
67+
//~^ ERROR `extern` block uses type
68+
fn repr_rust(x: Option<Rust<num::NonZeroU8>>); //~ ERROR `extern` block uses type
69+
fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR `extern` block uses type
6970
}
7071

71-
pub fn main() { }
72+
pub fn main() {}

0 commit comments

Comments
 (0)