From 70f9d520793318617949e660458bd717548ec8d6 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 20 Jan 2023 15:59:56 +0000 Subject: [PATCH 01/15] Add and use expect methods to hir. --- compiler/rustc_hir/src/hir.rs | 343 +++++++++++++++++- .../rustc_hir_analysis/src/astconv/mod.rs | 3 +- .../src/check/compare_impl_item.rs | 16 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 8 +- .../src/coherence/builtin.rs | 2 +- .../src/coherence/unsafety.rs | 4 +- compiler/rustc_hir_analysis/src/collect.rs | 3 +- 7 files changed, 356 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d6566860f8170..4640317ac7328 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2263,7 +2263,7 @@ pub struct TraitItem<'hir> { pub defaultness: Defaultness, } -impl TraitItem<'_> { +impl<'hir> TraitItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2273,6 +2273,27 @@ impl TraitItem<'_> { pub fn trait_item_id(&self) -> TraitItemId { TraitItemId { owner_id: self.owner_id } } + + /// Expect an [`TraitItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option) { + let TraitItemKind::Const(ty, body) = self.kind else { unreachable!() }; + (ty, body) + } + + /// Expect an [`TraitItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { + let TraitItemKind::Fn(ty, trfn) = &self.kind else { unreachable!() }; + (ty, trfn) + } + + /// Expect an [`TraitItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { + let TraitItemKind::Type(bounds, ty) = self.kind else { unreachable!() }; + (bounds, ty) + } } /// Represents a trait method's body (or just argument names). @@ -2325,7 +2346,7 @@ pub struct ImplItem<'hir> { pub vis_span: Span, } -impl ImplItem<'_> { +impl<'hir> ImplItem<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -2335,6 +2356,27 @@ impl ImplItem<'_> { pub fn impl_item_id(&self) -> ImplItemId { ImplItemId { owner_id: self.owner_id } } + + /// Expect an [`ImplItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ImplItemKind::Const(ty, body) = self.kind else { unreachable!() }; + (ty, body) + } + + /// Expect an [`ImplItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) { + let ImplItemKind::Fn(ty, body) = &self.kind else { unreachable!() }; + (ty, *body) + } + + /// Expect an [`ImplItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_type(&self) -> &'hir Ty<'hir> { + let ImplItemKind::Type(ty) = self.kind else { unreachable!() }; + ty + } } /// Represents various kinds of content within an `impl`. @@ -2995,7 +3037,7 @@ pub struct Item<'hir> { pub vis_span: Span, } -impl Item<'_> { +impl<'hir> Item<'hir> { #[inline] pub fn hir_id(&self) -> HirId { // Items are always HIR owners. @@ -3005,6 +3047,127 @@ impl Item<'_> { pub fn item_id(&self) -> ItemId { ItemId { owner_id: self.owner_id } } + + /// Expect an [`ItemKind::ExternCrate`] or panic. + #[track_caller] + pub fn expect_extern_crate(&self) -> Option { + let ItemKind::ExternCrate(s) = self.kind else { unreachable!() }; + s + } + + /// Expect an [`ItemKind::Use`] or panic. + #[track_caller] + pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) { + let ItemKind::Use(p, uk) = self.kind else { unreachable!() }; + (p, uk) + } + + /// Expect an [`ItemKind::Static`] or panic. + #[track_caller] + pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) { + let ItemKind::Static(ty, mutbl, body) = self.kind else { unreachable!() }; + (ty, mutbl, body) + } + /// Expect an [`ItemKind::Const`] or panic. + #[track_caller] + pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { + let ItemKind::Const(ty, body) = self.kind else { unreachable!() }; + (ty, body) + } + /// Expect an [`ItemKind::Fn`] or panic. + #[track_caller] + pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) { + let ItemKind::Fn(sig, gen, body) = &self.kind else { unreachable!() }; + (sig, gen, *body) + } + + /// Expect an [`ItemKind::Macro`] or panic. + #[track_caller] + pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) { + let ItemKind::Macro(def, mk) = &self.kind else { unreachable!() }; + (def, *mk) + } + + /// Expect an [`ItemKind::Mod`] or panic. + #[track_caller] + pub fn expect_mod(&self) -> &'hir Mod<'hir> { + let ItemKind::Mod(m) = self.kind else { unreachable!() }; + m + } + + /// Expect an [`ItemKind::ForeignMod`] or panic. + #[track_caller] + pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) { + let ItemKind::ForeignMod { abi, items } = self.kind else { unreachable!() }; + (abi, items) + } + + /// Expect an [`ItemKind::GlobalAsm`] or panic. + #[track_caller] + pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> { + let ItemKind::GlobalAsm(asm) = self.kind else { unreachable!() }; + asm + } + + /// Expect an [`ItemKind::TyAlias`] or panic. + #[track_caller] + pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { + let ItemKind::TyAlias(ty, gen) = self.kind else { unreachable!() }; + (ty, gen) + } + + /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. + /// Expect an [`ItemKind::OpaqueTy`] or panic. + #[track_caller] + pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { + let ItemKind::OpaqueTy(ty) = &self.kind else { unreachable!() }; + ty + } + + /// Expect an [`ItemKind::Enum`] or panic. + #[track_caller] + pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) { + let ItemKind::Enum(def, gen) = &self.kind else { unreachable!() }; + (def, gen) + } + + /// Expect an [`ItemKind::Struct`] or panic. + #[track_caller] + pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Struct(data, gen) = &self.kind else { unreachable!() }; + (data, gen) + } + + /// A union definition, e.g., `union Foo {x: A, y: B}`. + /// Expect an [`ItemKind::Union`] or panic. + #[track_caller] + pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { + let ItemKind::Union(data, gen) = &self.kind else { unreachable!() }; + (data, gen) + } + + /// Expect an [`ItemKind::Trait`] or panic. + #[track_caller] + pub fn expect_trait( + self, + ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) { + let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { unreachable!() }; + (is_auto, unsafety, gen, bounds, items) + } + + /// Expect an [`ItemKind::TraitAlias`] or panic. + #[track_caller] + pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) { + let ItemKind::TraitAlias(gen, bounds) = self.kind else { unreachable!() }; + (gen, bounds) + } + + /// Expect an [`ItemKind::Impl`] or panic. + #[track_caller] + pub fn expect_impl(&self) -> &'hir Impl<'hir> { + let ItemKind::Impl(imp) = self.kind else { unreachable!() }; + imp + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -3590,6 +3753,180 @@ impl<'hir> Node<'hir> { pub fn tuple_fields(&self) -> Option<&'hir [FieldDef<'hir>]> { if let Node::Ctor(&VariantData::Tuple(fields, _, _)) = self { Some(fields) } else { None } } + + /// Expect a [`Node::Param`] or panic. + #[track_caller] + pub fn expect_param(self) -> &'hir Param<'hir> { + let Node::Param(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Item`] or panic. + #[track_caller] + pub fn expect_item(self) -> &'hir Item<'hir> { + let Node::Item(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::ForeignItem`] or panic. + #[track_caller] + pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> { + let Node::ForeignItem(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::TraitItem`] or panic. + #[track_caller] + pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> { + let Node::TraitItem(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::ImplItem`] or panic. + #[track_caller] + pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> { + let Node::ImplItem(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Variant`] or panic. + #[track_caller] + pub fn expect_variant(self) -> &'hir Variant<'hir> { + let Node::Variant(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Field`] or panic. + #[track_caller] + pub fn expect_field(self) -> &'hir FieldDef<'hir> { + let Node::Field(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::AnonConst`] or panic. + #[track_caller] + pub fn expect_anon_const(self) -> &'hir AnonConst { + let Node::AnonConst(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Expr`] or panic. + #[track_caller] + pub fn expect_expr(self) -> &'hir Expr<'hir> { + let Node::Expr(this) = self else { unreachable!() }; + this + } + /// Expect a [`Node::ExprField`] or panic. + #[track_caller] + pub fn expect_expr_field(self) -> &'hir ExprField<'hir> { + let Node::ExprField(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Stmt`] or panic. + #[track_caller] + pub fn expect_stmt(self) -> &'hir Stmt<'hir> { + let Node::Stmt(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::PathSegment`] or panic. + #[track_caller] + pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> { + let Node::PathSegment(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Ty`] or panic. + #[track_caller] + pub fn expect_ty(self) -> &'hir Ty<'hir> { + let Node::Ty(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::TypeBinding`] or panic. + #[track_caller] + pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> { + let Node::TypeBinding(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::TraitRef`] or panic. + #[track_caller] + pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> { + let Node::TraitRef(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Pat`] or panic. + #[track_caller] + pub fn expect_pat(self) -> &'hir Pat<'hir> { + let Node::Pat(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::PatField`] or panic. + #[track_caller] + pub fn expect_pat_field(self) -> &'hir PatField<'hir> { + let Node::PatField(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Arm`] or panic. + #[track_caller] + pub fn expect_arm(self) -> &'hir Arm<'hir> { + let Node::Arm(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Block`] or panic. + #[track_caller] + pub fn expect_block(self) -> &'hir Block<'hir> { + let Node::Block(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Local`] or panic. + #[track_caller] + pub fn expect_local(self) -> &'hir Local<'hir> { + let Node::Local(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Ctor`] or panic. + #[track_caller] + pub fn expect_ctor(self) -> &'hir VariantData<'hir> { + let Node::Ctor(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Lifetime`] or panic. + #[track_caller] + pub fn expect_lifetime(self) -> &'hir Lifetime { + let Node::Lifetime(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::GenericParam`] or panic. + #[track_caller] + pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> { + let Node::GenericParam(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Crate`] or panic. + #[track_caller] + pub fn expect_crate(self) -> &'hir Mod<'hir> { + let Node::Crate(this) = self else { unreachable!() }; + this + } + + /// Expect a [`Node::Infer`] or panic. + #[track_caller] + pub fn expect_infer(self) -> &'hir InferArg { + let Node::Infer(this) = self else { unreachable!() }; + this + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6435b05cef8a8..1b7509d6d421d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -3124,8 +3124,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) = hir.get(fn_hir_id) else { return None }; - let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) = - hir.get_parent(fn_hir_id) else { bug!("ImplItem should have Impl parent") }; + let i = hir.get_parent(fn_hir_id).expect_item().expect_impl(); let trait_ref = self.instantiate_mono_trait_ref( i.of_trait.as_ref()?, diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index cfebcceef3cdb..53f5cb2cc9a7c 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -8,7 +8,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; -use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind}; +use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; @@ -916,7 +916,7 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box`, the // span points only at the type `Box, but we want to cover the whole // argument pattern and type. - let ImplItemKind::Fn(ref sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{impl_m:?} is not a method") }; + let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx .hir() .body_param_names(body) @@ -1078,12 +1078,12 @@ fn extract_spans_for_error_reporting<'tcx>( ) -> (Span, Option) { let tcx = infcx.tcx; let mut impl_args = { - let ImplItemKind::Fn(sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }; let trait_args = trait_m.def_id.as_local().map(|def_id| { - let TraitItemKind::Fn(sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a TraitItemKind::Fn", trait_m) }; + let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }); @@ -1356,7 +1356,7 @@ fn compare_number_of_method_arguments<'tcx>( .def_id .as_local() .and_then(|def_id| { - let TraitItemKind::Fn(trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).kind else { bug!("{:?} is not a method", impl_m) }; + let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn(); let pos = trait_number_args.saturating_sub(1); trait_m_sig.decl.inputs.get(pos).map(|arg| { if pos == 0 { @@ -1368,7 +1368,7 @@ fn compare_number_of_method_arguments<'tcx>( }) .or(trait_item_span); - let ImplItemKind::Fn(impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind else { bug!("{:?} is not a method", impl_m) }; + let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let pos = impl_number_args.saturating_sub(1); let impl_span = impl_m_sig .decl @@ -1704,7 +1704,7 @@ pub(super) fn compare_impl_const_raw( ); // Locate the Span containing just the type of the offending impl - let ImplItemKind::Const(ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).kind else { bug!("{impl_const_item:?} is not a impl const") }; + let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const(); cause.span = ty.span; let mut diag = struct_span_err!( @@ -1717,7 +1717,7 @@ pub(super) fn compare_impl_const_raw( let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| { // Add a label to the Span containing just the type of the const - let TraitItemKind::Const(ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).kind else { bug!("{trait_const_item:?} is not a trait const") }; + let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const(); ty.span }); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 11237afe8a0e3..dd8ecd670cb0f 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1053,8 +1053,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b // All field types must be well-formed. for field in &variant.fields { let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_wf_obligation( hir_ty.span, @@ -1087,8 +1087,8 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b { let last = idx == variant.fields.len() - 1; let field_id = field.did.expect_local(); - let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id) - else { bug!() }; + let hir::FieldDef { ty: hir_ty, .. } = + tcx.hir().get_by_def_id(field_id).expect_field(); let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did)); wfcx.register_bound( traits::ObligationCause::new( diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 55de68f83f284..cd63235857b22 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -54,7 +54,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => {} } - let ItemKind::Impl(impl_) = tcx.hir().expect_item(impl_did).kind else { bug!("expected Drop impl item") }; + let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); tcx.sess.emit_err(DropImplOnWrongItem { span: impl_.self_ty.span }); } diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index fe6119dce8735..c6b16171311fb 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -3,15 +3,13 @@ use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::Unsafety; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Impl)); let item = tcx.hir().expect_item(def_id); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = item.expect_impl(); if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) { let trait_ref = trait_ref.subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index c17778ce8bc09..1cbface07429a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1342,8 +1342,7 @@ fn suggest_impl_trait<'tcx>( fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option>> { let icx = ItemCtxt::new(tcx, def_id); - let item = tcx.hir().expect_item(def_id.expect_local()); - let hir::ItemKind::Impl(impl_) = item.kind else { bug!() }; + let impl_ = tcx.hir().expect_item(def_id.expect_local()).expect_impl(); impl_ .of_trait .as_ref() From ee9e8cd0ec8c204d6c51acbc3663c40d089a3e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roy=20Wellington=20=E2=85=A3?= Date: Sat, 21 Jan 2023 17:33:03 -0500 Subject: [PATCH 02/15] This function appears to be unused The comment says that it is called from main.js, but there don't seem to be any references to it in main.js. A quick ripgrep says there are no references in all of librustdoc. --- src/librustdoc/html/static/js/storage.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index db2db83ca6310..61856303483e7 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -153,22 +153,6 @@ function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) { } } -// This function is called from "main.js". -// eslint-disable-next-line no-unused-vars -function useSystemTheme(value) { - if (value === undefined) { - value = true; - } - - updateLocalStorage("use-system-theme", value); - - // update the toggle if we're on the settings page - const toggle = document.getElementById("use-system-theme"); - if (toggle && toggle instanceof HTMLInputElement) { - toggle.checked = value; - } -} - const updateSystemTheme = (function() { if (!window.matchMedia) { // fallback to the CSS computed value From fa214c3b11f6444c268b4ca7d93219df3dc020a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roy=20Wellington=20=E2=85=A3?= Date: Sat, 21 Jan 2023 17:34:30 -0500 Subject: [PATCH 03/15] Fix typo in comment --- src/librustdoc/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 56b40d8c66baf..2c514a0c8267b 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -509,7 +509,7 @@ impl Options { // these values up both in `dataset` and in the storage API, so it needs to be able // to convert the names back and forth. Despite doing this kebab-case to // StudlyCaps transformation automatically, the JS DOM API does not provide a - // mechanism for doing the just transformation on a string. So we want to avoid + // mechanism for doing just the transformation on a string. So we want to avoid // the StudlyCaps representation in the `dataset` property. // // We solve this by replacing all the `-`s with `_`s. We do that here, when we From ba80c662f448c69cbd184d18630b8824f0169b2e Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Sat, 28 Jan 2023 14:19:01 +0100 Subject: [PATCH 04/15] slice: Add a specialization for clone_into when T is Copy The implementation for the ToOwned::clone_into method on [T] is a copy of the code for vec::clone_from. In 361398009be6 the code for vec::clone_from gained a specialization for when T is Copy. This commit copies that specialization over to the clone_into implementation. --- library/alloc/src/slice.rs | 43 +++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index fecacc2bb6395..093dcbbe8bf77 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -782,6 +782,38 @@ impl BorrowMut<[T]> for Vec { } } +// Specializable trait for implementing ToOwned::clone_into. This is +// public in the crate and has the Allocator parameter so that +// vec::clone_from use it too. +#[cfg(not(no_global_oom_handling))] +pub(crate) trait SpecCloneIntoVec { + fn clone_into(&self, target: &mut Vec); +} + +#[cfg(not(no_global_oom_handling))] +impl SpecCloneIntoVec for [T] { + default fn clone_into(&self, target: &mut Vec) { + // drop anything in target that will not be overwritten + target.truncate(self.len()); + + // target.len <= self.len due to the truncate above, so the + // slices here are always in-bounds. + let (init, tail) = self.split_at(target.len()); + + // reuse the contained values' allocations/resources. + target.clone_from_slice(init); + target.extend_from_slice(tail); + } +} + +#[cfg(not(no_global_oom_handling))] +impl SpecCloneIntoVec for [T] { + fn clone_into(&self, target: &mut Vec) { + target.clear(); + target.extend_from_slice(self); + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for [T] { @@ -797,16 +829,7 @@ impl ToOwned for [T] { } fn clone_into(&self, target: &mut Vec) { - // drop anything in target that will not be overwritten - target.truncate(self.len()); - - // target.len <= self.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = self.split_at(target.len()); - - // reuse the contained values' allocations/resources. - target.clone_from_slice(init); - target.extend_from_slice(tail); + SpecCloneIntoVec::clone_into(self, target); } } From a34f11c006936f0935c0f3484f9a292901d0eade Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Sat, 28 Jan 2023 14:52:31 +0100 Subject: [PATCH 05/15] vec: Use SpecCloneIntoVec::clone_into to implement Vec::clone_from In the past, Vec::clone_from was implemented using slice::clone_into. The code from clone_into was later duplicated into clone_from in 8725e4c337, which is the commit that adds custom allocator support to Vec. Presumably this was done because the slice::clone_into only works for vecs with the default allocator so it would have the wrong type to clone into Vec. Now that the clone_into implementation is moved out into a specializable trait anyway we might as well use that to share the code between the two methods. --- library/alloc/src/vec/mod.rs | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 36b0b3c9e7cc0..a07f3da78d33e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2646,35 +2646,6 @@ impl ops::DerefMut for Vec { } } -#[cfg(not(no_global_oom_handling))] -trait SpecCloneFrom { - fn clone_from(this: &mut Self, other: &Self); -} - -#[cfg(not(no_global_oom_handling))] -impl SpecCloneFrom for Vec { - default fn clone_from(this: &mut Self, other: &Self) { - // drop anything that will not be overwritten - this.truncate(other.len()); - - // self.len <= other.len due to the truncate above, so the - // slices here are always in-bounds. - let (init, tail) = other.split_at(this.len()); - - // reuse the contained values' allocations/resources. - this.clone_from_slice(init); - this.extend_from_slice(tail); - } -} - -#[cfg(not(no_global_oom_handling))] -impl SpecCloneFrom for Vec { - fn clone_from(this: &mut Self, other: &Self) { - this.clear(); - this.extend_from_slice(other); - } -} - #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { @@ -2695,7 +2666,7 @@ impl Clone for Vec { } fn clone_from(&mut self, other: &Self) { - SpecCloneFrom::clone_from(self, other) + crate::slice::SpecCloneIntoVec::clone_into(other.as_slice(), self); } } From a9aed861acee892602a03be72624ab7895e1db61 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 21 Jan 2023 20:51:21 +0000 Subject: [PATCH 06/15] Reimplement NormalizeArrayLen. --- compiler/rustc_mir_transform/src/lib.rs | 2 +- .../src/normalize_array_len.rs | 321 ++++-------------- ...e_oob_for_slices.main.ConstProp.32bit.diff | 6 +- ...e_oob_for_slices.main.ConstProp.64bit.diff | 6 +- tests/mir-opt/issue_76432.rs | 1 + ...ray_len.array_bound.NormalizeArrayLen.diff | 6 +- ...len.array_bound_mut.NormalizeArrayLen.diff | 6 +- ...array_len.array_len.NormalizeArrayLen.diff | 6 +- ....array_len_by_value.NormalizeArrayLen.diff | 6 +- ...y_len.array_len_raw.NormalizeArrayLen.diff | 50 +++ ....array_len_reborrow.NormalizeArrayLen.diff | 44 +++ tests/mir-opt/lower_array_len.rs | 16 + ...y_len_e2e.array_bound.PreCodegen.after.mir | 41 --- ...n_e2e.array_bound_mut.PreCodegen.after.mir | 54 --- ...ray_len_e2e.array_len.PreCodegen.after.mir | 11 - ...2e.array_len_by_value.PreCodegen.after.mir | 11 - tests/mir-opt/lower_array_len_e2e.rs | 39 --- 17 files changed, 191 insertions(+), 435 deletions(-) create mode 100644 tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff create mode 100644 tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff delete mode 100644 tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir delete mode 100644 tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir delete mode 100644 tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir delete mode 100644 tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir delete mode 100644 tests/mir-opt/lower_array_len_e2e.rs diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index abf89e550b149..43d5b44525848 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -549,13 +549,13 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &[ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode. &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first - &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &unreachable_prop::UnreachablePropagation, &uninhabited_enum_branching::UninhabitedEnumBranching, &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")), &inline::Inline, &remove_storage_markers::RemoveStorageMarkers, &remove_zsts::RemoveZsts, + &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &const_goto::ConstGoto, &remove_unneeded_drops::RemoveUnneededDrops, &sroa::ScalarReplacementOfAggregates, diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 1708b287e56f2..8894e729502f2 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -1,288 +1,105 @@ //! This pass eliminates casting of arrays into slices when their length //! is taken using `.len()` method. Handy to preserve information in MIR for const prop +use crate::ssa::SsaLocals; use crate::MirPass; -use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::intern::Interned; -use rustc_index::bit_set::BitSet; use rustc_index::vec::IndexVec; +use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::{self, ReErased, Region, TyCtxt}; - -const MAX_NUM_BLOCKS: usize = 800; -const MAX_NUM_LOCALS: usize = 3000; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_mir_dataflow::impls::borrowed_locals; pub struct NormalizeArrayLen; impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { // See #105929 - sess.mir_opt_level() >= 4 && sess.opts.unstable_opts.unsound_mir_opts + sess.mir_opt_level() >= 3 } + #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // early returns for edge cases of highly unrolled functions - if body.basic_blocks.len() > MAX_NUM_BLOCKS { - return; - } - if body.local_decls.len() > MAX_NUM_LOCALS { - return; - } + debug!(def_id = ?body.source.def_id()); normalize_array_len_calls(tcx, body) } } -pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - // We don't ever touch terminators, so no need to invalidate the CFG cache - let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); - let local_decls = &mut body.local_decls; +fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let borrowed_locals = borrowed_locals(body); + let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals); - // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]` - let mut interesting_locals = BitSet::new_empty(local_decls.len()); - for (local, decl) in local_decls.iter_enumerated() { - match decl.ty.kind() { - ty::Array(..) => { - interesting_locals.insert(local); - } - ty::Ref(.., ty, Mutability::Not) => match ty.kind() { - ty::Array(..) => { - interesting_locals.insert(local); - } - _ => {} - }, - _ => {} - } - } - if interesting_locals.is_empty() { - // we have found nothing to analyze - return; - } - let num_intesting_locals = interesting_locals.count(); - let mut state = FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - let mut patches_scratchpad = - FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - let mut replacements_scratchpad = - FxIndexMap::with_capacity_and_hasher(num_intesting_locals, Default::default()); - for block in basic_blocks { - // make length calls for arrays [T; N] not to decay into length calls for &[T] - // that forbids constant propagation - normalize_array_len_call( - tcx, - block, - local_decls, - &interesting_locals, - &mut state, - &mut patches_scratchpad, - &mut replacements_scratchpad, - ); - state.clear(); - patches_scratchpad.clear(); - replacements_scratchpad.clear(); - } -} + let slice_lengths = compute_slice_length(tcx, &ssa, body); + debug!(?slice_lengths); -struct Patcher<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - patches_scratchpad: &'a FxIndexMap, - replacements_scratchpad: &'a mut FxIndexMap, - local_decls: &'a mut IndexVec>, - statement_idx: usize, + Replacer { tcx, slice_lengths }.visit_body_preserves_cfg(body); } -impl<'tcx> Patcher<'_, 'tcx> { - fn patch_expand_statement( - &mut self, - statement: &mut Statement<'tcx>, - ) -> Option>> { - let idx = self.statement_idx; - if let Some(len_statemnt_idx) = self.patches_scratchpad.get(&idx).copied() { - let mut statements = Vec::with_capacity(2); - - // we are at statement that performs a cast. The only sound way is - // to create another local that performs a similar copy without a cast and then - // use this copy in the Len operation - - match &statement.kind { - StatementKind::Assign(box ( - .., - Rvalue::Cast( - CastKind::Pointer(ty::adjustment::PointerCast::Unsize), - operand, - _, - ), - )) => { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - // create new local - let ty = operand.ty(self.local_decls, self.tcx); - let local_decl = LocalDecl::with_source_info(ty, statement.source_info); - let local = self.local_decls.push(local_decl); - // make it live - let mut make_live_statement = statement.clone(); - make_live_statement.kind = StatementKind::StorageLive(local); - statements.push(make_live_statement); - // copy into it - - let operand = Operand::Copy(*place); - let mut make_copy_statement = statement.clone(); - let assign_to = Place::from(local); - let rvalue = Rvalue::Use(operand); - make_copy_statement.kind = - StatementKind::Assign(Box::new((assign_to, rvalue))); - statements.push(make_copy_statement); - - // to reorder we have to copy and make NOP - statements.push(statement.clone()); - statement.make_nop(); - - self.replacements_scratchpad.insert(len_statemnt_idx, local); - } - _ => { - unreachable!("it's a bug in the implementation") - } - } - } - _ => { - unreachable!("it's a bug in the implementation") +fn compute_slice_length<'tcx>( + tcx: TyCtxt<'tcx>, + ssa: &SsaLocals, + body: &Body<'tcx>, +) -> IndexVec>> { + let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls); + + for (local, rvalue) in ssa.assignments(body) { + match rvalue { + Rvalue::Cast( + CastKind::Pointer(ty::adjustment::PointerCast::Unsize), + operand, + cast_ty, + ) => { + let operand_ty = operand.ty(body, tcx); + debug!(?operand_ty); + if let Some(operand_ty) = operand_ty.builtin_deref(true) + && let ty::Array(_, len) = operand_ty.ty.kind() + && let Some(cast_ty) = cast_ty.builtin_deref(true) + && let ty::Slice(..) = cast_ty.ty.kind() + { + slice_lengths[local] = Some(*len); } } - - self.statement_idx += 1; - - Some(statements.into_iter()) - } else if let Some(local) = self.replacements_scratchpad.get(&idx).copied() { - let mut statements = Vec::with_capacity(2); - - match &statement.kind { - StatementKind::Assign(box (into, Rvalue::Len(place))) => { - let add_deref = if let Some(..) = place.as_local() { - false - } else if let Some(..) = place.local_or_deref_local() { - true - } else { - unreachable!("it's a bug in the implementation") - }; - // replace len statement - let mut len_statement = statement.clone(); - let mut place = Place::from(local); - if add_deref { - place = self.tcx.mk_place_deref(place); - } - len_statement.kind = - StatementKind::Assign(Box::new((*into, Rvalue::Len(place)))); - statements.push(len_statement); - - // make temporary dead - let mut make_dead_statement = statement.clone(); - make_dead_statement.kind = StatementKind::StorageDead(local); - statements.push(make_dead_statement); - - // make original statement NOP - statement.make_nop(); + // The length information is stored in the fat pointer, so we treat `operand` as a value. + Rvalue::Use(operand) => { + if let Some(rhs) = operand.place() && let Some(rhs) = rhs.as_local() { + slice_lengths[local] = slice_lengths[rhs]; } - _ => { - unreachable!("it's a bug in the implementation") + } + // The length information is stored in the fat pointer. + // Reborrowing copies length information from one pointer to the other. + Rvalue::Ref(_, _, rhs) | Rvalue::AddressOf(_, rhs) => { + if let [PlaceElem::Deref] = rhs.projection[..] { + slice_lengths[local] = slice_lengths[rhs.local]; } } - - self.statement_idx += 1; - - Some(statements.into_iter()) - } else { - self.statement_idx += 1; - None + _ => {} } } + + slice_lengths } -fn normalize_array_len_call<'tcx>( +struct Replacer<'tcx> { tcx: TyCtxt<'tcx>, - block: &mut BasicBlockData<'tcx>, - local_decls: &mut IndexVec>, - interesting_locals: &BitSet, - state: &mut FxIndexMap, - patches_scratchpad: &mut FxIndexMap, - replacements_scratchpad: &mut FxIndexMap, -) { - for (statement_idx, statement) in block.statements.iter_mut().enumerate() { - match &mut statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - match rvalue { - Rvalue::Cast( - CastKind::Pointer(ty::adjustment::PointerCast::Unsize), - operand, - cast_ty, - ) => { - let Some(local) = place.as_local() else { return }; - match operand { - Operand::Copy(place) | Operand::Move(place) => { - let Some(operand_local) = place.local_or_deref_local() else { return; }; - if !interesting_locals.contains(operand_local) { - return; - } - let operand_ty = local_decls[operand_local].ty; - match (operand_ty.kind(), cast_ty.kind()) { - (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { - if of_ty_src == of_ty_dst { - // this is a cast from [T; N] into [T], so we are good - state.insert(local, statement_idx); - } - } - // current way of patching doesn't allow to work with `mut` - ( - ty::Ref( - Region(Interned(ReErased, _)), - operand_ty, - Mutability::Not, - ), - ty::Ref( - Region(Interned(ReErased, _)), - cast_ty, - Mutability::Not, - ), - ) => { - match (operand_ty.kind(), cast_ty.kind()) { - // current way of patching doesn't allow to work with `mut` - (ty::Array(of_ty_src, ..), ty::Slice(of_ty_dst)) => { - if of_ty_src == of_ty_dst { - // this is a cast from [T; N] into [T], so we are good - state.insert(local, statement_idx); - } - } - _ => {} - } - } - _ => {} - } - } - _ => {} - } - } - Rvalue::Len(place) => { - let Some(local) = place.local_or_deref_local() else { - return; - }; - if let Some(cast_statement_idx) = state.get(&local).copied() { - patches_scratchpad.insert(cast_statement_idx, statement_idx); - } - } - _ => { - // invalidate - state.remove(&place.local); - } - } - } - _ => {} - } - } + slice_lengths: IndexVec>>, +} - let mut patcher = Patcher { - tcx, - patches_scratchpad: &*patches_scratchpad, - replacements_scratchpad, - local_decls, - statement_idx: 0, - }; +impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } - block.expand_statements(|st| patcher.patch_expand_statement(st)); + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, loc: Location) { + if let Rvalue::Len(place) = rvalue + && let [PlaceElem::Deref] = &place.projection[..] + && let Some(len) = self.slice_lengths[place.local] + { + *rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant { + span: rustc_span::DUMMY_SP, + user_ty: None, + literal: ConstantKind::from_const(len, self.tcx), + }))); + } + self.super_rvalue(rvalue, loc); + } } diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 4bd0aa0987239..38d402b8f2161 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -33,11 +33,11 @@ StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 } bb1: { diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 4bd0aa0987239..38d402b8f2161 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -33,11 +33,11 @@ StorageLive(_4); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:13: +3:15 StorageLive(_5); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 _5 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:23: +3:24 - _6 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 + _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - _7 = Lt(_5, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ _7 = Lt(const 3_usize, _6); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 -+ assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ _7 = const false; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 ++ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:+3:18: +3:25 } bb1: { diff --git a/tests/mir-opt/issue_76432.rs b/tests/mir-opt/issue_76432.rs index c8b405ca8eaaf..fbbfd4ceb112b 100644 --- a/tests/mir-opt/issue_76432.rs +++ b/tests/mir-opt/issue_76432.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmir-enable-passes=-NormalizeArrayLen // Check that we do not insert StorageDead at each target if StorageDead was never seen // EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff diff --git a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff index 9bc7060e958eb..59de067f4a4f8 100644 --- a/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_bound.NormalizeArrayLen.diff @@ -13,7 +13,6 @@ let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 bb0: { StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 @@ -23,13 +22,10 @@ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 } diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff index cf427cfd1e6db..17574b1b63568 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.NormalizeArrayLen.diff @@ -16,7 +16,6 @@ let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 bb0: { StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 @@ -26,13 +25,10 @@ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = Len((*_6)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 ++ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 } diff --git a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff index 3ed68f5f72568..66feff62f4246 100644 --- a/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_len.NormalizeArrayLen.diff @@ -6,19 +6,15 @@ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 bb0: { StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 } diff --git a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff index f0e0cdcfdc0e4..c0a277edc4670 100644 --- a/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff +++ b/tests/mir-opt/lower_array_len.array_len_by_value.NormalizeArrayLen.diff @@ -6,19 +6,15 @@ let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 bb0: { StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 ++ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 goto -> bb1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 } diff --git a/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff new file mode 100644 index 0000000000000..8b35fd57fa016 --- /dev/null +++ b/tests/mir-opt/lower_array_len.array_len_raw.NormalizeArrayLen.diff @@ -0,0 +1,50 @@ +- // MIR for `array_len_raw` before NormalizeArrayLen ++ // MIR for `array_len_raw` after NormalizeArrayLen + + fn array_len_raw(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:38: +0:41 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:55: +0:60 + let _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + let _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:27 + let _7: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:14: +3:19 + scope 1 { + debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12 + let _5: *const [u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 2 { + debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 3 { + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _4 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _3 = &(*_4); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:21: +1:25 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:24: +1:25 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:26 + StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + _5 = &raw const (*_2); // scope 1 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + StorageLive(_7); // scope 2 at $DIR/lower_array_len.rs:+3:14: +3:19 + _7 = &(*_5); // scope 3 at $DIR/lower_array_len.rs:+3:14: +3:19 + _6 = &(*_7); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 +- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 ++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:27 + } + + bb1: { + StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:26: +3:27 + StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff new file mode 100644 index 0000000000000..8bdd2ede6bc41 --- /dev/null +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.NormalizeArrayLen.diff @@ -0,0 +1,44 @@ +- // MIR for `array_len_reborrow` before NormalizeArrayLen ++ // MIR for `array_len_reborrow` after NormalizeArrayLen + + fn array_len_reborrow(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:50 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:64: +0:69 + let _2: &mut [u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + let mut _3: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + let mut _4: &mut [u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+3:5: +3:14 + scope 1 { + debug arr => _2; // in scope 1 at $DIR/lower_array_len.rs:+1:9: +1:12 + let _5: &[u8]; // in scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + scope 2 { + debug arr => _5; // in scope 2 at $DIR/lower_array_len.rs:+2:9: +2:12 + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:9: +1:12 + StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _4 = &mut _1; // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _3 = &mut (*_4); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + _2 = move _3 as &mut [u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:25: +1:33 + StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:32: +1:33 + StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:33: +1:34 + StorageLive(_5); // scope 1 at $DIR/lower_array_len.rs:+2:9: +2:12 + _5 = &(*_2); // scope 1 at $DIR/lower_array_len.rs:+2:15: +2:20 + StorageLive(_6); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + _6 = &(*_5); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 +- _0 = Len((*_6)); // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 ++ _0 = const N; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + goto -> bb1; // scope 2 at $DIR/lower_array_len.rs:+3:5: +3:14 + } + + bb1: { + StorageDead(_6); // scope 2 at $DIR/lower_array_len.rs:+3:13: +3:14 + StorageDead(_5); // scope 1 at $DIR/lower_array_len.rs:+4:1: +4:2 + StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+4:1: +4:2 + return; // scope 0 at $DIR/lower_array_len.rs:+4:2: +4:2 + } + } + diff --git a/tests/mir-opt/lower_array_len.rs b/tests/mir-opt/lower_array_len.rs index ea0224b21d72d..972d46cb8e2bd 100644 --- a/tests/mir-opt/lower_array_len.rs +++ b/tests/mir-opt/lower_array_len.rs @@ -31,10 +31,26 @@ pub fn array_len_by_value(arr: [u8; N]) -> usize { arr.len() } +// EMIT_MIR lower_array_len.array_len_reborrow.NormalizeArrayLen.diff +pub fn array_len_reborrow(mut arr: [u8; N]) -> usize { + let arr: &mut [_] = &mut arr; + let arr = &*arr; + arr.len() +} + +// EMIT_MIR lower_array_len.array_len_raw.NormalizeArrayLen.diff +pub fn array_len_raw(arr: [u8; N]) -> usize { + let arr: &[_] = &arr; + let arr = std::ptr::addr_of!(*arr); + unsafe { &*arr }.len() +} + fn main() { let _ = array_bound(3, &[0, 1, 2, 3]); let mut tmp = [0, 1, 2, 3, 4]; let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); let _ = array_len(&[0]); let _ = array_len_by_value([0, 2]); + let _ = array_len_reborrow([0, 2]); + let _ = array_len_raw([0, 2]); } diff --git a/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir deleted file mode 100644 index dee1d538395ef..0000000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir +++ /dev/null @@ -1,41 +0,0 @@ -// MIR for `array_bound` after PreCodegen - -fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - } - - bb1: { - _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 - } - - bb3: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:11 - goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:2: +6:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir deleted file mode 100644 index e35fe758ab12d..0000000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir +++ /dev/null @@ -1,54 +0,0 @@ -// MIR for `array_bound_mut` after PreCodegen - -fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let mut _6: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - let _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - let mut _8: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - let mut _9: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _4 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 - _3 = Lt(_1, move _4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 - switchInt(move _3) -> [0: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 - } - - bb1: { - _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - _6 = Lt(_1, _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _1) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 - goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 - } - - bb3: { - StorageLive(_7); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - _7 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 - _8 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - _9 = Lt(const 0_usize, _8); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 - } - - bb4: { - (*_2)[_7] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22 - StorageDead(_7); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 - } - - bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir deleted file mode 100644 index 4b19f67955889..0000000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir +++ /dev/null @@ -1,11 +0,0 @@ -// MIR for `array_len` after PreCodegen - -fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:52: +0:57 - - bb0: { - _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir b/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir deleted file mode 100644 index 4dc0ba9a268ea..0000000000000 --- a/tests/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir +++ /dev/null @@ -1,11 +0,0 @@ -// MIR for `array_len_by_value` after PreCodegen - -fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:60: +0:65 - - bb0: { - _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 - return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 - } -} diff --git a/tests/mir-opt/lower_array_len_e2e.rs b/tests/mir-opt/lower_array_len_e2e.rs deleted file mode 100644 index d8e4e521ee682..0000000000000 --- a/tests/mir-opt/lower_array_len_e2e.rs +++ /dev/null @@ -1,39 +0,0 @@ -// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts - -// EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir -pub fn array_bound(index: usize, slice: &[u8; N]) -> u8 { - if index < slice.len() { - slice[index] - } else { - 42 - } -} - -// EMIT_MIR lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir -pub fn array_bound_mut(index: usize, slice: &mut [u8; N]) -> u8 { - if index < slice.len() { - slice[index] - } else { - slice[0] = 42; - - 42 - } -} - -// EMIT_MIR lower_array_len_e2e.array_len.PreCodegen.after.mir -pub fn array_len(arr: &[u8; N]) -> usize { - arr.len() -} - -// EMIT_MIR lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir -pub fn array_len_by_value(arr: [u8; N]) -> usize { - arr.len() -} - -fn main() { - let _ = array_bound(3, &[0, 1, 2, 3]); - let mut tmp = [0, 1, 2, 3, 4]; - let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); - let _ = array_len(&[0]); - let _ = array_len_by_value([0, 2]); -} From b456307cb10584f8ac48492500f0a1bca15d1adb Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 29 Jan 2023 22:09:51 +0000 Subject: [PATCH 07/15] Remove obsolete comment. --- compiler/rustc_mir_transform/src/normalize_array_len.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 8894e729502f2..b36c8a0bd5369 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -13,7 +13,6 @@ pub struct NormalizeArrayLen; impl<'tcx> MirPass<'tcx> for NormalizeArrayLen { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // See #105929 sess.mir_opt_level() >= 3 } From f7cc20af8c7bf085d0fdc3ff20b4f3b857b7e9e2 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 30 Jan 2023 07:20:38 +0200 Subject: [PATCH 08/15] use a more descriptive name --- compiler/rustc_middle/src/mir/mono.rs | 9 ++++++--- compiler/rustc_monomorphize/src/partitioning/mod.rs | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 1e8d5f7eae87a..7a05ee2ff37fd 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -318,16 +318,19 @@ impl<'tcx> CodegenUnit<'tcx> { base_n::encode(hash, base_n::CASE_INSENSITIVE) } - pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) { + pub fn create_size_estimate(&mut self, tcx: TyCtxt<'tcx>) { // Estimate the size of a codegen unit as (approximately) the number of MIR // statements it corresponds to. self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); } #[inline] + /// Should only be called if [`create_size_estimate`] has previously been called. + /// + /// [`create_size_estimate`]: Self::create_size_estimate pub fn size_estimate(&self) -> usize { - // Should only be called if `estimate_size` has previously been called. - self.size_estimate.expect("estimate_size must be called before getting a size_estimate") + self.size_estimate + .expect("create_size_estimate must be called before getting a size_estimate") } pub fn modify_size_estimate(&mut self, delta: usize) { diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index fd6bcad18983a..615126e8b5896 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -180,7 +180,7 @@ pub fn partition<'tcx>( partitioner.place_root_mono_items(cx, mono_items) }; - initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); @@ -200,7 +200,7 @@ pub fn partition<'tcx>( partitioner.place_inlined_mono_items(cx, initial_partitioning) }; - post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); + post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx)); debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); From a4aebf030e32d67e72db8b52be74fb6223a3006f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 05:50:06 +0000 Subject: [PATCH 09/15] Improve ICE messages for `*::expect_*` --- compiler/rustc_hir/src/hir.rs | 118 ++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 4640317ac7328..ef4a8754ac27e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2277,23 +2277,28 @@ impl<'hir> TraitItem<'hir> { /// Expect an [`TraitItemKind::Const`] or panic. #[track_caller] pub fn expect_const(&self) -> (&'hir Ty<'hir>, Option) { - let TraitItemKind::Const(ty, body) = self.kind else { unreachable!() }; + let TraitItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; (ty, body) } /// Expect an [`TraitItemKind::Fn`] or panic. #[track_caller] pub fn expect_fn(&self) -> (&FnSig<'hir>, &TraitFn<'hir>) { - let TraitItemKind::Fn(ty, trfn) = &self.kind else { unreachable!() }; + let TraitItemKind::Fn(ty, trfn) = &self.kind else { self.expect_failed("a function") }; (ty, trfn) } /// Expect an [`TraitItemKind::ExternCrate`] or panic. #[track_caller] pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { - let TraitItemKind::Type(bounds, ty) = self.kind else { unreachable!() }; + let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") }; (bounds, ty) } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents a trait method's body (or just argument names). @@ -2360,23 +2365,28 @@ impl<'hir> ImplItem<'hir> { /// Expect an [`ImplItemKind::Const`] or panic. #[track_caller] pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { - let ImplItemKind::Const(ty, body) = self.kind else { unreachable!() }; + let ImplItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; (ty, body) } /// Expect an [`ImplItemKind::Fn`] or panic. #[track_caller] pub fn expect_fn(&self) -> (&FnSig<'hir>, BodyId) { - let ImplItemKind::Fn(ty, body) = &self.kind else { unreachable!() }; + let ImplItemKind::Fn(ty, body) = &self.kind else { self.expect_failed("a function") }; (ty, *body) } - /// Expect an [`ImplItemKind::ExternCrate`] or panic. + /// Expect an [`ImplItemKind::Type`] or panic. #[track_caller] pub fn expect_type(&self) -> &'hir Ty<'hir> { - let ImplItemKind::Type(ty) = self.kind else { unreachable!() }; + let ImplItemKind::Type(ty) = self.kind else { self.expect_failed("a type") }; ty } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } /// Represents various kinds of content within an `impl`. @@ -3051,68 +3061,68 @@ impl<'hir> Item<'hir> { /// Expect an [`ItemKind::ExternCrate`] or panic. #[track_caller] pub fn expect_extern_crate(&self) -> Option { - let ItemKind::ExternCrate(s) = self.kind else { unreachable!() }; + let ItemKind::ExternCrate(s) = self.kind else { self.expect_failed("an extern crate") }; s } /// Expect an [`ItemKind::Use`] or panic. #[track_caller] pub fn expect_use(&self) -> (&'hir UsePath<'hir>, UseKind) { - let ItemKind::Use(p, uk) = self.kind else { unreachable!() }; + let ItemKind::Use(p, uk) = self.kind else { self.expect_failed("a use") }; (p, uk) } /// Expect an [`ItemKind::Static`] or panic. #[track_caller] pub fn expect_static(&self) -> (&'hir Ty<'hir>, Mutability, BodyId) { - let ItemKind::Static(ty, mutbl, body) = self.kind else { unreachable!() }; + let ItemKind::Static(ty, mutbl, body) = self.kind else { self.expect_failed("a static") }; (ty, mutbl, body) } /// Expect an [`ItemKind::Const`] or panic. #[track_caller] pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) { - let ItemKind::Const(ty, body) = self.kind else { unreachable!() }; + let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") }; (ty, body) } /// Expect an [`ItemKind::Fn`] or panic. #[track_caller] pub fn expect_fn(&self) -> (&FnSig<'hir>, &'hir Generics<'hir>, BodyId) { - let ItemKind::Fn(sig, gen, body) = &self.kind else { unreachable!() }; + let ItemKind::Fn(sig, gen, body) = &self.kind else { self.expect_failed("a function") }; (sig, gen, *body) } /// Expect an [`ItemKind::Macro`] or panic. #[track_caller] pub fn expect_macro(&self) -> (&ast::MacroDef, MacroKind) { - let ItemKind::Macro(def, mk) = &self.kind else { unreachable!() }; + let ItemKind::Macro(def, mk) = &self.kind else { self.expect_failed("a macro") }; (def, *mk) } /// Expect an [`ItemKind::Mod`] or panic. #[track_caller] pub fn expect_mod(&self) -> &'hir Mod<'hir> { - let ItemKind::Mod(m) = self.kind else { unreachable!() }; + let ItemKind::Mod(m) = self.kind else { self.expect_failed("a module") }; m } /// Expect an [`ItemKind::ForeignMod`] or panic. #[track_caller] pub fn expect_foreign_mod(&self) -> (Abi, &'hir [ForeignItemRef]) { - let ItemKind::ForeignMod { abi, items } = self.kind else { unreachable!() }; + let ItemKind::ForeignMod { abi, items } = self.kind else { self.expect_failed("a foreign module") }; (abi, items) } /// Expect an [`ItemKind::GlobalAsm`] or panic. #[track_caller] pub fn expect_global_asm(&self) -> &'hir InlineAsm<'hir> { - let ItemKind::GlobalAsm(asm) = self.kind else { unreachable!() }; + let ItemKind::GlobalAsm(asm) = self.kind else { self.expect_failed("a global asm") }; asm } /// Expect an [`ItemKind::TyAlias`] or panic. #[track_caller] pub fn expect_ty_alias(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>) { - let ItemKind::TyAlias(ty, gen) = self.kind else { unreachable!() }; + let ItemKind::TyAlias(ty, gen) = self.kind else { self.expect_failed("a type alias") }; (ty, gen) } @@ -3120,21 +3130,21 @@ impl<'hir> Item<'hir> { /// Expect an [`ItemKind::OpaqueTy`] or panic. #[track_caller] pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> { - let ItemKind::OpaqueTy(ty) = &self.kind else { unreachable!() }; + let ItemKind::OpaqueTy(ty) = &self.kind else { self.expect_failed("an opaque type") }; ty } /// Expect an [`ItemKind::Enum`] or panic. #[track_caller] pub fn expect_enum(&self) -> (&EnumDef<'hir>, &'hir Generics<'hir>) { - let ItemKind::Enum(def, gen) = &self.kind else { unreachable!() }; + let ItemKind::Enum(def, gen) = &self.kind else { self.expect_failed("an enum") }; (def, gen) } /// Expect an [`ItemKind::Struct`] or panic. #[track_caller] pub fn expect_struct(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { - let ItemKind::Struct(data, gen) = &self.kind else { unreachable!() }; + let ItemKind::Struct(data, gen) = &self.kind else { self.expect_failed("a struct") }; (data, gen) } @@ -3142,7 +3152,7 @@ impl<'hir> Item<'hir> { /// Expect an [`ItemKind::Union`] or panic. #[track_caller] pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) { - let ItemKind::Union(data, gen) = &self.kind else { unreachable!() }; + let ItemKind::Union(data, gen) = &self.kind else { self.expect_failed("a union") }; (data, gen) } @@ -3151,23 +3161,28 @@ impl<'hir> Item<'hir> { pub fn expect_trait( self, ) -> (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]) { - let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { unreachable!() }; + let ItemKind::Trait(is_auto, unsafety, gen, bounds, items) = self.kind else { self.expect_failed("a trait") }; (is_auto, unsafety, gen, bounds, items) } /// Expect an [`ItemKind::TraitAlias`] or panic. #[track_caller] pub fn expect_trait_alias(&self) -> (&'hir Generics<'hir>, GenericBounds<'hir>) { - let ItemKind::TraitAlias(gen, bounds) = self.kind else { unreachable!() }; + let ItemKind::TraitAlias(gen, bounds) = self.kind else { self.expect_failed("a trait alias") }; (gen, bounds) } /// Expect an [`ItemKind::Impl`] or panic. #[track_caller] pub fn expect_impl(&self) -> &'hir Impl<'hir> { - let ItemKind::Impl(imp) = self.kind else { unreachable!() }; + let ItemKind::Impl(imp) = self.kind else { self.expect_failed("an impl") }; imp } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} item, found {self:?}") + } } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -3757,176 +3772,181 @@ impl<'hir> Node<'hir> { /// Expect a [`Node::Param`] or panic. #[track_caller] pub fn expect_param(self) -> &'hir Param<'hir> { - let Node::Param(this) = self else { unreachable!() }; + let Node::Param(this) = self else { self.expect_failed("a parameter") }; this } /// Expect a [`Node::Item`] or panic. #[track_caller] pub fn expect_item(self) -> &'hir Item<'hir> { - let Node::Item(this) = self else { unreachable!() }; + let Node::Item(this) = self else { self.expect_failed("a item") }; this } /// Expect a [`Node::ForeignItem`] or panic. #[track_caller] pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> { - let Node::ForeignItem(this) = self else { unreachable!() }; + let Node::ForeignItem(this) = self else { self.expect_failed("a foreign item") }; this } /// Expect a [`Node::TraitItem`] or panic. #[track_caller] pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> { - let Node::TraitItem(this) = self else { unreachable!() }; + let Node::TraitItem(this) = self else { self.expect_failed("a trait item") }; this } /// Expect a [`Node::ImplItem`] or panic. #[track_caller] pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> { - let Node::ImplItem(this) = self else { unreachable!() }; + let Node::ImplItem(this) = self else { self.expect_failed("an implementation item") }; this } /// Expect a [`Node::Variant`] or panic. #[track_caller] pub fn expect_variant(self) -> &'hir Variant<'hir> { - let Node::Variant(this) = self else { unreachable!() }; + let Node::Variant(this) = self else { self.expect_failed("a variant") }; this } /// Expect a [`Node::Field`] or panic. #[track_caller] pub fn expect_field(self) -> &'hir FieldDef<'hir> { - let Node::Field(this) = self else { unreachable!() }; + let Node::Field(this) = self else { self.expect_failed("a field definition") }; this } /// Expect a [`Node::AnonConst`] or panic. #[track_caller] pub fn expect_anon_const(self) -> &'hir AnonConst { - let Node::AnonConst(this) = self else { unreachable!() }; + let Node::AnonConst(this) = self else { self.expect_failed("an anonymous constant") }; this } /// Expect a [`Node::Expr`] or panic. #[track_caller] pub fn expect_expr(self) -> &'hir Expr<'hir> { - let Node::Expr(this) = self else { unreachable!() }; + let Node::Expr(this) = self else { self.expect_failed("an expression") }; this } /// Expect a [`Node::ExprField`] or panic. #[track_caller] pub fn expect_expr_field(self) -> &'hir ExprField<'hir> { - let Node::ExprField(this) = self else { unreachable!() }; + let Node::ExprField(this) = self else { self.expect_failed("an expression field") }; this } /// Expect a [`Node::Stmt`] or panic. #[track_caller] pub fn expect_stmt(self) -> &'hir Stmt<'hir> { - let Node::Stmt(this) = self else { unreachable!() }; + let Node::Stmt(this) = self else { self.expect_failed("a statement") }; this } /// Expect a [`Node::PathSegment`] or panic. #[track_caller] pub fn expect_path_segment(self) -> &'hir PathSegment<'hir> { - let Node::PathSegment(this) = self else { unreachable!() }; + let Node::PathSegment(this) = self else { self.expect_failed("a path segment") }; this } /// Expect a [`Node::Ty`] or panic. #[track_caller] pub fn expect_ty(self) -> &'hir Ty<'hir> { - let Node::Ty(this) = self else { unreachable!() }; + let Node::Ty(this) = self else { self.expect_failed("a type") }; this } /// Expect a [`Node::TypeBinding`] or panic. #[track_caller] pub fn expect_type_binding(self) -> &'hir TypeBinding<'hir> { - let Node::TypeBinding(this) = self else { unreachable!() }; + let Node::TypeBinding(this) = self else { self.expect_failed("a type binding") }; this } /// Expect a [`Node::TraitRef`] or panic. #[track_caller] pub fn expect_trait_ref(self) -> &'hir TraitRef<'hir> { - let Node::TraitRef(this) = self else { unreachable!() }; + let Node::TraitRef(this) = self else { self.expect_failed("a trait reference") }; this } /// Expect a [`Node::Pat`] or panic. #[track_caller] pub fn expect_pat(self) -> &'hir Pat<'hir> { - let Node::Pat(this) = self else { unreachable!() }; + let Node::Pat(this) = self else { self.expect_failed("a pattern") }; this } /// Expect a [`Node::PatField`] or panic. #[track_caller] pub fn expect_pat_field(self) -> &'hir PatField<'hir> { - let Node::PatField(this) = self else { unreachable!() }; + let Node::PatField(this) = self else { self.expect_failed("a pattern field") }; this } /// Expect a [`Node::Arm`] or panic. #[track_caller] pub fn expect_arm(self) -> &'hir Arm<'hir> { - let Node::Arm(this) = self else { unreachable!() }; + let Node::Arm(this) = self else { self.expect_failed("an arm") }; this } /// Expect a [`Node::Block`] or panic. #[track_caller] pub fn expect_block(self) -> &'hir Block<'hir> { - let Node::Block(this) = self else { unreachable!() }; + let Node::Block(this) = self else { self.expect_failed("a block") }; this } /// Expect a [`Node::Local`] or panic. #[track_caller] pub fn expect_local(self) -> &'hir Local<'hir> { - let Node::Local(this) = self else { unreachable!() }; + let Node::Local(this) = self else { self.expect_failed("a local") }; this } /// Expect a [`Node::Ctor`] or panic. #[track_caller] pub fn expect_ctor(self) -> &'hir VariantData<'hir> { - let Node::Ctor(this) = self else { unreachable!() }; + let Node::Ctor(this) = self else { self.expect_failed("a constructor") }; this } /// Expect a [`Node::Lifetime`] or panic. #[track_caller] pub fn expect_lifetime(self) -> &'hir Lifetime { - let Node::Lifetime(this) = self else { unreachable!() }; + let Node::Lifetime(this) = self else { self.expect_failed("a lifetime") }; this } /// Expect a [`Node::GenericParam`] or panic. #[track_caller] pub fn expect_generic_param(self) -> &'hir GenericParam<'hir> { - let Node::GenericParam(this) = self else { unreachable!() }; + let Node::GenericParam(this) = self else { self.expect_failed("a generic parameter") }; this } /// Expect a [`Node::Crate`] or panic. #[track_caller] pub fn expect_crate(self) -> &'hir Mod<'hir> { - let Node::Crate(this) = self else { unreachable!() }; + let Node::Crate(this) = self else { self.expect_failed("a crate") }; this } /// Expect a [`Node::Infer`] or panic. #[track_caller] pub fn expect_infer(self) -> &'hir InferArg { - let Node::Infer(this) = self else { unreachable!() }; + let Node::Infer(this) = self else { self.expect_failed("an infer") }; this } + + #[track_caller] + fn expect_failed(&self, expected: &'static str) -> ! { + panic!("expected {expected} node, found {self:?}") + } } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. From b2ef837b6c52d1cb0977c7fc1e62af5ee546827e Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 05:50:37 +0000 Subject: [PATCH 10/15] Use `expect_{use,fn}` in a couple of places --- compiler/rustc_hir_analysis/src/check/compare_impl_item.rs | 2 +- compiler/rustc_hir_analysis/src/check_unused.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 53f5cb2cc9a7c..92a96d713585f 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1504,7 +1504,7 @@ fn compare_synthetic_generics<'tcx>( let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; let impl_m = tcx.hir().expect_impl_item(impl_m); - let hir::ImplItemKind::Fn(sig, _) = &impl_m.kind else { unreachable!() }; + let (sig, _) = impl_m.expect_fn(); let input_tys = sig.decl.inputs; struct Visitor(Option, hir::def_id::LocalDefId); diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index ebb78213a63a1..5716be4f1a954 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -29,7 +29,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { if item.span.is_dummy() { continue; } - let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; + let (path, _) = item.expect_use(); let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { format!("unused import: `{}`", snippet) } else { From 883145f75d105abc32911f536738f66d74d32f4f Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 05:55:20 +0000 Subject: [PATCH 11/15] fix `TraitItemKind::expect_type` docs --- compiler/rustc_hir/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ef4a8754ac27e..95422f74120d4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2288,7 +2288,7 @@ impl<'hir> TraitItem<'hir> { (ty, trfn) } - /// Expect an [`TraitItemKind::ExternCrate`] or panic. + /// Expect an [`TraitItemKind::Type`] or panic. #[track_caller] pub fn expect_type(&self) -> (GenericBounds<'hir>, Option<&'hir Ty<'hir>>) { let TraitItemKind::Type(bounds, ty) = self.kind else { self.expect_failed("a type") }; From 727a1fd1945685f21d4d2b1d86dbf6429372f3ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roy=20Wellington=20=E2=85=A3?= Date: Sat, 21 Jan 2023 18:21:43 -0500 Subject: [PATCH 12/15] Keep all theme-updating logic together MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior to this PR, if the page is restored from the browser bfcache¹, we call `switchToSavedTheme`. But `switchToSavedTheme` never looks at the `use-system-theme` preference. Further, if it can't find a saved theme, it will fall back to the default of "light". For a user with cookies disabled² whose preferred color scheme is dark, this means the theme will wobble back and forth between dark and light. The sequence that occurs is, 1. The page is loaded. During a page load, we consult `use-system-theme`: as cookies are disabled, this preference is unset. The default is true. Because the default is true, we look at the preferred color scheme: for our example user, that's "dark". **The page theme is set to dark.** We'll attempt to store these preferences in localStorage, but fail due to cookies being disabled. 2. The user navigates through the docs. Subsequent page loads happen, and the same process in step 1 recurs. Previous pages are (potentially) put into the bfcache. 3. The user navigates backwards/forwards, causing a page in bfcache to be pulled out of cache. The `pageShow` event handler is triggered. However, this calls `switchToSavedTheme`: this doesn't consider the system theme, as noted above. Instead, it only looks for a saved theme. However, with cookies disabled, there is none. It defaults to light. **The page theme is set to light!** The user wonders why the dark theme is lost. There are effectively two functions trying to determine and apply the correct theme: `updateSystemTheme` and `switchToSavedTheme`. Thus, we merge them into just one: `updateTheme`. This function contains all the logic for determining the correct theme, and is called in all circumstances where we need to set the theme: * The initial page load * If the browser preferred color scheme (i.e., light/dark mode) is changed * If the page is restored from bfcache * If the user updates the theme preferences (i.e., in `settings.js`) Fixes #94250. ¹bfcache: https://web.dev/bfcache/ The bfcache is used to sleep a page, if the user navigates away from it, and to restore it from cache if the user returns to it. ²Note that the browser preference that enables/disables cookies really controls many forms of storage. The same preference thus also affects localStorage. (This is so a normal browser user doesn't need to understand the distinction between "cookies" and "localStorage".) --- src/librustdoc/html/static/js/settings.js | 4 +- src/librustdoc/html/static/js/storage.js | 96 ++++++++++++----------- 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 84df1b7d3911a..d51cce37d6462 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global getSettingValue, getVirtualKey, updateLocalStorage, updateSystemTheme */ +/* global getSettingValue, getVirtualKey, updateLocalStorage, updateTheme */ /* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */ /* global MAIN_ID, getVar, getSettingsButton */ @@ -19,7 +19,7 @@ case "theme": case "preferred-dark-theme": case "preferred-light-theme": - updateSystemTheme(); + updateTheme(); updateLightAndDark(); break; case "line-numbers": diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 61856303483e7..8836d1b2e464b 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -153,63 +153,74 @@ function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) { } } -const updateSystemTheme = (function() { - if (!window.matchMedia) { - // fallback to the CSS computed value - return () => { - const cssTheme = getComputedStyle(document.documentElement) - .getPropertyValue("content"); - - switchTheme( - window.currentTheme, - window.mainTheme, - JSON.parse(cssTheme) || "light", - true - ); +const updateTheme = (function() { + /** + * Update the current theme to match whatever the current combination of + * * the preference for using the system theme + * (if this is the case, the value of preferred-light-theme, if the + * system theme is light, otherwise if dark, the value of + * preferred-dark-theme.) + * * the preferred theme + * … dictates that it should be. + */ + function updateTheme() { + const use = (theme, saveTheme) => { + switchTheme(window.currentTheme, window.mainTheme, theme, saveTheme); }; - } - // only listen to (prefers-color-scheme: dark) because light is the default - const mql = window.matchMedia("(prefers-color-scheme: dark)"); - - function handlePreferenceChange(mql) { - const use = theme => { - switchTheme(window.currentTheme, window.mainTheme, theme, true); - }; // maybe the user has disabled the setting in the meantime! if (getSettingValue("use-system-theme") !== "false") { const lightTheme = getSettingValue("preferred-light-theme") || "light"; const darkTheme = getSettingValue("preferred-dark-theme") || "dark"; - if (mql.matches) { - use(darkTheme); + if (isDarkMode()) { + use(darkTheme, true); } else { // prefers a light theme, or has no preference - use(lightTheme); + use(lightTheme, true); } // note: we save the theme so that it doesn't suddenly change when // the user disables "use-system-theme" and reloads the page or // navigates to another page } else { - use(getSettingValue("theme")); + use(getSettingValue("theme"), false); } } - mql.addListener(handlePreferenceChange); + // This is always updated below to a function () => bool. + let isDarkMode; - return () => { - handlePreferenceChange(mql); - }; -})(); + // Determine the function for isDarkMode, and if we have + // `window.matchMedia`, set up an event listener on the preferred color + // scheme. + // + // Otherwise, fall back to the prefers-color-scheme value CSS captured in + // the "content" property. + if (window.matchMedia) { + // only listen to (prefers-color-scheme: dark) because light is the default + const mql = window.matchMedia("(prefers-color-scheme: dark)"); -function switchToSavedTheme() { - switchTheme( - window.currentTheme, - window.mainTheme, - getSettingValue("theme") || "light", - false - ); -} + isDarkMode = () => mql.matches; + + if (mql.addEventListener) { + mql.addEventListener("change", updateTheme); + } else { + // This is deprecated, see: + // https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/addListener + mql.addListener(updateTheme); + } + } else { + // fallback to the CSS computed value + const cssContent = getComputedStyle(document.documentElement) + .getPropertyValue("content"); + // (Note: the double-quotes come from that this is a CSS value, which + // might be a length, string, etc.) + const cssColorScheme = cssContent || "\"light\""; + isDarkMode = () => (cssColorScheme === "\"dark\""); + } + + return updateTheme; +})(); if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { // update the preferred dark theme if the user is already using a dark theme @@ -219,13 +230,10 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) { && darkThemes.indexOf(localStoredTheme) >= 0) { updateLocalStorage("preferred-dark-theme", localStoredTheme); } - - // call the function to initialize the theme at least once! - updateSystemTheme(); -} else { - switchToSavedTheme(); } +updateTheme(); + if (getSettingValue("source-sidebar-show") === "true") { // At this point in page load, `document.body` is not available yet. // Set a class on the `` element instead. @@ -243,6 +251,6 @@ if (getSettingValue("source-sidebar-show") === "true") { // specifically when talking to a remote website with no caching. window.addEventListener("pageshow", ev => { if (ev.persisted) { - setTimeout(switchToSavedTheme, 0); + setTimeout(updateTheme, 0); } }); From d4585408dc28b7d03a38aa29a0394e9e7ef2de69 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 10:53:11 +0000 Subject: [PATCH 13/15] Split `has_allow_dead_code_or_lang_attr` into sub functions --- compiler/rustc_passes/src/dead.rs | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 127acb46e9242..c061787c30d2d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -459,30 +459,32 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { } fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - if tcx.has_attr(def_id.to_def_id(), sym::lang) { - return true; + fn has_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + tcx.has_attr(def_id.to_def_id(), sym::lang) + // Stable attribute for #[lang = "panic_impl"] + || tcx.has_attr(def_id.to_def_id(), sym::panic_handler) } - // Stable attribute for #[lang = "panic_impl"] - if tcx.has_attr(def_id.to_def_id(), sym::panic_handler) { - return true; + fn has_allow_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow } - if tcx.def_kind(def_id).has_codegen_attrs() { - let cg_attrs = tcx.codegen_fn_attrs(def_id); + fn has_used_like_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + tcx.def_kind(def_id).has_codegen_attrs() && { + let cg_attrs = tcx.codegen_fn_attrs(def_id); - // #[used], #[no_mangle], #[export_name], etc also keeps the item alive - // forcefully, e.g., for placing it in a specific section. - if cg_attrs.contains_extern_indicator() - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { - return true; + // #[used], #[no_mangle], #[export_name], etc also keeps the item alive + // forcefully, e.g., for placing it in a specific section. + cg_attrs.contains_extern_indicator() + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) } } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0 == lint::Allow + has_lang_attr(tcx, def_id) + || has_used_like_attr(tcx, def_id) + || has_allow_dead_code(tcx, def_id) } // These check_* functions seeds items that From 48af3a96e6106e67d0518c329f769e669b6e363c Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 30 Jan 2023 10:54:33 +0000 Subject: [PATCH 14/15] Consider `#[allow(dead_code)]` before lang items --- compiler/rustc_passes/src/dead.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c061787c30d2d..83adfeb6b10b6 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -482,9 +482,9 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool } } - has_lang_attr(tcx, def_id) + has_allow_dead_code(tcx, def_id) || has_used_like_attr(tcx, def_id) - || has_allow_dead_code(tcx, def_id) + || has_lang_attr(tcx, def_id) } // These check_* functions seeds items that From 8348f25493be139e726cb2d6b3ea8bf0417a4f53 Mon Sep 17 00:00:00 2001 From: Lucille Blumire Date: Mon, 30 Jan 2023 14:22:41 +0000 Subject: [PATCH 15/15] Update bastion-of-the-turbofish.rs The original tweet in the chain linked to, and thus the through line of links back to Anna's tweet where she named the turbofish (https://web.archive.org/web/20210911061514/https://twitter.com/whoisaldeka/status/914914008225816576) are lost as the user whoisaldeka has deleted their twitter account. Switching to an archive link preserves this through line, allowing someone to browse back to see the point at which Anna created the turbofish, as was the original intent of including this context. --- tests/ui/parser/bastion-of-the-turbofish.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/parser/bastion-of-the-turbofish.rs b/tests/ui/parser/bastion-of-the-turbofish.rs index e12857008a5e0..7ceea676d3a37 100644 --- a/tests/ui/parser/bastion-of-the-turbofish.rs +++ b/tests/ui/parser/bastion-of-the-turbofish.rs @@ -34,7 +34,7 @@ // See https://github.com/rust-lang/rust/pull/53562 // and https://github.com/rust-lang/rfcs/pull/2527 -// and https://twitter.com/garblefart/status/1393236602856611843 +// and https://web.archive.org/web/20211010063452/https://twitter.com/garblefart/status/1393236602856611843 // for context. fn main() {