11use std:: iter;
22use std:: ops:: ControlFlow ;
33
4- use rustc_abi:: { BackendRepr , ExternAbi , TagEncoding , Variants , WrappingRange } ;
4+ use rustc_abi:: {
5+ BackendRepr , ExternAbi , FieldIdx , TagEncoding , VariantIdx , Variants , WrappingRange ,
6+ } ;
57use rustc_data_structures:: fx:: FxHashSet ;
68use rustc_errors:: DiagMessage ;
79use rustc_hir:: { Expr , ExprKind , LangItem } ;
810use rustc_middle:: bug;
911use rustc_middle:: ty:: layout:: { LayoutOf , SizeSkeleton } ;
1012use rustc_middle:: ty:: {
11- self , AdtKind , GenericArgsRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt ,
13+ self , Adt , AdtKind , GenericArgsRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable ,
14+ TypeVisitableExt ,
1215} ;
1316use rustc_session:: { declare_lint, declare_lint_pass, impl_lint_pass} ;
1417use rustc_span:: def_id:: LocalDefId ;
@@ -24,7 +27,7 @@ use crate::lints::{
2427 AtomicOrderingStore , ImproperCTypes , InvalidAtomicOrderingDiag , InvalidNanComparisons ,
2528 InvalidNanComparisonsSuggestion , UnpredictableFunctionPointerComparisons ,
2629 UnpredictableFunctionPointerComparisonsSuggestion , UnusedComparisons ,
27- VariantSizeDifferencesDiag ,
30+ UsesPowerAlignment , VariantSizeDifferencesDiag ,
2831} ;
2932use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
3033
@@ -727,7 +730,33 @@ declare_lint! {
727730 "proper use of libc types in foreign item definitions"
728731}
729732
730- declare_lint_pass ! ( ImproperCTypesDefinitions => [ IMPROPER_CTYPES_DEFINITIONS ] ) ;
733+ declare_lint ! {
734+ /// The AIX target follows the power alignment rule. This rule specifies
735+ /// that structs with either a:
736+ /// - floating-point data type as its first member, or
737+ /// - first member being an aggregate whose recursively first member is a
738+ /// floating-point data type
739+ /// must have its natural alignment. This is currently unimplemented within
740+ /// the compiler, so a warning is produced in these situations.
741+ ///
742+ /// ### Example
743+ ///
744+ /// ```rust
745+ /// pub struct Floats {
746+ /// a: f64,
747+ /// b: u8,
748+ /// c: f64,
749+ /// }
750+ /// ```
751+ ///
752+ /// A warning should be produced for the above struct as the first member
753+ /// of the struct is an f64.
754+ USES_POWER_ALIGNMENT ,
755+ Warn ,
756+ "floating point types within structs do not follow the power alignment rule under repr(C)"
757+ }
758+
759+ declare_lint_pass ! ( ImproperCTypesDefinitions => [ IMPROPER_CTYPES_DEFINITIONS , USES_POWER_ALIGNMENT ] ) ;
731760
732761#[ derive( Clone , Copy ) ]
733762pub ( crate ) enum CItemKind {
@@ -1539,6 +1568,51 @@ impl ImproperCTypesDefinitions {
15391568 vis. check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, true , false ) ;
15401569 }
15411570 }
1571+
1572+ fn check_arg_for_power_alignment < ' tcx > (
1573+ & mut self ,
1574+ cx : & LateContext < ' tcx > ,
1575+ ty : Ty < ' tcx > ,
1576+ ) -> bool {
1577+ // Structs (under repr(C)) follow the power alignment rule if:
1578+ // - the first argument of the struct is a floating-point type, or
1579+ // - the first argument of the struct is an aggregate whose
1580+ // recursively first member is a floating-point type
1581+ if ty. is_floating_point ( ) {
1582+ return true ;
1583+ } else if let Adt ( adt_def, _) = ty. kind ( )
1584+ && adt_def. is_struct ( )
1585+ {
1586+ let first_variant = adt_def. variant ( VariantIdx :: ZERO ) ;
1587+ if let Some ( first) = first_variant. fields . get ( FieldIdx :: ZERO ) {
1588+ let field_ty = cx. tcx . type_of ( first. did ) . instantiate_identity ( ) ;
1589+ return self . check_arg_for_power_alignment ( cx, field_ty) ;
1590+ }
1591+ }
1592+ return false ;
1593+ }
1594+
1595+ fn check_struct_for_power_alignment < ' tcx > (
1596+ & mut self ,
1597+ cx : & LateContext < ' tcx > ,
1598+ item : & ' tcx hir:: Item < ' tcx > ,
1599+ ) {
1600+ let adt_def = cx. tcx . adt_def ( item. owner_id . to_def_id ( ) ) ;
1601+ if adt_def. repr ( ) . c ( )
1602+ && cx. tcx . sess . target . os == "aix"
1603+ && !adt_def. all_fields ( ) . next ( ) . is_none ( )
1604+ {
1605+ let struct_variant_data = item. expect_struct ( ) . 0 ;
1606+ // Analyze only the first member of the struct to see if it
1607+ // follows the power alignment rule.
1608+ let first_field_def = struct_variant_data. fields ( ) [ 0 ] ;
1609+ let def_id = first_field_def. def_id ;
1610+ let ty = cx. tcx . type_of ( def_id) . instantiate_identity ( ) ;
1611+ if self . check_arg_for_power_alignment ( cx, ty) {
1612+ cx. emit_span_lint ( USES_POWER_ALIGNMENT , first_field_def. span , UsesPowerAlignment ) ;
1613+ }
1614+ }
1615+ }
15421616}
15431617
15441618/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
@@ -1562,8 +1636,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
15621636 }
15631637 // See `check_fn`..
15641638 hir:: ItemKind :: Fn { .. } => { }
1639+ // Structs are checked based on if they follow the power alignment
1640+ // rule (under repr(C)).
1641+ hir:: ItemKind :: Struct ( ..) => {
1642+ self . check_struct_for_power_alignment ( cx, item) ;
1643+ }
15651644 // See `check_field_def`..
1566- hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Struct ( .. ) | hir :: ItemKind :: Enum ( ..) => { }
1645+ hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Enum ( ..) => { }
15671646 // Doesn't define something that can contain a external type to be checked.
15681647 hir:: ItemKind :: Impl ( ..)
15691648 | hir:: ItemKind :: TraitAlias ( ..)
0 commit comments