lint: normalize projections using opaque types · rust-lang/rust@4ff1678 (original) (raw)

Original file line number Diff line number Diff line change
@@ -927,22 +927,33 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
927 927 fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
928 928 use rustc_middle::ty::TypeFoldable;
929 929
930 -struct ProhibitOpaqueTypes<'tcx> {
930 +struct ProhibitOpaqueTypes<'a, 'tcx> {
931 +cx: &'a LateContext<'a, 'tcx>,
931 932 ty: Option<Ty<'tcx>>,
932 933 };
933 934
934 -impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'tcx> {
935 +impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
935 936 fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
936 -if let ty::Opaque(..) = ty.kind {
937 -self.ty = Some(ty);
938 -true
939 -} else {
940 - ty.super_visit_with(self)
937 +match ty.kind {
938 + ty::Opaque(..) => {
939 +self.ty = Some(ty);
940 +true
941 +}
942 +// Consider opaque types within projections FFI-safe if they do not normalize
943 +// to more opaque types.
944 + ty::Projection(..) => {
945 +let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
946 +
947 +// If `ty` is a opaque type directly then `super_visit_with` won't invoke
948 +// this function again.
949 +if ty.has_opaque_types() { self.visit_ty(ty) } else { false }
950 +}
951 + _ => ty.super_visit_with(self),
941 952 }
942 953 }
943 954 }
944 955
945 -let mut visitor = ProhibitOpaqueTypes { ty: None };
956 +let mut visitor = ProhibitOpaqueTypes { cx: self.cx, ty: None };
946 957 ty.visit_with(&mut visitor);
947 958 if let Some(ty) = visitor.ty {
948 959 self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);