Skip to content

Commit 1013f4f

Browse files
committed
[AIX] Emit linting diagnositc to detect structs that follow the power alignment rule under repr(C)
1 parent 27f3361 commit 1013f4f

File tree

7 files changed

+187
-16
lines changed

7 files changed

+187
-16
lines changed

compiler/rustc_lint/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,8 @@ lint_unused_closure =
915915
}{$post} that must be used
916916
.note = closures are lazy and do nothing unless called
917917
918+
lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
919+
918920
lint_unused_comparisons = comparison is useless due to type limits
919921
920922
lint_unused_coroutine =

compiler/rustc_lint/src/lints.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,10 @@ pub(crate) struct OverflowingLiteral<'a> {
16921692
pub lit: String,
16931693
}
16941694

1695+
#[derive(LintDiagnostic)]
1696+
#[diag(lint_uses_power_alignment)]
1697+
pub(crate) struct UsesPowerAlignment;
1698+
16951699
#[derive(LintDiagnostic)]
16961700
#[diag(lint_unused_comparisons)]
16971701
pub(crate) struct UnusedComparisons;

compiler/rustc_lint/src/types.rs

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
use std::iter;
22
use 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+
};
57
use rustc_data_structures::fx::FxHashSet;
68
use rustc_errors::DiagMessage;
79
use rustc_hir::{Expr, ExprKind, LangItem};
810
use rustc_middle::bug;
911
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
1012
use rustc_middle::ty::{
11-
self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
13+
self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
14+
TypeVisitableExt,
1215
};
1316
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
1417
use 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
};
2932
use 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)]
733762
pub(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(..)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
2+
--> $DIR/reprc-power-alignment.rs:10:5
3+
|
4+
LL | a: f64,
5+
| ^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/reprc-power-alignment.rs:6:9
9+
|
10+
LL | #![warn(uses_power_alignment)]
11+
| ^^^^^^^^^^^^^^^^^^^^
12+
13+
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
14+
--> $DIR/reprc-power-alignment.rs:23:5
15+
|
16+
LL | a: f32,
17+
| ^^^^^^
18+
19+
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
20+
--> $DIR/reprc-power-alignment.rs:37:5
21+
|
22+
LL | x: Floats,
23+
| ^^^^^^^^^
24+
25+
warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
26+
--> $DIR/reprc-power-alignment.rs:49:5
27+
|
28+
LL | x: FloatAgg1,
29+
| ^^^^^^^^^^^^
30+
31+
warning: 4 warnings emitted
32+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//@ check-pass
2+
//@ revisions: aix
3+
//@[aix] compile-flags: --target powerpc64-ibm-aix
4+
//@[aix] needs-llvm-components: powerpc
5+
6+
#![warn(uses_power_alignment)]
7+
8+
#[repr(C)]
9+
pub struct Floats {
10+
a: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
11+
b: u8,
12+
c: f64,
13+
}
14+
15+
pub struct Floats2 {
16+
a: f64,
17+
b: u32,
18+
c: f64,
19+
}
20+
21+
#[repr(C)]
22+
pub struct Floats3 {
23+
a: f32, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
24+
b: f32,
25+
c: i64,
26+
}
27+
28+
#[repr(C)]
29+
pub struct Floats4 {
30+
a: u64,
31+
b: u32,
32+
c: f32,
33+
}
34+
35+
#[repr(C)]
36+
pub struct FloatAgg1 {
37+
x: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
38+
y: f64,
39+
}
40+
41+
#[repr(C)]
42+
pub struct FloatAgg2 {
43+
x: i64,
44+
y: Floats,
45+
}
46+
47+
#[repr(C)]
48+
pub struct FloatAgg3 {
49+
x: FloatAgg1, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
50+
y: FloatAgg2,
51+
}
52+
53+
fn main() { }

tests/ui/lint/clashing-extern-fn.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ mod sameish_members {
248248

249249
mod same_sized_members_clash {
250250
mod a {
251+
#[allow(uses_power_alignment)]
251252
#[repr(C)]
252253
struct Point3 {
253254
x: f32,

tests/ui/lint/clashing-extern-fn.stderr

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
2-
--> $DIR/clashing-extern-fn.rs:482:55
2+
--> $DIR/clashing-extern-fn.rs:483:55
33
|
44
LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -9,7 +9,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
99
= note: `#[warn(improper_ctypes)]` on by default
1010

1111
warning: `extern` block uses type `Option<UnsafeCell<NonZero<usize>>>`, which is not FFI-safe
12-
--> $DIR/clashing-extern-fn.rs:486:46
12+
--> $DIR/clashing-extern-fn.rs:487:46
1313
|
1414
LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZero<usize>>>;
1515
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -151,7 +151,7 @@ LL | fn draw_point(p: Point);
151151
found `unsafe extern "C" fn(sameish_members::b::Point)`
152152

153153
warning: `origin` redeclared with a different signature
154-
--> $DIR/clashing-extern-fn.rs:269:13
154+
--> $DIR/clashing-extern-fn.rs:270:13
155155
|
156156
LL | fn origin() -> Point3;
157157
| ---------------------- `origin` previously declared here
@@ -163,7 +163,7 @@ LL | fn origin() -> Point3;
163163
found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
164164

165165
warning: `transparent_incorrect` redeclared with a different signature
166-
--> $DIR/clashing-extern-fn.rs:292:13
166+
--> $DIR/clashing-extern-fn.rs:293:13
167167
|
168168
LL | fn transparent_incorrect() -> T;
169169
| -------------------------------- `transparent_incorrect` previously declared here
@@ -175,7 +175,7 @@ LL | fn transparent_incorrect() -> isize;
175175
found `unsafe extern "C" fn() -> isize`
176176

177177
warning: `missing_return_type` redeclared with a different signature
178-
--> $DIR/clashing-extern-fn.rs:310:13
178+
--> $DIR/clashing-extern-fn.rs:311:13
179179
|
180180
LL | fn missing_return_type() -> usize;
181181
| ---------------------------------- `missing_return_type` previously declared here
@@ -187,7 +187,7 @@ LL | fn missing_return_type();
187187
found `unsafe extern "C" fn()`
188188

189189
warning: `non_zero_usize` redeclared with a different signature
190-
--> $DIR/clashing-extern-fn.rs:328:13
190+
--> $DIR/clashing-extern-fn.rs:329:13
191191
|
192192
LL | fn non_zero_usize() -> core::num::NonZero<usize>;
193193
| ------------------------------------------------- `non_zero_usize` previously declared here
@@ -199,7 +199,7 @@ LL | fn non_zero_usize() -> usize;
199199
found `unsafe extern "C" fn() -> usize`
200200

201201
warning: `non_null_ptr` redeclared with a different signature
202-
--> $DIR/clashing-extern-fn.rs:330:13
202+
--> $DIR/clashing-extern-fn.rs:331:13
203203
|
204204
LL | fn non_null_ptr() -> core::ptr::NonNull<usize>;
205205
| ----------------------------------------------- `non_null_ptr` previously declared here
@@ -211,7 +211,7 @@ LL | fn non_null_ptr() -> *const usize;
211211
found `unsafe extern "C" fn() -> *const usize`
212212

213213
warning: `option_non_zero_usize_incorrect` redeclared with a different signature
214-
--> $DIR/clashing-extern-fn.rs:424:13
214+
--> $DIR/clashing-extern-fn.rs:425:13
215215
|
216216
LL | fn option_non_zero_usize_incorrect() -> usize;
217217
| ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@@ -223,7 +223,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize;
223223
found `unsafe extern "C" fn() -> isize`
224224

225225
warning: `option_non_null_ptr_incorrect` redeclared with a different signature
226-
--> $DIR/clashing-extern-fn.rs:426:13
226+
--> $DIR/clashing-extern-fn.rs:427:13
227227
|
228228
LL | fn option_non_null_ptr_incorrect() -> *const usize;
229229
| --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
@@ -235,7 +235,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize;
235235
found `unsafe extern "C" fn() -> *const isize`
236236

237237
warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
238-
--> $DIR/clashing-extern-fn.rs:482:13
238+
--> $DIR/clashing-extern-fn.rs:483:13
239239
|
240240
LL | fn hidden_niche_transparent_no_niche() -> usize;
241241
| ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
@@ -247,7 +247,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
247247
found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
248248

249249
warning: `hidden_niche_unsafe_cell` redeclared with a different signature
250-
--> $DIR/clashing-extern-fn.rs:486:13
250+
--> $DIR/clashing-extern-fn.rs:487:13
251251
|
252252
LL | fn hidden_niche_unsafe_cell() -> usize;
253253
| --------------------------------------- `hidden_niche_unsafe_cell` previously declared here

0 commit comments

Comments
 (0)