Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion compiler/rustc_abi/src/callconv/reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl Reg {
128 => dl.f128_align,
_ => panic!("unsupported float: {self:?}"),
},
RegKind::Vector { .. } => dl.llvmlike_vector_align(self.size),
RegKind::Vector { .. } => dl.rust_vector_align(self.size),
}
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,7 @@ where
BackendRepr::SimdScalableVector { element, count, number_of_vectors },
size.checked_mul(number_of_vectors.0 as u64, dl)
.ok_or_else(|| LayoutCalculatorError::SizeOverflow)?,
dl.llvmlike_vector_align(size),
dl.rust_vector_align(size),
),
// Non-power-of-two vectors have padding up to the next power-of-two.
// If we're a packed repr, remove the padding while keeping the alignment as close
Expand All @@ -1523,7 +1523,7 @@ where
(BackendRepr::Memory { sized: true }, size, Align::max_aligned_factor(size))
}
SimdVectorKind::PackedFixed | SimdVectorKind::Fixed => {
(BackendRepr::SimdVector { element, count }, size, dl.llvmlike_vector_align(size))
(BackendRepr::SimdVector { element, count }, size, dl.rust_vector_align(size))
}
};
let size = size.align_to(align);
Expand Down
16 changes: 12 additions & 4 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,17 +658,25 @@ impl TargetDataLayout {

/// psABI-mandated alignment for a vector type, if any
#[inline]
fn cabi_vector_align(&self, vec_size: Size) -> Option<Align> {
fn c_vector_align(&self, vec_size: Size) -> Option<Align> {
self.vector_align
.iter()
.find(|(size, _align)| *size == vec_size)
.map(|(_size, align)| *align)
}

/// an alignment resembling the one LLVM would pick for a vector
/// Rust-assigned alignment of any vector type
///
/// When the shape of a vector matches that in a C psABI, we *must* agree when performing FFI.
/// This currently answers correctly for C compatibility purposes as it is a useful default.
/// Otherwise this choice is arbitrary, as vector types do not necessarily match hardware so
/// this can conjure "imaginary" answers that just happen to be convenient for us.
///
/// Importantly, Rust vector alignment is not required to be monotonic between vector sizes,
/// even though it currently is.
#[inline]
pub fn llvmlike_vector_align(&self, vec_size: Size) -> Align {
self.cabi_vector_align(vec_size)
pub fn rust_vector_align(&self, vec_size: Size) -> Align {
self.c_vector_align(vec_size)
.unwrap_or(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap())
}

Expand Down
25 changes: 19 additions & 6 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
},
vis_span: self.lower_span(f.vis.span),
mut_restriction: self.lower_mut_restriction(&f.mut_restriction),
default: f
.default
.as_ref()
Expand Down Expand Up @@ -1792,11 +1793,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

pub(super) fn lower_impl_restriction(
&mut self,
r: &ImplRestriction,
) -> &'hir hir::ImplRestriction<'hir> {
let kind = match &r.kind {
fn lower_restriction_kind(&mut self, kind: &RestrictionKind) -> hir::RestrictionKind<'hir> {
match kind {
RestrictionKind::Unrestricted => hir::RestrictionKind::Unrestricted,
RestrictionKind::Restricted { path, id, shorthand: _ } => {
let res = self.get_partial_res(*id);
Expand All @@ -1820,10 +1818,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::RestrictionKind::Unrestricted
}
}
};
}
}

pub(super) fn lower_impl_restriction(
&mut self,
r: &ImplRestriction,
) -> &'hir hir::ImplRestriction<'hir> {
let kind = self.lower_restriction_kind(&r.kind);
self.arena.alloc(hir::ImplRestriction { kind, span: self.lower_span(r.span) })
}

pub(super) fn lower_mut_restriction(
&mut self,
r: &MutRestriction,
) -> &'hir hir::MutRestriction<'hir> {
let kind = self.lower_restriction_kind(&r.kind);
self.arena.alloc(hir::MutRestriction { kind, span: self.lower_span(r.span) })
}

/// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
/// the carried impl trait definitions and bounds.
#[instrument(level = "debug", skip(self, f))]
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4498,6 +4498,7 @@ pub struct PolyTraitRef<'hir> {
pub struct FieldDef<'hir> {
pub span: Span,
pub vis_span: Span,
pub mut_restriction: &'hir MutRestriction<'hir>,
pub ident: Ident,
#[stable_hash(ignore)]
pub hir_id: HirId,
Expand Down Expand Up @@ -4755,6 +4756,12 @@ pub struct ImplRestriction<'hir> {
pub span: Span,
}

#[derive(Debug, Clone, Copy, StableHash)]
pub struct MutRestriction<'hir> {
pub kind: RestrictionKind<'hir>,
pub span: Span,
}

