@@ -166,6 +166,23 @@ fn get_fn_sig_from_mir_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Sig<'tc
166166 }
167167}
168168
169+ // FIXME(ctypes): it seems that tests/ui/lint/opaque-ty-ffi-normalization-cycle.rs relies this:
170+ // we consider opaque aliases that normalise to something else to be unsafe.
171+ // ...is it the behaviour we want?
172+ /// a modified version of cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty)
173+ /// so that opaque types prevent normalisation once region erasure occurs
174+ fn erase_and_maybe_normalize < ' tcx > ( cx : & LateContext < ' tcx > , value : Ty < ' tcx > ) -> Ty < ' tcx > {
175+ if ( !value. has_aliases ( ) ) || value. has_opaque_types ( ) {
176+ cx. tcx . erase_and_anonymize_regions ( value)
177+ } else {
178+ cx. tcx . try_normalize_erasing_regions ( cx. typing_env ( ) , value) . unwrap_or ( value)
179+ // note: the code above ^^^ would only cause a call to the commented code below vvv
180+ //let value = cx.tcx.erase_and_anonymize_regions(value);
181+ //let mut folder = TryNormalizeAfterErasingRegionsFolder::new(cx.tcx, cx.typing_env());
182+ //value.try_fold_with(&mut folder).unwrap_or(value)
183+ }
184+ }
185+
169186/// Getting the (normalized) type out of a field (for, e.g., an enum variant or a tuple).
170187#[ inline]
171188fn get_type_from_field < ' tcx > (
@@ -174,7 +191,7 @@ fn get_type_from_field<'tcx>(
174191 args : GenericArgsRef < ' tcx > ,
175192) -> Ty < ' tcx > {
176193 let field_ty = field. ty ( cx. tcx , args) ;
177- cx . tcx . try_normalize_erasing_regions ( cx. typing_env ( ) , field_ty ) . unwrap_or ( field_ty)
194+ erase_and_maybe_normalize ( cx, field_ty)
178195}
179196
180197fn variant_has_complex_ctor ( variant : & ty:: VariantDef ) -> bool {
@@ -553,10 +570,7 @@ fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> Type
553570 Some ( item_ty) => * item_ty,
554571 None => bug ! ( "Empty tuple (AKA unit type) should be Sized, right?" ) ,
555572 } ;
556- let item_ty = cx
557- . tcx
558- . try_normalize_erasing_regions ( cx. typing_env ( ) , item_ty)
559- . unwrap_or ( item_ty) ;
573+ let item_ty = erase_and_maybe_normalize ( cx, item_ty) ;
560574 match get_type_sizedness ( cx, item_ty) {
561575 s @ ( TypeSizedness :: MetaSized
562576 | TypeSizedness :: Unsized
@@ -1415,25 +1429,52 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14151429
14161430 ty:: Never => self . visit_uninhabited ( state, ty) ,
14171431
1418- // While opaque types are checked for earlier, if a projection in a struct field
1419- // normalizes to an opaque type, then it will reach this branch.
1432+ // This is only half of the checking-for-opaque-aliases story:
1433+ // since they are liable to vanish on normalisation, we need a specific to find them through
1434+ // other aliases, which is called in the next branch of this `match ty.kind()` statement
14201435 ty:: Alias ( ty:: Opaque , ..) => {
14211436 FfiResult :: new_with_reason ( ty, fluent:: lint_improper_ctypes_opaque, None )
14221437 }
14231438
1424- // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
1439+ // `extern "C" fn` function definitions can have type parameters, which may or may not be FFI-safe,
14251440 // so they are currently ignored for the purposes of this lint.
1426- ty:: Param ( ..) | ty:: Alias ( ty:: Projection | ty:: Inherent , ..)
1427- if state. can_expect_ty_params ( ) =>
1428- {
1429- FfiSafe
1441+ // function pointers can do the same
1442+ //
1443+ // however, these ty_kind:s can also be encountered because the type isn't normalized yet.
1444+ ty:: Param ( ..) | ty:: Alias ( ty:: Projection | ty:: Inherent | ty:: Free , ..) => {
1445+ if ty. has_opaque_types ( ) {
1446+ // FIXME(ctypes): this is suboptimal because we give up
1447+ // on reporting anything *else* than the opaque part of the type
1448+ // but this is better than not reporting anything, or crashing
1449+ self . visit_for_opaque_ty ( ty) . unwrap ( )
1450+ } else {
1451+ // in theory, thanks to erase_and_maybe_normalize,
1452+ // normalisation has already occurred
1453+ debug_assert_eq ! (
1454+ self . cx
1455+ . tcx
1456+ . try_normalize_erasing_regions( self . cx. typing_env( ) , ty, )
1457+ . unwrap_or( ty) ,
1458+ ty,
1459+ ) ;
1460+
1461+ if matches ! (
1462+ ty. kind( ) ,
1463+ ty:: Param ( ..) | ty:: Alias ( ty:: Projection | ty:: Inherent , ..)
1464+ ) && state. can_expect_ty_params ( )
1465+ {
1466+ FfiSafe
1467+ } else {
1468+ // ty::Alias(ty::Free), and all params/aliases for something
1469+ // defined beyond the FFI boundary
1470+ bug ! ( "unexpected type in foreign function: {:?}" , ty)
1471+ }
1472+ }
14301473 }
14311474
14321475 ty:: UnsafeBinder ( _) => todo ! ( "FIXME(unsafe_binder)" ) ,
14331476
1434- ty:: Param ( ..)
1435- | ty:: Alias ( ty:: Projection | ty:: Inherent | ty:: Free , ..)
1436- | ty:: Infer ( ..)
1477+ ty:: Infer ( ..)
14371478 | ty:: Bound ( ..)
14381479 | ty:: Error ( _)
14391480 | ty:: Closure ( ..)
@@ -1469,10 +1510,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
14691510 }
14701511
14711512 fn check_type ( & mut self , state : VisitorState , ty : Ty < ' tcx > ) -> FfiResult < ' tcx > {
1472- let ty = self . cx . tcx . try_normalize_erasing_regions ( self . cx . typing_env ( ) , ty) . unwrap_or ( ty) ;
1473- if let Some ( res) = self . visit_for_opaque_ty ( ty) {
1474- return res;
1475- }
1513+ let ty = erase_and_maybe_normalize ( self . cx , ty) ;
14761514 self . visit_type ( state, ty)
14771515 }
14781516}
0 commit comments