Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ pub(crate) unsafe fn create_module<'ll>(
}
}

// Ensure the data-layout values hardcoded remain the defaults.
// Ensure our hardcoded data-layout values remain the defaults.
{
let tm = crate::back::write::create_informational_target_machine(tcx.sess, false);
unsafe {
Expand All @@ -219,7 +219,9 @@ pub(crate) unsafe fn create_module<'ll>(
str::from_utf8(unsafe { CStr::from_ptr(llvm_data_layout) }.to_bytes())
.expect("got a non-UTF8 data-layout from LLVM");

if target_data_layout != llvm_data_layout {
if tcx.sess.target.os == "aix" {
// FIXME(workingjubilee): Currently skipping this logic for testing purposes
} else if target_data_layout != llvm_data_layout {
tcx.dcx().emit_err(crate::errors::MismatchedDataLayout {
rustc_target: sess.opts.target_triple.to_string().as_str(),
rustc_layout: target_data_layout.as_str(),
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -1017,7 +1017,5 @@ lint_useless_ptr_null_checks_fn_ret = returned pointer of `{$fn_name}` call is n
lint_useless_ptr_null_checks_ref = references are not nullable, so checking them for null will always return false
.label = expression has type `{$orig_ty}`

lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type

lint_variant_size_differences =
enum variant is more than three times larger ({$largest} bytes) than the next largest
4 changes: 0 additions & 4 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1741,10 +1741,6 @@ pub(crate) struct OverflowingLiteral<'a> {
pub lit: String,
}

#[derive(LintDiagnostic)]
#[diag(lint_uses_power_alignment)]
pub(crate) struct UsesPowerAlignment;

#[derive(LintDiagnostic)]
#[diag(lint_unused_comparisons)]
pub(crate) struct UnusedComparisons;
Expand Down
132 changes: 5 additions & 127 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::iter;
use std::ops::ControlFlow;

use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange};
use rustc_abi::{BackendRepr, TagEncoding, Variants, WrappingRange};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::DiagMessage;
use rustc_hir::intravisit::VisitorExt;
use rustc_hir::{AmbigArg, Expr, ExprKind, HirId, LangItem};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
use rustc_middle::ty::{
self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt,
self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
};
use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
use rustc_span::def_id::LocalDefId;
Expand All @@ -26,7 +25,7 @@ use crate::lints::{
AmbiguousWidePointerComparisonsExpectSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment,
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
VariantSizeDifferencesDiag,
};
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
Expand Down Expand Up @@ -752,62 +751,7 @@ declare_lint! {
"proper use of libc types in foreign item definitions"
}

declare_lint! {
/// The `uses_power_alignment` lint detects specific `repr(C)`
/// aggregates on AIX.
/// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment
/// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment),
/// which can also be set for XLC by `#pragma align(power)` or
/// `-qalign=power`. Aggregates with a floating-point type as the
/// recursively first field (as in "at offset 0") modify the layout of
/// *subsequent* fields of the associated structs to use an alignment value
/// where the floating-point type is aligned on a 4-byte boundary.
///
/// Effectively, subsequent floating-point fields act as-if they are `repr(packed(4))`. This
/// would be unsound to do in a `repr(C)` type without all the restrictions that come with
/// `repr(packed)`. Rust instead chooses a layout that maintains soundness of Rust code, at the
/// expense of incompatibility with C code.
///
/// ### Example
///
/// ```rust,ignore (fails on non-powerpc64-ibm-aix)
/// #[repr(C)]
/// pub struct Floats {
/// a: f64,
/// b: u8,
/// c: f64,
/// }
/// ```
///
/// This will produce:
///
/// ```text
/// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type
/// --> <source>:5:3
/// |
/// 5 | c: f64,
/// | ^^^^^^
/// |
/// = note: `#[warn(uses_power_alignment)]` on by default
/// ```
///
/// ### Explanation
///
/// The power alignment rule specifies that the above struct has the
/// following alignment:
/// - offset_of!(Floats, a) == 0
/// - offset_of!(Floats, b) == 8
/// - offset_of!(Floats, c) == 12
///
/// However, Rust currently aligns `c` at `offset_of!(Floats, c) == 16`.
/// Using offset 12 would be unsound since `f64` generally must be 8-aligned on this target.
/// Thus, a warning is produced for the above struct.
USES_POWER_ALIGNMENT,
Warn,
"Structs do not follow the power alignment rule under repr(C)"
}

declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]);
declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]);

#[derive(Clone, Copy)]
pub(crate) enum CItemKind {
Expand Down Expand Up @@ -1647,68 +1591,6 @@ impl ImproperCTypesDefinitions {
vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
}
}

fn check_arg_for_power_alignment<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
ty: Ty<'tcx>,
) -> bool {
assert!(cx.tcx.sess.target.os == "aix");
// Structs (under repr(C)) follow the power alignment rule if:
// - the first field of the struct is a floating-point type that
// is greater than 4-bytes, or
// - the first field of the struct is an aggregate whose
// recursively first field is a floating-point type greater than
// 4 bytes.
if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 {
return true;
} else if let Adt(adt_def, _) = ty.kind()
&& adt_def.is_struct()
&& adt_def.repr().c()
&& !adt_def.repr().packed()
&& adt_def.repr().align.is_none()
{
let struct_variant = adt_def.variant(VariantIdx::ZERO);
// Within a nested struct, all fields are examined to correctly
// report if any fields after the nested struct within the
// original struct are misaligned.
for struct_field in &struct_variant.fields {
let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity();
if self.check_arg_for_power_alignment(cx, field_ty) {
return true;
}
}
}
return false;
}

fn check_struct_for_power_alignment<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
item: &'tcx hir::Item<'tcx>,
) {
let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id());
// repr(C) structs also with packed or aligned representation
// should be ignored.
if adt_def.repr().c()
&& !adt_def.repr().packed()
&& adt_def.repr().align.is_none()
&& cx.tcx.sess.target.os == "aix"
&& !adt_def.all_fields().next().is_none()
{
let struct_variant_data = item.expect_struct().2;
for field_def in struct_variant_data.fields().iter().skip(1) {
// Struct fields (after the first field) are checked for the
// power alignment rule, as fields after the first are likely
// to be the fields that are misaligned.
let def_id = field_def.def_id;
let ty = cx.tcx.type_of(def_id).instantiate_identity();
if self.check_arg_for_power_alignment(cx, ty) {
cx.emit_span_lint(USES_POWER_ALIGNMENT, field_def.span, UsesPowerAlignment);
}
}
}
}
}

/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
Expand All @@ -1732,11 +1614,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
}
// See `check_fn`..
hir::ItemKind::Fn { .. } => {}
// Structs are checked based on if they follow the power alignment
// rule (under repr(C)).
hir::ItemKind::Struct(..) => {
self.check_struct_for_power_alignment(cx, item);
}
hir::ItemKind::Struct(..) => {}
// See `check_field_def`..
hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {}
// Doesn't define something that can contain a external type to be checked.
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ pub(crate) fn target() -> Target {
std: None, // ?
},
pointer_width: 64,
data_layout: "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(),
// Note that the f64:32:64 deviates from what LLVM thinks should be the case,
// because LLVM doesn't know the layout actually used for AIX's C ABI,
// as clang reimplements it instead of trusting the datalayout string implicitly.
// See https://github.com/llvm/llvm-project/issues/133599 for more.
data_layout: "E-m:a-Fi64-i64:64-f64:32:64-i128:128-n32:64-S128-v256:256:256-v512:512:512"
.into(),
arch: "powerpc64".into(),
options: base,
}
Expand Down
Loading
Loading