Skip to content
Closed
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
51 changes: 1 addition & 50 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::BTreeSet;
use std::fmt::{self, Write};
use std::ops::{Bound, Deref};
use std::ops::Deref;
use std::{cmp, iter};

use rustc_hashes::Hash64;
Expand Down Expand Up @@ -348,7 +348,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool,
is_special_no_niche: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
always_sized: bool,
Expand Down Expand Up @@ -380,7 +379,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
variants,
is_enum,
is_special_no_niche,
scalar_valid_range,
always_sized,
present_first,
)
Expand Down Expand Up @@ -530,7 +528,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool,
is_special_no_niche: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
always_sized: bool,
present_first: VariantIdx,
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
Expand Down Expand Up @@ -570,52 +567,6 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
return Ok(st);
}

let (start, end) = scalar_valid_range;
match st.backend_repr {
BackendRepr::Scalar(ref mut scalar) | BackendRepr::ScalarPair(ref mut scalar, _) => {
// Enlarging validity ranges would result in missed
// optimizations, *not* wrongly assuming the inner
// value is valid. e.g. unions already enlarge validity ranges,
// because the values may be uninitialized.
//
// Because of that we only check that the start and end
// of the range is representable with this scalar type.

let max_value = scalar.size(dl).unsigned_int_max();
if let Bound::Included(start) = start {
// FIXME(eddyb) this might be incorrect - it doesn't
// account for wrap-around (end < start) ranges.
assert!(start <= max_value, "{start} > {max_value}");
scalar.valid_range_mut().start = start;
}
if let Bound::Included(end) = end {
// FIXME(eddyb) this might be incorrect - it doesn't
// account for wrap-around (end < start) ranges.
assert!(end <= max_value, "{end} > {max_value}");
scalar.valid_range_mut().end = end;
}

// Update `largest_niche` if we have introduced a larger niche.
let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
if let Some(niche) = niche {
match st.largest_niche {
Some(largest_niche) => {
// Replace the existing niche even if they're equal,
// because this one is at a lower offset.
if largest_niche.available(dl) <= niche.available(dl) {
st.largest_niche = Some(niche);
}
}
None => st.largest_niche = Some(niche),
}
}
}
_ => assert!(
start == Bound::Unbounded && end == Bound::Unbounded,
"nonscalar layout for layout_scalar_valid_range type: {st:#?}",
),
}

Ok(st)
}

Expand Down
26 changes: 0 additions & 26 deletions compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,32 +92,6 @@ impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;
}

pub(crate) struct RustcLayoutScalarValidRangeStartParser;

impl SingleAttributeParser for RustcLayoutScalarValidRangeStartParser {
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const TEMPLATE: AttributeTemplate = template!(List: &["start"]);

fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
parse_single_integer(cx, args)
.map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span))
}
}

pub(crate) struct RustcLayoutScalarValidRangeEndParser;

impl SingleAttributeParser for RustcLayoutScalarValidRangeEndParser {
const PATH: &[Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
const TEMPLATE: AttributeTemplate = template!(List: &["end"]);

fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
parse_single_integer(cx, args)
.map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span))
}
}

pub(crate) struct RustcLegacyConstGenericsParser;

