Skip to content
/ rust Public
forked from rust-lang/rust

Commit d89662e

Browse files
authored
Rollup merge of rust-lang#135552 - amy-kwan:amy-kwan/reprc-struct-diagnostic-power-alignment, r=workingjubilee
[AIX] Lint on structs that have a different alignment in AIX's C ABI This PR adds a linting diagnostic on AIX for repr(C) structs that are required to follow the power alignment rule. A repr(C) struct needs to follow the power alignment rule if the struct: - Has a floating-point data type (greater than 4-bytes) as its first member, or - The first member of the struct is an aggregate, whose recursively first member is a floating-point data type (greater than 4-bytes). The power alignment rule for eligible structs is currently unimplemented, so a linting diagnostic is produced when such a struct is encountered.
2 parents 488c78c + cd2ecc4 commit d89662e

File tree

7 files changed

+411
-16
lines changed

7 files changed

+411
-16
lines changed

compiler/rustc_lint/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,8 @@ lint_unused_result = unused result of type `{$ty}`
972972
973973
lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result
974974
975+
lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
976+
975977
lint_variant_size_differences =
976978
enum variant is more than three times larger ({$largest} bytes) than the next largest
977979

compiler/rustc_lint/src/lints.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,10 @@ pub(crate) struct OverflowingLiteral<'a> {
16941694
pub lit: String,
16951695
}
16961696

1697+
#[derive(LintDiagnostic)]
1698+
#[diag(lint_uses_power_alignment)]
1699+
pub(crate) struct UsesPowerAlignment;
1700+
16971701
#[derive(LintDiagnostic)]
16981702
#[diag(lint_unused_comparisons)]
16991703
pub(crate) struct UnusedComparisons;

compiler/rustc_lint/src/types.rs

+129-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use std::iter;
22
use std::ops::ControlFlow;
33

4-
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange};
4+
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange};
55
use rustc_data_structures::fx::FxHashSet;
66
use rustc_errors::DiagMessage;
77
use rustc_hir::{Expr, ExprKind, LangItem};
88
use rustc_middle::bug;
99
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
1010
use rustc_middle::ty::{
11-
self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
11+
self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
12+
TypeVisitableExt,
1213
};
1314
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
1415
use rustc_span::def_id::LocalDefId;
@@ -23,7 +24,7 @@ use crate::lints::{
2324
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
2425
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
2526
InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
26-
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
27+
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment,
2728
VariantSizeDifferencesDiag,
2829
};
2930
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
@@ -727,7 +728,60 @@ declare_lint! {
727728
"proper use of libc types in foreign item definitions"
728729
}
729730

730-
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);
731+
declare_lint! {
732+
/// The `uses_power_alignment` lint detects specific `repr(C)`
733+
/// aggregates on AIX.
734+
/// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
735+
/// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
736+
/// which can also be set for XLC by `#pragma align(power)` or
737+
/// `-qalign=power`. Aggregates with a floating-point type as the
738+
/// recursively first field (as in "at offset 0") modify the layout of
739+
/// *subsequent* fields of the associated structs to use an alignment value
740+
/// where the floating-point type is aligned on a 4-byte boundary.
741+
///
742+
/// The power alignment rule for structs needed for C compatibility is
743+
/// unimplementable within `repr(C)` in the compiler without building in
744+
/// handling of references to packed fields and infectious nested layouts,
745+
/// so a warning is produced in these situations.
746+
///
747+
/// ### Example
748+
///
749+
/// ```rust,ignore (fails on non-powerpc64-ibm-aix)
750+
/// #[repr(C)]
751+
/// pub struct Floats {
752+
/// a: f64,
753+
/// b: u8,
754+
/// c: f64,
755+
/// }
756+
/// ```
757+
///
758+
/// This will produce:
759+
///
760+
/// ```text
761+
/// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
762+
/// --> <source>:5:3
763+
/// |
764+
/// 5 | c: f64,
765+
/// | ^^^^^^
766+
/// |
767+
/// = note: `#[warn(uses_power_alignment)]` on by default
768+
/// ```
769+
///
770+
/// ### Explanation
771+
///
772+
/// The power alignment rule specifies that the above struct has the
773+
/// following alignment:
774+
/// - offset_of!(Floats, a) == 0
775+
/// - offset_of!(Floats, b) == 8
776+
/// - offset_of!(Floats, c) == 12
777+
/// However, rust currently aligns `c` at offset_of!(Floats, c) == 16.
778+
/// Thus, a warning should be produced for the above struct in this case.
779+
USES_POWER_ALIGNMENT,
780+
Warn,
781+
"Structs do not follow the power alignment rule under repr(C)"
782+
}
783+
784+
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]);
731785

