Skip to content
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -800,9 +800,9 @@ pub enum PatKind<'tcx> {
},

/// One of the following:
/// * `&str`/`&[u8]` (represented as a valtree), which will be handled as a string/slice pattern
/// and thus exhaustiveness checking will detect if you use the same string/slice twice in
/// different patterns.
/// * `&str` (represented as a valtree), which will be handled as a string pattern and thus
/// exhaustiveness checking will detect if you use the same string twice in different
/// patterns.
/// * integer, bool, char or float (represented as a valtree), which will be handled by
/// exhaustiveness to cover exactly its own value, similar to `&str`, but these values are
/// much simpler.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,8 +1326,8 @@ enum TestKind<'tcx> {
Eq {
value: Const<'tcx>,
// Integer types are handled by `SwitchInt`, and constants with ADT
// types are converted back into patterns, so this can only be `&str`,
// `&[T]`, `f32` or `f64`.
// types and `&[T]` types are converted back into patterns, so this can
// only be `&str`, `f32` or `f64`.
ty: Ty<'tcx>,
},

Expand Down
108 changes: 19 additions & 89 deletions compiler/rustc_mir_build/src/builder/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use std::sync::Arc;
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::{LangItem, RangeEnd};
use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
Expand Down Expand Up @@ -178,21 +177,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
_ => {}
}

assert_eq!(expect_ty, ty);
if !ty.is_scalar() {
// Use `PartialEq::eq` instead of `BinOp::Eq`
// (the binop can only handle primitives)
self.non_scalar_compare(
// Make sure that we do *not* call any user-defined code here.
// The only type that can end up here is string literals, which have their
// comparison defined in `core`.
// (Interestingly this means that exhaustiveness analysis relies, for soundness,
// on the `PartialEq` impl for `str` to b correct!)
match *ty.kind() {
ty::Ref(_, deref_ty, _) if deref_ty == self.tcx.types.str_ => {}
_ => {
span_bug!(source_info.span, "invalid type for non-scalar compare: {ty}")
}
};
self.string_compare(
block,
success_block,
fail_block,
source_info,
expect,
expect_ty,
Operand::Copy(place),
ty,
);
} else {
assert_eq!(expect_ty, ty);
self.compare(
block,
success_block,
Expand Down Expand Up @@ -370,97 +378,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
}

/// Compare two values using `<T as std::compare::PartialEq>::eq`.
/// If the values are already references, just call it directly, otherwise
/// take a reference to the values first and then call it.
fn non_scalar_compare(
/// Compare two values of type `&str` using `<str as std::cmp::PartialEq>::eq`.
fn string_compare(
&mut self,
block: BasicBlock,
success_block: BasicBlock,
fail_block: BasicBlock,
source_info: SourceInfo,
mut expect: Operand<'tcx>,
expect_ty: Ty<'tcx>,
mut val: Operand<'tcx>,
mut ty: Ty<'tcx>,
expect: Operand<'tcx>,
val: Operand<'tcx>,
) {
// If we're using `b"..."` as a pattern, we need to insert an
// unsizing coercion, as the byte string has the type `&[u8; N]`.
//
// We want to do this even when the scrutinee is a reference to an
// array, so we can call `<[u8]>::eq` rather than having to find an
// `<[u8; N]>::eq`.
let unsize = |ty: Ty<'tcx>| match ty.kind() {
ty::Ref(region, rty, _) => match rty.kind() {
ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
_ => None,
},
_ => None,
};
let opt_ref_ty = unsize(ty);
let opt_ref_test_ty = unsize(expect_ty);
match (opt_ref_ty, opt_ref_test_ty) {
// nothing to do, neither is an array
(None, None) => {}
(Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
let tcx = self.tcx;
// make both a slice
ty = Ty::new_imm_ref(tcx, *region, Ty::new_slice(tcx, *elem_ty));
if opt_ref_ty.is_some() {
let temp = self.temp(ty, source_info.span);
self.cfg.push_assign(
block,
source_info,
temp,
Rvalue::Cast(
CastKind::PointerCoercion(
PointerCoercion::Unsize,
CoercionSource::Implicit,
),
val,
ty,
),
);
val = Operand::Copy(temp);
}
if opt_ref_test_ty.is_some() {
let slice = self.temp(ty, source_info.span);
self.cfg.push_assign(
block,
source_info,
slice,
Rvalue::Cast(
CastKind::PointerCoercion(
PointerCoercion::Unsize,
CoercionSource::Implicit,
),
expect,
ty,
),
);
expect = Operand::Move(slice);
}
}
}

// Figure out the type on which we are calling `PartialEq`. This involves an extra wrapping
// reference: we can only compare two `&T`, and then compare_ty will be `T`.
// Make sure that we do *not* call any user-defined code here.
// The only types that can end up here are string and byte literals,
// which have their comparison defined in `core`.
// (Interestingly this means that exhaustiveness analysis relies, for soundness,
// on the `PartialEq` impls for `str` and `[u8]` to b correct!)
let compare_ty = match *ty.kind() {
ty::Ref(_, deref_ty, _)
if deref_ty == self.tcx.types.str_ || deref_ty != self.tcx.types.u8 =>
{
deref_ty
}
_ => span_bug!(source_info.span, "invalid type for non-scalar compare: {}", ty),
};

let str_ty = self.tcx.types.str_;
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]);
let method = trait_method(self.tcx, eq_def_id, sym::eq, [str_ty, str_ty]);

let bool_ty = self.tcx.types.bool;
let eq_result = self.temp(bool_ty, source_info.span);
Expand Down
13 changes: 6 additions & 7 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ impl RibKind<'_> {
/// resolving, the name is looked up from inside out.
#[derive(Debug)]
pub(crate) struct Rib<'ra, R = Res> {
pub bindings: FxHashMap<Ident, R>,
pub bindings: FxIndexMap<Ident, R>,
pub patterns_with_skipped_bindings: UnordMap<DefId, Vec<(Span, Result<(), ErrorGuaranteed>)>>,
pub kind: RibKind<'ra>,
}
Expand Down Expand Up @@ -1642,8 +1642,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

