From ac34a6fcd5229f1308e74c8a84a38dc4a27cee4b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 17 Dec 2024 23:59:38 +0000 Subject: [PATCH 01/15] Stabilize the `cell_update` feature Included API: impl Cell { pub fn update(&self, f: impl FnOnce(T) -> T); } Closes: https://github.com/rust-lang/rust/issues/50186 --- library/core/src/cell.rs | 4 +--- library/coretests/tests/lib.rs | 1 - src/tools/miri/src/lib.rs | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 09117e4968db6..e23a58eaece26 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -549,8 +549,6 @@ impl Cell { /// # Examples /// /// ``` - /// #![feature(cell_update)] - /// /// use std::cell::Cell; /// /// let c = Cell::new(5); @@ -558,7 +556,7 @@ impl Cell { /// assert_eq!(c.get(), 6); /// ``` #[inline] - #[unstable(feature = "cell_update", issue = "50186")] + #[stable(feature = "cell_update", since = "CURRENT_RUSTC_VERSION")] pub fn update(&self, f: impl FnOnce(T) -> T) { let old = self.get(); self.set(f(old)); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 7ad154796f649..cec9430396e9a 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -12,7 +12,6 @@ #![feature(async_iterator)] #![feature(bigint_helper_methods)] #![feature(bstr)] -#![feature(cell_update)] #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 03f76cfa6524c..f2cca7e1faf13 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -1,6 +1,5 @@ #![feature(rustc_private)] #![feature(cfg_match)] -#![feature(cell_update)] #![feature(float_gamma)] #![feature(float_erf)] #![feature(map_try_insert)] From fe03f76794989508a92af17d2cf519249fae825d Mon Sep 17 00:00:00 2001 From: xizheyin Date: Thu, 3 Apr 2025 16:19:46 +0800 Subject: [PATCH 02/15] std: Add performance warnings to HashMap::get_disjoint_mut Signed-off-by: xizheyin --- library/std/src/collections/hash/map.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 2487f5a2a503f..863d5a40997f8 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -973,6 +973,9 @@ where /// Returns an array of length `N` with the results of each query. For soundness, at most one /// mutable reference will be returned to any value. `None` will be used if the key is missing. /// + /// This method performs a check to ensure there are no duplicate keys, which has time-complexity O(n^2), + /// so be careful when passing many keys. + /// /// # Panics /// /// Panics if any keys are overlapping. From 35a20ded329500de1acba172a2b50bdfef85f431 Mon Sep 17 00:00:00 2001 From: Makai Date: Fri, 18 Apr 2025 14:34:20 +0800 Subject: [PATCH 03/15] Implement `SmirInterface` - With `Context` wrapped by `SmirInterface`, the stable-mir's TLV stores a pointer to `SmirInterface`, while the rustc-specific TLV stores a pointer to tables. - This PR make the `rustc_smir` mod public. --- compiler/rustc_smir/src/lib.rs | 3 +- compiler/rustc_smir/src/rustc_internal/mod.rs | 20 +- compiler/rustc_smir/src/rustc_smir/context.rs | 261 +++++++---- compiler/rustc_smir/src/rustc_smir/mod.rs | 2 +- .../src/stable_mir/compiler_interface.rs | 416 +++++++++++++----- 5 files changed, 495 insertions(+), 207 deletions(-) diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 5d465bca4eef1..bdc2353b62587 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -20,7 +20,6 @@ pub mod rustc_internal; -// Make this module private for now since external users should not call these directly. -mod rustc_smir; +pub mod rustc_smir; pub mod stable_mir; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index a546a44c87004..c6f8b1f0047ed 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -18,9 +18,10 @@ use rustc_span::def_id::{CrateNum, DefId}; use scoped_tls::scoped_thread_local; use stable_mir::Error; use stable_mir::abi::Layout; +use stable_mir::compiler_interface::SmirInterface; use stable_mir::ty::IndexedVal; -use crate::rustc_smir::context::TablesWrapper; +use crate::rustc_smir::context::Context; use crate::rustc_smir::{Stable, Tables}; use crate::stable_mir; @@ -196,12 +197,12 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { // datastructures and stable MIR datastructures scoped_thread_local! (static TLV: Cell<*const ()>); -pub(crate) fn init<'tcx, F, T>(tables: &TablesWrapper<'tcx>, f: F) -> T +pub(crate) fn init<'tcx, F, T>(cx: &Context<'tcx>, f: F) -> T where F: FnOnce() -> T, { assert!(!TLV.is_set()); - let ptr = tables as *const _ as *const (); + let ptr = cx as *const _ as *const (); TLV.set(&Cell::new(ptr), || f()) } @@ -212,8 +213,8 @@ pub(crate) fn with_tables(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) - TLV.with(|tlv| { let ptr = tlv.get(); assert!(!ptr.is_null()); - let wrapper = ptr as *const TablesWrapper<'_>; - let mut tables = unsafe { (*wrapper).0.borrow_mut() }; + let context = ptr as *const Context<'_>; + let mut tables = unsafe { (*context).0.borrow_mut() }; f(&mut *tables) }) } @@ -222,7 +223,7 @@ pub fn run(tcx: TyCtxt<'_>, f: F) -> Result where F: FnOnce() -> T, { - let tables = TablesWrapper(RefCell::new(Tables { + let tables = Context(RefCell::new(Tables { tcx, def_ids: IndexMap::default(), alloc_ids: IndexMap::default(), @@ -233,7 +234,12 @@ where mir_consts: IndexMap::default(), layouts: IndexMap::default(), })); - stable_mir::compiler_interface::run(&tables, || init(&tables, f)) + + let interface = SmirInterface { cx: tables }; + + // Pass the `SmirInterface` to compiler_interface::run + // and initialize the rustc-specific TLS with tables. + stable_mir::compiler_interface::run(&interface, || init(&interface.cx, f)) } /// Instantiate and run the compiler with the provided arguments and callback. diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 240f6f7fe45a1..ed13e04bf2918 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -20,7 +20,6 @@ use rustc_middle::ty::{ use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; use stable_mir::abi::{FnAbi, Layout, LayoutShape}; -use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::{BinOp, Body, Place, UnOp}; @@ -37,8 +36,11 @@ use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate}; use crate::stable_mir; -impl<'tcx> Context for TablesWrapper<'tcx> { - fn target_info(&self) -> MachineInfo { +/// Internal context holding direct rustc access. +pub struct Context<'tcx>(pub RefCell>); + +impl<'tcx> Context<'tcx> { + pub fn target_info(&self) -> MachineInfo { let mut tables = self.0.borrow_mut(); MachineInfo { endian: tables.tcx.data_layout.endian.stable(&mut *tables), @@ -48,31 +50,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn entry_fn(&self) -> Option { + pub fn entry_fn(&self) -> Option { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; Some(tables.crate_item(tcx.entry_fn(())?.0)) } - fn all_local_items(&self) -> stable_mir::CrateItems { + /// Retrieve all items of the local crate that have a MIR associated with them. + pub fn all_local_items(&self) -> stable_mir::CrateItems { let mut tables = self.0.borrow_mut(); tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect() } - fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body { + /// Retrieve the body of a function. + /// This function will panic if the body is not available. + pub fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body { let mut tables = self.0.borrow_mut(); let def_id = tables[item]; tables.tcx.instance_mir(rustc_middle::ty::InstanceKind::Item(def_id)).stable(&mut tables) } - fn has_body(&self, def: DefId) -> bool { + /// Check whether the body of a function is available. + pub fn has_body(&self, def: DefId) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.internal(&mut *tables, tcx); tables.item_has_body(def_id) } - fn foreign_modules(&self, crate_num: CrateNum) -> Vec { + pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.foreign_modules(crate_num.internal(&mut *tables, tcx)) @@ -81,21 +87,23 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn crate_functions(&self, crate_num: CrateNum) -> Vec { + /// Retrieve all functions defined in this crate. + pub fn crate_functions(&self, crate_num: CrateNum) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let krate = crate_num.internal(&mut *tables, tcx); filter_def_ids(tcx, krate, |def_id| tables.to_fn_def(def_id)) } - fn crate_statics(&self, crate_num: CrateNum) -> Vec { + /// Retrieve all static items defined in this crate. + pub fn crate_statics(&self, crate_num: CrateNum) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let krate = crate_num.internal(&mut *tables, tcx); filter_def_ids(tcx, krate, |def_id| tables.to_static(def_id)) } - fn foreign_module( + pub fn foreign_module( &self, mod_def: stable_mir::ty::ForeignModuleDef, ) -> stable_mir::ty::ForeignModule { @@ -105,7 +113,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { mod_def.stable(&mut *tables) } - fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec { + pub fn foreign_items(&self, mod_def: stable_mir::ty::ForeignModuleDef) -> Vec { let mut tables = self.0.borrow_mut(); let def_id = tables[mod_def.def_id()]; tables @@ -119,12 +127,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn all_trait_decls(&self) -> stable_mir::TraitDecls { + pub fn all_trait_decls(&self) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect() } - fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { + pub fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.traits(crate_num.internal(&mut *tables, tcx)) @@ -133,14 +141,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { + pub fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { let mut tables = self.0.borrow_mut(); let def_id = tables[trait_def.0]; let trait_def = tables.tcx.trait_def(def_id); trait_def.stable(&mut *tables) } - fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls { + pub fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; iter::once(LOCAL_CRATE) @@ -150,7 +158,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls { + pub fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.trait_impls_in_crate(crate_num.internal(&mut *tables, tcx)) @@ -159,21 +167,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { + pub fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { let mut tables = self.0.borrow_mut(); let def_id = tables[impl_def.0]; let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap(); impl_trait.stable(&mut *tables) } - fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { + pub fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; let generics = tables.tcx.generics_of(def_id); generics.stable(&mut *tables) } - fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { + pub fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; let GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id); @@ -191,7 +199,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn explicit_predicates_of( + pub fn explicit_predicates_of( &self, def_id: stable_mir::DefId, ) -> stable_mir::ty::GenericPredicates { @@ -212,17 +220,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn local_crate(&self) -> stable_mir::Crate { + /// Get information about the local crate. + pub fn local_crate(&self) -> stable_mir::Crate { let tables = self.0.borrow(); smir_crate(tables.tcx, LOCAL_CRATE) } - fn external_crates(&self) -> Vec { + /// Retrieve a list of all external crates. + pub fn external_crates(&self) -> Vec { let tables = self.0.borrow(); tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect() } - fn find_crates(&self, name: &str) -> Vec { + /// Find a crate with the given name. + pub fn find_crates(&self, name: &str) -> Vec { let tables = self.0.borrow(); let crates: Vec = [LOCAL_CRATE] .iter() @@ -235,7 +246,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { crates } - fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol { + /// Returns the name of given `DefId`. + pub fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol { let tables = self.0.borrow(); if trimmed { with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id])) @@ -244,7 +256,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn tool_attrs( + /// Return registered tool attributes with the given attribute name. + /// + /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool + /// attributes will simply return an empty list. + /// + /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. + /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. + pub fn tool_attrs( &self, def_id: stable_mir::DefId, attr: &[stable_mir::Symbol], @@ -268,7 +287,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn all_tool_attrs(&self, def_id: stable_mir::DefId) -> Vec { + /// Get all tool attributes of a definition. + pub fn all_tool_attrs( + &self, + def_id: stable_mir::DefId, + ) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let did = tables[def_id]; @@ -292,12 +315,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .collect() } - fn span_to_string(&self, span: stable_mir::ty::Span) -> String { + /// Returns printable, human readable form of `Span`. + pub fn span_to_string(&self, span: stable_mir::ty::Span) -> String { let tables = self.0.borrow(); tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span]) } - fn get_filename(&self, span: &Span) -> Filename { + /// Return filename from given `Span`, for diagnostic purposes. + pub fn get_filename(&self, span: &Span) -> Filename { let tables = self.0.borrow(); tables .tcx @@ -308,23 +333,27 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .to_string() } - fn get_lines(&self, span: &Span) -> LineInfo { + /// Return lines corresponding to this `Span`. + pub fn get_lines(&self, span: &Span) -> LineInfo { let tables = self.0.borrow(); let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]); LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 } } - fn item_kind(&self, item: CrateItem) -> ItemKind { + /// Returns the `kind` of given `DefId`. + pub fn item_kind(&self, item: CrateItem) -> ItemKind { let tables = self.0.borrow(); new_item_kind(tables.tcx.def_kind(tables[item.0])) } - fn is_foreign_item(&self, item: DefId) -> bool { + /// Returns whether this is a foreign item. + pub fn is_foreign_item(&self, item: DefId) -> bool { let tables = self.0.borrow(); tables.tcx.is_foreign_item(tables[item]) } - fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { + /// Returns the kind of a given foreign item. + pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { let mut tables = self.0.borrow_mut(); let def_id = tables[def.def_id()]; let tcx = tables.tcx; @@ -339,32 +368,37 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn adt_kind(&self, def: AdtDef) -> AdtKind { + /// Returns the kind of a given algebraic data type. + pub fn adt_kind(&self, def: AdtDef) -> AdtKind { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).adt_kind().stable(&mut *tables) } - fn adt_is_box(&self, def: AdtDef) -> bool { + /// Returns if the ADT is a box. + pub fn adt_is_box(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).is_box() } - fn adt_is_simd(&self, def: AdtDef) -> bool { + /// Returns whether this ADT is simd. + pub fn adt_is_simd(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).repr().simd() } - fn adt_is_cstr(&self, def: AdtDef) -> bool { + /// Returns whether this definition is a C string. + pub fn adt_is_cstr(&self, def: AdtDef) -> bool { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); tables.tcx.is_lang_item(def_id, LangItem::CStr) } - fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { + /// Retrieve the function signature for the given generic arguments. + pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); @@ -373,7 +407,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { sig.stable(&mut *tables) } - fn intrinsic(&self, def: DefId) -> Option { + /// Retrieve the intrinsic definition if the item corresponds one. + pub fn intrinsic(&self, def: DefId) -> Option { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.internal(&mut *tables, tcx); @@ -381,14 +416,16 @@ impl<'tcx> Context for TablesWrapper<'tcx> { intrinsic.map(|_| IntrinsicDef(def)) } - fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { + /// Retrieve the plain function name of an intrinsic. + pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); tcx.intrinsic(def_id).unwrap().name.to_string() } - fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { + /// Retrieve the closure signature for the given generic arguments. + pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let args_ref = args.internal(&mut *tables, tcx); @@ -396,25 +433,28 @@ impl<'tcx> Context for TablesWrapper<'tcx> { sig.stable(&mut *tables) } - fn adt_variants_len(&self, def: AdtDef) -> usize { + /// The number of variants in this ADT. + pub fn adt_variants_len(&self, def: AdtDef) -> usize { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).variants().len() } - fn variant_name(&self, def: VariantDef) -> Symbol { + /// The name of a variant. + pub fn variant_name(&self, def: VariantDef) -> Symbol { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).name.to_string() } - fn variant_fields(&self, def: VariantDef) -> Vec { + pub fn variant_fields(&self, def: VariantDef) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect() } - fn eval_target_usize(&self, cnst: &MirConst) -> Result { + /// Evaluate constant as a target usize. + pub fn eval_target_usize(&self, cnst: &MirConst) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let mir_const = cnst.internal(&mut *tables, tcx); @@ -422,7 +462,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .try_eval_target_usize(tables.tcx, ty::TypingEnv::fully_monomorphized()) .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } - fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { + pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let mir_const = cnst.internal(&mut *tables, tcx); @@ -431,7 +471,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } - fn try_new_const_zst(&self, ty: Ty) -> Result { + /// Create a new zero-sized constant. + pub fn try_new_const_zst(&self, ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty_internal = ty.internal(&mut *tables, tcx); @@ -456,7 +497,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables)) } - fn new_const_str(&self, value: &str) -> MirConst { + /// Create a new constant that represents the given string value. + pub fn new_const_str(&self, value: &str) -> MirConst { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_static_str(tcx); @@ -467,12 +509,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { mir::Const::from_value(val, ty).stable(&mut tables) } - fn new_const_bool(&self, value: bool) -> MirConst { + /// Create a new constant that represents the given boolean value. + pub fn new_const_bool(&self, value: bool) -> MirConst { let mut tables = self.0.borrow_mut(); mir::Const::from_bool(tables.tcx, value).stable(&mut tables) } - fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + /// Create a new constant that represents the given value. + pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx)); @@ -487,7 +531,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Ok(mir::Const::from_scalar(tcx, mir::interpret::Scalar::Int(scalar), ty) .stable(&mut tables)) } - fn try_new_ty_const_uint( + pub fn try_new_ty_const_uint( &self, value: u128, uint_ty: UintTy, @@ -509,27 +553,35 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables)) } - fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty { + /// Create a new type from the given kind. + pub fn new_rigid_ty(&self, kind: RigidTy) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let internal_kind = kind.internal(&mut *tables, tcx); tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables) } - fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty { + /// Create a new box type, `Box`, for the given inner type `T`. + pub fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let inner = ty.internal(&mut *tables, tcx); ty::Ty::new_box(tables.tcx, inner).stable(&mut *tables) } - fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty { + /// Returns the type of given crate item. + pub fn def_ty(&self, item: stable_mir::DefId) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; tcx.type_of(item.internal(&mut *tables, tcx)).instantiate_identity().stable(&mut *tables) } - fn def_ty_with_args(&self, item: stable_mir::DefId, args: &GenericArgs) -> stable_mir::ty::Ty { + /// Returns the type of given definition instantiated with the given arguments. + pub fn def_ty_with_args( + &self, + item: stable_mir::DefId, + args: &GenericArgs, + ) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let args = args.internal(&mut *tables, tcx); @@ -544,33 +596,38 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables) } - fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String { + /// Returns literal value of a const as a string. + pub fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; cnst.internal(&mut *tables, tcx).to_string() } - fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { + /// `Span` of an item. + pub fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span { let mut tables = self.0.borrow_mut(); tables.tcx.def_span(tables[def_id]).stable(&mut *tables) } - fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String { + /// Obtain the representation of a type. + pub fn ty_pretty(&self, ty: stable_mir::ty::Ty) -> String { let tables = self.0.borrow_mut(); tables.types[ty].to_string() } - fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind { + /// Obtain the representation of a type. + pub fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind { let mut tables = self.0.borrow_mut(); tables.types[ty].kind().stable(&mut *tables) } - fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String { + pub fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String { let tables = self.0.borrow_mut(); tables.ty_consts[ct].to_string() } - fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty { + /// Get the discriminant Ty for this Ty if there's one. + pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let internal_kind = ty.internal(&mut *tables, tcx); @@ -578,7 +635,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { internal_ty.discriminant_ty(tables.tcx).stable(&mut *tables) } - fn instance_body(&self, def: InstanceDef) -> Option { + /// Get the body of an Instance which is already monomorphized. + pub fn instance_body(&self, def: InstanceDef) -> Option { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; tables @@ -586,63 +644,74 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables)) } - fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty { + /// Get the instance type with generic instantiations applied and lifetimes erased. + pub fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation"); instance.ty(tables.tcx, ty::TypingEnv::fully_monomorphized()).stable(&mut *tables) } - fn instance_args(&self, def: InstanceDef) -> GenericArgs { + /// Get the instantiation types. + pub fn instance_args(&self, def: InstanceDef) -> GenericArgs { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; instance.args.stable(&mut *tables) } - fn instance_abi(&self, def: InstanceDef) -> Result { + /// Get an instance ABI. + pub fn instance_abi(&self, def: InstanceDef) -> Result { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables)) } - fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + /// Get the ABI of a function pointer. + pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let sig = fn_ptr.internal(&mut *tables, tcx); Ok(tables.fn_abi_of_fn_ptr(sig, List::empty())?.stable(&mut *tables)) } - fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { + /// Get the instance. + pub fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId { let mut tables = self.0.borrow_mut(); let def_id = tables.instances[def].def_id(); tables.create_def_id(def_id) } - fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { + /// Get the instance mangled name. + pub fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { let tables = self.0.borrow_mut(); let instance = tables.instances[instance]; tables.tcx.symbol_name(instance).name.to_string() } - fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { + /// Check if this is an empty DropGlue shim. + pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; matches!(instance.def, ty::InstanceKind::DropGlue(_, None)) } - fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { + /// Check if this is an empty AsyncDropGlueCtor shim. + pub fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; matches!(instance.def, ty::InstanceKind::AsyncDropGlueCtorShim(_, None)) } - fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { + /// Convert a non-generic crate item into an instance. + /// This function will panic if the item is generic. + pub fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); let def_id = tables[def_id]; Instance::mono(tables.tcx, def_id).stable(&mut *tables) } - fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool { + /// Item requires monomorphization. + pub fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool { let tables = self.0.borrow(); let def_id = tables[def_id]; let generics = tables.tcx.generics_of(def_id); @@ -650,7 +719,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { result } - fn resolve_instance( + /// Resolve an instance from the given function definition and generic arguments. + pub fn resolve_instance( &self, def: stable_mir::ty::FnDef, args: &stable_mir::ty::GenericArgs, @@ -670,7 +740,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance { + /// Resolve an instance for drop_in_place for the given type. + pub fn resolve_drop_in_place(&self, ty: stable_mir::ty::Ty) -> stable_mir::mir::mono::Instance { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let internal_ty = ty.internal(&mut *tables, tcx); @@ -678,7 +749,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { instance.stable(&mut *tables) } - fn resolve_for_fn_ptr( + /// Resolve instance for a function pointer. + pub fn resolve_for_fn_ptr( &self, def: FnDef, args: &GenericArgs, @@ -696,7 +768,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables) } - fn resolve_closure( + /// Resolve instance for a closure with the requested type. + pub fn resolve_closure( &self, def: ClosureDef, args: &GenericArgs, @@ -713,7 +786,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ) } - fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { + /// Try to evaluate an instance into a constant. + pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; let tcx = tables.tcx; @@ -733,21 +807,24 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .map_err(|e| e.stable(&mut *tables))? } - fn eval_static_initializer(&self, def: StaticDef) -> Result { + /// Evaluate a static's initializer. + pub fn eval_static_initializer(&self, def: StaticDef) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = def.0.internal(&mut *tables, tcx); tables.tcx.eval_static_initializer(def_id).stable(&mut *tables) } - fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc { + /// Retrieve global allocation for the given allocation ID. + pub fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let alloc_id = alloc.internal(&mut *tables, tcx); tables.tcx.global_alloc(alloc_id).stable(&mut *tables) } - fn vtable_allocation( + /// Retrieve the id for the virtual table. + pub fn vtable_allocation( &self, global_alloc: &GlobalAlloc, ) -> Option { @@ -765,7 +842,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Some(alloc_id.stable(&mut *tables)) } - fn krate(&self, def_id: stable_mir::DefId) -> Crate { + pub fn krate(&self, def_id: stable_mir::DefId) -> Crate { let tables = self.0.borrow(); smir_crate(tables.tcx, tables[def_id].krate) } @@ -773,7 +850,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { /// Retrieve the instance name for diagnostic messages. /// /// This will return the specialized name, e.g., `Vec::new`. - fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { + pub fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; if trimmed { @@ -787,7 +864,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn ty_layout(&self, ty: Ty) -> Result { + /// Get the layout of a type. + pub fn ty_layout(&self, ty: Ty) -> Result { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty.internal(&mut *tables, tcx); @@ -795,19 +873,22 @@ impl<'tcx> Context for TablesWrapper<'tcx> { Ok(layout.stable(&mut *tables)) } - fn layout_shape(&self, id: Layout) -> LayoutShape { + /// Get the layout shape. + pub fn layout_shape(&self, id: Layout) -> LayoutShape { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; id.internal(&mut *tables, tcx).0.stable(&mut *tables) } - fn place_pretty(&self, place: &Place) -> String { + /// Get a debug string representation of a place. + pub fn place_pretty(&self, place: &Place) -> String { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; format!("{:?}", place.internal(&mut *tables, tcx)) } - fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { + /// Get the resulting type of binary operation. + pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let rhs_internal = rhs.internal(&mut *tables, tcx); @@ -816,7 +897,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ty.stable(&mut *tables) } - fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { + /// Get the resulting type of unary operation. + pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let arg_internal = arg.internal(&mut *tables, tcx); @@ -824,7 +906,8 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ty.stable(&mut *tables) } - fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems { + /// Get all associated items of a definition. + pub fn associated_items(&self, def_id: stable_mir::DefId) -> stable_mir::AssocItems { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let def_id = tables[def_id]; @@ -840,8 +923,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } -pub(crate) struct TablesWrapper<'tcx>(pub RefCell>); - /// Implement error handling for extracting function ABI information. impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> { type FnAbiOfResult = Result<&'tcx rustc_target::callconv::FnAbi<'tcx, ty::Ty<'tcx>>, Error>; diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index dea8f54a67097..b5003baaf633c 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -25,7 +25,7 @@ use crate::stable_mir; mod alloc; mod builder; -pub(crate) mod context; +pub mod context; mod convert; pub struct Tables<'tcx> { diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs index 33d950bb951cd..58e6c6d7a93fe 100644 --- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs +++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs @@ -5,6 +5,7 @@ use std::cell::Cell; +use rustc_smir::context::Context; use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::crate_def::Attribute; use stable_mir::mir::alloc::{AllocId, GlobalAlloc}; @@ -22,47 +23,116 @@ use stable_mir::{ ItemKind, Symbol, TraitDecls, mir, }; -use crate::stable_mir; +use crate::{rustc_smir, stable_mir}; + +/// Stable public API for querying compiler information. +/// +/// All queries are delegated to an internal [`Context`] that provides +/// similar APIs but based on internal rustc constructs. +/// +/// Do not use this directly. This is currently used in the macro expansion. +pub struct SmirInterface<'tcx> { + pub(crate) cx: Context<'tcx>, +} + +impl<'tcx> SmirInterface<'tcx> { + pub fn entry_fn(&self) -> Option { + self.cx.entry_fn() + } -/// This trait defines the interface between stable_mir and the Rust compiler. -/// Do not use this directly. -pub trait Context { - fn entry_fn(&self) -> Option; /// Retrieve all items of the local crate that have a MIR associated with them. - fn all_local_items(&self) -> CrateItems; + pub fn all_local_items(&self) -> CrateItems { + self.cx.all_local_items() + } + /// Retrieve the body of a function. /// This function will panic if the body is not available. - fn mir_body(&self, item: DefId) -> mir::Body; + pub fn mir_body(&self, item: DefId) -> mir::Body { + self.cx.mir_body(item) + } + /// Check whether the body of a function is available. - fn has_body(&self, item: DefId) -> bool; - fn foreign_modules(&self, crate_num: CrateNum) -> Vec; + pub fn has_body(&self, item: DefId) -> bool { + self.cx.has_body(item) + } + + pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec { + self.cx.foreign_modules(crate_num) + } /// Retrieve all functions defined in this crate. - fn crate_functions(&self, crate_num: CrateNum) -> Vec; + pub fn crate_functions(&self, crate_num: CrateNum) -> Vec { + self.cx.crate_functions(crate_num) + } /// Retrieve all static items defined in this crate. - fn crate_statics(&self, crate_num: CrateNum) -> Vec; - fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule; - fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec; - fn all_trait_decls(&self) -> TraitDecls; - fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls; - fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl; - fn all_trait_impls(&self) -> ImplTraitDecls; - fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls; - fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait; - fn generics_of(&self, def_id: DefId) -> Generics; - fn predicates_of(&self, def_id: DefId) -> GenericPredicates; - fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates; + pub fn crate_statics(&self, crate_num: CrateNum) -> Vec { + self.cx.crate_statics(crate_num) + } + + pub fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule { + self.cx.foreign_module(mod_def) + } + + pub fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec { + self.cx.foreign_items(mod_def) + } + + pub fn all_trait_decls(&self) -> TraitDecls { + self.cx.all_trait_decls() + } + + pub fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls { + self.cx.trait_decls(crate_num) + } + + pub fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl { + self.cx.trait_decl(trait_def) + } + + pub fn all_trait_impls(&self) -> ImplTraitDecls { + self.cx.all_trait_impls() + } + + pub fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls { + self.cx.trait_impls(crate_num) + } + + pub fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait { + self.cx.trait_impl(trait_impl) + } + + pub fn generics_of(&self, def_id: DefId) -> Generics { + self.cx.generics_of(def_id) + } + + pub fn predicates_of(&self, def_id: DefId) -> GenericPredicates { + self.cx.predicates_of(def_id) + } + + pub fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates { + self.cx.explicit_predicates_of(def_id) + } + /// Get information about the local crate. - fn local_crate(&self) -> Crate; + pub fn local_crate(&self) -> Crate { + self.cx.local_crate() + } + /// Retrieve a list of all external crates. - fn external_crates(&self) -> Vec; + pub fn external_crates(&self) -> Vec { + self.cx.external_crates() + } /// Find a crate with the given name. - fn find_crates(&self, name: &str) -> Vec; + pub fn find_crates(&self, name: &str) -> Vec { + self.cx.find_crates(name) + } - /// Returns the name of given `DefId` - fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; + /// Returns the name of given `DefId`. + pub fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol { + self.cx.def_name(def_id, trimmed) + } /// Return registered tool attributes with the given attribute name. /// @@ -71,218 +141,350 @@ pub trait Context { /// /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. - fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec; + pub fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec { + self.cx.tool_attrs(def_id, attr) + } /// Get all tool attributes of a definition. - fn all_tool_attrs(&self, def_id: DefId) -> Vec; + pub fn all_tool_attrs(&self, def_id: DefId) -> Vec { + self.cx.all_tool_attrs(def_id) + } - /// Returns printable, human readable form of `Span` - fn span_to_string(&self, span: Span) -> String; + /// Returns printable, human readable form of `Span`. + pub fn span_to_string(&self, span: Span) -> String { + self.cx.span_to_string(span) + } - /// Return filename from given `Span`, for diagnostic purposes - fn get_filename(&self, span: &Span) -> Filename; + /// Return filename from given `Span`, for diagnostic purposes. + pub fn get_filename(&self, span: &Span) -> Filename { + self.cx.get_filename(span) + } - /// Return lines corresponding to this `Span` - fn get_lines(&self, span: &Span) -> LineInfo; + /// Return lines corresponding to this `Span`. + pub fn get_lines(&self, span: &Span) -> LineInfo { + self.cx.get_lines(span) + } - /// Returns the `kind` of given `DefId` - fn item_kind(&self, item: CrateItem) -> ItemKind; + /// Returns the `kind` of given `DefId`. + pub fn item_kind(&self, item: CrateItem) -> ItemKind { + self.cx.item_kind(item) + } /// Returns whether this is a foreign item. - fn is_foreign_item(&self, item: DefId) -> bool; + pub fn is_foreign_item(&self, item: DefId) -> bool { + self.cx.is_foreign_item(item) + } /// Returns the kind of a given foreign item. - fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind; + pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { + self.cx.foreign_item_kind(def) + } - /// Returns the kind of a given algebraic data type - fn adt_kind(&self, def: AdtDef) -> AdtKind; + /// Returns the kind of a given algebraic data type. + pub fn adt_kind(&self, def: AdtDef) -> AdtKind { + self.cx.adt_kind(def) + } /// Returns if the ADT is a box. - fn adt_is_box(&self, def: AdtDef) -> bool; + pub fn adt_is_box(&self, def: AdtDef) -> bool { + self.cx.adt_is_box(def) + } /// Returns whether this ADT is simd. - fn adt_is_simd(&self, def: AdtDef) -> bool; + pub fn adt_is_simd(&self, def: AdtDef) -> bool { + self.cx.adt_is_simd(def) + } /// Returns whether this definition is a C string. - fn adt_is_cstr(&self, def: AdtDef) -> bool; + pub fn adt_is_cstr(&self, def: AdtDef) -> bool { + self.cx.adt_is_cstr(def) + } /// Retrieve the function signature for the given generic arguments. - fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig; + pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { + self.cx.fn_sig(def, args) + } /// Retrieve the intrinsic definition if the item corresponds one. - fn intrinsic(&self, item: DefId) -> Option; + pub fn intrinsic(&self, item: DefId) -> Option { + self.cx.intrinsic(item) + } /// Retrieve the plain function name of an intrinsic. - fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol; + pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { + self.cx.intrinsic_name(def) + } /// Retrieve the closure signature for the given generic arguments. - fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig; + pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { + self.cx.closure_sig(args) + } /// The number of variants in this ADT. - fn adt_variants_len(&self, def: AdtDef) -> usize; + pub fn adt_variants_len(&self, def: AdtDef) -> usize { + self.cx.adt_variants_len(def) + } /// The name of a variant. - fn variant_name(&self, def: VariantDef) -> Symbol; - fn variant_fields(&self, def: VariantDef) -> Vec; + pub fn variant_name(&self, def: VariantDef) -> Symbol { + self.cx.variant_name(def) + } + + pub fn variant_fields(&self, def: VariantDef) -> Vec { + self.cx.variant_fields(def) + } /// Evaluate constant as a target usize. - fn eval_target_usize(&self, cnst: &MirConst) -> Result; - fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result; + pub fn eval_target_usize(&self, cnst: &MirConst) -> Result { + self.cx.eval_target_usize(cnst) + } + + pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { + self.cx.eval_target_usize_ty(cnst) + } /// Create a new zero-sized constant. - fn try_new_const_zst(&self, ty: Ty) -> Result; + pub fn try_new_const_zst(&self, ty: Ty) -> Result { + self.cx.try_new_const_zst(ty) + } /// Create a new constant that represents the given string value. - fn new_const_str(&self, value: &str) -> MirConst; + pub fn new_const_str(&self, value: &str) -> MirConst { + self.cx.new_const_str(value) + } /// Create a new constant that represents the given boolean value. - fn new_const_bool(&self, value: bool) -> MirConst; + pub fn new_const_bool(&self, value: bool) -> MirConst { + self.cx.new_const_bool(value) + } /// Create a new constant that represents the given value. - fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result; - fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result; + pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + self.cx.try_new_const_uint(value, uint_ty) + } + + pub fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + self.cx.try_new_ty_const_uint(value, uint_ty) + } /// Create a new type from the given kind. - fn new_rigid_ty(&self, kind: RigidTy) -> Ty; + pub fn new_rigid_ty(&self, kind: RigidTy) -> Ty { + self.cx.new_rigid_ty(kind) + } /// Create a new box type, `Box`, for the given inner type `T`. - fn new_box_ty(&self, ty: Ty) -> Ty; + pub fn new_box_ty(&self, ty: Ty) -> Ty { + self.cx.new_box_ty(ty) + } /// Returns the type of given crate item. - fn def_ty(&self, item: DefId) -> Ty; + pub fn def_ty(&self, item: DefId) -> Ty { + self.cx.def_ty(item) + } /// Returns the type of given definition instantiated with the given arguments. - fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty; + pub fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty { + self.cx.def_ty_with_args(item, args) + } /// Returns literal value of a const as a string. - fn mir_const_pretty(&self, cnst: &MirConst) -> String; + pub fn mir_const_pretty(&self, cnst: &MirConst) -> String { + self.cx.mir_const_pretty(cnst) + } - /// `Span` of an item - fn span_of_an_item(&self, def_id: DefId) -> Span; + /// `Span` of an item. + pub fn span_of_an_item(&self, def_id: DefId) -> Span { + self.cx.span_of_an_item(def_id) + } - fn ty_const_pretty(&self, ct: TyConstId) -> String; + pub fn ty_const_pretty(&self, ct: TyConstId) -> String { + self.cx.ty_const_pretty(ct) + } /// Obtain the representation of a type. - fn ty_pretty(&self, ty: Ty) -> String; + pub fn ty_pretty(&self, ty: Ty) -> String { + self.cx.ty_pretty(ty) + } /// Obtain the representation of a type. - fn ty_kind(&self, ty: Ty) -> TyKind; + pub fn ty_kind(&self, ty: Ty) -> TyKind { + self.cx.ty_kind(ty) + } - // Get the discriminant Ty for this Ty if there's one. - fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty; + /// Get the discriminant Ty for this Ty if there's one. + pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty { + self.cx.rigid_ty_discriminant_ty(ty) + } /// Get the body of an Instance which is already monomorphized. - fn instance_body(&self, instance: InstanceDef) -> Option; + pub fn instance_body(&self, instance: InstanceDef) -> Option { + self.cx.instance_body(instance) + } /// Get the instance type with generic instantiations applied and lifetimes erased. - fn instance_ty(&self, instance: InstanceDef) -> Ty; + pub fn instance_ty(&self, instance: InstanceDef) -> Ty { + self.cx.instance_ty(instance) + } /// Get the instantiation types. - fn instance_args(&self, def: InstanceDef) -> GenericArgs; + pub fn instance_args(&self, def: InstanceDef) -> GenericArgs { + self.cx.instance_args(def) + } /// Get the instance. - fn instance_def_id(&self, instance: InstanceDef) -> DefId; + pub fn instance_def_id(&self, instance: InstanceDef) -> DefId { + self.cx.instance_def_id(instance) + } /// Get the instance mangled name. - fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol; + pub fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { + self.cx.instance_mangled_name(instance) + } /// Check if this is an empty DropGlue shim. - fn is_empty_drop_shim(&self, def: InstanceDef) -> bool; + pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { + self.cx.is_empty_drop_shim(def) + } /// Check if this is an empty AsyncDropGlueCtor shim. - fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool; + pub fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { + self.cx.is_empty_async_drop_ctor_shim(def) + } /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. - fn mono_instance(&self, def_id: DefId) -> Instance; + pub fn mono_instance(&self, def_id: DefId) -> Instance { + self.cx.mono_instance(def_id) + } /// Item requires monomorphization. - fn requires_monomorphization(&self, def_id: DefId) -> bool; + pub fn requires_monomorphization(&self, def_id: DefId) -> bool { + self.cx.requires_monomorphization(def_id) + } /// Resolve an instance from the given function definition and generic arguments. - fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option; + pub fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option { + self.cx.resolve_instance(def, args) + } /// Resolve an instance for drop_in_place for the given type. - fn resolve_drop_in_place(&self, ty: Ty) -> Instance; + pub fn resolve_drop_in_place(&self, ty: Ty) -> Instance { + self.cx.resolve_drop_in_place(ty) + } /// Resolve instance for a function pointer. - fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option; + pub fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option { + self.cx.resolve_for_fn_ptr(def, args) + } /// Resolve instance for a closure with the requested type. - fn resolve_closure( + pub fn resolve_closure( &self, def: ClosureDef, args: &GenericArgs, kind: ClosureKind, - ) -> Option; + ) -> Option { + self.cx.resolve_closure(def, args, kind) + } /// Evaluate a static's initializer. - fn eval_static_initializer(&self, def: StaticDef) -> Result; + pub fn eval_static_initializer(&self, def: StaticDef) -> Result { + self.cx.eval_static_initializer(def) + } /// Try to evaluate an instance into a constant. - fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result; + pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { + self.cx.eval_instance(def, const_ty) + } /// Retrieve global allocation for the given allocation ID. - fn global_alloc(&self, id: AllocId) -> GlobalAlloc; + pub fn global_alloc(&self, id: AllocId) -> GlobalAlloc { + self.cx.global_alloc(id) + } /// Retrieve the id for the virtual table. - fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option; - fn krate(&self, def_id: DefId) -> Crate; - fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol; + pub fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option { + self.cx.vtable_allocation(global_alloc) + } + + pub fn krate(&self, def_id: DefId) -> Crate { + self.cx.krate(def_id) + } + + pub fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { + self.cx.instance_name(def, trimmed) + } /// Return information about the target machine. - fn target_info(&self) -> MachineInfo; + pub fn target_info(&self) -> MachineInfo { + self.cx.target_info() + } /// Get an instance ABI. - fn instance_abi(&self, def: InstanceDef) -> Result; + pub fn instance_abi(&self, def: InstanceDef) -> Result { + self.cx.instance_abi(def) + } /// Get the ABI of a function pointer. - fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result; + pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + self.cx.fn_ptr_abi(fn_ptr) + } /// Get the layout of a type. - fn ty_layout(&self, ty: Ty) -> Result; + pub fn ty_layout(&self, ty: Ty) -> Result { + self.cx.ty_layout(ty) + } /// Get the layout shape. - fn layout_shape(&self, id: Layout) -> LayoutShape; + pub fn layout_shape(&self, id: Layout) -> LayoutShape { + self.cx.layout_shape(id) + } /// Get a debug string representation of a place. - fn place_pretty(&self, place: &Place) -> String; + pub fn place_pretty(&self, place: &Place) -> String { + self.cx.place_pretty(place) + } /// Get the resulting type of binary operation. - fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty; + pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { + self.cx.binop_ty(bin_op, rhs, lhs) + } /// Get the resulting type of unary operation. - fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty; + pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { + self.cx.unop_ty(un_op, arg) + } /// Get all associated items of a definition. - fn associated_items(&self, def_id: DefId) -> AssocItems; + pub fn associated_items(&self, def_id: DefId) -> AssocItems { + self.cx.associated_items(def_id) + } } -// A thread local variable that stores a pointer to the tables mapping between TyCtxt -// datastructures and stable MIR datastructures +// A thread local variable that stores a pointer to [`SmirInterface`]. scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>); -pub fn run(context: &dyn Context, f: F) -> Result +pub fn run<'tcx, T, F>(interface: &SmirInterface<'tcx>, f: F) -> Result where F: FnOnce() -> T, { if TLV.is_set() { Err(Error::from("StableMIR already running")) } else { - let ptr: *const () = (&raw const context) as _; + let ptr: *const () = (interface as *const SmirInterface<'tcx>) as *const (); TLV.set(&Cell::new(ptr), || Ok(f())) } } -/// Execute the given function with access the compiler [Context]. +/// Execute the given function with access the [`SmirInterface`]. /// -/// I.e., This function will load the current context and calls a function with it. +/// I.e., This function will load the current interface and calls a function with it. /// Do not nest these, as that will ICE. -pub(crate) fn with(f: impl FnOnce(&dyn Context) -> R) -> R { +pub(crate) fn with(f: impl FnOnce(&SmirInterface<'_>) -> R) -> R { assert!(TLV.is_set()); TLV.with(|tlv| { let ptr = tlv.get(); assert!(!ptr.is_null()); - f(unsafe { *(ptr as *const &dyn Context) }) + f(unsafe { &*(ptr as *const SmirInterface<'_>) }) }) } From 16381b3133c2ab6da503d7680700fe63705636b5 Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sun, 20 Apr 2025 21:20:29 +0800 Subject: [PATCH 04/15] Use `currently` for futher improvement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jonas Böttiger --- library/std/src/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 863d5a40997f8..847c1950fcedf 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -973,7 +973,7 @@ where /// Returns an array of length `N` with the results of each query. For soundness, at most one /// mutable reference will be returned to any value. `None` will be used if the key is missing. /// - /// This method performs a check to ensure there are no duplicate keys, which has time-complexity O(n^2), + /// This method performs a check to ensure there are no duplicate keys, which currently has a time-complexity of O(n^2), /// so be careful when passing many keys. /// /// # Panics From 08baec4ebfe4e3679f322324c1740e0690289760 Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 22 Apr 2025 13:07:15 -0700 Subject: [PATCH 05/15] add a test for byte string literal pattern mutability mismatches --- .../byte-string-mutability-mismatch.rs | 19 ++++++++++++++ .../byte-string-mutability-mismatch.stderr | 25 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/ui/pattern/byte-string-mutability-mismatch.rs create mode 100644 tests/ui/pattern/byte-string-mutability-mismatch.stderr diff --git a/tests/ui/pattern/byte-string-mutability-mismatch.rs b/tests/ui/pattern/byte-string-mutability-mismatch.rs new file mode 100644 index 0000000000000..4ffdb5f9b99e8 --- /dev/null +++ b/tests/ui/pattern/byte-string-mutability-mismatch.rs @@ -0,0 +1,19 @@ +//! Byte string literal patterns use the mutability of the literal, rather than the mutability of +//! the pattern's scrutinee. Since byte string literals are always shared references, it's a +//! mismatch to use a byte string literal pattern to match on a mutable array or slice reference. + +fn main() { + let mut val = [97u8, 10u8]; + match &mut val { + b"a\n" => {}, + //~^ ERROR mismatched types + //~| types differ in mutability + _ => {}, + } + match &mut val[..] { + b"a\n" => {}, + //~^ ERROR mismatched types + //~| types differ in mutability + _ => {}, + } +} diff --git a/tests/ui/pattern/byte-string-mutability-mismatch.stderr b/tests/ui/pattern/byte-string-mutability-mismatch.stderr new file mode 100644 index 0000000000000..ee796278e69d5 --- /dev/null +++ b/tests/ui/pattern/byte-string-mutability-mismatch.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/byte-string-mutability-mismatch.rs:8:9 + | +LL | match &mut val { + | -------- this expression has type `&mut [u8; 2]` +LL | b"a\n" => {}, + | ^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/byte-string-mutability-mismatch.rs:14:10 + | +LL | match &mut val[..] { + | ------------ this expression has type `&mut [u8]` +LL | b"a\n" => {}, + | ^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 61840254c512412525dfe796b855af7237b8d7b9 Mon Sep 17 00:00:00 2001 From: dianne Date: Mon, 24 Mar 2025 17:08:14 -0700 Subject: [PATCH 06/15] make `str` literal patterns usable in deref patterns Specifically, this allows string literal patterns to be used where a `str` is expected when `deref_patterns` is enabled. --- compiler/rustc_hir_typeck/src/pat.rs | 11 +++++++ .../src/builder/matches/test.rs | 23 +++++++++++++ compiler/rustc_mir_build/src/thir/constant.rs | 6 ++++ .../src/thir/pattern/const_to_pat.rs | 10 ++++++ tests/ui/pattern/deref-patterns/needs-gate.rs | 7 ++++ .../pattern/deref-patterns/needs-gate.stderr | 10 +++++- tests/ui/pattern/deref-patterns/strings.rs | 32 +++++++++++++++++++ .../ui/pattern/deref-patterns/typeck_fail.rs | 8 ++--- .../pattern/deref-patterns/typeck_fail.stderr | 26 +++------------ 9 files changed, 104 insertions(+), 29 deletions(-) create mode 100644 tests/ui/pattern/deref-patterns/strings.rs diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index e5e4fc7f8b77f..bb85396277c5c 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -775,6 +775,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + // When `deref_patterns` is enabled, in order to allow `deref!("..."): String`, we allow + // string literal patterns to have type `str`. This is accounted for when lowering to MIR. + if self.tcx.features().deref_patterns() + && let hir::PatExprKind::Lit { + lit: Spanned { node: ast::LitKind::Str(..), .. }, .. + } = lt.kind + && self.try_structurally_resolve_type(span, expected).is_str() + { + pat_ty = self.tcx.types.str_; + } + if self.tcx.features().string_deref_patterns() && let hir::PatExprKind::Lit { lit: Spanned { node: ast::LitKind::Str(..), .. }, .. diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 73cc3c86e22f7..210b9cce581fd 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -146,6 +146,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut place = place; let mut block = block; match ty.kind() { + ty::Str => { + // String literal patterns may have type `str` if `deref_patterns` is + // enabled, in order to allow `deref!("..."): String`. In this case, `value` + // is of type `&str`, so we compare it to `&place`. + if !tcx.features().deref_patterns() { + span_bug!( + test.span, + "matching on `str` went through without enabling deref_patterns" + ); + } + let re_erased = tcx.lifetimes.re_erased; + let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_); + let ref_place = self.temp(ref_str_ty, test.span); + // `let ref_place: &str = &place;` + self.cfg.push_assign( + block, + self.source_info(test.span), + ref_place, + Rvalue::Ref(re_erased, BorrowKind::Shared, place), + ); + place = ref_place; + ty = ref_str_ty; + } ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => { if !tcx.features().string_deref_patterns() { span_bug!( diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index b3210813703ca..a5ae74280d06e 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -37,6 +37,12 @@ pub(crate) fn lit_to_const<'tcx>( let str_bytes = s.as_str().as_bytes(); ty::ValTree::from_raw_bytes(tcx, str_bytes) } + (ast::LitKind::Str(s, _), ty::Str) if tcx.features().deref_patterns() => { + // String literal patterns may have type `str` if `deref_patterns` is enabled, in order + // to allow `deref!("..."): String`. + let str_bytes = s.as_str().as_bytes(); + ty::ValTree::from_raw_bytes(tcx, str_bytes) + } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_)) => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index a40001bf74556..b7d203e3cd78c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -280,6 +280,16 @@ impl<'tcx> ConstToPat<'tcx> { slice: None, suffix: Box::new([]), }, + ty::Str => { + // String literal patterns may have type `str` if `deref_patterns` is enabled, in + // order to allow `deref!("..."): String`. Since we need a `&str` for the comparison + // when lowering to MIR in `Builder::perform_test`, treat the constant as a `&str`. + // This works because `str` and `&str` have the same valtree representation. + let ref_str_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, ty); + PatKind::Constant { + value: mir::Const::Ty(ref_str_ty, ty::Const::new_value(tcx, cv, ref_str_ty)), + } + } ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs index 2d5ec45217fbb..a26a4fedc5c51 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.rs +++ b/tests/ui/pattern/deref-patterns/needs-gate.rs @@ -12,4 +12,11 @@ fn main() { //~^ ERROR: mismatched types _ => {} } + + // `deref_patterns` allows string and byte string literals to have non-ref types. + match *"test" { + "test" => {} + //~^ ERROR: mismatched types + _ => {} + } } diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr index 8687b5dc977db..b1ae03753fec7 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.stderr +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -23,7 +23,15 @@ help: consider dereferencing to access the inner value using the Deref trait LL | match *Box::new(0) { | + -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:18:9 + | +LL | match *"test" { + | ------- this expression has type `str` +LL | "test" => {} + | ^^^^^^ expected `str`, found `&str` + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/strings.rs b/tests/ui/pattern/deref-patterns/strings.rs new file mode 100644 index 0000000000000..b55451e318179 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/strings.rs @@ -0,0 +1,32 @@ +//@ run-pass +//! Test deref patterns using string and bytestring literals. + +#![feature(deref_patterns)] +#![allow(incomplete_features)] + +fn main() { + for (test_in, test_expect) in [("zero", 0), ("one", 1), ("two", 2)] { + // Test string literal patterns having type `str`. + let test_actual = match *test_in { + "zero" => 0, + "one" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test string literals in explicit `deref!(_)` patterns. + let test_actual = match test_in.to_string() { + deref!("zero") => 0, + deref!("one") => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + } + + // Test that we can still mutate in the match arm after using a literal to test equality: + let mut test = "test".to_string(); + if let deref!(s @ "test") = &mut test { + s.make_ascii_uppercase(); + } + assert_eq!(test, "TEST"); +} diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs index 4b9ad7d25f090..52d84f7a34de3 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.rs +++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs @@ -2,18 +2,14 @@ #![allow(incomplete_features)] fn main() { - // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a - // place of type `str`. + // FIXME(deref_patterns): fails to typecheck because string literal patterns don't peel + // references from the scrutinee. match "foo".to_string() { - deref!("foo") => {} - //~^ ERROR: mismatched types "foo" => {} //~^ ERROR: mismatched types _ => {} } match &"foo".to_string() { - deref!("foo") => {} - //~^ ERROR: mismatched types "foo" => {} //~^ ERROR: mismatched types _ => {} diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr index 3e2f356188220..e87528c1c51a9 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.stderr +++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr @@ -1,34 +1,16 @@ error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:8:16 + --> $DIR/typeck_fail.rs:8:9 | LL | match "foo".to_string() { | ----------------- this expression has type `String` -LL | deref!("foo") => {} - | ^^^^^ expected `str`, found `&str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:10:9 - | -LL | match "foo".to_string() { - | ----------------- this expression has type `String` -... LL | "foo" => {} | ^^^^^ expected `String`, found `&str` error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:15:16 - | -LL | match &"foo".to_string() { - | ------------------ this expression has type `&String` -LL | deref!("foo") => {} - | ^^^^^ expected `str`, found `&str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:17:9 + --> $DIR/typeck_fail.rs:13:9 | LL | match &"foo".to_string() { | ------------------ this expression has type `&String` -... LL | "foo" => {} | ^^^^^ expected `&String`, found `&str` | @@ -36,7 +18,7 @@ LL | "foo" => {} found reference `&'static str` error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:24:9 + --> $DIR/typeck_fail.rs:20:9 | LL | match Some(0) { | ------- this expression has type `Option<{integer}>` @@ -46,6 +28,6 @@ LL | Ok(0) => {} = note: expected enum `Option<{integer}>` found enum `Result<_, _>` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0308`. From 32503440cd40975ea6f0779e4abbaaca389582fe Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 15 Apr 2025 23:35:52 -0700 Subject: [PATCH 07/15] make `[u8]` and `[u8;N]` literal patterns usable in deref patterns Specifically, this allows byte string literal patterns to be used where a `[u8]` or `[u8;N]` is expected when `deref_patterns` is enabled. --- compiler/rustc_hir_typeck/src/pat.rs | 35 ++++++++++--- compiler/rustc_mir_build/src/thir/constant.rs | 8 ++- .../deref-patterns/byte-string-type-errors.rs | 34 ++++++++++++ .../byte-string-type-errors.stderr | 52 +++++++++++++++++++ tests/ui/pattern/deref-patterns/needs-gate.rs | 10 ++++ .../pattern/deref-patterns/needs-gate.stderr | 18 ++++++- tests/ui/pattern/deref-patterns/strings.rs | 34 ++++++++++++ 7 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 tests/ui/pattern/deref-patterns/byte-string-type-errors.rs create mode 100644 tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index bb85396277c5c..6391e843dc4af 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -759,19 +759,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Byte string patterns behave the same way as array patterns // They can denote both statically and dynamically-sized byte arrays. + // Additionally, when `deref_patterns` is enabled, byte string literal patterns may have + // types `[u8]` or `[u8; N]`, in order to type, e.g., `deref!(b"..."): Vec`. let mut pat_ty = ty; if let hir::PatExprKind::Lit { lit: Spanned { node: ast::LitKind::ByteStr(..), .. }, .. } = lt.kind { + let tcx = self.tcx; let expected = self.structurally_resolve_type(span, expected); - if let ty::Ref(_, inner_ty, _) = *expected.kind() - && self.try_structurally_resolve_type(span, inner_ty).is_slice() - { - let tcx = self.tcx; - trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); - pat_ty = - Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, Ty::new_slice(tcx, tcx.types.u8)); + match *expected.kind() { + // Allow `b"...": &[u8]` + ty::Ref(_, inner_ty, _) + if self.try_structurally_resolve_type(span, inner_ty).is_slice() => + { + trace!(?lt.hir_id.local_id, "polymorphic byte string lit"); + pat_ty = Ty::new_imm_ref( + tcx, + tcx.lifetimes.re_static, + Ty::new_slice(tcx, tcx.types.u8), + ); + } + // Allow `b"...": [u8; 3]` for `deref_patterns` + ty::Array(..) if tcx.features().deref_patterns() => { + pat_ty = match *ty.kind() { + ty::Ref(_, inner_ty, _) => inner_ty, + _ => span_bug!(span, "found byte string literal with non-ref type {ty:?}"), + } + } + // Allow `b"...": [u8]` for `deref_patterns` + ty::Slice(..) if tcx.features().deref_patterns() => { + pat_ty = Ty::new_slice(tcx, tcx.types.u8); + } + // Otherwise, `b"...": &[u8; 3]` + _ => {} } } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index a5ae74280d06e..b4fa55e1c1fdb 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -44,12 +44,16 @@ pub(crate) fn lit_to_const<'tcx>( ty::ValTree::from_raw_bytes(tcx, str_bytes) } (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) - if matches!(inner_ty.kind(), ty::Slice(_)) => + if matches!(inner_ty.kind(), ty::Slice(_) | ty::Array(..)) => { let bytes = data as &[u8]; ty::ValTree::from_raw_bytes(tcx, bytes) } - (ast::LitKind::ByteStr(data, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { + (ast::LitKind::ByteStr(data, _), ty::Slice(_) | ty::Array(..)) + if tcx.features().deref_patterns() => + { + // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is + // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. let bytes = data as &[u8]; ty::ValTree::from_raw_bytes(tcx, bytes) } diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs new file mode 100644 index 0000000000000..29a33e3e2c3b6 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs @@ -0,0 +1,34 @@ +//! Test type errors for byte string literal patterns. `deref_patterns` allows byte string literal +//! patterns to have type `[u8]` or `[u8; N]` when matching on a slice or array; this can affect the +//! "found" type reported in error messages when matching on a slice or array of the wrong type. + +#![feature(deref_patterns)] +#![expect(incomplete_features)] + +fn main() { + // Baseline 1: under normal circumstances, byte string literal patterns have type `&[u8; N]`, + // the same as byte string literals. + if let b"test" = () {} + //~^ ERROR mismatched types + //~| expected `()`, found `&[u8; 4]` + + // Baseline 2: there's a special case for byte string patterns in stable rust, allowing them to + // match on slice references. This affects the error when matching on a non-`&[u8]` slice ref, + // reporting the "found" type as `&[u8]`. + if let b"test" = &[] as &[i8] {} + //~^ ERROR mismatched types + //~| expected `&[i8]`, found `&[u8]` + + // Test matching on a non-`[u8]` slice: the pattern has type `[u8]` if a slice is expected. + if let b"test" = *(&[] as &[i8]) {} + //~^ ERROR mismatched types + //~| expected `[i8]`, found `[u8]` + + // Test matching on a non-`[u8;4]` array: the pattern has type `[u8;4]` if an array is expected. + if let b"test" = [()] {} + //~^ ERROR mismatched types + //~| expected `[(); 1]`, found `[u8; 4]` + if let b"test" = *b"this array is too long" {} + //~^ ERROR mismatched types + //~| expected an array with a size of 22, found one with a size of 4 +} diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr new file mode 100644 index 0000000000000..d29a5b59252c9 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr @@ -0,0 +1,52 @@ +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:11:12 + | +LL | if let b"test" = () {} + | ^^^^^^^ -- this expression has type `()` + | | + | expected `()`, found `&[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:18:12 + | +LL | if let b"test" = &[] as &[i8] {} + | ^^^^^^^ ------------ this expression has type `&[i8]` + | | + | expected `&[i8]`, found `&[u8]` + | + = note: expected reference `&[i8]` + found reference `&'static [u8]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:23:12 + | +LL | if let b"test" = *(&[] as &[i8]) {} + | ^^^^^^^ --------------- this expression has type `[i8]` + | | + | expected `[i8]`, found `[u8]` + | + = note: expected slice `[i8]` + found slice `[u8]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:28:12 + | +LL | if let b"test" = [()] {} + | ^^^^^^^ ---- this expression has type `[(); 1]` + | | + | expected `[(); 1]`, found `[u8; 4]` + | + = note: expected array `[(); 1]` + found array `[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:31:12 + | +LL | if let b"test" = *b"this array is too long" {} + | ^^^^^^^ -------------------------- this expression has type `[u8; 22]` + | | + | expected an array with a size of 22, found one with a size of 4 + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs index a26a4fedc5c51..7944744ee839c 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.rs +++ b/tests/ui/pattern/deref-patterns/needs-gate.rs @@ -19,4 +19,14 @@ fn main() { //~^ ERROR: mismatched types _ => {} } + match *b"test" { + b"test" => {} + //~^ ERROR: mismatched types + _ => {} + } + match *(b"test" as &[u8]) { + b"test" => {} + //~^ ERROR: mismatched types + _ => {} + } } diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr index b1ae03753fec7..e886ca9805581 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.stderr +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -31,7 +31,23 @@ LL | match *"test" { LL | "test" => {} | ^^^^^^ expected `str`, found `&str` -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:23:9 + | +LL | match *b"test" { + | -------- this expression has type `[u8; 4]` +LL | b"test" => {} + | ^^^^^^^ expected `[u8; 4]`, found `&[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:28:9 + | +LL | match *(b"test" as &[u8]) { + | ------------------- this expression has type `[u8]` +LL | b"test" => {} + | ^^^^^^^ expected `[u8]`, found `&[u8; 4]` + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/strings.rs b/tests/ui/pattern/deref-patterns/strings.rs index b55451e318179..536e943b3f672 100644 --- a/tests/ui/pattern/deref-patterns/strings.rs +++ b/tests/ui/pattern/deref-patterns/strings.rs @@ -29,4 +29,38 @@ fn main() { s.make_ascii_uppercase(); } assert_eq!(test, "TEST"); + + for (test_in, test_expect) in [(b"0", 0), (b"1", 1), (b"2", 2)] { + // Test byte string literal patterns having type `[u8; N]` + let test_actual = match *test_in { + b"0" => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literal patterns having type `[u8]` + let test_actual = match *(test_in as &[u8]) { + b"0" => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literals used as arrays in explicit `deref!(_)` patterns. + let test_actual = match Box::new(*test_in) { + deref!(b"0") => 0, + deref!(b"1") => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literals used as slices in explicit `deref!(_)` patterns. + let test_actual = match test_in.to_vec() { + deref!(b"0") => 0, + deref!(b"1") => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + } } From 4c7e866fc8e0d4025c3e9c97dde8688b4a0dd8f8 Mon Sep 17 00:00:00 2001 From: dianne Date: Fri, 18 Apr 2025 21:49:40 -0700 Subject: [PATCH 08/15] update unstable book to mention string/bytestring typing --- .../src/language-features/deref-patterns.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md index d0102a665b0b0..d0a64538e8ccc 100644 --- a/src/doc/unstable-book/src/language-features/deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -54,4 +54,25 @@ if let [b] = &mut *v { assert_eq!(v, [Box::new(Some(2))]); ``` +Additionally, when `deref_patterns` is enabled, string literal patterns may be written where `str` +is expected. Likewise, byte string literal patterns may be written where `[u8]` or `[u8; _]` is +expected. This lets them be used in `deref!(_)` patterns: + +```rust +# #![feature(deref_patterns)] +# #![allow(incomplete_features)] +match ("test".to_string(), b"test".to_vec()) { + (deref!("test"), deref!(b"test")) => {} + _ => panic!(), +} + +// Matching on slices and arrays using literals is possible elsewhere as well: +match *"test" { + "test" => {} + _ => panic!(), +} +``` + +Implicit deref pattern syntax is not yet supported for string or byte string literals. + [smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors From 19e44d463bf671f6ec1b02b32837ad54dd5d626f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Apr 2025 07:41:27 -0700 Subject: [PATCH 09/15] Don't warn about `v128` in wasm ABI transition This has other warnings if necessary and doesn't need extra warnings from this FCW. cc #138762 --- .../src/mono_checks/abi_check.rs | 6 ++++ tests/ui/lint/wasm_c_abi_transition.rs | 12 ++++++- tests/ui/lint/wasm_c_abi_transition.stderr | 31 ++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 94ee34c8b7bf3..81bf8c5d21c73 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -99,6 +99,12 @@ fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool return true; } + // Both the old and the new ABIs treat vector types like `v128` the same + // way. + if uses_vector_registers(&arg.mode, &arg.layout.backend_repr) { + return true; + } + // This matches `unwrap_trivial_aggregate` in the wasm ABI logic. if arg.layout.is_aggregate() { let cx = LayoutCx::new(tcx, TypingEnv::fully_monomorphized()); diff --git a/tests/ui/lint/wasm_c_abi_transition.rs b/tests/ui/lint/wasm_c_abi_transition.rs index 6a933a0de036f..411772ae890b7 100644 --- a/tests/ui/lint/wasm_c_abi_transition.rs +++ b/tests/ui/lint/wasm_c_abi_transition.rs @@ -3,7 +3,7 @@ //@ add-core-stubs //@ build-fail -#![feature(no_core)] +#![feature(no_core, repr_simd)] #![no_core] #![crate_type = "lib"] #![deny(wasm_c_abi)] @@ -45,3 +45,13 @@ pub fn call_other_fun(x: MyType) { pub struct MyZstType; #[allow(improper_ctypes_definitions)] pub extern "C" fn zst_safe(_x: (), _y: MyZstType) {} + +// The old and new wasm ABI treats simd types like `v128` the same way, so no +// wasm_c_abi warning should be emitted. +#[repr(simd)] +#[allow(non_camel_case_types)] +pub struct v128([i32; 4]); +#[target_feature(enable = "simd128")] +pub extern "C" fn my_safe_simd(x: v128) -> v128 { x } +//~^ WARN `extern` fn uses type `v128`, which is not FFI-safe +//~| WARN `extern` fn uses type `v128`, which is not FFI-safe diff --git a/tests/ui/lint/wasm_c_abi_transition.stderr b/tests/ui/lint/wasm_c_abi_transition.stderr index 389710d5cb3a2..b4526bf8d6873 100644 --- a/tests/ui/lint/wasm_c_abi_transition.stderr +++ b/tests/ui/lint/wasm_c_abi_transition.stderr @@ -1,3 +1,32 @@ +warning: `extern` fn uses type `v128`, which is not FFI-safe + --> $DIR/wasm_c_abi_transition.rs:55:35 + | +LL | pub extern "C" fn my_safe_simd(x: v128) -> v128 { x } + | ^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/wasm_c_abi_transition.rs:53:1 + | +LL | pub struct v128([i32; 4]); + | ^^^^^^^^^^^^^^^ + = note: `#[warn(improper_ctypes_definitions)]` on by default + +warning: `extern` fn uses type `v128`, which is not FFI-safe + --> $DIR/wasm_c_abi_transition.rs:55:44 + | +LL | pub extern "C" fn my_safe_simd(x: v128) -> v128 { x } + | ^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/wasm_c_abi_transition.rs:53:1 + | +LL | pub struct v128([i32; 4]); + | ^^^^^^^^^^^^^^^ + error: this function definition involves an argument of type `MyType` which is affected by the wasm ABI transition --> $DIR/wasm_c_abi_transition.rs:18:1 | @@ -33,7 +62,7 @@ LL | unsafe { other_fun(x) } = note: for more information, see issue #138762 = help: the "C" ABI Rust uses on wasm32-unknown-unknown will change to align with the standard "C" ABI for this target -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 2 warnings emitted Future incompatibility report: Future breakage diagnostic: error: this function definition involves an argument of type `MyType` which is affected by the wasm ABI transition From 51088fdcee082e2edcc08b26b7a248ee2efbb821 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 23 Apr 2025 11:07:26 +1000 Subject: [PATCH 10/15] Remove `synstructure::Structure::underscore_const` calls. The `synstructure` docs say "This method is a no-op, underscore consts are used by default now." The behaviour change occurred going from `synstructure` version 0.13.0 to 0.13.1. --- compiler/rustc_macros/src/diagnostics/mod.rs | 9 +++------ compiler/rustc_macros/src/hash_stable.rs | 2 -- compiler/rustc_macros/src/lift.rs | 1 - compiler/rustc_macros/src/serialize.rs | 12 +----------- compiler/rustc_macros/src/type_foldable.rs | 2 -- compiler/rustc_macros/src/type_visitable.rs | 2 -- 6 files changed, 4 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 91398f1a9da9d..55228248188e5 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -55,8 +55,7 @@ use synstructure::Structure; /// /// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`: /// -pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream { - s.underscore_const(true); +pub(super) fn diagnostic_derive(s: Structure<'_>) -> TokenStream { DiagnosticDerive::new(s).into_tokens() } @@ -102,8 +101,7 @@ pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream { /// /// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`: /// -pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream { - s.underscore_const(true); +pub(super) fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { LintDiagnosticDerive::new(s).into_tokens() } @@ -153,7 +151,6 @@ pub(super) fn lint_diagnostic_derive(mut s: Structure<'_>) -> TokenStream { /// /// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident }); /// ``` -pub(super) fn subdiagnostic_derive(mut s: Structure<'_>) -> TokenStream { - s.underscore_const(true); +pub(super) fn subdiagnostic_derive(s: Structure<'_>) -> TokenStream { SubdiagnosticDerive::new().into_tokens(s) } diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs index 6b3210cad7be6..a6396ba687d11 100644 --- a/compiler/rustc_macros/src/hash_stable.rs +++ b/compiler/rustc_macros/src/hash_stable.rs @@ -74,8 +74,6 @@ fn hash_stable_derive_with_mode( HashStableMode::Generic | HashStableMode::NoContext => parse_quote!(__CTX), }; - s.underscore_const(true); - // no_context impl is able to derive by-field, which is closer to a perfect derive. s.add_bounds(match mode { HashStableMode::Normal | HashStableMode::Generic => synstructure::AddBounds::Generics, diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index 341447f7e6f26..03ea396a42c75 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -4,7 +4,6 @@ use syn::parse_quote; pub(super) fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { s.add_bounds(synstructure::AddBounds::Generics); s.bind_with(|_| synstructure::BindStyle::Move); - s.underscore_const(true); let tcx: syn::Lifetime = parse_quote!('tcx); let newtcx: syn::GenericParam = parse_quote!('__lifted); diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 673e6cd618ff8..c7aaaf0da4679 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -12,7 +12,6 @@ pub(super) fn type_decodable_derive( let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx> }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -26,7 +25,6 @@ pub(super) fn meta_decodable_derive( s.add_impl_generic(parse_quote! { '__a }); let decoder_ty = quote! { DecodeContext<'__a, 'tcx> }; s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -35,7 +33,6 @@ pub(super) fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_span::SpanDecoder }); s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); decodable_body(s, decoder_ty) } @@ -46,13 +43,12 @@ pub(super) fn decodable_nocontext_derive( let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_serialize::Decoder }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); decodable_body(s, decoder_ty) } fn decodable_body( - mut s: synstructure::Structure<'_>, + s: synstructure::Structure<'_>, decoder_ty: TokenStream, ) -> proc_macro2::TokenStream { if let syn::Data::Union(_) = s.ast().data { @@ -98,7 +94,6 @@ fn decodable_body( } } }; - s.underscore_const(true); s.bound_impl( quote!(::rustc_serialize::Decodable<#decoder_ty>), @@ -133,7 +128,6 @@ pub(super) fn type_encodable_derive( } s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx> }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -147,7 +141,6 @@ pub(super) fn meta_encodable_derive( s.add_impl_generic(parse_quote! { '__a }); let encoder_ty = quote! { EncodeContext<'__a, 'tcx> }; s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); encodable_body(s, encoder_ty, true) } @@ -156,7 +149,6 @@ pub(super) fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_span::SpanEncoder }); s.add_bounds(synstructure::AddBounds::Generics); - s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -167,7 +159,6 @@ pub(super) fn encodable_nocontext_derive( let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder }); s.add_bounds(synstructure::AddBounds::Fields); - s.underscore_const(true); encodable_body(s, encoder_ty, false) } @@ -181,7 +172,6 @@ fn encodable_body( panic!("cannot derive on union") } - s.underscore_const(true); s.bind_with(|binding| { // Handle the lack of a blanket reference impl. if let syn::Type::Reference(_) = binding.ast().ty { diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index 85051311bee9e..91b747f18569d 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -6,8 +6,6 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m panic!("cannot derive on union") } - s.underscore_const(true); - if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { s.add_impl_generic(parse_quote! { 'tcx }); } diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index fb37e1a39edbe..f99c5113a6053 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -8,8 +8,6 @@ pub(super) fn type_visitable_derive( panic!("cannot derive on union") } - s.underscore_const(true); - // ignore fields with #[type_visitable(ignore)] s.filter(|bi| { let mut ignored = false; From 5b390cdc58fb7f0f0a162f96c55b36641666cbb7 Mon Sep 17 00:00:00 2001 From: Makai Date: Wed, 23 Apr 2025 12:28:14 +0800 Subject: [PATCH 11/15] Make `SmirInterface` pub(crate) and rename `Context` to `SmirContext` Co-authored-by: Celina G. Val --- compiler/rustc_smir/src/rustc_internal/mod.rs | 8 +- compiler/rustc_smir/src/rustc_smir/context.rs | 14 +- .../src/stable_mir/compiler_interface.rs | 194 ++++++++++-------- 3 files changed, 114 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index c6f8b1f0047ed..69582bd054f62 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -21,7 +21,7 @@ use stable_mir::abi::Layout; use stable_mir::compiler_interface::SmirInterface; use stable_mir::ty::IndexedVal; -use crate::rustc_smir::context::Context; +use crate::rustc_smir::context::SmirCtxt; use crate::rustc_smir::{Stable, Tables}; use crate::stable_mir; @@ -197,7 +197,7 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum { // datastructures and stable MIR datastructures scoped_thread_local! (static TLV: Cell<*const ()>); -pub(crate) fn init<'tcx, F, T>(cx: &Context<'tcx>, f: F) -> T +pub(crate) fn init<'tcx, F, T>(cx: &SmirCtxt<'tcx>, f: F) -> T where F: FnOnce() -> T, { @@ -213,7 +213,7 @@ pub(crate) fn with_tables(f: impl for<'tcx> FnOnce(&mut Tables<'tcx>) -> R) - TLV.with(|tlv| { let ptr = tlv.get(); assert!(!ptr.is_null()); - let context = ptr as *const Context<'_>; + let context = ptr as *const SmirCtxt<'_>; let mut tables = unsafe { (*context).0.borrow_mut() }; f(&mut *tables) }) @@ -223,7 +223,7 @@ pub fn run(tcx: TyCtxt<'_>, f: F) -> Result where F: FnOnce() -> T, { - let tables = Context(RefCell::new(Tables { + let tables = SmirCtxt(RefCell::new(Tables { tcx, def_ids: IndexMap::default(), alloc_ids: IndexMap::default(), diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index ed13e04bf2918..9a4cac243bd39 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -1,7 +1,4 @@ -//! Implementation of `[stable_mir::compiler_interface::Context]` trait. -//! -//! This trait is currently the main interface between the Rust compiler, -//! and the `stable_mir` crate. +//! Implementation of StableMIR Context. #![allow(rustc::usage_of_qualified_ty)] @@ -36,10 +33,13 @@ use crate::rustc_smir::builder::BodyBuilder; use crate::rustc_smir::{Stable, Tables, alloc, filter_def_ids, new_item_kind, smir_crate}; use crate::stable_mir; -/// Internal context holding direct rustc access. -pub struct Context<'tcx>(pub RefCell>); +/// Provides direct access to rustc's internal queries. +/// +/// The [`crate::stable_mir::compiler_interface::SmirInterface`] must go through +/// this context to obtain rustc-level information. +pub struct SmirCtxt<'tcx>(pub RefCell>); -impl<'tcx> Context<'tcx> { +impl<'tcx> SmirCtxt<'tcx> { pub fn target_info(&self) -> MachineInfo { let mut tables = self.0.borrow_mut(); MachineInfo { diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs index 58e6c6d7a93fe..cd61907dc6baa 100644 --- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs +++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs @@ -5,7 +5,7 @@ use std::cell::Cell; -use rustc_smir::context::Context; +use rustc_smir::context::SmirCtxt; use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::crate_def::Attribute; use stable_mir::mir::alloc::{AllocId, GlobalAlloc}; @@ -27,110 +27,110 @@ use crate::{rustc_smir, stable_mir}; /// Stable public API for querying compiler information. /// -/// All queries are delegated to an internal [`Context`] that provides +/// All queries are delegated to an internal [`SmirCtxt`] that provides /// similar APIs but based on internal rustc constructs. /// /// Do not use this directly. This is currently used in the macro expansion. -pub struct SmirInterface<'tcx> { - pub(crate) cx: Context<'tcx>, +pub(crate) struct SmirInterface<'tcx> { + pub(crate) cx: SmirCtxt<'tcx>, } impl<'tcx> SmirInterface<'tcx> { - pub fn entry_fn(&self) -> Option { + pub(crate) fn entry_fn(&self) -> Option { self.cx.entry_fn() } /// Retrieve all items of the local crate that have a MIR associated with them. - pub fn all_local_items(&self) -> CrateItems { + pub(crate) fn all_local_items(&self) -> CrateItems { self.cx.all_local_items() } /// Retrieve the body of a function. /// This function will panic if the body is not available. - pub fn mir_body(&self, item: DefId) -> mir::Body { + pub(crate) fn mir_body(&self, item: DefId) -> mir::Body { self.cx.mir_body(item) } /// Check whether the body of a function is available. - pub fn has_body(&self, item: DefId) -> bool { + pub(crate) fn has_body(&self, item: DefId) -> bool { self.cx.has_body(item) } - pub fn foreign_modules(&self, crate_num: CrateNum) -> Vec { + pub(crate) fn foreign_modules(&self, crate_num: CrateNum) -> Vec { self.cx.foreign_modules(crate_num) } /// Retrieve all functions defined in this crate. - pub fn crate_functions(&self, crate_num: CrateNum) -> Vec { + pub(crate) fn crate_functions(&self, crate_num: CrateNum) -> Vec { self.cx.crate_functions(crate_num) } /// Retrieve all static items defined in this crate. - pub fn crate_statics(&self, crate_num: CrateNum) -> Vec { + pub(crate) fn crate_statics(&self, crate_num: CrateNum) -> Vec { self.cx.crate_statics(crate_num) } - pub fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule { + pub(crate) fn foreign_module(&self, mod_def: ForeignModuleDef) -> ForeignModule { self.cx.foreign_module(mod_def) } - pub fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec { + pub(crate) fn foreign_items(&self, mod_def: ForeignModuleDef) -> Vec { self.cx.foreign_items(mod_def) } - pub fn all_trait_decls(&self) -> TraitDecls { + pub(crate) fn all_trait_decls(&self) -> TraitDecls { self.cx.all_trait_decls() } - pub fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls { + pub(crate) fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls { self.cx.trait_decls(crate_num) } - pub fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl { + pub(crate) fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl { self.cx.trait_decl(trait_def) } - pub fn all_trait_impls(&self) -> ImplTraitDecls { + pub(crate) fn all_trait_impls(&self) -> ImplTraitDecls { self.cx.all_trait_impls() } - pub fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls { + pub(crate) fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls { self.cx.trait_impls(crate_num) } - pub fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait { + pub(crate) fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait { self.cx.trait_impl(trait_impl) } - pub fn generics_of(&self, def_id: DefId) -> Generics { + pub(crate) fn generics_of(&self, def_id: DefId) -> Generics { self.cx.generics_of(def_id) } - pub fn predicates_of(&self, def_id: DefId) -> GenericPredicates { + pub(crate) fn predicates_of(&self, def_id: DefId) -> GenericPredicates { self.cx.predicates_of(def_id) } - pub fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates { + pub(crate) fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates { self.cx.explicit_predicates_of(def_id) } /// Get information about the local crate. - pub fn local_crate(&self) -> Crate { + pub(crate) fn local_crate(&self) -> Crate { self.cx.local_crate() } /// Retrieve a list of all external crates. - pub fn external_crates(&self) -> Vec { + pub(crate) fn external_crates(&self) -> Vec { self.cx.external_crates() } /// Find a crate with the given name. - pub fn find_crates(&self, name: &str) -> Vec { + pub(crate) fn find_crates(&self, name: &str) -> Vec { self.cx.find_crates(name) } /// Returns the name of given `DefId`. - pub fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol { + pub(crate) fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol { self.cx.def_name(def_id, trimmed) } @@ -141,244 +141,252 @@ impl<'tcx> SmirInterface<'tcx> { /// /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. - pub fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec { + pub(crate) fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec { self.cx.tool_attrs(def_id, attr) } /// Get all tool attributes of a definition. - pub fn all_tool_attrs(&self, def_id: DefId) -> Vec { + pub(crate) fn all_tool_attrs(&self, def_id: DefId) -> Vec { self.cx.all_tool_attrs(def_id) } /// Returns printable, human readable form of `Span`. - pub fn span_to_string(&self, span: Span) -> String { + pub(crate) fn span_to_string(&self, span: Span) -> String { self.cx.span_to_string(span) } /// Return filename from given `Span`, for diagnostic purposes. - pub fn get_filename(&self, span: &Span) -> Filename { + pub(crate) fn get_filename(&self, span: &Span) -> Filename { self.cx.get_filename(span) } /// Return lines corresponding to this `Span`. - pub fn get_lines(&self, span: &Span) -> LineInfo { + pub(crate) fn get_lines(&self, span: &Span) -> LineInfo { self.cx.get_lines(span) } /// Returns the `kind` of given `DefId`. - pub fn item_kind(&self, item: CrateItem) -> ItemKind { + pub(crate) fn item_kind(&self, item: CrateItem) -> ItemKind { self.cx.item_kind(item) } /// Returns whether this is a foreign item. - pub fn is_foreign_item(&self, item: DefId) -> bool { + pub(crate) fn is_foreign_item(&self, item: DefId) -> bool { self.cx.is_foreign_item(item) } /// Returns the kind of a given foreign item. - pub fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { + pub(crate) fn foreign_item_kind(&self, def: ForeignDef) -> ForeignItemKind { self.cx.foreign_item_kind(def) } /// Returns the kind of a given algebraic data type. - pub fn adt_kind(&self, def: AdtDef) -> AdtKind { + pub(crate) fn adt_kind(&self, def: AdtDef) -> AdtKind { self.cx.adt_kind(def) } /// Returns if the ADT is a box. - pub fn adt_is_box(&self, def: AdtDef) -> bool { + pub(crate) fn adt_is_box(&self, def: AdtDef) -> bool { self.cx.adt_is_box(def) } /// Returns whether this ADT is simd. - pub fn adt_is_simd(&self, def: AdtDef) -> bool { + pub(crate) fn adt_is_simd(&self, def: AdtDef) -> bool { self.cx.adt_is_simd(def) } /// Returns whether this definition is a C string. - pub fn adt_is_cstr(&self, def: AdtDef) -> bool { + pub(crate) fn adt_is_cstr(&self, def: AdtDef) -> bool { self.cx.adt_is_cstr(def) } /// Retrieve the function signature for the given generic arguments. - pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { + pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { self.cx.fn_sig(def, args) } /// Retrieve the intrinsic definition if the item corresponds one. - pub fn intrinsic(&self, item: DefId) -> Option { + pub(crate) fn intrinsic(&self, item: DefId) -> Option { self.cx.intrinsic(item) } /// Retrieve the plain function name of an intrinsic. - pub fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { + pub(crate) fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol { self.cx.intrinsic_name(def) } /// Retrieve the closure signature for the given generic arguments. - pub fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { + pub(crate) fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { self.cx.closure_sig(args) } /// The number of variants in this ADT. - pub fn adt_variants_len(&self, def: AdtDef) -> usize { + pub(crate) fn adt_variants_len(&self, def: AdtDef) -> usize { self.cx.adt_variants_len(def) } /// The name of a variant. - pub fn variant_name(&self, def: VariantDef) -> Symbol { + pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol { self.cx.variant_name(def) } - pub fn variant_fields(&self, def: VariantDef) -> Vec { + pub(crate) fn variant_fields(&self, def: VariantDef) -> Vec { self.cx.variant_fields(def) } /// Evaluate constant as a target usize. - pub fn eval_target_usize(&self, cnst: &MirConst) -> Result { + pub(crate) fn eval_target_usize(&self, cnst: &MirConst) -> Result { self.cx.eval_target_usize(cnst) } - pub fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { + pub(crate) fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result { self.cx.eval_target_usize_ty(cnst) } /// Create a new zero-sized constant. - pub fn try_new_const_zst(&self, ty: Ty) -> Result { + pub(crate) fn try_new_const_zst(&self, ty: Ty) -> Result { self.cx.try_new_const_zst(ty) } /// Create a new constant that represents the given string value. - pub fn new_const_str(&self, value: &str) -> MirConst { + pub(crate) fn new_const_str(&self, value: &str) -> MirConst { self.cx.new_const_str(value) } /// Create a new constant that represents the given boolean value. - pub fn new_const_bool(&self, value: bool) -> MirConst { + pub(crate) fn new_const_bool(&self, value: bool) -> MirConst { self.cx.new_const_bool(value) } /// Create a new constant that represents the given value. - pub fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + pub(crate) fn try_new_const_uint( + &self, + value: u128, + uint_ty: UintTy, + ) -> Result { self.cx.try_new_const_uint(value, uint_ty) } - pub fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result { + pub(crate) fn try_new_ty_const_uint( + &self, + value: u128, + uint_ty: UintTy, + ) -> Result { self.cx.try_new_ty_const_uint(value, uint_ty) } /// Create a new type from the given kind. - pub fn new_rigid_ty(&self, kind: RigidTy) -> Ty { + pub(crate) fn new_rigid_ty(&self, kind: RigidTy) -> Ty { self.cx.new_rigid_ty(kind) } /// Create a new box type, `Box`, for the given inner type `T`. - pub fn new_box_ty(&self, ty: Ty) -> Ty { + pub(crate) fn new_box_ty(&self, ty: Ty) -> Ty { self.cx.new_box_ty(ty) } /// Returns the type of given crate item. - pub fn def_ty(&self, item: DefId) -> Ty { + pub(crate) fn def_ty(&self, item: DefId) -> Ty { self.cx.def_ty(item) } /// Returns the type of given definition instantiated with the given arguments. - pub fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty { + pub(crate) fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty { self.cx.def_ty_with_args(item, args) } /// Returns literal value of a const as a string. - pub fn mir_const_pretty(&self, cnst: &MirConst) -> String { + pub(crate) fn mir_const_pretty(&self, cnst: &MirConst) -> String { self.cx.mir_const_pretty(cnst) } /// `Span` of an item. - pub fn span_of_an_item(&self, def_id: DefId) -> Span { + pub(crate) fn span_of_an_item(&self, def_id: DefId) -> Span { self.cx.span_of_an_item(def_id) } - pub fn ty_const_pretty(&self, ct: TyConstId) -> String { + pub(crate) fn ty_const_pretty(&self, ct: TyConstId) -> String { self.cx.ty_const_pretty(ct) } /// Obtain the representation of a type. - pub fn ty_pretty(&self, ty: Ty) -> String { + pub(crate) fn ty_pretty(&self, ty: Ty) -> String { self.cx.ty_pretty(ty) } /// Obtain the representation of a type. - pub fn ty_kind(&self, ty: Ty) -> TyKind { + pub(crate) fn ty_kind(&self, ty: Ty) -> TyKind { self.cx.ty_kind(ty) } /// Get the discriminant Ty for this Ty if there's one. - pub fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty { + pub(crate) fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> Ty { self.cx.rigid_ty_discriminant_ty(ty) } /// Get the body of an Instance which is already monomorphized. - pub fn instance_body(&self, instance: InstanceDef) -> Option { + pub(crate) fn instance_body(&self, instance: InstanceDef) -> Option { self.cx.instance_body(instance) } /// Get the instance type with generic instantiations applied and lifetimes erased. - pub fn instance_ty(&self, instance: InstanceDef) -> Ty { + pub(crate) fn instance_ty(&self, instance: InstanceDef) -> Ty { self.cx.instance_ty(instance) } /// Get the instantiation types. - pub fn instance_args(&self, def: InstanceDef) -> GenericArgs { + pub(crate) fn instance_args(&self, def: InstanceDef) -> GenericArgs { self.cx.instance_args(def) } /// Get the instance. - pub fn instance_def_id(&self, instance: InstanceDef) -> DefId { + pub(crate) fn instance_def_id(&self, instance: InstanceDef) -> DefId { self.cx.instance_def_id(instance) } /// Get the instance mangled name. - pub fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { + pub(crate) fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol { self.cx.instance_mangled_name(instance) } /// Check if this is an empty DropGlue shim. - pub fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { + pub(crate) fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { self.cx.is_empty_drop_shim(def) } /// Check if this is an empty AsyncDropGlueCtor shim. - pub fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { + pub(crate) fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { self.cx.is_empty_async_drop_ctor_shim(def) } /// Convert a non-generic crate item into an instance. /// This function will panic if the item is generic. - pub fn mono_instance(&self, def_id: DefId) -> Instance { + pub(crate) fn mono_instance(&self, def_id: DefId) -> Instance { self.cx.mono_instance(def_id) } /// Item requires monomorphization. - pub fn requires_monomorphization(&self, def_id: DefId) -> bool { + pub(crate) fn requires_monomorphization(&self, def_id: DefId) -> bool { self.cx.requires_monomorphization(def_id) } /// Resolve an instance from the given function definition and generic arguments. - pub fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option { + pub(crate) fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option { self.cx.resolve_instance(def, args) } /// Resolve an instance for drop_in_place for the given type. - pub fn resolve_drop_in_place(&self, ty: Ty) -> Instance { + pub(crate) fn resolve_drop_in_place(&self, ty: Ty) -> Instance { self.cx.resolve_drop_in_place(ty) } /// Resolve instance for a function pointer. - pub fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option { + pub(crate) fn resolve_for_fn_ptr(&self, def: FnDef, args: &GenericArgs) -> Option { self.cx.resolve_for_fn_ptr(def, args) } /// Resolve instance for a closure with the requested type. - pub fn resolve_closure( + pub(crate) fn resolve_closure( &self, def: ClosureDef, args: &GenericArgs, @@ -388,75 +396,79 @@ impl<'tcx> SmirInterface<'tcx> { } /// Evaluate a static's initializer. - pub fn eval_static_initializer(&self, def: StaticDef) -> Result { + pub(crate) fn eval_static_initializer(&self, def: StaticDef) -> Result { self.cx.eval_static_initializer(def) } /// Try to evaluate an instance into a constant. - pub fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result { + pub(crate) fn eval_instance( + &self, + def: InstanceDef, + const_ty: Ty, + ) -> Result { self.cx.eval_instance(def, const_ty) } /// Retrieve global allocation for the given allocation ID. - pub fn global_alloc(&self, id: AllocId) -> GlobalAlloc { + pub(crate) fn global_alloc(&self, id: AllocId) -> GlobalAlloc { self.cx.global_alloc(id) } /// Retrieve the id for the virtual table. - pub fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option { + pub(crate) fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option { self.cx.vtable_allocation(global_alloc) } - pub fn krate(&self, def_id: DefId) -> Crate { + pub(crate) fn krate(&self, def_id: DefId) -> Crate { self.cx.krate(def_id) } - pub fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { + pub(crate) fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol { self.cx.instance_name(def, trimmed) } /// Return information about the target machine. - pub fn target_info(&self) -> MachineInfo { + pub(crate) fn target_info(&self) -> MachineInfo { self.cx.target_info() } /// Get an instance ABI. - pub fn instance_abi(&self, def: InstanceDef) -> Result { + pub(crate) fn instance_abi(&self, def: InstanceDef) -> Result { self.cx.instance_abi(def) } /// Get the ABI of a function pointer. - pub fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { + pub(crate) fn fn_ptr_abi(&self, fn_ptr: PolyFnSig) -> Result { self.cx.fn_ptr_abi(fn_ptr) } /// Get the layout of a type. - pub fn ty_layout(&self, ty: Ty) -> Result { + pub(crate) fn ty_layout(&self, ty: Ty) -> Result { self.cx.ty_layout(ty) } /// Get the layout shape. - pub fn layout_shape(&self, id: Layout) -> LayoutShape { + pub(crate) fn layout_shape(&self, id: Layout) -> LayoutShape { self.cx.layout_shape(id) } /// Get a debug string representation of a place. - pub fn place_pretty(&self, place: &Place) -> String { + pub(crate) fn place_pretty(&self, place: &Place) -> String { self.cx.place_pretty(place) } /// Get the resulting type of binary operation. - pub fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { + pub(crate) fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { self.cx.binop_ty(bin_op, rhs, lhs) } /// Get the resulting type of unary operation. - pub fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { + pub(crate) fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { self.cx.unop_ty(un_op, arg) } /// Get all associated items of a definition. - pub fn associated_items(&self, def_id: DefId) -> AssocItems { + pub(crate) fn associated_items(&self, def_id: DefId) -> AssocItems { self.cx.associated_items(def_id) } } @@ -464,7 +476,7 @@ impl<'tcx> SmirInterface<'tcx> { // A thread local variable that stores a pointer to [`SmirInterface`]. scoped_tls::scoped_thread_local!(static TLV: Cell<*const ()>); -pub fn run<'tcx, T, F>(interface: &SmirInterface<'tcx>, f: F) -> Result +pub(crate) fn run<'tcx, T, F>(interface: &SmirInterface<'tcx>, f: F) -> Result where F: FnOnce() -> T, { From 780f95dd182b1a432159430add57e9ab7cb45dd6 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Mon, 7 Apr 2025 00:04:57 +1000 Subject: [PATCH 12/15] Impl new API `std::os::unix::fs::mkfifo` under feature `unix_fifo` Tracking issue #139324 Signed-off-by: Jiahao XU --- library/std/src/os/unix/fs.rs | 36 +++++++++++++++++++++++++++++ library/std/src/os/unix/fs/tests.rs | 20 ++++++++++++++++ library/std/src/sys/fs/mod.rs | 2 +- library/std/src/sys/fs/unix.rs | 6 +++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 0427feb29550f..4f9259f39c1ab 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -1100,3 +1100,39 @@ pub fn lchown>(dir: P, uid: Option, gid: Option) -> io: pub fn chroot>(dir: P) -> io::Result<()> { sys::fs::chroot(dir.as_ref()) } + +/// Create a FIFO special file at the specified path with the specified mode. +/// +/// # Examples +/// +/// ```no_run +/// # #![feature(unix_mkfifo)] +/// # #[cfg(not(unix))] +/// # fn main() {} +/// # #[cfg(unix)] +/// # fn main() -> std::io::Result<()> { +/// # use std::{ +/// # os::unix::fs::{mkfifo, PermissionsExt}, +/// # fs::{File, Permissions, remove_file}, +/// # io::{Write, Read}, +/// # }; +/// # let _ = remove_file("/tmp/fifo"); +/// mkfifo("/tmp/fifo", Permissions::from_mode(0o774))?; +/// +/// let mut wx = File::options().read(true).write(true).open("/tmp/fifo")?; +/// let mut rx = File::open("/tmp/fifo")?; +/// +/// wx.write_all(b"hello, world!")?; +/// drop(wx); +/// +/// let mut s = String::new(); +/// rx.read_to_string(&mut s)?; +/// +/// assert_eq!(s, "hello, world!"); +/// # Ok(()) +/// # } +/// ``` +#[unstable(feature = "unix_mkfifo", issue = "139324")] +pub fn mkfifo>(path: P, permissions: Permissions) -> io::Result<()> { + sys::fs::mkfifo(path.as_ref(), permissions.mode()) +} diff --git a/library/std/src/os/unix/fs/tests.rs b/library/std/src/os/unix/fs/tests.rs index db9621c8c205c..1840bb38c17c8 100644 --- a/library/std/src/os/unix/fs/tests.rs +++ b/library/std/src/os/unix/fs/tests.rs @@ -55,3 +55,23 @@ fn write_vectored_at() { let content = fs::read(&filename).unwrap(); assert_eq!(&content, expected); } + +#[test] +fn test_mkfifo() { + let tmp_dir = crate::test_helpers::tmpdir(); + + let fifo = tmp_dir.path().join("fifo"); + + mkfifo(&fifo, Permissions::from_mode(0o774)).unwrap(); + + let mut wx = fs::File::options().read(true).write(true).open(&fifo).unwrap(); + let mut rx = fs::File::open(fifo).unwrap(); + + wx.write_all(b"hello, world!").unwrap(); + drop(wx); + + let mut s = String::new(); + rx.read_to_string(&mut s).unwrap(); + + assert_eq!(s, "hello, world!"); +} diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index 3b176d0d16c44..221795077fa67 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -9,7 +9,7 @@ cfg_if::cfg_if! { if #[cfg(target_family = "unix")] { mod unix; use unix as imp; - pub use unix::{chown, fchown, lchown}; + pub use unix::{chown, fchown, lchown, mkfifo}; #[cfg(not(target_os = "fuchsia"))] pub use unix::chroot; pub(crate) use unix::debug_assert_fd_is_open; diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 87865be0387d5..018e7e98c23e3 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2148,6 +2148,12 @@ pub fn chroot(dir: &Path) -> io::Result<()> { Err(io::const_error!(io::ErrorKind::Unsupported, "chroot not supported by vxworks")) } +pub fn mkfifo(path: &Path, mode: u32) -> io::Result<()> { + run_path_with_cstr(path, &|path| { + cvt(unsafe { libc::mkfifo(path.as_ptr(), mode.try_into().unwrap()) }).map(|_| ()) + }) +} + pub use remove_dir_impl::remove_dir_all; // Fallback for REDOX, ESP-ID, Horizon, Vita, Vxworks and Miri From 2a5c349f422657f614bd44a36a28fa2f761f30ed Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Fri, 28 Mar 2025 08:45:33 -0400 Subject: [PATCH 13/15] Extend HIR to track the source and syntax of a lifetime An upcoming lint will want to be able to know if a lifetime is hidden (e.g. `&u8`, `ContainsLifetime`) or anonymous: (e.g. `&'_ u8`, `ContainsLifetime<'_>`). It will also want to know if the lifetime is related to a reference (`&u8`) or a path (`ContainsLifetime`). --- compiler/rustc_ast_lowering/src/item.rs | 11 +- compiler/rustc_ast_lowering/src/lib.rs | 121 ++++++++------ compiler/rustc_ast_lowering/src/path.rs | 17 +- compiler/rustc_hir/src/hir.rs | 159 +++++++++++++++---- compiler/rustc_hir/src/hir/tests.rs | 3 +- compiler/rustc_trait_selection/src/errors.rs | 27 +--- 6 files changed, 226 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fc32c4efce56a..c009abd729da9 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -5,7 +5,7 @@ use rustc_ast::*; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; -use rustc_hir::{self as hir, HirId, IsAnonInPath, PredicateOrigin}; +use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; @@ -1868,7 +1868,8 @@ impl<'hir> LoweringContext<'_, 'hir> { } GenericParamKind::Lifetime => { let lt_id = self.next_node_id(); - let lifetime = self.new_named_lifetime(id, lt_id, ident, IsAnonInPath::No); + let lifetime = + self.new_named_lifetime(id, lt_id, ident, LifetimeSource::Other, ident.into()); hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { lifetime, bounds, @@ -1901,7 +1902,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }), WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { hir::WherePredicateKind::RegionPredicate(hir::WhereRegionPredicate { - lifetime: self.lower_lifetime(lifetime), + lifetime: self.lower_lifetime( + lifetime, + LifetimeSource::Other, + lifetime.ident.into(), + ), bounds: self.lower_param_bounds( bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c40987541f4a5..534e85e8bcb9a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -54,8 +54,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, IsAnonInPath, ItemLocalMap, LangItem, ParamName, - TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, + LifetimeSyntax, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -1079,7 +1079,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { itctx: ImplTraitContext, ) -> hir::GenericArg<'hir> { match arg { - ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(lt)), + ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime( + lt, + LifetimeSource::Path { with_angle_brackets: true }, + lt.ident.into(), + )), ast::GenericArg::Type(ty) => { // We cannot just match on `TyKind::Infer` as `(_)` is represented as // `TyKind::Paren(TyKind::Infer)` and should also be lowered to `GenericArg::Infer` @@ -1198,35 +1202,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Ref(region, mt) => { - let region = region.unwrap_or_else(|| { - let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(t.id) - { - debug_assert_eq!(start.plus(1), end); - start - } else { - self.next_node_id() - }; - let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); - Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } - }); - let lifetime = self.lower_lifetime(®ion); + let lifetime = self.lower_ty_direct_lifetime(t, *region); hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)) } TyKind::PinnedRef(region, mt) => { - let region = region.unwrap_or_else(|| { - let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = - self.resolver.get_lifetime_res(t.id) - { - debug_assert_eq!(start.plus(1), end); - start - } else { - self.next_node_id() - }; - let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); - Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } - }); - let lifetime = self.lower_lifetime(®ion); + let lifetime = self.lower_ty_direct_lifetime(t, *region); let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)); let span = self.lower_span(t.span); let arg = hir::Ty { kind, span, hir_id: self.next_id() }; @@ -1302,7 +1282,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericBound::Outlives(lifetime) => { if lifetime_bound.is_none() { - lifetime_bound = Some(this.lower_lifetime(lifetime)); + lifetime_bound = Some(this.lower_lifetime( + lifetime, + LifetimeSource::Other, + lifetime.ident.into(), + )); } None } @@ -1393,6 +1377,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } } + fn lower_ty_direct_lifetime( + &mut self, + t: &Ty, + region: Option, + ) -> &'hir hir::Lifetime { + let (region, syntax) = match region { + Some(region) => (region, region.ident.into()), + + None => { + let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = + self.resolver.get_lifetime_res(t.id) + { + debug_assert_eq!(start.plus(1), end); + start + } else { + self.next_node_id() + }; + let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); + let region = Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }; + (region, LifetimeSyntax::Hidden) + } + }; + self.lower_lifetime(®ion, LifetimeSource::Reference, syntax) + } + /// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F = /// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a /// HIR type that references the TAIT. @@ -1474,9 +1483,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { precise_capturing_args: &[PreciseCapturingArg], ) -> &'hir [hir::PreciseCapturingArg<'hir>] { self.arena.alloc_from_iter(precise_capturing_args.iter().map(|arg| match arg { - PreciseCapturingArg::Lifetime(lt) => { - hir::PreciseCapturingArg::Lifetime(self.lower_lifetime(lt)) - } + PreciseCapturingArg::Lifetime(lt) => hir::PreciseCapturingArg::Lifetime( + self.lower_lifetime(lt, LifetimeSource::PreciseCapturing, lt.ident.into()), + ), PreciseCapturingArg::Arg(path, id) => { let [segment] = path.segments.as_slice() else { panic!(); @@ -1739,9 +1748,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p) => hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx)), - GenericBound::Outlives(lifetime) => { - hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) - } + GenericBound::Outlives(lifetime) => hir::GenericBound::Outlives(self.lower_lifetime( + lifetime, + LifetimeSource::OutlivesBound, + lifetime.ident.into(), + )), GenericBound::Use(args, span) => hir::GenericBound::Use( self.lower_precise_capturing_args(args), self.lower_span(*span), @@ -1749,12 +1760,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { - self.new_named_lifetime(l.id, l.id, l.ident, IsAnonInPath::No) + fn lower_lifetime( + &mut self, + l: &Lifetime, + source: LifetimeSource, + syntax: LifetimeSyntax, + ) -> &'hir hir::Lifetime { + self.new_named_lifetime(l.id, l.id, l.ident, source, syntax) } - fn lower_lifetime_anon_in_path(&mut self, id: NodeId, span: Span) -> &'hir hir::Lifetime { - self.new_named_lifetime(id, id, Ident::new(kw::UnderscoreLifetime, span), IsAnonInPath::Yes) + fn lower_lifetime_hidden_in_path( + &mut self, + id: NodeId, + span: Span, + with_angle_brackets: bool, + ) -> &'hir hir::Lifetime { + self.new_named_lifetime( + id, + id, + Ident::new(kw::UnderscoreLifetime, span), + LifetimeSource::Path { with_angle_brackets }, + LifetimeSyntax::Hidden, + ) } #[instrument(level = "debug", skip(self))] @@ -1763,7 +1790,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: NodeId, new_id: NodeId, ident: Ident, - is_anon_in_path: IsAnonInPath, + source: LifetimeSource, + syntax: LifetimeSyntax, ) -> &'hir hir::Lifetime { let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); let res = match res { @@ -1787,17 +1815,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } }; - #[cfg(debug_assertions)] - if is_anon_in_path == IsAnonInPath::Yes { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); - } - debug!(?res); self.arena.alloc(hir::Lifetime::new( self.lower_node_id(new_id), self.lower_ident(ident), res, - is_anon_in_path, + source, + syntax, )) } @@ -2389,7 +2413,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.next_id(), Ident::new(kw::UnderscoreLifetime, self.lower_span(span)), hir::LifetimeKind::ImplicitObjectLifetimeDefault, - IsAnonInPath::No, + LifetimeSource::Other, + LifetimeSyntax::Hidden, ); debug!("elided_dyn_bound: r={:?}", r); self.arena.alloc(r) diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 8dfc11b56b9b4..fabe40a9d0413 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -1,10 +1,9 @@ use std::sync::Arc; use rustc_ast::{self as ast, *}; -use rustc_hir as hir; -use rustc_hir::GenericArg; use rustc_hir::def::{DefKind, PartialRes, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, GenericArg}; use rustc_middle::{span_bug, ty}; use rustc_session::parse::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; @@ -433,23 +432,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Note: these spans are used for diagnostics when they can't be inferred. // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label - let elided_lifetime_span = if generic_args.span.is_empty() { + let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() { // If there are no brackets, use the identifier span. // HACK: we use find_ancestor_inside to properly suggest elided spans in paths // originating from macros, since the segment's span might be from a macro arg. - segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span) + (segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false) } else if generic_args.is_empty() { // If there are brackets, but not generic arguments, then use the opening bracket - generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) + (generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true) } else { // Else use an empty span right after the opening bracket. - generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo() + (generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true) }; generic_args.args.insert_many( 0, (start..end).map(|id| { - let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span); + let l = self.lower_lifetime_hidden_in_path( + id, + elided_lifetime_span, + with_angle_brackets, + ); GenericArg::Lifetime(l) }), ); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d02c767ea677a..2f8a853424789 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -36,43 +36,110 @@ pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] -pub enum IsAnonInPath { - No, - Yes, +pub enum LifetimeSource { + /// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type` + Reference, + + /// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>` + Path { + /// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`, + /// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>` + /// - false for `ContainsLifetime` + with_angle_brackets: bool, + }, + + /// E.g. `impl Trait + '_`, `impl Trait + 'a` + OutlivesBound, + + /// E.g. `impl Trait + use<'_>`, `impl Trait + use<'a>` + PreciseCapturing, + + /// Other usages which have not yet been categorized. Feel free to + /// add new sources that you find useful. + /// + /// Some non-exhaustive examples: + /// - `where T: 'a` + /// - `fn(_: dyn Trait + 'a)` + Other, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum LifetimeSyntax { + /// E.g. `&Type`, `ContainsLifetime` + Hidden, + + /// E.g. `&'_ Type`, `ContainsLifetime<'_>`, `impl Trait + '_`, `impl Trait + use<'_>` + Anonymous, + + /// E.g. `&'a Type`, `ContainsLifetime<'a>`, `impl Trait + 'a`, `impl Trait + use<'a>` + Named, } -/// A lifetime. The valid field combinations are non-obvious. The following -/// example shows some of them. See also the comments on `LifetimeKind`. +impl From for LifetimeSyntax { + fn from(ident: Ident) -> Self { + let name = ident.name; + + if name == kw::Empty { + unreachable!("A lifetime name should never be empty"); + } else if name == kw::UnderscoreLifetime { + LifetimeSyntax::Anonymous + } else { + debug_assert!(name.as_str().starts_with('\'')); + LifetimeSyntax::Named + } + } +} + +/// A lifetime. The valid field combinations are non-obvious and not all +/// combinations are possible. The following example shows some of +/// them. See also the comments on `LifetimeKind` and `LifetimeSource`. +/// /// ``` /// #[repr(C)] -/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No +/// struct S<'a>(&'a u32); // res=Param, name='a, source=Reference, syntax=Named /// unsafe extern "C" { -/// fn f1(s: S); // res=Param, name='_, IsAnonInPath::Yes -/// fn f2(s: S<'_>); // res=Param, name='_, IsAnonInPath::No -/// fn f3<'a>(s: S<'a>); // res=Param, name='a, IsAnonInPath::No +/// fn f1(s: S); // res=Param, name='_, source=Path, syntax=Hidden +/// fn f2(s: S<'_>); // res=Param, name='_, source=Path, syntax=Anonymous +/// fn f3<'a>(s: S<'a>); // res=Param, name='a, source=Path, syntax=Named /// } /// -/// struct St<'a> { x: &'a u32 } // res=Param, name='a, IsAnonInPath::No +/// struct St<'a> { x: &'a u32 } // res=Param, name='a, source=Reference, syntax=Named /// fn f() { -/// _ = St { x: &0 }; // res=Infer, name='_, IsAnonInPath::Yes -/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, IsAnonInPath::No +/// _ = St { x: &0 }; // res=Infer, name='_, source=Path, syntax=Hidden +/// _ = St::<'_> { x: &0 }; // res=Infer, name='_, source=Path, syntax=Anonymous /// } /// -/// struct Name<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No -/// const A: Name = Name("a"); // res=Static, name='_, IsAnonInPath::Yes -/// const B: &str = ""; // res=Static, name='_, IsAnonInPath::No -/// static C: &'_ str = ""; // res=Static, name='_, IsAnonInPath::No -/// static D: &'static str = ""; // res=Static, name='static, IsAnonInPath::No +/// struct Name<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named +/// const A: Name = Name("a"); // res=Static, name='_, source=Path, syntax=Hidden +/// const B: &str = ""; // res=Static, name='_, source=Reference, syntax=Hidden +/// static C: &'_ str = ""; // res=Static, name='_, source=Reference, syntax=Anonymous +/// static D: &'static str = ""; // res=Static, name='static, source=Reference, syntax=Named /// /// trait Tr {} -/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, IsAnonInPath::No +/// fn tr(_: Box) {} // res=ImplicitObjectLifetimeDefault, name='_, source=Other, syntax=Hidden +/// +/// fn capture_outlives<'a>() -> +/// impl FnOnce() + 'a // res=Param, ident='a, source=OutlivesBound, syntax=Named +/// { +/// || {} +/// } +/// +/// fn capture_precise<'a>() -> +/// impl FnOnce() + use<'a> // res=Param, ident='a, source=PreciseCapturing, syntax=Named +/// { +/// || {} +/// } /// /// // (commented out because these cases trigger errors) -/// // struct S1<'a>(&'a str); // res=Param, name='a, IsAnonInPath::No -/// // struct S2(S1); // res=Error, name='_, IsAnonInPath::Yes -/// // struct S3(S1<'_>); // res=Error, name='_, IsAnonInPath::No -/// // struct S4(S1<'a>); // res=Error, name='a, IsAnonInPath::No +/// // struct S1<'a>(&'a str); // res=Param, name='a, source=Reference, syntax=Named +/// // struct S2(S1); // res=Error, name='_, source=Path, syntax=Hidden +/// // struct S3(S1<'_>); // res=Error, name='_, source=Path, syntax=Anonymous +/// // struct S4(S1<'a>); // res=Error, name='a, source=Path, syntax=Named /// ``` +/// +/// Some combinations that cannot occur are `LifetimeSyntax::Hidden` with +/// `LifetimeSource::OutlivesBound` or `LifetimeSource::PreciseCapturing` +/// — there's no way to "elide" these lifetimes. #[derive(Debug, Copy, Clone, HashStable_Generic)] pub struct Lifetime { #[stable_hasher(ignore)] @@ -86,9 +153,13 @@ pub struct Lifetime { /// Semantics of this lifetime. pub kind: LifetimeKind, - /// Is the lifetime anonymous and in a path? Used only for error - /// suggestions. See `Lifetime::suggestion` for example use. - pub is_anon_in_path: IsAnonInPath, + /// The context in which the lifetime occurred. See `Lifetime::suggestion` + /// for example use. + pub source: LifetimeSource, + + /// The syntax that the user used to declare this lifetime. See + /// `Lifetime::suggestion` for example use. + pub syntax: LifetimeSyntax, } #[derive(Debug, Copy, Clone, HashStable_Generic)] @@ -185,9 +256,10 @@ impl Lifetime { hir_id: HirId, ident: Ident, kind: LifetimeKind, - is_anon_in_path: IsAnonInPath, + source: LifetimeSource, + syntax: LifetimeSyntax, ) -> Lifetime { - let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path }; + let lifetime = Lifetime { hir_id, ident, kind, source, syntax }; // Sanity check: elided lifetimes form a strict subset of anonymous lifetimes. #[cfg(debug_assertions)] @@ -209,23 +281,44 @@ impl Lifetime { self.ident.name == kw::UnderscoreLifetime } + pub fn is_syntactically_hidden(&self) -> bool { + matches!(self.syntax, LifetimeSyntax::Hidden) + } + + pub fn is_syntactically_anonymous(&self) -> bool { + matches!(self.syntax, LifetimeSyntax::Anonymous) + } + + pub fn is_static(&self) -> bool { + self.kind == LifetimeKind::Static + } + pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) { + use LifetimeSource::*; + use LifetimeSyntax::*; + debug_assert!(new_lifetime.starts_with('\'')); - match (self.is_anon_in_path, self.ident.span.is_empty()) { + match (self.syntax, self.source) { + // The user wrote `'a` or `'_`. + (Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")), + // The user wrote `Path`, and omitted the `'_,`. - (IsAnonInPath::Yes, true) => (self.ident.span, format!("{new_lifetime}, ")), + (Hidden, Path { with_angle_brackets: true }) => { + (self.ident.span, format!("{new_lifetime}, ")) + } // The user wrote `Path` and omitted the `<'_>`. - (IsAnonInPath::Yes, false) => { + (Hidden, Path { with_angle_brackets: false }) => { (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) } // The user wrote `&type` or `&mut type`. - (IsAnonInPath::No, true) => (self.ident.span, format!("{new_lifetime} ")), + (Hidden, Reference) => (self.ident.span, format!("{new_lifetime} ")), - // The user wrote `'a` or `'_`. - (IsAnonInPath::No, false) => (self.ident.span, format!("{new_lifetime}")), + (Hidden, source) => { + unreachable!("can't suggest for a hidden lifetime of {source:?}") + } } } } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index fcd0eafa46139..18f8c523f9d39 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -58,7 +58,8 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) { hir_id: HirId::INVALID, ident: Ident::new(sym::name, DUMMY_SP), kind: LifetimeKind::Static, - is_anon_in_path: IsAnonInPath::No, + source: LifetimeSource::Other, + syntax: LifetimeSyntax::Hidden, } }, syntax, diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 756d9a57b935c..1063115ed237f 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -9,7 +9,7 @@ use rustc_errors::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; -use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, IsAnonInPath, Node}; +use rustc_hir::{self as hir, AmbigArg, FnRetTy, GenericParamKind, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, GenericArg, Region, Ty, TyCtxt}; @@ -551,19 +551,6 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { impl<'v> Visitor<'v> for ImplicitLifetimeFinder { fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) { - let make_suggestion = |lifetime: &hir::Lifetime| { - if lifetime.is_anon_in_path == IsAnonInPath::Yes - && lifetime.ident.span.is_empty() - { - format!("{}, ", self.suggestion_param_name) - } else if lifetime.ident.name == kw::UnderscoreLifetime - && lifetime.ident.span.is_empty() - { - format!("{} ", self.suggestion_param_name) - } else { - self.suggestion_param_name.clone() - } - }; match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { for segment in path.segments { @@ -572,7 +559,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { matches!( arg, hir::GenericArg::Lifetime(lifetime) - if lifetime.is_anon_in_path == IsAnonInPath::Yes + if lifetime.is_syntactically_hidden() ) }) { self.suggestions.push(( @@ -591,10 +578,10 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { if let hir::GenericArg::Lifetime(lifetime) = arg && lifetime.is_anonymous() { - self.suggestions.push(( - lifetime.ident.span, - make_suggestion(lifetime), - )); + self.suggestions.push( + lifetime + .suggestion(&self.suggestion_param_name), + ); } } } @@ -602,7 +589,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { } } hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { - self.suggestions.push((lifetime.ident.span, make_suggestion(lifetime))); + self.suggestions.push(lifetime.suggestion(&self.suggestion_param_name)); } _ => {} } From 055a27da2afcc8a7d74a551c32e8a831a825d549 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Apr 2025 08:49:49 +1000 Subject: [PATCH 14/15] Remove some unnecessary clones. I found these by grepping for `&[a-z_\.]*\.clone()`, i.e. expressions like `&a.b.clone()`, which are sometimes unnecessary clones, and also looking at clones nearby to cases like that. --- compiler/rustc_ast_pretty/src/pprust/state.rs | 4 ++-- .../src/traits/query/type_op/ascribe_user_type.rs | 3 +-- library/alloc/src/collections/btree/set.rs | 2 +- src/bootstrap/src/core/build_steps/setup.rs | 6 +++--- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0985ebf945bbd..194ae9041b1a0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -799,7 +799,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere has_bang, Some(*ident), macro_def.body.delim, - ¯o_def.body.tokens.clone(), + ¯o_def.body.tokens, true, sp, ); @@ -1469,7 +1469,7 @@ impl<'a> State<'a> { true, None, m.args.delim, - &m.args.tokens.clone(), + &m.args.tokens, true, m.span(), ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 4eecde00eaa1e..f059bd0076897 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -117,8 +117,7 @@ fn relate_mir_and_user_args<'tcx>( CRATE_DEF_ID, ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span), ); - let instantiated_predicate = - ocx.normalize(&cause.clone(), param_env, instantiated_predicate); + let instantiated_predicate = ocx.normalize(&cause, param_env, instantiated_predicate); ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 041f80c1f2c52..7ad9e59dfede1 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -139,7 +139,7 @@ pub struct Iter<'a, T: 'a> { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Iter<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Iter").field(&self.iter.clone()).finish() + f.debug_tuple("Iter").field(&self.iter).finish() } } diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 83083e12ef1fc..9d07babe5196b 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -683,7 +683,7 @@ impl Step for Editor { match EditorKind::prompt_user() { Ok(editor_kind) => { if let Some(editor_kind) = editor_kind { - while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {} + while !t!(create_editor_settings_maybe(config, &editor_kind)) {} } else { println!("Ok, skipping editor setup!"); } @@ -695,7 +695,7 @@ impl Step for Editor { /// Create the recommended editor LSP config file for rustc development, or just print it /// If this method should be re-called, it returns `false`. -fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Result { +fn create_editor_settings_maybe(config: &Config, editor: &EditorKind) -> io::Result { let hashes = editor.hashes(); let (current_hash, historical_hashes) = hashes.split_last().unwrap(); let settings_path = editor.settings_path(config); @@ -752,7 +752,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu // exists but user modified, back it up Some(false) => { // exists and is not current version or outdated, so back it up - let backup = settings_path.clone().with_extension(editor.backup_extension()); + let backup = settings_path.with_extension(editor.backup_extension()); eprintln!( "WARNING: copying `{}` to `{}`", settings_path.file_name().unwrap().to_str().unwrap(), From af8047789dded51803be6cba1a708cddb1618020 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Apr 2025 08:50:11 +1000 Subject: [PATCH 15/15] Refactor `StableMir` to avoid some clones. Pass `args` to `run` instead of storing it in a field. This avoids the need to clone it within `run`. Also, change `args` from `Vec` to `&[String]`, avoiding the need for some vecs and clones. --- compiler/rustc_smir/src/rustc_internal/mod.rs | 15 +++++------ tests/ui-fulldeps/stable-mir/check_abi.rs | 2 +- .../stable-mir/check_allocation.rs | 2 +- .../stable-mir/check_assoc_items.rs | 2 +- .../ui-fulldeps/stable-mir/check_attribute.rs | 2 +- tests/ui-fulldeps/stable-mir/check_binop.rs | 2 +- .../stable-mir/check_crate_defs.rs | 2 +- tests/ui-fulldeps/stable-mir/check_def_ty.rs | 2 +- tests/ui-fulldeps/stable-mir/check_defs.rs | 2 +- tests/ui-fulldeps/stable-mir/check_foreign.rs | 2 +- .../ui-fulldeps/stable-mir/check_instance.rs | 2 +- .../stable-mir/check_intrinsics.rs | 2 +- .../ui-fulldeps/stable-mir/check_item_kind.rs | 2 +- .../stable-mir/check_normalization.rs | 2 +- .../stable-mir/check_trait_queries.rs | 2 +- .../ui-fulldeps/stable-mir/check_transform.rs | 2 +- tests/ui-fulldeps/stable-mir/check_ty_fold.rs | 2 +- .../stable-mir/compilation-result.rs | 26 ++++++++++--------- tests/ui-fulldeps/stable-mir/crate-info.rs | 2 +- tests/ui-fulldeps/stable-mir/projections.rs | 2 +- tests/ui-fulldeps/stable-mir/smir_internal.rs | 2 +- tests/ui-fulldeps/stable-mir/smir_serde.rs | 2 +- tests/ui-fulldeps/stable-mir/smir_visitor.rs | 4 +-- 23 files changed, 43 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 146ba17d14fc8..8a7c1bd89fab6 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -256,7 +256,7 @@ where /// // Your code goes in here. /// # ControlFlow::Continue(()) /// } -/// # let args = vec!["--verbose".to_string()]; +/// # let args = &["--verbose".to_string()]; /// let result = run!(args, analyze_code); /// # assert_eq!(result, Err(CompilerError::Skipped)) /// # } @@ -278,7 +278,7 @@ where /// // Your code goes in here. /// # ControlFlow::Continue(()) /// } -/// # let args = vec!["--verbose".to_string()]; +/// # let args = &["--verbose".to_string()]; /// # let extra_args = vec![]; /// let result = run!(args, || analyze_code(extra_args)); /// # assert_eq!(result, Err(CompilerError::Skipped)) @@ -340,7 +340,6 @@ macro_rules! run_driver { C: Send, F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { - args: Vec, callback: Option, result: Option>, } @@ -352,14 +351,14 @@ macro_rules! run_driver { F: FnOnce($(optional!($with_tcx TyCtxt))?) -> ControlFlow + Send, { /// Creates a new `StableMir` instance, with given test_function and arguments. - pub fn new(args: Vec, callback: F) -> Self { - StableMir { args, callback: Some(callback), result: None } + pub fn new(callback: F) -> Self { + StableMir { callback: Some(callback), result: None } } /// Runs the compiler against given target and tests it with `test_function` - pub fn run(&mut self) -> Result> { + pub fn run(&mut self, args: &[String]) -> Result> { let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> { - run_compiler(&self.args.clone(), self); + run_compiler(&args, self); Ok(()) }); match (compiler_result, self.result.take()) { @@ -409,7 +408,7 @@ macro_rules! run_driver { } } - StableMir::new($args, $callback).run() + StableMir::new($callback).run($args) }}; } diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index ebf2e333f085a..71edf813a7be2 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -145,7 +145,7 @@ fn get_item<'a>( fn main() { let path = "alloc_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs index ae2609bbc1221..692c24f054451 100644 --- a/tests/ui-fulldeps/stable-mir/check_allocation.rs +++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs @@ -219,7 +219,7 @@ fn get_item<'a>( fn main() { let path = "alloc_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--edition=2021".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs index 9d611543b5aa7..755bec8747bc8 100644 --- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs +++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs @@ -85,7 +85,7 @@ fn check_items(items: &[T], expected: &[&str]) { fn main() { let path = "assoc_items.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index 4148fc0cb6a07..81d5399d88aa6 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -57,7 +57,7 @@ fn get_item<'a>( fn main() { let path = "attribute_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs index 6a141e9c5775c..f9559d9958d28 100644 --- a/tests/ui-fulldeps/stable-mir/check_binop.rs +++ b/tests/ui-fulldeps/stable-mir/check_binop.rs @@ -81,7 +81,7 @@ impl<'a> MirVisitor for Visitor<'a> { fn main() { let path = "binop_input.rs"; generate_input(&path).unwrap(); - let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; + let args = &["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; run!(args, test_binops).unwrap(); } diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs index 31c47192d090f..6863242f22571 100644 --- a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs @@ -84,7 +84,7 @@ fn contains(items: &[T], expected: &[&str]) { fn main() { let path = "crate_definitions.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs index 00a34f138673b..f86a8e0ae6189 100644 --- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs +++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs @@ -76,7 +76,7 @@ fn check_fn_def(ty: Ty) { fn main() { let path = "defs_ty_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs index 1ba73377d6e9f..ab741378bb713 100644 --- a/tests/ui-fulldeps/stable-mir/check_defs.rs +++ b/tests/ui-fulldeps/stable-mir/check_defs.rs @@ -112,7 +112,7 @@ fn get_instances(body: mir::Body) -> Vec { fn main() { let path = "defs_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs index 4419050ceb2c1..398024c4ff082 100644 --- a/tests/ui-fulldeps/stable-mir/check_foreign.rs +++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs @@ -58,7 +58,7 @@ fn test_foreign() -> ControlFlow<()> { fn main() { let path = "foreign_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 1510a622cdfdb..b19e5b033c469 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -87,7 +87,7 @@ fn test_body(body: mir::Body) { fn main() { let path = "instance_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 3f04abbb9d76d..52424857dc196 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -115,7 +115,7 @@ impl<'a> MirVisitor for CallsVisitor<'a> { fn main() { let path = "binop_input.rs"; generate_input(&path).unwrap(); - let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; + let args = &["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; run!(args, test_intrinsics).unwrap(); } diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs index bb8c00c64c955..d1124c75a8997 100644 --- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs +++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs @@ -47,7 +47,7 @@ fn test_item_kind() -> ControlFlow<()> { fn main() { let path = "item_kind_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_normalization.rs b/tests/ui-fulldeps/stable-mir/check_normalization.rs index 797cb4cd5d051..16e8c0339ed47 100644 --- a/tests/ui-fulldeps/stable-mir/check_normalization.rs +++ b/tests/ui-fulldeps/stable-mir/check_normalization.rs @@ -61,7 +61,7 @@ fn check_ty(ty: Ty) { fn main() { let path = "normalization_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-type=lib".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs index d9170d0c40811..fcf04a1fc3a3f 100644 --- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs +++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs @@ -72,7 +72,7 @@ fn assert_impl(impl_names: &HashSet, target: &str) { fn main() { let path = "trait_queries.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index 604cc72c3418e..9087c1cf45027 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -120,7 +120,7 @@ fn get_item<'a>( fn main() { let path = "transform_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs index 23233f8406cf5..18b9e32e4e809 100644 --- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs +++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs @@ -78,7 +78,7 @@ impl<'a> MirVisitor for PlaceVisitor<'a> { fn main() { let path = "ty_fold_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs index 39416636fd673..19b9c8b7de508 100644 --- a/tests/ui-fulldeps/stable-mir/compilation-result.rs +++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs @@ -25,40 +25,42 @@ use std::io::Write; fn main() { let path = "input_compilation_result_test.rs"; generate_input(&path).unwrap(); - let args = vec!["rustc".to_string(), path.to_string()]; - test_continue(args.clone()); - test_break(args.clone()); - test_failed(args.clone()); - test_skipped(args.clone()); + let args = &["rustc".to_string(), path.to_string()]; + test_continue(args); + test_break(args); + test_failed(args); + test_skipped(args); test_captured(args) } -fn test_continue(args: Vec) { +fn test_continue(args: &[String]) { let result = run!(args, || ControlFlow::Continue::<(), bool>(true)); assert_eq!(result, Ok(true)); } -fn test_break(args: Vec) { +fn test_break(args: &[String]) { let result = run!(args, || ControlFlow::Break::(false)); assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false))); } #[allow(unreachable_code)] -fn test_skipped(mut args: Vec) { +fn test_skipped(args: &[String]) { + let mut args = args.to_vec(); args.push("--version".to_string()); - let result = run!(args, || unreachable!() as ControlFlow<()>); + let result = run!(&args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::Skipped)); } #[allow(unreachable_code)] -fn test_failed(mut args: Vec) { +fn test_failed(args: &[String]) { + let mut args = args.to_vec(); args.push("--cfg=broken".to_string()); - let result = run!(args, || unreachable!() as ControlFlow<()>); + let result = run!(&args, || unreachable!() as ControlFlow<()>); assert_eq!(result, Err(stable_mir::CompilerError::Failed)); } /// Test that we are able to pass a closure and set the return according to the captured value. -fn test_captured(args: Vec) { +fn test_captured(args: &[String]) { let captured = "10".to_string(); let result = run!(args, || ControlFlow::Continue::<(), usize>(captured.len())); assert_eq!(result, Ok(captured.len())); diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index e2086d5e57907..7fc4edafb9338 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -186,7 +186,7 @@ fn get_item<'a>( fn main() { let path = "input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs index f3bd894ac6903..103c97bc48e17 100644 --- a/tests/ui-fulldeps/stable-mir/projections.rs +++ b/tests/ui-fulldeps/stable-mir/projections.rs @@ -146,7 +146,7 @@ fn get_item<'a>( fn main() { let path = "input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-type=lib".to_string(), "--crate-name".to_string(), diff --git a/tests/ui-fulldeps/stable-mir/smir_internal.rs b/tests/ui-fulldeps/stable-mir/smir_internal.rs index f9972dc27e3ff..0519b9de68050 100644 --- a/tests/ui-fulldeps/stable-mir/smir_internal.rs +++ b/tests/ui-fulldeps/stable-mir/smir_internal.rs @@ -40,7 +40,7 @@ fn test_translation(tcx: TyCtxt<'_>) -> ControlFlow<()> { fn main() { let path = "internal_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs index 3b3d743ad3263..0b39ec050024e 100644 --- a/tests/ui-fulldeps/stable-mir/smir_serde.rs +++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs @@ -46,7 +46,7 @@ fn serialize_to_json(_tcx: TyCtxt<'_>) -> ControlFlow<()> { fn main() { let path = "internal_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs index d225d9773fe51..caf71de2556c4 100644 --- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs +++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs @@ -183,14 +183,14 @@ impl mir::MutMirVisitor for TestMutVisitor { fn main() { let path = "sim_visitor_input.rs"; generate_input(&path).unwrap(); - let args = vec![ + let args = &[ "rustc".to_string(), "-Cpanic=abort".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), path.to_string(), ]; - run!(args.clone(), test_visitor).unwrap(); + run!(args, test_visitor).unwrap(); run!(args, test_mut_visitor).unwrap(); }