From 177dc5a372af66b2e3ba88d17484da35b5411ad9 Mon Sep 17 00:00:00 2001 From: Martin Pool Date: Thu, 8 Jan 2026 11:09:19 -0800 Subject: [PATCH 01/10] Clearer security warnings in std::env::current_exe docs Remove somewhat obvious comment about executing attacker-controlled programs. Be more clear the examples are not exhaustive. --- library/std/src/env.rs | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 615b767a4ea5a..1571ef0cd6072 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -712,28 +712,21 @@ pub fn temp_dir() -> PathBuf { /// /// # Security /// -/// The output of this function should not be trusted for anything -/// that might have security implications. Basically, if users can run -/// the executable, they can change the output arbitrarily. +/// The output of this function must be treated with care to avoid security +/// vulnerabilities, particularly in processes that run with privileges higher +/// than the user, such as setuid or setgid programs. /// -/// As an example, you can easily introduce a race condition. It goes -/// like this: +/// For example, on some Unix platforms, the result is calculated by +/// searching `$PATH` for an executable matching `argv[0]`, but both the +/// environment and arguments can be be set arbitrarily by the user who +/// invokes the program. /// -/// 1. You get the path to the current executable using `current_exe()`, and -/// store it in a variable. -/// 2. Time passes. A malicious actor removes the current executable, and -/// replaces it with a malicious one. -/// 3. You then use the stored path to re-execute the current -/// executable. +/// On Linux, if `fs.secure_hardlinks` is not set, an attacker who can +/// create hardlinks to the executable may be able to cause this function +/// to return an attacker-controlled path, which they later replace with +/// a different program. /// -/// You expected to safely execute the current executable, but you're -/// instead executing something completely different. The code you -/// just executed runs with your privileges. -/// -/// This sort of behavior has been known to [lead to privilege escalation] when -/// used incorrectly. -/// -/// [lead to privilege escalation]: https://securityvulns.com/Wdocument183.html +/// This list of illustrative example attacks is not exhaustive. /// /// # Examples /// From 8a021d98a7956593692582aad8af2235a4d0e097 Mon Sep 17 00:00:00 2001 From: Makai Date: Sun, 15 Feb 2026 23:34:54 +0800 Subject: [PATCH 02/10] rustc_public: rewrite `bridge_impl` to reduce boilerplate --- compiler/rustc_public/src/lib.rs | 55 +++++++++++++++++--------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_public/src/lib.rs b/compiler/rustc_public/src/lib.rs index 5da79196dd4ed..7244710b51e65 100644 --- a/compiler/rustc_public/src/lib.rs +++ b/compiler/rustc_public/src/lib.rs @@ -238,35 +238,40 @@ pub fn opaque(value: &T) -> Opaque { } macro_rules! bridge_impl { - ($name: ident, $ty: ty) => { - impl rustc_public_bridge::bridge::$name for $ty { - fn new(def: crate::DefId) -> Self { - Self(def) + ( $( $name:ident, $ty:ty ),* $(,)? ) => { + $( + impl rustc_public_bridge::bridge::$name for $ty { + fn new(def: crate::DefId) -> Self { + Self(def) + } } - } + )* }; } -bridge_impl!(CrateItem, crate::CrateItem); -bridge_impl!(AdtDef, crate::ty::AdtDef); -bridge_impl!(ForeignModuleDef, crate::ty::ForeignModuleDef); -bridge_impl!(ForeignDef, crate::ty::ForeignDef); -bridge_impl!(FnDef, crate::ty::FnDef); -bridge_impl!(ClosureDef, crate::ty::ClosureDef); -bridge_impl!(CoroutineDef, crate::ty::CoroutineDef); -bridge_impl!(CoroutineClosureDef, crate::ty::CoroutineClosureDef); -bridge_impl!(AliasDef, crate::ty::AliasDef); -bridge_impl!(ParamDef, crate::ty::ParamDef); -bridge_impl!(BrNamedDef, crate::ty::BrNamedDef); -bridge_impl!(TraitDef, crate::ty::TraitDef); -bridge_impl!(GenericDef, crate::ty::GenericDef); -bridge_impl!(ConstDef, crate::ty::ConstDef); -bridge_impl!(ImplDef, crate::ty::ImplDef); -bridge_impl!(RegionDef, crate::ty::RegionDef); -bridge_impl!(CoroutineWitnessDef, crate::ty::CoroutineWitnessDef); -bridge_impl!(AssocDef, crate::ty::AssocDef); -bridge_impl!(OpaqueDef, crate::ty::OpaqueDef); -bridge_impl!(StaticDef, crate::mir::mono::StaticDef); +#[rustfmt::skip] +bridge_impl!( + CrateItem, crate::CrateItem, + AdtDef, crate::ty::AdtDef, + ForeignModuleDef, crate::ty::ForeignModuleDef, + ForeignDef, crate::ty::ForeignDef, + FnDef, crate::ty::FnDef, + ClosureDef, crate::ty::ClosureDef, + CoroutineDef, crate::ty::CoroutineDef, + CoroutineClosureDef, crate::ty::CoroutineClosureDef, + AliasDef, crate::ty::AliasDef, + ParamDef, crate::ty::ParamDef, + BrNamedDef, crate::ty::BrNamedDef, + TraitDef, crate::ty::TraitDef, + GenericDef, crate::ty::GenericDef, + ConstDef, crate::ty::ConstDef, + ImplDef, crate::ty::ImplDef, + RegionDef, crate::ty::RegionDef, + CoroutineWitnessDef, crate::ty::CoroutineWitnessDef, + AssocDef, crate::ty::AssocDef, + OpaqueDef, crate::ty::OpaqueDef, + StaticDef, crate::mir::mono::StaticDef +); impl rustc_public_bridge::bridge::Prov for crate::ty::Prov { fn new(aid: crate::mir::alloc::AllocId) -> Self { From 945caf38d90e49cb9ab9d47cece23539dc9be1d1 Mon Sep 17 00:00:00 2001 From: Makai Date: Mon, 16 Feb 2026 00:30:28 +0800 Subject: [PATCH 03/10] rustc_public: remove the `CrateDefItems` trait --- compiler/rustc_public/src/crate_def.rs | 16 +--------------- compiler/rustc_public/src/lib.rs | 2 +- compiler/rustc_public/src/ty.rs | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_public/src/crate_def.rs b/compiler/rustc_public/src/crate_def.rs index 02297c5317621..7395ad63242e1 100644 --- a/compiler/rustc_public/src/crate_def.rs +++ b/compiler/rustc_public/src/crate_def.rs @@ -2,7 +2,7 @@ //! such as, a function, a trait, an enum, and any other definitions. use crate::ty::{GenericArgs, Span, Ty, index_impl}; -use crate::{AssocItems, Crate, Symbol, ThreadLocalIndex, with}; +use crate::{Crate, Symbol, ThreadLocalIndex, with}; /// A unique identification number for each item accessible for the current compilation unit. #[derive(Clone, Copy, PartialEq, Eq, Hash)] @@ -108,14 +108,6 @@ pub trait CrateDefType: CrateDef { } } -/// A trait for retrieving all items from a definition within a crate. -pub trait CrateDefItems: CrateDef { - /// Retrieve all associated items from a definition. - fn associated_items(&self) -> AssocItems { - with(|cx| cx.associated_items(self.def_id())) - } -} - #[derive(Clone, Debug, PartialEq, Eq)] pub struct Attribute { value: String, @@ -171,9 +163,3 @@ macro_rules! crate_def_with_ty { impl CrateDefType for $name {} }; } - -macro_rules! impl_crate_def_items { - ( $name:ident $(;)? ) => { - impl CrateDefItems for $name {} - }; -} diff --git a/compiler/rustc_public/src/lib.rs b/compiler/rustc_public/src/lib.rs index 5da79196dd4ed..14c8b2934e1e9 100644 --- a/compiler/rustc_public/src/lib.rs +++ b/compiler/rustc_public/src/lib.rs @@ -30,7 +30,7 @@ pub mod rustc_internal; use serde::Serialize; use crate::compiler_interface::with; -pub use crate::crate_def::{CrateDef, CrateDefItems, CrateDefType, DefId}; +pub use crate::crate_def::{CrateDef, CrateDefType, DefId}; pub use crate::error::*; use crate::mir::mono::StaticDef; use crate::mir::{Body, Mutability}; diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index d4f128f87d6ff..b23e6a8cdac78 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -7,11 +7,11 @@ use super::abi::ReprOptions; use super::mir::{Body, Mutability, Safety}; use super::{DefId, Error, Symbol, with}; use crate::abi::{FnAbi, Layout}; -use crate::crate_def::{CrateDef, CrateDefItems, CrateDefType}; +use crate::crate_def::{CrateDef, CrateDefType}; use crate::mir::alloc::{AllocId, read_target_int, read_target_uint}; use crate::mir::mono::StaticDef; use crate::target::MachineInfo; -use crate::{Filename, IndexedVal, Opaque, ThreadLocalIndex}; +use crate::{AssocItems, Filename, IndexedVal, Opaque, ThreadLocalIndex}; #[derive(Copy, Clone, Eq, PartialEq, Hash)] pub struct Ty(usize, ThreadLocalIndex); @@ -952,14 +952,14 @@ crate_def! { pub TraitDef; } -impl_crate_def_items! { - TraitDef; -} - impl TraitDef { pub fn declaration(trait_def: &TraitDef) -> TraitDecl { with(|cx| cx.trait_decl(trait_def)) } + + pub fn associated_items(&self) -> AssocItems { + with(|cx| cx.associated_items(self.def_id())) + } } crate_def! { @@ -978,15 +978,15 @@ crate_def! { pub ImplDef; } -impl_crate_def_items! { - ImplDef; -} - impl ImplDef { /// Retrieve information about this implementation. pub fn trait_impl(&self) -> ImplTrait { with(|cx| cx.trait_impl(self)) } + + pub fn associated_items(&self) -> AssocItems { + with(|cx| cx.associated_items(self.def_id())) + } } crate_def! { From 4b7a05eeee8560ca1909d659040ba153425b6baf Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 23 Feb 2026 18:50:43 +1100 Subject: [PATCH 04/10] Stop using `LinkedGraph` in `lexical_region_resolve` --- .../lexical_region_resolve/indexed_edges.rs | 68 ++++++++++++ .../src/infer/lexical_region_resolve/mod.rs | 100 +++++------------- 2 files changed, 95 insertions(+), 73 deletions(-) create mode 100644 compiler/rustc_infer/src/infer/lexical_region_resolve/indexed_edges.rs diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/indexed_edges.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/indexed_edges.rs new file mode 100644 index 0000000000000..ffc6e54f3cb06 --- /dev/null +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/indexed_edges.rs @@ -0,0 +1,68 @@ +use rustc_index::IndexVec; +use rustc_type_ir::RegionVid; + +use crate::infer::SubregionOrigin; +use crate::infer::region_constraints::{Constraint, ConstraintKind, RegionConstraintData}; + +/// Selects either out-edges or in-edges for [`IndexedConstraintEdges::adjacent_edges`]. +#[derive(Clone, Copy, Debug)] +pub(super) enum EdgeDirection { + Out, + In, +} + +/// Type alias for the pairs stored in [`RegionConstraintData::constraints`], +/// which we are indexing. +type ConstraintPair<'tcx> = (Constraint<'tcx>, SubregionOrigin<'tcx>); + +/// An index from region variables to their corresponding constraint edges, +/// used on some error paths. +pub(super) struct IndexedConstraintEdges<'data, 'tcx> { + out_edges: IndexVec>>, + in_edges: IndexVec>>, +} + +impl<'data, 'tcx> IndexedConstraintEdges<'data, 'tcx> { + pub(super) fn build_index(num_vars: usize, data: &'data RegionConstraintData<'tcx>) -> Self { + let mut out_edges = IndexVec::from_fn_n(|_| vec![], num_vars); + let mut in_edges = IndexVec::from_fn_n(|_| vec![], num_vars); + + for pair @ (c, _) in &data.constraints { + // Only push a var out-edge for `VarSub...` constraints. + match c.kind { + ConstraintKind::VarSubVar | ConstraintKind::VarSubReg => { + out_edges[c.sub.as_var()].push(pair) + } + ConstraintKind::RegSubVar | ConstraintKind::RegSubReg => {} + } + } + + // Index in-edges in reverse order, to match what current tests expect. + // (It's unclear whether this is important or not.) + for pair @ (c, _) in data.constraints.iter().rev() { + // Only push a var in-edge for `...SubVar` constraints. + match c.kind { + ConstraintKind::VarSubVar | ConstraintKind::RegSubVar => { + in_edges[c.sup.as_var()].push(pair) + } + ConstraintKind::VarSubReg | ConstraintKind::RegSubReg => {} + } + } + + IndexedConstraintEdges { out_edges, in_edges } + } + + /// Returns either the out-edges or in-edges of the specified region var, + /// as selected by `dir`. + pub(super) fn adjacent_edges( + &self, + region_vid: RegionVid, + dir: EdgeDirection, + ) -> &[&'data ConstraintPair<'tcx>] { + let edges = match dir { + EdgeDirection::Out => &self.out_edges, + EdgeDirection::In => &self.in_edges, + }; + &edges[region_vid] + } +} diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 5134b7b7ca8f1..e99dcd1ef15cb 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -3,9 +3,6 @@ use std::fmt; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::linked_graph::{ - Direction, INCOMING, LinkedGraph, NodeIndex, OUTGOING, -}; use rustc_data_structures::intern::Interned; use rustc_data_structures::unord::UnordSet; use rustc_index::{IndexSlice, IndexVec}; @@ -18,11 +15,14 @@ use rustc_span::Span; use tracing::{debug, instrument}; use super::outlives::test_type_match; +use crate::infer::lexical_region_resolve::indexed_edges::{EdgeDirection, IndexedConstraintEdges}; use crate::infer::region_constraints::{ - Constraint, ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound, + ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound, }; use crate::infer::{RegionRelations, RegionVariableOrigin, SubregionOrigin}; +mod indexed_edges; + /// This function performs lexical region resolution given a complete /// set of constraints and variable origins. It performs a fixed-point /// iteration to find region values which satisfy all constraints, @@ -118,8 +118,6 @@ struct RegionAndOrigin<'tcx> { origin: SubregionOrigin<'tcx>, } -type RegionGraph<'tcx> = LinkedGraph<(), Constraint<'tcx>>; - struct LexicalResolver<'cx, 'tcx> { region_rels: &'cx RegionRelations<'cx, 'tcx>, var_infos: VarInfos<'tcx>, @@ -626,9 +624,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // overlapping locations. let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars()); - // Only construct the graph when necessary, because it's moderately - // expensive. - let mut graph = None; + // Only construct the edge index when necessary, because it's moderately expensive. + let mut edges: Option> = None; for (node_vid, value) in var_data.values.iter_enumerated() { match *value { @@ -662,56 +659,18 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // influence the constraints on this value for // richer diagnostics in `static_impl_trait`. - let g = graph.get_or_insert_with(|| self.construct_graph()); - self.collect_error_for_expanding_node(g, &mut dup_vec, node_vid, errors); - } - } - } - } - - fn construct_graph(&self) -> RegionGraph<'tcx> { - let num_vars = self.num_vars(); - - let mut graph = LinkedGraph::new(); - - for _ in 0..num_vars { - graph.add_node(()); - } - - // Issue #30438: two distinct dummy nodes, one for incoming - // edges (dummy_source) and another for outgoing edges - // (dummy_sink). In `dummy -> a -> b -> dummy`, using one - // dummy node leads one to think (erroneously) there exists a - // path from `b` to `a`. Two dummy nodes sidesteps the issue. - let dummy_source = graph.add_node(()); - let dummy_sink = graph.add_node(()); - - for (c, _) in &self.data.constraints { - match c.kind { - ConstraintKind::VarSubVar => { - let sub_vid = c.sub.as_var(); - let sup_vid = c.sup.as_var(); - graph.add_edge(NodeIndex(sub_vid.index()), NodeIndex(sup_vid.index()), *c); - } - ConstraintKind::RegSubVar => { - graph.add_edge(dummy_source, NodeIndex(c.sup.as_var().index()), *c); - } - ConstraintKind::VarSubReg => { - graph.add_edge(NodeIndex(c.sub.as_var().index()), dummy_sink, *c); - } - ConstraintKind::RegSubReg => { - // this would be an edge from `dummy_source` to - // `dummy_sink`; just ignore it. + let e = edges.get_or_insert_with(|| { + IndexedConstraintEdges::build_index(self.num_vars(), &self.data) + }); + self.collect_error_for_expanding_node(e, &mut dup_vec, node_vid, errors); } } } - - graph } fn collect_error_for_expanding_node( &self, - graph: &RegionGraph<'tcx>, + edges: &IndexedConstraintEdges<'_, 'tcx>, dup_vec: &mut IndexSlice>, node_idx: RegionVid, errors: &mut Vec>, @@ -719,9 +678,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. let (mut lower_bounds, lower_vid_bounds, lower_dup) = - self.collect_bounding_regions(graph, node_idx, INCOMING, Some(dup_vec)); + self.collect_bounding_regions(edges, node_idx, EdgeDirection::In, Some(dup_vec)); let (mut upper_bounds, _, upper_dup) = - self.collect_bounding_regions(graph, node_idx, OUTGOING, Some(dup_vec)); + self.collect_bounding_regions(edges, node_idx, EdgeDirection::Out, Some(dup_vec)); if lower_dup || upper_dup { return; @@ -829,9 +788,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// those returned by a previous call for another region. fn collect_bounding_regions( &self, - graph: &RegionGraph<'tcx>, + edges: &IndexedConstraintEdges<'_, 'tcx>, orig_node_idx: RegionVid, - dir: Direction, + dir: EdgeDirection, mut dup_vec: Option<&mut IndexSlice>>, ) -> (Vec>, FxHashSet, bool) { struct WalkState<'tcx> { @@ -850,7 +809,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // to start off the process, walk the source node in the // direction specified - process_edges(&self.data, &mut state, graph, orig_node_idx, dir); + process_edges(&mut state, edges, orig_node_idx, dir); while let Some(node_idx) = state.stack.pop() { // check whether we've visited this node on some previous walk @@ -867,30 +826,25 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { ); } - process_edges(&self.data, &mut state, graph, node_idx, dir); + process_edges(&mut state, edges, node_idx, dir); } let WalkState { result, dup_found, set, .. } = state; return (result, set, dup_found); fn process_edges<'tcx>( - this: &RegionConstraintData<'tcx>, state: &mut WalkState<'tcx>, - graph: &RegionGraph<'tcx>, + edges: &IndexedConstraintEdges<'_, 'tcx>, source_vid: RegionVid, - dir: Direction, + dir: EdgeDirection, ) { debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); - let source_node_index = NodeIndex(source_vid.index()); - for (_, edge) in graph.adjacent_edges(source_node_index, dir) { - let get_origin = - || this.constraints.iter().find(|(c, _)| *c == edge.data).unwrap().1.clone(); - - match edge.data.kind { + for (c, origin) in edges.adjacent_edges(source_vid, dir) { + match c.kind { ConstraintKind::VarSubVar => { - let from_vid = edge.data.sub.as_var(); - let to_vid = edge.data.sup.as_var(); + let from_vid = c.sub.as_var(); + let to_vid = c.sup.as_var(); let opp_vid = if from_vid == source_vid { to_vid } else { from_vid }; if state.set.insert(opp_vid) { state.stack.push(opp_vid); @@ -898,13 +852,13 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } ConstraintKind::RegSubVar => { - let origin = get_origin(); - state.result.push(RegionAndOrigin { region: edge.data.sub, origin }); + let origin = origin.clone(); + state.result.push(RegionAndOrigin { region: c.sub, origin }); } ConstraintKind::VarSubReg => { - let origin = get_origin(); - state.result.push(RegionAndOrigin { region: edge.data.sup, origin }); + let origin = origin.clone(); + state.result.push(RegionAndOrigin { region: c.sup, origin }); } ConstraintKind::RegSubReg => panic!( From a2266501dc46e7a9677fd3ba538b335c17f92e32 Mon Sep 17 00:00:00 2001 From: arferreira Date: Wed, 25 Feb 2026 22:39:43 -0500 Subject: [PATCH 05/10] Remove mutation from macro path URL construction in generate_macro_def_id_path --- src/librustdoc/html/format.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 30dacde94cf03..b762f7eab8993 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -386,33 +386,32 @@ fn generate_macro_def_id_path( } else { ItemType::Macro }; - let mut path = clean::inline::get_item_path(tcx, def_id, item_type); - if path.len() < 2 { - // The minimum we can have is the crate name followed by the macro name. If shorter, then - // it means that `relative` was empty, which is an error. - debug!("macro path cannot be empty!"); + let path = clean::inline::get_item_path(tcx, def_id, item_type); + // The minimum we can have is the crate name followed by the macro name. If shorter, then + // it means that `relative` was empty, which is an error. + let [module_path @ .., last] = path.as_slice() else { + debug!("macro path is empty!"); + return Err(HrefError::NotInExternalCache); + }; + if module_path.is_empty() { + debug!("macro path too short: missing crate prefix (got 1 element, need at least 2)"); return Err(HrefError::NotInExternalCache); - } - - // FIXME: Try to use `iter().chain().once()` instead. - let mut prev = None; - if let Some(last) = path.pop() { - path.push(Symbol::intern(&format!("{}.{last}.html", item_type.as_str()))); - prev = Some(last); } let url = match cache.extern_locations[&def_id.krate] { ExternalLocation::Remote { ref url, is_absolute } => { let mut prefix = remote_url_prefix(url, is_absolute, cx.current.len()); - prefix.extend(path.iter().copied()); + prefix.extend(module_path.iter().copied()); + prefix.push_fmt(format_args!("{}.{last}.html", item_type.as_str())); prefix.finish() } ExternalLocation::Local => { // `root_path` always end with a `/`. format!( - "{root_path}{path}", + "{root_path}{path}/{item_type}.{last}.html", root_path = root_path.unwrap_or(""), - path = fmt::from_fn(|f| path.iter().joined("/", f)) + path = fmt::from_fn(|f| module_path.iter().joined("/", f)), + item_type = item_type.as_str(), ) } ExternalLocation::Unknown => { @@ -420,10 +419,6 @@ fn generate_macro_def_id_path( return Err(HrefError::NotInExternalCache); } }; - if let Some(prev) = prev { - path.pop(); - path.push(prev); - } Ok(HrefInfo { url, kind: item_type, rust_path: path }) } From d79efc5d005f6643e4a1406931d72a507c702cdc Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 26 Feb 2026 19:29:31 +0800 Subject: [PATCH 06/10] Recover feature lang_items for emscripten --- library/panic_unwind/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 5372c44cedf75..e89d5e60df62a 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -14,6 +14,7 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] +#![cfg_attr(all(target_os = "emscripten", not(emscripten_wasm_eh)), lang_items)] #![feature(cfg_emscripten_wasm_eh)] #![feature(core_intrinsics)] #![feature(panic_unwind)] From dfd18b7e890d12b1e3b41bc77eb356c1039f69e7 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Thu, 26 Feb 2026 23:34:41 +0800 Subject: [PATCH 07/10] Print path root when printing path --- compiler/rustc_resolve/src/lib.rs | 2 +- .../resolve/dot-notation-type-namespace-suggest-path-sep.rs | 6 +++--- .../dot-notation-type-namespace-suggest-path-sep.stderr | 6 +++--- tests/ui/resolve/issue-100365.rs | 4 ++-- tests/ui/resolve/issue-100365.stderr | 4 ++-- tests/ui/resolve/resolve-bad-visibility.rs | 4 ++-- tests/ui/resolve/resolve-bad-visibility.stderr | 4 ++-- .../rfcs/rfc-2126-extern-absolute-paths/single-segment.rs | 2 +- .../rfc-2126-extern-absolute-paths/single-segment.stderr | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 45cbc0b3c828d..bb7b9c42391e6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2504,7 +2504,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn names_to_string(names: impl Iterator) -> String { let mut result = String::new(); - for (i, name) in names.filter(|name| *name != kw::PathRoot).enumerate() { + for (i, name) in names.enumerate().filter(|(_, name)| *name != kw::PathRoot) { if i > 0 { result.push_str("::"); } diff --git a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs index 432e3c0b77efc..e9ff6306e16c2 100644 --- a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.rs @@ -35,9 +35,9 @@ fn main() { macro_rules! Type { () => { ::std::cell::Cell - //~^ ERROR expected value, found struct `std::cell::Cell` - //~| ERROR expected value, found struct `std::cell::Cell` - //~| ERROR expected value, found struct `std::cell::Cell` + //~^ ERROR expected value, found struct `::std::cell::Cell` + //~| ERROR expected value, found struct `::std::cell::Cell` + //~| ERROR expected value, found struct `::std::cell::Cell` }; (alias) => { Alias diff --git a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr index d74814dd876c2..e0e2c3a5fd822 100644 --- a/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr +++ b/tests/ui/resolve/dot-notation-type-namespace-suggest-path-sep.stderr @@ -70,7 +70,7 @@ LL - let _ = foo.bar; LL + let _ = foo::bar; | -error[E0423]: expected value, found struct `std::cell::Cell` +error[E0423]: expected value, found struct `::std::cell::Cell` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 | LL | ::std::cell::Cell @@ -86,7 +86,7 @@ LL - Type!().get(); LL + ::get(); | -error[E0423]: expected value, found struct `std::cell::Cell` +error[E0423]: expected value, found struct `::std::cell::Cell` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 | LL | ::std::cell::Cell @@ -166,7 +166,7 @@ LL - Vec.new LL + Vec::new | -error[E0423]: expected value, found struct `std::cell::Cell` +error[E0423]: expected value, found struct `::std::cell::Cell` --> $DIR/dot-notation-type-namespace-suggest-path-sep.rs:37:9 | LL | ::std::cell::Cell diff --git a/tests/ui/resolve/issue-100365.rs b/tests/ui/resolve/issue-100365.rs index 1d8835036065b..2ecaf93601013 100644 --- a/tests/ui/resolve/issue-100365.rs +++ b/tests/ui/resolve/issue-100365.rs @@ -15,8 +15,8 @@ fn main() { macro_rules! Trait { () => { ::std::iter::Iterator - //~^ ERROR expected value, found trait `std::iter::Iterator` - //~| ERROR expected value, found trait `std::iter::Iterator` + //~^ ERROR expected value, found trait `::std::iter::Iterator` + //~| ERROR expected value, found trait `::std::iter::Iterator` }; } diff --git a/tests/ui/resolve/issue-100365.stderr b/tests/ui/resolve/issue-100365.stderr index 7a880c6f31acd..7dea31713df2f 100644 --- a/tests/ui/resolve/issue-100365.stderr +++ b/tests/ui/resolve/issue-100365.stderr @@ -34,7 +34,7 @@ LL - let _ = Into::<()>.into; LL + let _ = Into::<()>::into; | -error[E0423]: expected value, found trait `std::iter::Iterator` +error[E0423]: expected value, found trait `::std::iter::Iterator` --> $DIR/issue-100365.rs:17:9 | LL | ::std::iter::Iterator @@ -45,7 +45,7 @@ LL | Trait!().map(std::convert::identity); // no `help` here! | = note: this error originates in the macro `Trait` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0423]: expected value, found trait `std::iter::Iterator` +error[E0423]: expected value, found trait `::std::iter::Iterator` --> $DIR/issue-100365.rs:17:9 | LL | ::std::iter::Iterator diff --git a/tests/ui/resolve/resolve-bad-visibility.rs b/tests/ui/resolve/resolve-bad-visibility.rs index 55e381e8be1a1..bfc5e90c31e71 100644 --- a/tests/ui/resolve/resolve-bad-visibility.rs +++ b/tests/ui/resolve/resolve-bad-visibility.rs @@ -2,8 +2,8 @@ enum E {} trait Tr {} -pub(in E) struct S; //~ ERROR expected module, found enum `E` -pub(in Tr) struct Z; //~ ERROR expected module, found trait `Tr` +pub(in E) struct S; //~ ERROR expected module, found enum `::E` +pub(in Tr) struct Z; //~ ERROR expected module, found trait `::Tr` pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules pub(in nonexistent) struct G; //~ ERROR cannot find pub(in too_soon) struct H; //~ ERROR cannot find diff --git a/tests/ui/resolve/resolve-bad-visibility.stderr b/tests/ui/resolve/resolve-bad-visibility.stderr index 4530757c3de55..d9fd4400b8e0e 100644 --- a/tests/ui/resolve/resolve-bad-visibility.stderr +++ b/tests/ui/resolve/resolve-bad-visibility.stderr @@ -1,10 +1,10 @@ -error[E0577]: expected module, found enum `E` +error[E0577]: expected module, found enum `::E` --> $DIR/resolve-bad-visibility.rs:5:8 | LL | pub(in E) struct S; | ^ not a module -error[E0577]: expected module, found trait `Tr` +error[E0577]: expected module, found trait `::Tr` --> $DIR/resolve-bad-visibility.rs:6:8 | LL | pub(in Tr) struct Z; diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.rs b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.rs index 0828927a3976e..b773e419b16dd 100644 --- a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.rs +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.rs @@ -6,6 +6,6 @@ use crate; //~ ERROR imports need to be explicitly named use *; //~ ERROR cannot glob-import all possible crates fn main() { - let s = ::xcrate; //~ ERROR expected value, found crate `xcrate` + let s = ::xcrate; //~ ERROR expected value, found crate `::xcrate` //~^ NOTE not a value } diff --git a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.stderr b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.stderr index 13eb4e25ed6bb..fcd18a847d910 100644 --- a/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.stderr +++ b/tests/ui/rfcs/rfc-2126-extern-absolute-paths/single-segment.stderr @@ -15,7 +15,7 @@ error: cannot glob-import all possible crates LL | use *; | ^ -error[E0423]: expected value, found crate `xcrate` +error[E0423]: expected value, found crate `::xcrate` --> $DIR/single-segment.rs:9:13 | LL | let s = ::xcrate; From b12629f8a954cb59f7c3f1fa8052153dc35015f2 Mon Sep 17 00:00:00 2001 From: Lukasz Anforowicz Date: Thu, 29 May 2025 23:52:29 +0000 Subject: [PATCH 08/10] Add new unstable attribute: `#[export_visibility = ...]`. --- .../src/attributes/codegen_attrs.rs | 41 ++++++- compiler/rustc_attr_parsing/src/context.rs | 1 + .../rustc_codegen_ssa/src/codegen_attrs.rs | 20 +++- compiler/rustc_codegen_ssa/src/errors.rs | 17 +++ compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_feature/src/unstable.rs | 2 + .../rustc_hir/src/attrs/data_structures.rs | 15 +++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + .../src/middle/codegen_fn_attrs.rs | 7 ++ .../rustc_monomorphize/src/partitioning.rs | 5 + compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + src/tools/run-make-support/Cargo.toml | 2 +- .../run-make-support/src/artifact_names.rs | 16 ++- src/tools/run-make-support/src/targets.rs | 14 +++ tests/codegen-llvm/export-visibility.rs | 102 ++++++++++++++++++ .../run-make/cdylib-export-visibility/foo.rs | 29 +++++ .../cdylib-export-visibility/rmake.rs | 87 +++++++++++++++ ...sibility-with-rustc-std-internal-symbol.rs | 11 ++ ...lity-with-rustc-std-internal-symbol.stderr | 8 ++ ...export-visibility-with-unrecognized-arg.rs | 34 ++++++ ...rt-visibility-with-unrecognized-arg.stderr | 57 ++++++++++ .../export-visibility-without-export-name.rs | 8 ++ ...port-visibility-without-export-name.stderr | 8 ++ .../feature-gate-export-visibility.rs | 11 ++ .../feature-gate-export-visibility.stderr | 13 +++ 26 files changed, 504 insertions(+), 8 deletions(-) create mode 100644 tests/codegen-llvm/export-visibility.rs create mode 100644 tests/run-make/cdylib-export-visibility/foo.rs create mode 100644 tests/run-make/cdylib-export-visibility/rmake.rs create mode 100644 tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.rs create mode 100644 tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.stderr create mode 100644 tests/ui/attributes/export-visibility-with-unrecognized-arg.rs create mode 100644 tests/ui/attributes/export-visibility-with-unrecognized-arg.stderr create mode 100644 tests/ui/attributes/export-visibility-without-export-name.rs create mode 100644 tests/ui/attributes/export-visibility-without-export-name.stderr create mode 100644 tests/ui/feature-gates/feature-gate-export-visibility.rs create mode 100644 tests/ui/feature-gates/feature-gate-export-visibility.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 4909e0d35173c..0100d34187aa7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,4 +1,6 @@ -use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy}; +use rustc_hir::attrs::{ + CoverageAttrKind, ExportVisibilityAttrValue, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy, +}; use rustc_session::parse::feature_err; use super::prelude::*; @@ -153,6 +155,43 @@ impl SingleAttributeParser for ExportNameParser { } } +pub(crate) struct ExportVisibilityParser; + +impl SingleAttributeParser for ExportVisibilityParser { + const PATH: &[rustc_span::Symbol] = &[sym::export_visibility]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::Static)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "visibility"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(sv) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + let str_to_visibility = [("target_default", ExportVisibilityAttrValue::TargetDefault)]; + for &(s, visibility) in str_to_visibility.iter() { + if s == sv.as_str() { + return Some(AttributeKind::ExportVisibility { visibility, span: cx.attr_span }); + } + } + + let allowed_str_values = str_to_visibility + .into_iter() + .map(|(s, _visibility)| s) + .map(Symbol::intern) + .collect::>(); + cx.expected_specific_argument_strings(nv.value_span, &allowed_str_values); + None + } +} + pub(crate) struct RustcObjcClassParser; impl SingleAttributeParser for RustcObjcClassParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 802ee56f504b0..72f30016b89b5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -184,6 +184,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 1ceb01337b118..dd6570801c05e 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,6 +1,7 @@ use rustc_abi::{Align, ExternAbi}; use rustc_hir::attrs::{ - AttributeKind, EiiImplResolution, InlineAttr, Linkage, RtsanSetting, UsedBy, + AttributeKind, EiiImplResolution, ExportVisibilityAttrValue, InlineAttr, Linkage, RtsanSetting, + UsedBy, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; @@ -70,6 +71,13 @@ fn process_builtin_attrs( match attr { AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD, AttributeKind::ExportName { name, .. } => codegen_fn_attrs.symbol_name = Some(*name), + AttributeKind::ExportVisibility { visibility, .. } => { + codegen_fn_attrs.export_visibility = Some(match visibility { + ExportVisibilityAttrValue::TargetDefault => { + tcx.sess.default_visibility().into() + } + }); + } AttributeKind::Inline(inline, span) => { codegen_fn_attrs.inline = *inline; interesting_spans.inline = Some(*span); @@ -533,6 +541,16 @@ fn handle_lang_items( } err.emit(); } + + if codegen_fn_attrs.export_visibility.is_some() { + let span = find_attr!(attrs, ExportVisibility{span, ..} => *span).unwrap_or_default(); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) { + tcx.dcx().emit_err(errors::ExportVisibilityWithRustcStdInternalSymbol { span }); + } + if !codegen_fn_attrs.contains_extern_indicator() { + tcx.dcx().emit_err(errors::ExportVisibilityWithoutNoMangleNorExportName { span }); + } + } } /// Generate the [`CodegenFnAttrs`] for an item (identified by the [`LocalDefId`]). diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index be1965f674911..5d57ec8d3c6f1 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1268,3 +1268,20 @@ pub(crate) struct LtoProcMacro; #[diag("cannot prefer dynamic linking when performing LTO")] #[note("only 'staticlib', 'bin', and 'cdylib' outputs are supported with LTO")] pub(crate) struct DynamicLinkingWithLTO; + +#[derive(Diagnostic)] +#[diag("`#[export_visibility = ...]` cannot be used on internal language items")] +pub(crate) struct ExportVisibilityWithRustcStdInternalSymbol { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag( + "`#[export_visibility = ...]` will be ignored \ + without `export_name`, `no_mangle`, or similar attribute" +)] +pub(crate) struct ExportVisibilityWithoutNoMangleNorExportName { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index db8f459ef0451..d1f30a14e74c2 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -649,6 +649,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"), FutureWarnPreceding, EncodeCrossCrate::No ), + gated!(export_visibility, Normal, template!(NameValueStr: "visibility"), ErrorPreceding, EncodeCrossCrate::No, experimental!(export_visibility)), ungated!( unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1d123385961aa..6ea5b53c7ebdf 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -474,6 +474,8 @@ declare_features! ( (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), /// Allows using `#[export_stable]` which indicates that an item is exportable. (incomplete, export_stable, "1.88.0", Some(139939)), + /// Allows `#[export_visibility]` on definitions of statics and/or functions. + (unstable, export_visibility, "CURRENT_RUSTC_VERSION", Some(151425)), /// Externally implementable items (unstable, extern_item_impls, "1.94.0", Some(125418)), /// Allows defining `extern type`s. diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 91409108a7533..26b9def29fbd0 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -251,6 +251,15 @@ impl Deprecation { } } +/// Pre-parsed value of `#[export_visibility = ...]` attribute. +/// +/// In a future RFC we may consider adding support for `Hidden`, `Protected`, and/or +/// `Interposable`. +#[derive(Clone, Copy, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum ExportVisibilityAttrValue { + TargetDefault, +} + /// There are three valid forms of the attribute: /// `#[used]`, which is equivalent to `#[used(linker)]` on targets that support it, but `#[used(compiler)]` if not. /// `#[used(compiler)]` @@ -1045,6 +1054,12 @@ pub enum AttributeKind { /// Represents `#[export_stable]`. ExportStable, + /// Represents [`#[export_visibility = ...]`](https://github.com/rust-lang/rust/issues/151425) + ExportVisibility { + visibility: ExportVisibilityAttrValue, + span: Span, + }, + /// Represents `#[feature(...)]` Feature(ThinVec, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index cd41a2b9b28c7..7ed1ced4c6e9c 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -43,6 +43,7 @@ impl AttributeKind { EiiImpls(..) => No, ExportName { .. } => Yes, ExportStable => No, + ExportVisibility { .. } => Yes, Feature(..) => No, FfiConst(..) => No, FfiPure(..) => No, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 4f600af0cbfce..0fb60841f9faa 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -79,6 +79,12 @@ pub struct CodegenFnAttrs { /// be set when `link_name` is set. This is for foreign items with the /// "raw-dylib" kind. pub link_ordinal: Option, + /// The `#[export_visibility = "..."]` attribute, with values interpreted + /// as follows: + /// * `None` - use the "inherent" visibility (either based on the target platform, or provided via + /// `-Zdefault-visibility=...` command-line flag) + /// * `Some(...)` - use the item/symbol-specific visibility + pub export_visibility: Option, /// The `#[target_feature(enable = "...")]` attribute and the enabled /// features (only enabled features are supported right now). /// Implied target features have already been applied. @@ -224,6 +230,7 @@ impl CodegenFnAttrs { optimize: OptimizeAttr::Default, symbol_name: None, link_ordinal: None, + export_visibility: None, target_features: vec![], foreign_item_symbol_aliases: vec![], safe_target_features: false, diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index d8f4e01945075..c1d5706985cb7 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -931,6 +931,11 @@ fn mono_item_visibility<'tcx>( } fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { + // If present, then symbol-specific `#[export_visibility = ...]` "wins". + if let Some(visibility) = tcx.codegen_fn_attrs(id).export_visibility { + return visibility; + } + // Fast-path to avoid expensive query call below if tcx.sess.default_visibility() == SymbolVisibility::Interposable { return Visibility::Default; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dacb02afe1612..b7176c05be1ed 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -254,6 +254,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::EiiDeclaration { .. } | AttributeKind::ExportName { .. } | AttributeKind::ExportStable + | AttributeKind::ExportVisibility { .. } | AttributeKind::Feature(..) | AttributeKind::FfiConst(..) | AttributeKind::Fundamental diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 731a838530729..35c614e9e5771 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -907,6 +907,7 @@ symbols! { export_name, export_stable, export_symbols: "export-symbols", + export_visibility, expr, expr_2021, expr_fragment_specifier_2024, diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 918f5ef0d5069..8f43c266ca359 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -13,7 +13,7 @@ edition = "2024" bstr = "1.12" gimli = "0.32" libc = "0.2" -object = "0.37" +object = { version = "0.37", features = ["read", "compression", "wasm"] } regex = "1.11" serde_json = "1.0" similar = "2.7" diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs index a2bb118694462..bbb3c3e734a1f 100644 --- a/src/tools/run-make-support/src/artifact_names.rs +++ b/src/tools/run-make-support/src/artifact_names.rs @@ -2,7 +2,7 @@ //! libraries which are target-dependent. use crate::target; -use crate::targets::is_windows_msvc; +use crate::targets::{is_wasi, is_windows, is_windows_msvc}; /// Construct the static library name based on the target. #[track_caller] @@ -22,18 +22,24 @@ pub fn dynamic_lib_name(name: &str) -> String { format!("{}{name}.{}", dynamic_lib_prefix(), dynamic_lib_extension()) } +/// Returns the value of `DLL_PREFIX` from `library/std/src/sys/env_consts.rs` +/// for the target platform indicated by `crate::target()`. fn dynamic_lib_prefix() -> &'static str { - if target().contains("windows") { "" } else { "lib" } + // FIXME: Cover more exotic platform like `uefi`. + if is_wasi() || is_windows() { "" } else { "lib" } } -/// Construct the dynamic library extension based on the target. +/// Returns the value of `DLL_EXTENSION` from `library/std/src/sys/env_consts.rs` +/// for the target platform indicated by `crate::target()`. #[must_use] pub fn dynamic_lib_extension() -> &'static str { + // FIXME: Cover more exotic platform like `uefi`. let target = target(); - if target.contains("apple") { "dylib" - } else if target.contains("windows") { + } else if is_wasi() { + "wasm" + } else if is_windows() { "dll" } else if target.contains("aix") { "a" diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index 6288f5f7c59da..dcc23f6a9f82b 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -34,6 +34,20 @@ pub fn is_win7() -> bool { target().contains("win7") } +/// Check if target uses WASI +pub fn is_wasi() -> bool { + // The condition below is roughly equivalent to the following `cfg` + // attribute from `library/std/src/sys/env_consts.rs`. + // + // ``` + // #[cfg(all( + // target_family = "wasm", + // not(any(target_os = "emscripten", target_os = "linux")) + // ))] + // ``` + target().starts_with("wasm") && !target().contains("linux") && !target().contains("emscripten") +} + /// Check if target uses macOS. #[must_use] pub fn is_darwin() -> bool { diff --git a/tests/codegen-llvm/export-visibility.rs b/tests/codegen-llvm/export-visibility.rs new file mode 100644 index 0000000000000..ff0b785e53d97 --- /dev/null +++ b/tests/codegen-llvm/export-visibility.rs @@ -0,0 +1,102 @@ +// Verifies that `#[export_visibility = ...]` can override the visibility +// that is normally implied by `#[export_name]` or `#[no_mangle]`. +// +// High-level test expectations for items with `#[export_name = ...]` +// (or with `#[no_mangle]`) and: +// +// * Without `#[export_visibility = ...]` => public +// * `#[export_visibility = "target_default"]` => value inherited from the target +// platform or from the `-Zdefault-visibility=...` command-line flag +// (this expectation depends on whether the `...-HIDDEN` vs `...-PROTECTED` +// test revisions are used). +// +// Note that what we call "public" in the expectations above is also referred +// to as "default" in LLVM docs - see +// https://llvm.org/docs/LangRef.html#visibility-styles + +//@ revisions: LINUX-X86-HIDDEN LINUX-X86-PROTECTED +//@[LINUX-X86-HIDDEN] compile-flags: -Zdefault-visibility=hidden +//@[LINUX-X86-PROTECTED] compile-flags: -Zdefault-visibility=protected + +// Exact LLVM IR differs depending on the target triple (e.g. `hidden constant` +// vs `internal constant` vs `constant`). Because of this, we only apply the +// specific test expectations below to one specific target triple. +// +// Note that `tests/run-make/cdylib-export-visibility` provides similar +// test coverage, but in an LLVM-IR-agnostic / platform-agnostic way. +//@[LINUX-X86-HIDDEN] needs-llvm-components: x86 +//@[LINUX-X86-HIDDEN] compile-flags: --target x86_64-unknown-linux-gnu +//@[LINUX-X86-PROTECTED] needs-llvm-components: x86 +//@[LINUX-X86-PROTECTED] compile-flags: --target x86_64-unknown-linux-gnu + +// This test focuses on rlib to exercise the scenario described in +// https://github.com/rust-lang/rust/issues/73958#issuecomment-2891711649 +#![crate_type = "rlib"] +#![feature(export_visibility)] +// Relying on `minicore` makes it easier to run the test, even if the host is +// not a linux-x86 machine. +//@ add-minicore +//@ edition: 2024 +#![feature(no_core)] +#![no_core] +use minicore::*; + +/////////////////////////////////////////////////////////////////////// +// The tests below focus on how `#[export_visibility = ...]` works for +// a `static`. The tests are based on similar tests in +// `tests/codegen/default-visibility.rs` + +#[unsafe(export_name = "static_export_name_no_attr")] +pub static TEST_STATIC_NO_ATTR: u32 = 1101; + +#[unsafe(export_name = "static_export_name_target_default")] +#[export_visibility = "target_default"] +pub static TESTED_STATIC_ATTR_ASKS_TO_TARGET_DEFAULT: u32 = 1102; + +#[unsafe(no_mangle)] +pub static static_no_mangle_no_attr: u32 = 1201; + +#[unsafe(no_mangle)] +#[export_visibility = "target_default"] +pub static static_no_mangle_target_default: u32 = 1202; + +// LINUX-X86-HIDDEN: @static_export_name_no_attr = local_unnamed_addr constant +// LINUX-X86-HIDDEN: @static_export_name_target_default = hidden local_unnamed_addr constant +// LINUX-X86-HIDDEN: @static_no_mangle_no_attr = local_unnamed_addr constant +// LINUX-X86-HIDDEN: @static_no_mangle_target_default = hidden local_unnamed_addr constant + +// LINUX-X86-PROTECTED: @static_export_name_no_attr = local_unnamed_addr constant +// LINUX-X86-PROTECTED: @static_export_name_target_default = protected local_unnamed_addr constant +// LINUX-X86-PROTECTED: @static_no_mangle_no_attr = local_unnamed_addr constant +// LINUX-X86-PROTECTED: @static_no_mangle_target_default = protected local_unnamed_addr constant + +/////////////////////////////////////////////////////////////////////// +// The tests below focus on how `#[export_visibility = ...]` works for +// a `fn`. +// +// The tests below try to mimics how `cxx` exports known/hardcoded helpers (e.g. +// `cxxbridge1$string$drop` [1]) as well as build-time-generated thunks (e.g. +// `serde_json_lenient$cxxbridge1$decode_json` from https://crbug.com/418073233#comment7). +// +// [1] +// https://github.com/dtolnay/cxx/blob/ebdd6a0c63ae10dc5224ed21970b7a0504657434/src/symbols/rust_string.rs#L83-L86 + +#[unsafe(export_name = "test_fn_no_attr")] +unsafe extern "C" fn test_fn_no_attr() -> u32 { + // We return a unique integer to ensure that each function has a unique body + // and therefore that identical code folding (ICF) won't fold the functions + // when linking. + 2001 +} + +#[unsafe(export_name = "test_fn_target_default")] +#[export_visibility = "target_default"] +unsafe extern "C" fn test_fn_asks_for_target_default() -> u32 { + 2002 +} + +// LINUX-X86-HIDDEN: define noundef i32 @test_fn_no_attr +// LINUX-X86-HIDDEN: define hidden noundef i32 @test_fn_target_default + +// LINUX-X86-PROTECTED: define noundef i32 @test_fn_no_attr +// LINUX-X86-PROTECTED: define protected noundef i32 @test_fn_target_default diff --git a/tests/run-make/cdylib-export-visibility/foo.rs b/tests/run-make/cdylib-export-visibility/foo.rs new file mode 100644 index 0000000000000..0b0b9239a2080 --- /dev/null +++ b/tests/run-make/cdylib-export-visibility/foo.rs @@ -0,0 +1,29 @@ +#![crate_type = "cdylib"] +#![feature(export_visibility)] +// `no_std` makes it slightly easier to run the test when cross-compiling. +// Ideally the test would use `no_core`, but `//@ add-minicore` doesn't seem +// to work... +#![no_std] +//@ edition: 2024 + +#[unsafe(no_mangle)] +unsafe extern "C" fn test_fn_no_export_visibility_attribute() -> u32 { + // Using unique integer means that the functions return different results + // and therefore identical code folding (ICF) in the linker won't apply. + 16 // line number; can't use `line!` with `no_core` +} + +#[unsafe(no_mangle)] +#[export_visibility = "target_default"] +unsafe extern "C" fn test_fn_export_visibility_asks_for_target_default() -> u32 { + // Using unique integer means that the functions return different results + // and therefore identical code folding (ICF) in the linker won't apply. + 24 // line number; can't use `line!` with `no_core` +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + // The infinite loop should never run - we only look at symbol visibilities + // of `test_fn_...` above. + loop {} +} diff --git a/tests/run-make/cdylib-export-visibility/rmake.rs b/tests/run-make/cdylib-export-visibility/rmake.rs new file mode 100644 index 0000000000000..05baefd65dcb0 --- /dev/null +++ b/tests/run-make/cdylib-export-visibility/rmake.rs @@ -0,0 +1,87 @@ +// This test builds `foo.rs` into a `cdylib` and verifies that +// `#[export_visibility = ...]` affects visibility of symbols. +// +// This test is loosely based on manual test steps described when +// discussing the related RFC at: +// https://github.com/rust-lang/rfcs/pull/3834#issuecomment-3403039933 + +//@ needs-crate-type: cdylib +//@ needs-dynamic-linking + +// See https://github.com/rust-lang/rust/pull/151431#issuecomment-3923604898 +// and earlier comments that explain the problems encountered when attempting +// to enable this test for WASM. +//@ ignore-wasm + +// See https://github.com/rust-lang/rust/pull/151431#issuecomment-3923203589 +// for why this test skips `nvptx64-nvidia-cuda` and similar targets. +//@ ignore-nvptx64 + +use std::collections::HashSet; + +use run_make_support::symbols::exported_dynamic_symbol_names; +use run_make_support::targets::is_wasi; +use run_make_support::{dynamic_lib_name, object, rustc}; + +struct TestCase { + name: &'static str, + extra_rustc_arg: Option<&'static str>, + expected_exported_symbols: &'static [&'static str], + expected_private_symbols: &'static [&'static str], +} + +impl TestCase { + fn run(&self) { + let test_name = self.name; + + let mut rustc = rustc(); + rustc.input("foo.rs"); + rustc.arg("-Cpanic=abort"); + if let Some(extra_arg) = self.extra_rustc_arg { + rustc.arg(extra_arg); + } + rustc.run(); + + let lib_path = dynamic_lib_name("foo"); + let object_file_bytes = std::fs::read(&lib_path) + .unwrap_or_else(|e| panic!("{test_name}: failed to read `{lib_path}`: {e}")); + let object_file = object::File::parse(object_file_bytes.as_slice()) + .unwrap_or_else(|e| panic!("{test_name}: failed to parse `{lib_path}`: {e}")); + let actual_exported_symbols = + exported_dynamic_symbol_names(&object_file).into_iter().collect::>(); + + for s in self.expected_exported_symbols { + assert!( + actual_exported_symbols.contains(s), + "{test_name}: Expecting `{s}` to be an actually exported symbol in `{lib_path}`", + ); + } + for s in self.expected_private_symbols { + assert!( + !actual_exported_symbols.contains(s), + "{test_name}: Expecting `{s}` to *not* be exported from `{lib_path}`", + ); + } + } +} + +fn main() { + TestCase { + name: "Test #1", + extra_rustc_arg: Some("-Zdefault-visibility=hidden"), + expected_exported_symbols: &["test_fn_no_export_visibility_attribute"], + expected_private_symbols: &["test_fn_export_visibility_asks_for_target_default"], + } + .run(); + + TestCase { + name: "Test #2", + extra_rustc_arg: None, + expected_exported_symbols: &[ + "test_fn_no_export_visibility_attribute", + "test_fn_export_visibility_asks_for_target_default", + ], + expected_private_symbols: &[], + } + .run(); +} diff --git a/tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.rs b/tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.rs new file mode 100644 index 0000000000000..fcacaf160827d --- /dev/null +++ b/tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.rs @@ -0,0 +1,11 @@ +// This test verfies that `#[export_visibility = ...]` will report an error +// when applied to an item that also has `#[rustc_std_internal_symbol]` +// attribute. +#![feature(export_visibility)] +#![feature(rustc_attrs)] +#[export_visibility = "target_default"] +//~^ERROR: #[export_visibility = ...]` cannot be used on internal language items +#[rustc_std_internal_symbol] +pub static TESTED_STATIC: [u8; 6] = *b"foobar"; + +fn main() {} diff --git a/tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.stderr b/tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.stderr new file mode 100644 index 0000000000000..6685a20905760 --- /dev/null +++ b/tests/ui/attributes/export-visibility-with-rustc-std-internal-symbol.stderr @@ -0,0 +1,8 @@ +error: `#[export_visibility = ...]` cannot be used on internal language items + --> $DIR/export-visibility-with-rustc-std-internal-symbol.rs:6:1 + | +LL | #[export_visibility = "target_default"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/attributes/export-visibility-with-unrecognized-arg.rs b/tests/ui/attributes/export-visibility-with-unrecognized-arg.rs new file mode 100644 index 0000000000000..17aeddbd7cc13 --- /dev/null +++ b/tests/ui/attributes/export-visibility-with-unrecognized-arg.rs @@ -0,0 +1,34 @@ +// This test verfies that `#[export_visibility = ...]` will report an error +// when the argument cannot be parsed. +#![feature(export_visibility)] +#[no_mangle] +#[export_visibility = "unrecognized visibility value"] +//~^ ERROR: malformed `export_visibility` attribute input +pub static TESTED_STATIC: [u8; 6] = *b"foobar"; + +// The following `static`s verify that `hidden`, `protected`, and `interposable` +// are not supported yet. +#[no_mangle] +#[export_visibility = "hidden"] +//~^ ERROR: malformed `export_visibility` attribute input +pub static TESTED_STATIC_HIDDEN: [u8; 6] = *b"foobar"; +#[no_mangle] +#[export_visibility = "protected"] +//~^ ERROR: malformed `export_visibility` attribute input +pub static TESTED_STATIC_PROTECTED: [u8; 6] = *b"foobar"; +#[no_mangle] +#[export_visibility = "interposable"] +//~^ ERROR: malformed `export_visibility` attribute input +pub static TESTED_STATIC_INTERPOSABLE: [u8; 6] = *b"foobar"; + +// The following `static`s verify that other visibility spellings are also not supported. +#[no_mangle] +#[export_visibility = "default"] +//~^ ERROR: malformed `export_visibility` attribute input +pub static TESTED_STATIC_DEFAULT: [u8; 6] = *b"foobar"; +#[no_mangle] +#[export_visibility = "public"] +//~^ ERROR: malformed `export_visibility` attribute input +pub static TESTED_STATIC_PUBLIC: [u8; 6] = *b"foobar"; + +fn main() {} diff --git a/tests/ui/attributes/export-visibility-with-unrecognized-arg.stderr b/tests/ui/attributes/export-visibility-with-unrecognized-arg.stderr new file mode 100644 index 0000000000000..1c75610f8755c --- /dev/null +++ b/tests/ui/attributes/export-visibility-with-unrecognized-arg.stderr @@ -0,0 +1,57 @@ +error[E0539]: malformed `export_visibility` attribute input + --> $DIR/export-visibility-with-unrecognized-arg.rs:5:1 + | +LL | #[export_visibility = "unrecognized visibility value"] + | ^^^^^^^^^^^^^^^^^^^^^^-------------------------------^ + | | | + | | the only valid argument here is "target_default" + | help: must be of the form: `#[export_visibility = "visibility"]` + +error[E0539]: malformed `export_visibility` attribute input + --> $DIR/export-visibility-with-unrecognized-arg.rs:12:1 + | +LL | #[export_visibility = "hidden"] + | ^^^^^^^^^^^^^^^^^^^^^^--------^ + | | | + | | the only valid argument here is "target_default" + | help: must be of the form: `#[export_visibility = "visibility"]` + +error[E0539]: malformed `export_visibility` attribute input + --> $DIR/export-visibility-with-unrecognized-arg.rs:16:1 + | +LL | #[export_visibility = "protected"] + | ^^^^^^^^^^^^^^^^^^^^^^-----------^ + | | | + | | the only valid argument here is "target_default" + | help: must be of the form: `#[export_visibility = "visibility"]` + +error[E0539]: malformed `export_visibility` attribute input + --> $DIR/export-visibility-with-unrecognized-arg.rs:20:1 + | +LL | #[export_visibility = "interposable"] + | ^^^^^^^^^^^^^^^^^^^^^^--------------^ + | | | + | | the only valid argument here is "target_default" + | help: must be of the form: `#[export_visibility = "visibility"]` + +error[E0539]: malformed `export_visibility` attribute input + --> $DIR/export-visibility-with-unrecognized-arg.rs:26:1 + | +LL | #[export_visibility = "default"] + | ^^^^^^^^^^^^^^^^^^^^^^---------^ + | | | + | | the only valid argument here is "target_default" + | help: must be of the form: `#[export_visibility = "visibility"]` + +error[E0539]: malformed `export_visibility` attribute input + --> $DIR/export-visibility-with-unrecognized-arg.rs:30:1 + | +LL | #[export_visibility = "public"] + | ^^^^^^^^^^^^^^^^^^^^^^--------^ + | | | + | | the only valid argument here is "target_default" + | help: must be of the form: `#[export_visibility = "visibility"]` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/attributes/export-visibility-without-export-name.rs b/tests/ui/attributes/export-visibility-without-export-name.rs new file mode 100644 index 0000000000000..bc50388206ad8 --- /dev/null +++ b/tests/ui/attributes/export-visibility-without-export-name.rs @@ -0,0 +1,8 @@ +// This test verfies that `#[export_visibility = ...]` cannot be used without +// either `#[export_name = ...]` or `#[no_mangle]`. +#![feature(export_visibility)] +#[export_visibility = "target_default"] +//~^ ERROR: #[export_visibility = ...]` will be ignored +pub static TESTED_STATIC: [u8; 6] = *b"foobar"; + +fn main() {} diff --git a/tests/ui/attributes/export-visibility-without-export-name.stderr b/tests/ui/attributes/export-visibility-without-export-name.stderr new file mode 100644 index 0000000000000..027c4fd62faa0 --- /dev/null +++ b/tests/ui/attributes/export-visibility-without-export-name.stderr @@ -0,0 +1,8 @@ +error: `#[export_visibility = ...]` will be ignored without `export_name`, `no_mangle`, or similar attribute + --> $DIR/export-visibility-without-export-name.rs:4:1 + | +LL | #[export_visibility = "target_default"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/feature-gates/feature-gate-export-visibility.rs b/tests/ui/feature-gates/feature-gate-export-visibility.rs new file mode 100644 index 0000000000000..eb059b2729fe0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-export-visibility.rs @@ -0,0 +1,11 @@ +// This test verfies that `#[export_visibility = ...]` cannot be used without +// opting into the corresponding unstable feature via +// `#![feature(export_visibility)]`. +#[export_visibility = "target_default"] +//~^ ERROR: the `#[export_visibility]` attribute is an experimental feature +// `#[export_name = ...]` is present to avoid hitting the following error: +// export visibility will be ignored without `export_name`, `no_mangle`, or similar attribute +#[unsafe(export_name = "exported_static")] +pub static TESTED_STATIC: [u8; 6] = *b"foobar"; + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-export-visibility.stderr b/tests/ui/feature-gates/feature-gate-export-visibility.stderr new file mode 100644 index 0000000000000..9e5bc27bc745e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-export-visibility.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `#[export_visibility]` attribute is an experimental feature + --> $DIR/feature-gate-export-visibility.rs:4:1 + | +LL | #[export_visibility = "target_default"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #151425 for more information + = help: add `#![feature(export_visibility)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. From 9092262255e1c79b473e91fb43e45eaaa005ec8d Mon Sep 17 00:00:00 2001 From: randomicon00 <20146907+randomicon00@users.noreply.github.com> Date: Tue, 24 Feb 2026 22:28:52 -0500 Subject: [PATCH 09/10] fix: mem::conjure_zst panic message to use any::type_name instead of stringify! --- library/core/src/mem/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index eb6f8f9757215..d8521e79006e3 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1488,12 +1488,13 @@ pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { /// /// [inhabited]: https://doc.rust-lang.org/reference/glossary.html#inhabited #[unstable(feature = "mem_conjure_zst", issue = "95383")] +#[rustc_const_unstable(feature = "mem_conjure_zst", issue = "95383")] pub const unsafe fn conjure_zst() -> T { const_assert!( size_of::() == 0, - "mem::conjure_zst invoked on a nonzero-sized type", - "mem::conjure_zst invoked on type {t}, which is not zero-sized", - t: &str = stringify!(T) + "mem::conjure_zst invoked on a non-zero-sized type", + "mem::conjure_zst invoked on type {name}, which is not zero-sized", + name: &str = crate::any::type_name::() ); // SAFETY: because the caller must guarantee that it's inhabited and zero-sized, From 882ae150e93f7c1aef17018a64540fa8b5bec943 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 27 Feb 2026 12:39:20 +1100 Subject: [PATCH 10/10] Work around a false `err.emit();` type error in rust-analyzer --- compiler/rustc_interface/src/util.rs | 2 +- compiler/rustc_parse/src/lib.rs | 2 +- compiler/rustc_session/src/config.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 08e40116b47c0..f1b80ec13a307 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -300,7 +300,7 @@ internal compiler error: query cycle handler thread panicked, aborting process"; diag.help( "try lowering `-Z threads` or checking the operating system's resource limits", ); - diag.emit(); + diag.emit() }) }) }) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 1502e5ef5496f..1124f5830b6e6 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -132,7 +132,7 @@ pub fn new_parser_from_file<'a>( if let Some(sp) = sp { err.span(sp); } - err.emit(); + err.emit() }); new_parser_from_source_file(psess, source_file, strip_tokens) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b278a6179fe7f..0677ca0fddbaa 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1615,7 +1615,7 @@ pub fn build_target_config( let mut err = early_dcx.early_struct_fatal(format!("error loading target specification: {e}")); err.help("run `rustc --print target-list` for a list of built-in targets"); - err.emit(); + err.emit() } } }