// Allow all following defaults to refer to this type parameter.
let i = &Ident::with_dummy_span(param.ident.name);
forward_ty_ban_rib.bindings.remove(i);
forward_ty_ban_rib_const_param_ty.bindings.remove(i);
forward_ty_ban_rib.bindings.swap_remove(i);
forward_ty_ban_rib_const_param_ty.bindings.swap_remove(i);
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
// Const parameters can't have param bounds.
Expand Down Expand Up @@ -1678,8 +1678,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {

// Allow all following defaults to refer to this const parameter.
let i = &Ident::with_dummy_span(param.ident.name);
forward_const_ban_rib.bindings.remove(i);
forward_const_ban_rib_const_param_ty.bindings.remove(i);
forward_const_ban_rib.bindings.swap_remove(i);
forward_const_ban_rib_const_param_ty.bindings.swap_remove(i);
}
}
}
Expand Down Expand Up @@ -2888,7 +2888,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
break;
}

#[allow(rustc::potential_query_instability)] // FIXME
seen_bindings
.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
}
Expand Down Expand Up @@ -4003,7 +4002,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
}
}

fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxHashMap<Ident, Res> {
fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxIndexMap<Ident, Res> {
&mut self.ribs[ns].last_mut().unwrap().bindings
}

Expand Down
5 changes: 0 additions & 5 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
if let Some(rib) = &self.last_block_rib
&& let RibKind::Normal = rib.kind
{
#[allow(rustc::potential_query_instability)] // FIXME
for (ident, &res) in &rib.bindings {
if let Res::Local(_) = res
&& path.len() == 1
Expand Down Expand Up @@ -1019,7 +1018,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
if let Some(err_code) = err.code {
if err_code == E0425 {
for label_rib in &self.label_ribs {
#[allow(rustc::potential_query_instability)] // FIXME
for (label_ident, node_id) in &label_rib.bindings {
let ident = path.last().unwrap().ident;
if format!("'{ident}") == label_ident.to_string() {
Expand Down Expand Up @@ -2265,7 +2263,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
};

// Locals and type parameters
#[allow(rustc::potential_query_instability)] // FIXME
for (ident, &res) in &rib.bindings {
if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
names.push(TypoSuggestion::typo_from_ident(*ident, res));
Expand Down Expand Up @@ -2793,7 +2790,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
let within_scope = self.is_label_valid_from_rib(rib_index);

let rib = &self.label_ribs[rib_index];
#[allow(rustc::potential_query_instability)] // FIXME
let names = rib
.bindings
.iter()
Expand All @@ -2805,7 +2801,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
// Upon finding a similar name, get the ident that it was from - the span
// contained within helps make a useful diagnostic. In addition, determine
// whether this candidate is within scope.
#[allow(rustc::potential_query_instability)] // FIXME
let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap();
(*ident, within_scope)
})
Expand Down
12 changes: 4 additions & 8 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1149,9 +1149,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
///
/// [memory layout]: self#memory-layout
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
}

Expand Down Expand Up @@ -1203,9 +1202,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
/// [memory layout]: self#memory-layout
#[unstable(feature = "allocator_api", issue = "32838")]
// #[unstable(feature = "box_vec_non_null", reason = "new API", issue = "130364")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
pub const unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
pub unsafe fn from_non_null_in(raw: NonNull<T>, alloc: A) -> Self {
// SAFETY: guaranteed by the caller.
unsafe { Box::from_raw_in(raw.as_ptr(), alloc) }
}
Expand Down Expand Up @@ -1550,9 +1548,8 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
/// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This
/// is so that there is no conflict with a method on the inner type.
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
#[inline]
pub const fn allocator(b: &Self) -> &A {
pub fn allocator(b: &Self) -> &A {
&b.1
}

Expand Down Expand Up @@ -1639,8 +1636,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
/// let bar = Pin::from(foo);
/// ```
#[stable(feature = "box_into_pin", since = "1.63.0")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
pub const fn into_pin(boxed: Self) -> Pin<Self>
pub fn into_pin(boxed: Self) -> Pin<Self>
where
A: 'static,
{
Expand Down
Loading
Loading