732786
#[derive(Clone, Copy)]
733787
pub(crate) enum CItemKind {
@@ -1539,6 +1593,71 @@ impl ImproperCTypesDefinitions {
15391593
vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
15401594
}
15411595
}
1596+
1597+
fn check_arg_for_power_alignment<'tcx>(
1598+
&mut self,
1599+
cx: &LateContext<'tcx>,
1600+
ty: Ty<'tcx>,
1601+
) -> bool {
1602+
// Structs (under repr(C)) follow the power alignment rule if:
1603+
// - the first field of the struct is a floating-point type that
1604+
// is greater than 4-bytes, or
1605+
// - the first field of the struct is an aggregate whose
1606+
// recursively first field is a floating-point type greater than
1607+
// 4 bytes.
1608+
if cx.tcx.sess.target.os != "aix" {
1609+
return false;
1610+
}
1611+
if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 {
1612+
return true;
1613+
} else if let Adt(adt_def, _) = ty.kind()
1614+
&& adt_def.is_struct()
1615+
{
1616+
let struct_variant = adt_def.variant(VariantIdx::ZERO);
1617+
// Within a nested struct, all fields are examined to correctly
1618+
// report if any fields after the nested struct within the
1619+
// original struct are misaligned.
1620+
for struct_field in &struct_variant.fields {
1621+
let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity();
1622+
if self.check_arg_for_power_alignment(cx, field_ty) {
1623+
return true;
1624+
}
1625+
}
1626+
}
1627+
return false;
1628+
}
1629+
1630+
fn check_struct_for_power_alignment<'tcx>(
1631+
&mut self,
1632+
cx: &LateContext<'tcx>,
1633+
item: &'tcx hir::Item<'tcx>,
1634+
) {
1635+
let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id());
1636+
if adt_def.repr().c()
1637+
&& !adt_def.repr().packed()
1638+
&& cx.tcx.sess.target.os == "aix"
1639+
&& !adt_def.all_fields().next().is_none()
1640+
{
1641+
let struct_variant_data = item.expect_struct().0;
1642+
for (index, ..) in struct_variant_data.fields().iter().enumerate() {
1643+
// Struct fields (after the first field) are checked for the
1644+
// power alignment rule, as fields after the first are likely
1645+
// to be the fields that are misaligned.
1646+
if index != 0 {
1647+
let first_field_def = struct_variant_data.fields()[index];
1648+
let def_id = first_field_def.def_id;
1649+
let ty = cx.tcx.type_of(def_id).instantiate_identity();
1650+
if self.check_arg_for_power_alignment(cx, ty) {
1651+
cx.emit_span_lint(
1652+
USES_POWER_ALIGNMENT,
1653+
first_field_def.span,
1654+
UsesPowerAlignment,
1655+
);
1656+
}
1657+
}
1658+
}
1659+
}
1660+
}
15421661
}
15431662

