1
1
use std:: iter;
2
2
use std:: ops:: ControlFlow ;
3
3
4
- use rustc_abi:: { BackendRepr , ExternAbi , TagEncoding , Variants , WrappingRange } ;
4
+ use rustc_abi:: { BackendRepr , ExternAbi , TagEncoding , VariantIdx , Variants , WrappingRange } ;
5
5
use rustc_data_structures:: fx:: FxHashSet ;
6
6
use rustc_errors:: DiagMessage ;
7
7
use rustc_hir:: { Expr , ExprKind , LangItem } ;
8
8
use rustc_middle:: bug;
9
9
use rustc_middle:: ty:: layout:: { LayoutOf , SizeSkeleton } ;
10
10
use rustc_middle:: ty:: {
11
- self , AdtKind , GenericArgsRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable , TypeVisitableExt ,
11
+ self , Adt , AdtKind , GenericArgsRef , Ty , TyCtxt , TypeSuperVisitable , TypeVisitable ,
12
+ TypeVisitableExt ,
12
13
} ;
13
14
use rustc_session:: { declare_lint, declare_lint_pass, impl_lint_pass} ;
14
15
use rustc_span:: def_id:: LocalDefId ;
@@ -23,7 +24,7 @@ use crate::lints::{
23
24
AmbiguousWidePointerComparisonsAddrSuggestion , AtomicOrderingFence , AtomicOrderingLoad ,
24
25
AtomicOrderingStore , ImproperCTypes , InvalidAtomicOrderingDiag , InvalidNanComparisons ,
25
26
InvalidNanComparisonsSuggestion , UnpredictableFunctionPointerComparisons ,
26
- UnpredictableFunctionPointerComparisonsSuggestion , UnusedComparisons ,
27
+ UnpredictableFunctionPointerComparisonsSuggestion , UnusedComparisons , UsesPowerAlignment ,
27
28
VariantSizeDifferencesDiag ,
28
29
} ;
29
30
use crate :: { LateContext , LateLintPass , LintContext , fluent_generated as fluent} ;
@@ -727,7 +728,43 @@ declare_lint! {
727
728
"proper use of libc types in foreign item definitions"
728
729
}
729
730
730
- declare_lint_pass ! ( ImproperCTypesDefinitions => [ IMPROPER_CTYPES_DEFINITIONS ] ) ;
731
+ declare_lint ! {
732
+ /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
733
+ /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
734
+ /// which can also be set for XLC by `#pragma align(power)` or
735
+ /// `-qalign=power`. Aggregates with a floating-point type as the
736
+ /// recursively first field (as in "at offset 0") modify the layout of
737
+ /// *subsequent* fields of the associated structs to use an alignment value
738
+ /// where the floating-point type is aligned on a 4-byte boundary.
739
+ ///
740
+ /// The power alignment rule for structs needed for C compatibility is
741
+ /// unimplementable within `repr(C)` in the compiler without building in
742
+ /// handling of references to packed fields and infectious nested layouts,
743
+ /// so a warning is produced in these situations.
744
+ ///
745
+ /// ### Example
746
+ ///
747
+ /// ```rust
748
+ /// pub struct Floats {
749
+ /// a: f64,
750
+ /// b: u8,
751
+ /// c: f64,
752
+ /// }
753
+ /// ```
754
+ ///
755
+ /// The power alignment rule specifies that the above struct has the
756
+ /// following alignment:
757
+ /// - offset_of!(Floats, a) == 0
758
+ /// - offset_of!(Floats, b) == 8
759
+ /// - offset_of!(Floats, c) == 12
760
+ /// However, rust currently aligns `c` at offset_of!(Floats, c) == 16.
761
+ /// Thus, a warning should be produced for the above struct in this case.
762
+ USES_POWER_ALIGNMENT ,
763
+ Warn ,
764
+ "Structs do not follow the power alignment rule under repr(C)"
765
+ }
766
+
767
+ declare_lint_pass ! ( ImproperCTypesDefinitions => [ IMPROPER_CTYPES_DEFINITIONS , USES_POWER_ALIGNMENT ] ) ;
731
768
732
769
#[ derive( Clone , Copy ) ]
733
770
pub ( crate ) enum CItemKind {
@@ -1539,6 +1576,71 @@ impl ImproperCTypesDefinitions {
1539
1576
vis. check_type_for_ffi_and_report_errors ( span, fn_ptr_ty, true , false ) ;
1540
1577
}
1541
1578
}
1579
+
1580
+ fn check_arg_for_power_alignment < ' tcx > (
1581
+ & mut self ,
1582
+ cx : & LateContext < ' tcx > ,
1583
+ ty : Ty < ' tcx > ,
1584
+ ) -> bool {
1585
+ // Structs (under repr(C)) follow the power alignment rule if:
1586
+ // - the first field of the struct is a floating-point type that
1587
+ // is greater than 4-bytes, or
1588
+ // - the first field of the struct is an aggregate whose
1589
+ // recursively first field is a floating-point type greater than
1590
+ // 4 bytes.
1591
+ if cx. tcx . sess . target . os != "aix" {
1592
+ return false ;
1593
+ }
1594
+ if ty. is_floating_point ( ) && ty. primitive_size ( cx. tcx ) . bytes ( ) > 4 {
1595
+ return true ;
1596
+ } else if let Adt ( adt_def, _) = ty. kind ( )
1597
+ && adt_def. is_struct ( )
1598
+ {
1599
+ let struct_variant = adt_def. variant ( VariantIdx :: ZERO ) ;
1600
+ // Within a nested struct, all fields are examined to correctly
1601
+ // report if any fields after the nested struct within the
1602
+ // original struct are misaligned.
1603
+ for struct_field in & struct_variant. fields {
1604
+ let field_ty = cx. tcx . type_of ( struct_field. did ) . instantiate_identity ( ) ;
1605
+ if self . check_arg_for_power_alignment ( cx, field_ty) {
1606
+ return true ;
1607
+ }
1608
+ }
1609
+ }
1610
+ return false ;
1611
+ }
1612
+
1613
+ fn check_struct_for_power_alignment < ' tcx > (
1614
+ & mut self ,
1615
+ cx : & LateContext < ' tcx > ,
1616
+ item : & ' tcx hir:: Item < ' tcx > ,
1617
+ ) {
1618
+ let adt_def = cx. tcx . adt_def ( item. owner_id . to_def_id ( ) ) ;
1619
+ if adt_def. repr ( ) . c ( )
1620
+ && !adt_def. repr ( ) . packed ( )
1621
+ && cx. tcx . sess . target . os == "aix"
1622
+ && !adt_def. all_fields ( ) . next ( ) . is_none ( )
1623
+ {
1624
+ let struct_variant_data = item. expect_struct ( ) . 0 ;
1625
+ for ( index, ..) in struct_variant_data. fields ( ) . iter ( ) . enumerate ( ) {
1626
+ // Struct fields (after the first field) are checked for the
1627
+ // power alignment rule, as fields after the first are likely
1628
+ // to be the fields that are misaligned.
1629
+ if index != 0 {
1630
+ let first_field_def = struct_variant_data. fields ( ) [ index] ;
1631
+ let def_id = first_field_def. def_id ;
1632
+ let ty = cx. tcx . type_of ( def_id) . instantiate_identity ( ) ;
1633
+ if self . check_arg_for_power_alignment ( cx, ty) {
1634
+ cx. emit_span_lint (
1635
+ USES_POWER_ALIGNMENT ,
1636
+ first_field_def. span ,
1637
+ UsesPowerAlignment ,
1638
+ ) ;
1639
+ }
1640
+ }
1641
+ }
1642
+ }
1643
+ }
1542
1644
}
1543
1645
1544
1646
/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
@@ -1562,8 +1664,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
1562
1664
}
1563
1665
// See `check_fn`..
1564
1666
hir:: ItemKind :: Fn { .. } => { }
1667
+ // Structs are checked based on if they follow the power alignment
1668
+ // rule (under repr(C)).
1669
+ hir:: ItemKind :: Struct ( ..) => {
1670
+ self . check_struct_for_power_alignment ( cx, item) ;
1671
+ }
1565
1672
// See `check_field_def`..
1566
- hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Struct ( .. ) | hir :: ItemKind :: Enum ( ..) => { }
1673
+ hir:: ItemKind :: Union ( ..) | hir:: ItemKind :: Enum ( ..) => { }
1567
1674
// Doesn't define something that can contain a external type to be checked.
1568
1675
hir:: ItemKind :: Impl ( ..)
1569
1676
| hir:: ItemKind :: TraitAlias ( ..)
0 commit comments