11use std:: iter;
22use std:: ops:: ControlFlow ;
33
4- use rustc_abi:: {
5- BackendRepr , ExternAbi , FieldIdx , TagEncoding , VariantIdx , Variants , WrappingRange ,
6- } ;
4+ use rustc_abi:: { BackendRepr , ExternAbi , TagEncoding , VariantIdx , Variants , WrappingRange } ;
75use rustc_data_structures:: fx:: FxHashSet ;
86use rustc_errors:: DiagMessage ;
97use rustc_hir:: { Expr , ExprKind , LangItem } ;
@@ -26,8 +24,8 @@ use crate::lints::{
2624 AmbiguousWidePointerComparisonsAddrSuggestion , AtomicOrderingFence , AtomicOrderingLoad ,
2725 AtomicOrderingStore , ImproperCTypes , InvalidAtomicOrderingDiag , InvalidNanComparisons ,
2826 InvalidNanComparisonsSuggestion , UnpredictableFunctionPointerComparisons ,
29- UnpredictableFunctionPointerComparisonsSuggestion , UnusedComparisons ,
30- UsesPowerAlignment , VariantSizeDifferencesDiag ,
27+ UnpredictableFunctionPointerComparisonsSuggestion , UnusedComparisons , UsesPowerAlignment ,
28+ VariantSizeDifferencesDiag ,
3129} ;
3230use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
3331
@@ -731,13 +729,23 @@ declare_lint! {
731729}
732730
733731declare_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.
732+ /// In it's platform C ABI, the AIX target follows the power alignment rule
733+ /// for structs. This rule applies the natural alignment of the first struct
734+ /// field if it is a floating-point type that is greater than 4-bytes, or
735+ /// is an aggregate whose recursively "first" field is a floating-point
736+ /// type greater than 4-bytes.
737+ /// The alignment for subsequent fields of the associated structs use an
738+ /// alignment value where the floating-point type is aligned on a 4-byte
739+ /// boundary.
740+ /// In this case, "natural alignment" (detailed in
741+ /// https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment)
742+ /// refers to the floating-point type being aligned to a multiple of its
743+ /// size (for example, the size of a double is 8-bytes, and so is 8-byte
744+ /// aligned).
745+ ///
746+ /// The power alignment rule for structs need for C compatibility is
747+ /// currently unimplemented within repr(C) in the compiler, so a warning is
748+ /// produced in these situations.
741749 ///
742750 /// ### Example
743751 ///
@@ -749,11 +757,16 @@ declare_lint! {
749757 /// }
750758 /// ```
751759 ///
752- /// A warning should be produced for the above struct as the first member
753- /// of the struct is an f64.
760+ /// The power alignment rule specifies that the above struct has the
761+ /// following alignment:
762+ /// - offset_of!(Floats, a) == 0
763+ /// - offset_of!(Floats, b) == 8
764+ /// - offset_of!(Floats, c) == 12
765+ /// However, rust currently aligns `c` at offset_of!(Floats, c) == 16.
766+ /// Thus, a warning should be produced for the above struct in this case.
754767 USES_POWER_ALIGNMENT ,
755768 Warn ,
756- "floating point types within structs do not follow the power alignment rule under repr(C)"
769+ "Structs do not follow the power alignment rule under repr(C)"
757770}
758771
759772declare_lint_pass ! ( ImproperCTypesDefinitions => [ IMPROPER_CTYPES_DEFINITIONS , USES_POWER_ALIGNMENT ] ) ;
@@ -1575,18 +1588,25 @@ impl ImproperCTypesDefinitions {
15751588 ty : Ty < ' tcx > ,
15761589 ) -> bool {
15771590 // 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 ( ) {
1591+ // - the first field of the struct is a floating-point type that
1592+ // is greater than 4-bytes, or
1593+ // - the first field of the struct is an aggregate whose
1594+ // recursively first field is a floating-point type greater than
1595+ // 4 bytes.
1596+ if ty. is_floating_point ( ) && ty. primitive_size ( cx. tcx ) . bytes ( ) > 4 {
15821597 return true ;
15831598 } else if let Adt ( adt_def, _) = ty. kind ( )
15841599 && adt_def. is_struct ( )
15851600 {
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) ;
1601+ let struct_variant = adt_def. variant ( VariantIdx :: ZERO ) ;
1602+ // Within a nested struct, all fields are examined to correctly
1603+ // report if any fields after the nested struct within the
1604+ // original struct are misaligned.
1605+ for struct_field in & struct_variant. fields {
1606+ let field_ty = cx. tcx . type_of ( struct_field. did ) . instantiate_identity ( ) ;
1607+ if self . check_arg_for_power_alignment ( cx, field_ty) {
1608+ return true ;
1609+ }
15901610 }
15911611 }
15921612 return false ;
@@ -1599,17 +1619,26 @@ impl ImproperCTypesDefinitions {
15991619 ) {
16001620 let adt_def = cx. tcx . adt_def ( item. owner_id . to_def_id ( ) ) ;
16011621 if adt_def. repr ( ) . c ( )
1602- && cx. tcx . sess . target . os == "aix"
1622+ && !adt_def . repr ( ) . packed ( ) && cx. tcx . sess . target . os == "aix"
16031623 && !adt_def. all_fields ( ) . next ( ) . is_none ( )
16041624 {
16051625 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 ) ;
1626+ for ( index, ..) in struct_variant_data. fields ( ) . iter ( ) . enumerate ( ) {
1627+ // Struct fields (after the first field) are checked for the
1628+ // power alignment rule, as fields after the first are likely
1629+ // to be the fields that are misaligned.
1630+ if index != 0 {
1631+ let first_field_def = struct_variant_data. fields ( ) [ index] ;
1632+ let def_id = first_field_def. def_id ;
1633+ let ty = cx. tcx . type_of ( def_id) . instantiate_identity ( ) ;
1634+ if self . check_arg_for_power_alignment ( cx, ty) {
1635+ cx. emit_span_lint (
1636+ USES_POWER_ALIGNMENT ,
1637+ first_field_def. span ,
1638+ UsesPowerAlignment ,
1639+ ) ;
1640+ }
1641+ }
16131642 }
16141643 }
16151644 }
0 commit comments