impl SingleAttributeParser for RustcLegacyConstGenericsParser {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
/// Parse a single integer.
///
/// Used by attributes that take a single integer as argument, such as
/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
/// `#[link_ordinal]`.
/// `cx` is the context given to the attribute.
/// `args` is the parser for the attribute arguments.
pub(crate) fn parse_single_integer(
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,6 @@ attribute_parsers!(
Single<RustcDumpSymbolNameParser>,
Single<RustcForceInlineParser>,
Single<RustcIfThisChangedParser>,
Single<RustcLayoutScalarValidRangeEndParser>,
Single<RustcLayoutScalarValidRangeStartParser>,
Single<RustcLegacyConstGenericsParser>,
Single<RustcLintOptDenyFieldAccessParser>,
Single<RustcMacroTransparencyParser>,
Expand Down
100 changes: 66 additions & 34 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
// First check that the base type is valid
self.visit_value(&val.transmute(self.ecx.layout_of(*base)?, self.ecx)?)?;
// When you extend this match, make sure to also add tests to
// tests/ui/type/pattern_types/validity.rs((
// tests/ui/type/pattern_types/validity.rs
match **pat {
// Range and non-null patterns are precisely reflected into `valid_range` and thus
// handled fully by `visit_scalar` (called below).
Expand All @@ -1507,6 +1507,34 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
// we won't see optimizations actually breaking such programs.
ty::PatternKind::Or(_patterns) => {}
}
// FIXME(pattern_types): handle everything based on the pattern, not on the layout.
// it's ok to run scalar validation even if the pattern type is `u8 is 0..=255` and thus
// allows uninit values, because that's rare and so not a perf issue.
match val.layout.backend_repr {
BackendRepr::Scalar(scalar_layout) => {
if !scalar_layout.is_uninit_valid() {
// There is something to check here.
// We read directly via `ecx` since the read cannot fail -- we already read
// this field above when recursing into the field.
let scalar = self.ecx.read_scalar(val)?;
self.visit_scalar(scalar, scalar_layout)?;
}
}
BackendRepr::ScalarPair(a_layout, b_layout) => {
// We can only proceed if *both* scalars need to be initialized.
// FIXME: find a way to also check ScalarPair when one side can be uninit but
// the other must be init.
if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() {
// We read directly via `ecx` since the read cannot fail -- we already read
// this field above when recursing into the field.
let (a, b) = self.ecx.read_immediate(val)?.to_scalar_pair();
self.visit_scalar(a, a_layout)?;
self.visit_scalar(b, b_layout)?;
}
}
BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => unreachable!(),
BackendRepr::Memory { .. } => unreachable!()
}
}
ty::Adt(adt, _) if adt.is_maybe_dangling() => {
let old_may_dangle = mem::replace(&mut self.may_dangle, true);
Expand All @@ -1529,51 +1557,55 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt,
}
}

// *After* all of this, check further information stored in the layout. We need to check
// this to handle types like `NonNull` where the `Scalar` info is more restrictive than what
// the fields say (`rustc_layout_scalar_valid_range_start`). But in most cases, this will
// just propagate what the fields say, and then we want the error to point at the field --
// so, we first recurse, then we do this check.
// *After* all of this, check further information stored in the layout.
// On leaf types like `!` or empty enums, this will raise the error.
// This means that for types wrapping such a type, we won't ever get here, but it's
// just the simplest way to check for this case.
//
// FIXME: We could avoid some redundant checks here. For newtypes wrapping
// scalars, we do the same check on every "level" (e.g., first we check
// MyNewtype and then the scalar in there).
// the fields of MyNewtype, and then we check MyNewType again).
if val.layout.is_uninhabited() {
let ty = val.layout.ty;
throw_validation_failure!(
self.path,
format!("encountered a value of uninhabited type `{ty}`")
);
}
match val.layout.backend_repr {
BackendRepr::Scalar(scalar_layout) => {
if !scalar_layout.is_uninit_valid() {
// There is something to check here.
// We read directly via `ecx` since the read cannot fail -- we already read
// this field above when recursing into the field.
let scalar = self.ecx.read_scalar(val)?;
self.visit_scalar(scalar, scalar_layout)?;
if cfg!(debug_assertions) {
// Check that we don't miss any new changes to layout computation in our checks above.
match val.layout.backend_repr {
BackendRepr::Scalar(scalar_layout) => {
if !scalar_layout.is_uninit_valid() {
// There is something to check here.
// We read directly via `ecx` since the read cannot fail -- we already read
// this field above when recursing into the field.
let scalar = self
.ecx
.read_scalar(val)
.expect("the above checks should have fully handled this situation");
self.visit_scalar(scalar, scalar_layout)
.expect("the above checks should have fully handled this situation");
}
}
}
BackendRepr::ScalarPair(a_layout, b_layout) => {
// We can only proceed if *both* scalars need to be initialized.
// FIXME: find a way to also check ScalarPair when one side can be uninit but
// the other must be init.
if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() {
// We read directly via `ecx` since the read cannot fail -- we already read
// this field above when recursing into the field.
let (a, b) = self.ecx.read_immediate(val)?.to_scalar_pair();
self.visit_scalar(a, a_layout)?;
self.visit_scalar(b, b_layout)?;
BackendRepr::ScalarPair(a_layout, b_layout) => {
// We can only proceed if *both* scalars need to be initialized.
// FIXME: find a way to also check ScalarPair when one side can be uninit but
// the other must be init.
if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() {
let (a, b) = self
.ecx
.read_immediate(val)
.expect("the above checks should have fully handled this situation")
.to_scalar_pair();
self.visit_scalar(a, a_layout)
.expect("the above checks should have fully handled this situation");
self.visit_scalar(b, b_layout)
.expect("the above checks should have fully handled this situation");
}
}
}
BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => {
// No checks here, we assume layout computation gets this right.
// (This is harder to check since Miri does not represent these as `Immediate`. We
// also cannot use field projections since this might be a newtype around a vector.)
}
BackendRepr::Memory { .. } => {
// Nothing to do.
BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => {}
BackendRepr::Memory { .. } => {}
}
}

Expand Down
10 changes: 0 additions & 10 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,16 +573,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes, Layout related:
// ==========================================================================

rustc_attr!(
rustc_layout_scalar_valid_range_start,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in the standard library",
),
rustc_attr!(
rustc_layout_scalar_valid_range_end,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in the standard library",
),
rustc_attr!(
rustc_simd_monomorphize_lane_limit,
"the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1421,12 +1421,6 @@ pub enum AttributeKind {
/// Represents `#[rustc_intrinsic_const_stable_indirect]`
RustcIntrinsicConstStableIndirect,

/// Represents `#[rustc_layout_scalar_valid_range_end]`.
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),

/// Represents `#[rustc_layout_scalar_valid_range_start]`.
RustcLayoutScalarValidRangeStart(Box<u128>, Span),

/// Represents `#[rustc_legacy_const_generics]`
RustcLegacyConstGenerics {
fn_indexes: ThinVec<(usize, Span)>,
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ impl AttributeKind {
RustcInsignificantDtor => Yes,
RustcIntrinsic => Yes,
RustcIntrinsicConstStableIndirect => No,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcLegacyConstGenerics { .. } => Yes,
RustcLintOptDenyFieldAccess { .. } => Yes,
RustcLintOptTy => Yes,
Expand Down
9 changes: 2 additions & 7 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! crate as a kind of pass. This should eventually be factored away.

use std::cell::Cell;
use std::ops::{Bound, ControlFlow};
use std::ops::ControlFlow;
use std::{assert_matches, iter};

use rustc_abi::{ExternAbi, Size};
Expand Down Expand Up @@ -1039,12 +1039,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
.fields()
.iter()
.map(|f| tcx.type_of(f.def_id).instantiate_identity().skip_norm_wip());
// constructors for structs with `layout_scalar_valid_range` are unsafe to call
let safety = match tcx.layout_scalar_valid_range(adt_def_id) {
(Bound::Unbounded, Bound::Unbounded) => hir::Safety::Safe,
_ => hir::Safety::Unsafe,
};
ty::Binder::dummy(tcx.mk_fn_sig_rust_abi(inputs, ty, safety))
ty::Binder::dummy(tcx.mk_fn_sig_rust_abi(inputs, ty, hir::Safety::Safe))
}

Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
Expand Down
13 changes: 1 addition & 12 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::env::VarError;
use std::ffi::OsStr;
use std::hash::{Hash, Hasher};
use std::marker::PointeeSized;
use std::ops::{Bound, Deref};
use std::ops::Deref;
use std::sync::{Arc, OnceLock};
use std::{fmt, iter, mem};

Expand Down Expand Up @@ -910,17 +910,6 @@ impl<'tcx> TyCtxt<'tcx> {
matches!(self.as_lang_item(def_id), Some(LangItem::Sized | LangItem::MetaSized))
}

/// Returns a range of the start/end indices specified with the
/// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
let start = find_attr!(self, def_id, RustcLayoutScalarValidRangeStart(n, _) => Bound::Included(**n)).unwrap_or(Bound::Unbounded);
let end =
find_attr!(self, def_id, RustcLayoutScalarValidRangeEnd(n, _) => Bound::Included(**n))
.unwrap_or(Bound::Unbounded);
(start, end)
}

pub fn lift<T: Lift<TyCtxt<'tcx>>>(self, value: T) -> T::Lifted {
value.lift_to_interner(self)
}
Expand Down
13 changes: 1 addition & 12 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use std::ops::Bound;
use std::{cmp, fmt};

use rustc_abi as abi;
Expand Down Expand Up @@ -465,17 +464,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
// Newtype.
if def.variants().len() == 1 {
if let Some(SizeSkeleton::Pointer { non_zero, tail }) = v0 {
return Ok(SizeSkeleton::Pointer {
non_zero: non_zero
|| match tcx.layout_scalar_valid_range(def.did()) {
(Bound::Included(start), Bound::Unbounded) => start > 0,
(Bound::Included(start), Bound::Included(end)) => {
0 < start && start < end
}
_ => false,
},
tail,
});
return Ok(SizeSkeleton::Pointer { non_zero, tail });
} else {
return Err(err);
}
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_mir_build/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1276,5 +1276,3 @@ mod expr;
mod matches;
mod misc;
mod scope;

pub(crate) use expr::category::Category as ExprCategory;
Loading
Loading