15441663
/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
@@ -1562,8 +1681,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
15621681
}
15631682
// See `check_fn`..
15641683
hir::ItemKind::Fn { .. } => {}
1684+
// Structs are checked based on if they follow the power alignment
1685+
// rule (under repr(C)).
1686+
hir::ItemKind::Struct(..) => {
1687+
self.check_struct_for_power_alignment(cx, item);
1688+
}
15651689
// See `check_field_def`..
1566-
hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {}
1690+
hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
15671691
// Doesn't define something that can contain a external type to be checked.
15681692
hir::ItemKind::Impl(..)
15691693
| hir::ItemKind::TraitAlias(..)
+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
//@ check-pass
2+
//@ compile-flags: --target powerpc64-ibm-aix
3+
//@ needs-llvm-components: powerpc
4+
//@ add-core-stubs
5+
#![feature(no_core)]
6+
#![no_core]
7+
#![no_std]
8+
9+
extern crate minicore;
10+
use minicore::*;
11+
12+
#[warn(uses_power_alignment)]
13+
14+
#[repr(C)]
15+
pub struct Floats {
16+
a: f64,
17+
b: u8,
18+
c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
19+
d: f32,
20+
}
21+
22+
pub struct Floats2 {
23+
a: f64,
24+
b: u32,
25+
c: f64,
26+
}
27+
28+
#[repr(C)]
29+
pub struct Floats3 {
30+
a: f32,
31+
b: f32,
32+
c: i64,
33+
}
34+
35+
#[repr(C)]
36+
pub struct Floats4 {
37+
a: u64,
38+
b: u32,
39+
c: f32,
40+
}
41+
42+
#[repr(C)]
43+
pub struct Floats5 {
44+
a: f32,
45+
b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
46+
c: f32,
47+
}
48+
49+
#[repr(C)]
50+
pub struct FloatAgg1 {
51+
x: Floats,
52+
y: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
53+
}
54+
55+
#[repr(C)]
56+
pub struct FloatAgg2 {
57+
x: i64,
58+
y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
59+
}
60+
61+
#[repr(C)]
62+
pub struct FloatAgg3 {
63+
x: FloatAgg1,
64+
// NOTE: the "power" alignment rule is infectious to nested struct fields.
65+
y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
66+
z: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
67+
}
68+
69+
#[repr(C)]
70+
pub struct FloatAgg4 {
71+
x: FloatAgg1,
72+
y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
73+
}
74+
75+
#[repr(C)]
76+
pub struct FloatAgg5 {
77+
x: FloatAgg1,
78+
y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
79+
z: FloatAgg3, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
80+
}
81+
82+
#[repr(C)]
83+
pub struct FloatAgg6 {
84+
x: i64,
85+
y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
86+
z: u8,
87+
}
88+
89+
#[repr(C)]
90+
pub struct FloatAgg7 {
91+
x: i64,
92+
y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
93+
z: u8,
94+
zz: f32,
95+
}
96+
97+
#[repr(C)]
98+
pub struct A {
99+
d: f64,
100+
}
101+
#[repr(C)]
102+
pub struct B {
103+
a: A,
104+
f: f32,
105+
d: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
106+
}
107+
#[repr(C)]
108+
pub struct C {
109+
c: u8,
110+
b: B, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
111+
}
112+
#[repr(C)]
113+
pub struct D {
114+
x: f64,
115+
}
116+
#[repr(C)]
117+
pub struct E {
118+
x: i32,
119+
d: D, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
120+
}
121+
#[repr(C)]
122+
pub struct F {
123+
a: u8,
124+
b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
125+
}
126+
#[repr(C)]
127+
pub struct G {
128+
a: u8,
129+
b: u8,
130+
c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
131+
d: f32,
132+
e: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
133+
}
134+
// Should not warn on #[repr(packed)].
135+
#[repr(packed)]
136+
pub struct H {
137+
a: u8,
138+
b: u8,
139+
c: f64,
140+
d: f32,
141+
e: f64,
142+
}
143+
#[repr(C, packed)]
144+
pub struct I {
145+
a: u8,
146+
b: u8,
147+
c: f64,
148+
d: f32,
149+
e: f64,
150+
}
151+
152+
fn main() { }

0 commit comments

Comments
 (0)