#[derive(Debug, Clone, Copy, StableHash)]
pub enum RestrictionKind<'hir> {
/// The restriction does not affect the item.
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1405,8 +1405,21 @@ pub fn walk_struct_def<'v, V: Visitor<'v>>(

pub fn walk_field_def<'v, V: Visitor<'v>>(
visitor: &mut V,
FieldDef { hir_id, ident, ty, default, span: _, vis_span: _, def_id: _, safety: _ }: &'v FieldDef<'v>,
FieldDef {
hir_id,
ident,
ty,
default,
span: _,
vis_span: _,
mut_restriction,
def_id: _,
safety: _,
}: &'v FieldDef<'v>,
) -> V::Result {
if let RestrictionKind::Restricted(path) = mut_restriction.kind {
walk_list!(visitor, visit_path_segment, path.segments);
}
try_visit!(visitor.visit_id(*hir_id));
try_visit!(visitor.visit_ident(*ident));
visit_opt!(visitor, visit_anon_const, default);
Expand Down
24 changes: 19 additions & 5 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,7 @@ impl<'a> State<'a> {
self.commasep(Inconsistent, struct_def.fields(), |s, field| {
s.maybe_print_comment(field.span.lo());
s.print_attrs(s.attrs(field.hir_id));
s.print_mut_restriction(field.mut_restriction);
s.print_type(field.ty);
});
self.pclose();
Expand All @@ -922,6 +923,7 @@ impl<'a> State<'a> {
self.hardbreak_if_not_bol();
self.maybe_print_comment(field.span.lo());
self.print_attrs(self.attrs(field.hir_id));
self.print_mut_restriction(field.mut_restriction);
self.print_ident(field.ident);
self.word_nbsp(":");
self.print_type(field.ty);
Expand Down Expand Up @@ -2655,17 +2657,29 @@ impl<'a> State<'a> {
}
}

fn print_impl_restriction(&mut self, r: &hir::ImplRestriction<'_>) {
match r.kind {
fn print_restriction<S: Into<std::borrow::Cow<'static, str>>>(
&mut self,
k: &hir::RestrictionKind<'_>,
prefix: S,
) {
match k {
hir::RestrictionKind::Unrestricted => {}
hir::RestrictionKind::Restricted(path) => {
self.word("impl(");
self.word_nbsp("in");
self.word(prefix.into());
self.word_nbsp("(in");
self.print_path(path, false);
self.word(")");
self.word_nbsp(")");
}
}
}

fn print_mut_restriction(&mut self, r: &hir::MutRestriction<'_>) {
self.print_restriction(&r.kind, "mut");
}

fn print_impl_restriction(&mut self, r: &hir::ImplRestriction<'_>) {
self.print_restriction(&r.kind, "impl");
}
}

/// Does this expression require a semicolon to be treated
Expand Down
15 changes: 12 additions & 3 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Spanned, Symbol};

use crate::Res;
use crate::late::PatternSource;
use crate::late::{PatternSource, ResolvingRestrictionKind};

#[derive(Diagnostic)]
#[diag("can't use {$is_self ->
Expand Down Expand Up @@ -546,8 +546,17 @@ pub(crate) struct ExpectedModuleFound {
pub(crate) struct Indeterminate(#[primary_span] pub(crate) Span);

#[derive(Diagnostic)]
#[diag("trait implementation can only be restricted to ancestor modules")]
pub(crate) struct RestrictionAncestorOnly(#[primary_span] pub(crate) Span);
#[diag(
"{$kind ->
[impl] trait implementation
*[mut] field mutation
} can only be restricted to ancestor modules"
)]
pub(crate) struct RestrictionAncestorOnly {
#[primary_span]
pub(crate) span: Span,
pub(crate) kind: ResolvingRestrictionKind,
}

#[derive(Diagnostic)]
#[diag("cannot use a tool module through an import")]
Expand Down
38 changes: 33 additions & 5 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,23 @@ pub(crate) enum AliasPossibility {
Maybe,
}

/// Whether resolving `impl` or `mut` restriction paths
#[derive(Debug, Clone, Copy)]
pub(crate) enum ResolvingRestrictionKind {
Impl,
Mut,
}

impl IntoDiagArg for ResolvingRestrictionKind {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
use std::borrow::Cow;
match self {
ResolvingRestrictionKind::Impl => DiagArgValue::Str(Cow::Borrowed("impl")),
ResolvingRestrictionKind::Mut => DiagArgValue::Str(Cow::Borrowed("mut")),
}
}
}

#[derive(Copy, Clone, Debug)]
pub(crate) enum PathSource<'a, 'ast, 'ra> {
/// Type paths `Path`.
Expand Down Expand Up @@ -1489,11 +1506,12 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc
ty,
is_placeholder: _,
default,
mut_restriction: _,
mut_restriction,
safety: _,
} = f;
walk_list!(self, visit_attribute, attrs);
try_visit!(self.visit_vis(vis));
self.resolve_restriction_path(&mut_restriction.kind, ResolvingRestrictionKind::Mut);
visit_opt!(self, visit_ident, ident);
try_visit!(self.visit_ty(ty));
if let Some(v) = &default {
Expand Down Expand Up @@ -2864,7 +2882,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

ItemKind::Trait(Trait { generics, bounds, items, impl_restriction, .. }) => {
// resolve paths for `impl` restrictions
self.resolve_impl_restriction_path(impl_restriction);
self.resolve_restriction_path(
&impl_restriction.kind,
ResolvingRestrictionKind::Impl,
);

// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(
Expand Down Expand Up @@ -4480,8 +4501,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
}

fn resolve_impl_restriction_path(&mut self, restriction: &'ast ast::ImplRestriction) {
match &restriction.kind {
fn resolve_restriction_path(
&mut self,
restriction: &'ast ast::RestrictionKind,
kind: ResolvingRestrictionKind,
) {
match &restriction {
ast::RestrictionKind::Unrestricted => (),
ast::RestrictionKind::Restricted { path, id, shorthand: _ } => {
self.smart_resolve_path(*id, &None, path, PathSource::Module);
Expand All @@ -4494,7 +4519,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
) {
self.r
.dcx()
.create_err(crate::diagnostics::RestrictionAncestorOnly(path.span))
.create_err(crate::diagnostics::RestrictionAncestorOnly {
span: path.span,
kind,
})
.emit();
}
}
Expand Down
30 changes: 16 additions & 14 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1810,22 +1810,22 @@ pub const unsafe fn read<T>(src: *const T) -> T {
pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
// Always true thanks to the repr, but to demonstrate
const {
assert!(mem::offset_of!(Packed::<T>, 0) == 0);
assert!(size_of::<T>() == size_of::<Packed<T>>());
assert!(mem::offset_of!(Unaligned::<T>, 0) == 0);
assert!(size_of::<T>() == size_of::<Unaligned<T>>());
}

let src = src.cast::<Packed<T>>();
let src = src.cast::<Unaligned<T>>();
// SAFETY: the caller must guarantee that `src` is valid for reads.
// Reading it as `Packed<T>` instead of `T` reads those same bytes because
// Reading it as `Unaligned<T>` instead of `T` reads those same bytes because
// it's the same size (thus zero offset), but with alignment 1 instead.
//
// Similarly, because it's the same bytes it's sound to transmute from the
// `Packed<T>` to `T`. Transmute is a value-based (not a place-based)
// `Unaligned<T>` to `T`. Transmute is a value-based (not a place-based)
// operation that doesn't care about alignment.
unsafe {
let packed = read(src);
let unaligned = read(src);
// Can't just destructure because that's not allowed in const fn
mem::transmute_neo(packed)
mem::transmute_neo(unaligned)
}
}

Expand Down Expand Up @@ -2020,14 +2020,14 @@ pub const unsafe fn write<T>(dst: *mut T, src: T) {
pub const unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
// Always true thanks to the repr, but to demonstrate
const {
assert!(mem::offset_of!(Packed::<T>, 0) == 0);
assert!(size_of::<T>() == size_of::<Packed<T>>());
assert!(mem::offset_of!(Unaligned::<T>, 0) == 0);
assert!(size_of::<T>() == size_of::<Unaligned<T>>());
}

let dst = dst.cast::<Packed<T>>();
let src = Packed(src);
let dst = dst.cast::<Unaligned<T>>();
let src = Unaligned(src);
// SAFETY: the caller must guarantee that `dst` is valid for writes.
// Writing it as `Packed<T>` instead of `T` writes those same bytes because
// Writing it as `Unaligned<T>` instead of `T` writes those same bytes because
// it's the same size (thus zero offset), but with alignment 1 instead.
unsafe { write(dst, src) }
}
Expand Down Expand Up @@ -2828,5 +2828,7 @@ pub macro addr_of_mut($place:expr) {
&raw mut $place
}

#[repr(C, packed)]
struct Packed<T>(T);
/// Used in [`read_unaligned`] and [`write_unaligned`] to load and store `T`
/// with alignment 1 rather than its usual `align_of::<T>()` alignment.
#[repr(Rust, packed)]
struct Unaligned<T>(T);
6 changes: 3 additions & 3 deletions tests/mir-opt/pre-codegen/unaligned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ pub unsafe fn unaligned_copy_generic<T>(src: *const T, dst: *mut T) {
// CHECK: debug src => _1;
// CHECK: debug dst => _2;
// CHECK: debug val => [[VAL:_.+]];
// CHECK: [[SRC_P:_.+]] = copy _1 as *const {{.+}}::Packed<T> (PtrToPtr);
// CHECK: [[SRC_P:_.+]] = copy _1 as *const {{.+}}::Unaligned<T> (PtrToPtr);
// CHECK: [[PACKED1:_.+]] = copy (*[[SRC_P]]);
// CHECK: [[VAL]] = copy [[PACKED1]] as T (Transmute);
// CHECK: [[DST_P:_.+]] = copy _2 as *mut {{.+}}::Packed<T> (PtrToPtr);
// CHECK: [[PACKED2:_.+]] = {{.+}}::Packed::<T>(copy [[VAL]]);
// CHECK: [[DST_P:_.+]] = copy _2 as *mut {{.+}}::Unaligned<T> (PtrToPtr);
// CHECK: [[PACKED2:_.+]] = {{.+}}::Unaligned::<T>(copy [[VAL]]);
// CHECK: (*[[DST_P]]) = copy [[PACKED2]];
// CHECK-NOT: copy_nonoverlapping
// CHECK-NOT: drop
Expand Down
Loading
Loading