From 65a91d179f56e9866c7d501293121887330e4956 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 8 Mar 2026 22:02:16 +0900 Subject: [PATCH 01/23] Add suggestion for E0401 on inner const items --- compiler/rustc_resolve/src/diagnostics.rs | 26 +++++++---- compiler/rustc_resolve/src/errors.rs | 15 ++++++ compiler/rustc_resolve/src/ident.rs | 8 ++-- compiler/rustc_resolve/src/lib.rs | 3 +- ...om-outer-item-in-const-item.default.stderr | 19 +++++++- ...m-in-const-item.generic_const_items.stderr | 19 +++++++- ...ic-params-from-outer-item-in-const-item.rs | 3 ++ ...ic-params-from-outer-item-suggestion.fixed | 39 ++++++++++++++++ ...neric-params-from-outer-item-suggestion.rs | 39 ++++++++++++++++ ...c-params-from-outer-item-suggestion.stderr | 46 +++++++++++++++++++ 10 files changed, 200 insertions(+), 17 deletions(-) create mode 100644 tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed create mode 100644 tests/ui/resolve/generic-params-from-outer-item-suggestion.rs create mode 100644 tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 1b1198af41c0e..a8a78854d7293 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -573,12 +573,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span, label: None, refer_to_type_directly: None, + use_let: None, sugg: None, static_or_const, is_self, - item: inner_item.as_ref().map(|(span, kind)| { + item: inner_item.as_ref().map(|(label_span, _, kind)| { errs::GenericParamsFromOuterItemInnerItem { - span: *span, + span: *label_span, descr: kind.descr().to_string(), is_self, } @@ -586,10 +587,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let sm = self.tcx.sess.source_map(); + // Note: do not early return for missing def_id here, + // we still want to provide suggestions for `Res::SelfTyParam` and `Res::SelfTyAlias`. let def_id = match outer_res { Res::SelfTyParam { .. } => { err.label = Some(Label::SelfTyParam(span)); - return self.dcx().create_err(err); + None } Res::SelfTyAlias { alias_to: def_id, .. } => { err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword( @@ -598,15 +601,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ))); err.refer_to_type_directly = current_self_ty.map(|snippet| errs::UseTypeDirectly { span, snippet }); - return self.dcx().create_err(err); + None } Res::Def(DefKind::TyParam, def_id) => { err.label = Some(Label::TyParam(self.def_span(def_id))); - def_id + Some(def_id) } Res::Def(DefKind::ConstParam, def_id) => { err.label = Some(Label::ConstParam(self.def_span(def_id))); - def_id + Some(def_id) } _ => { bug!( @@ -617,8 +620,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } }; - if let HasGenericParams::Yes(span) = has_generic_params - && !matches!(inner_item, Some((_, ItemKind::Delegation(..)))) + if let Some((_, item_span, ItemKind::Const(_))) = inner_item.as_ref() { + err.use_let = Some(errs::GenericParamsFromOuterItemUseLet { + span: sm.span_until_whitespace(*item_span), + }); + } + + if let Some(def_id) = def_id + && let HasGenericParams::Yes(span) = has_generic_params + && !matches!(inner_item, Some((_, _, ItemKind::Delegation(..)))) { let name = self.tcx.item_name(def_id); let (span, snippet) = if span.is_empty() { diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 63ffdbc37f7d1..d09c76d7947a9 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -33,6 +33,8 @@ pub(crate) struct GenericParamsFromOuterItem { #[subdiagnostic] pub(crate) refer_to_type_directly: Option, #[subdiagnostic] + pub(crate) use_let: Option, + #[subdiagnostic] pub(crate) sugg: Option, #[subdiagnostic] pub(crate) static_or_const: Option, @@ -87,6 +89,19 @@ pub(crate) struct GenericParamsFromOuterItemSugg { pub(crate) span: Span, pub(crate) snippet: String, } + +#[derive(Subdiagnostic)] +#[suggestion( + "try using a local `let` binding instead", + code = "let", + applicability = "maybe-incorrect", + style = "verbose" +)] +pub(crate) struct GenericParamsFromOuterItemUseLet { + #[primary_span] + pub(crate) span: Span, +} + #[derive(Subdiagnostic)] #[suggestion( "refer to the type directly here instead", diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7cfd5b5f861a4..56e77cdde91f1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1582,12 +1582,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let item = if let Some(diag_metadata) = diag_metadata && let Some(current_item) = diag_metadata.current_item { - let span = current_item + let label_span = current_item .kind .ident() .map(|i| i.span) .unwrap_or(current_item.span); - Some((span, current_item.kind.clone())) + Some((label_span, current_item.span, current_item.kind.clone())) } else { None }; @@ -1679,12 +1679,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let item = if let Some(diag_metadata) = diag_metadata && let Some(current_item) = diag_metadata.current_item { - let span = current_item + let label_span = current_item .kind .ident() .map(|i| i.span) .unwrap_or(current_item.span); - Some((span, current_item.kind.clone())) + Some((label_span, current_item.span, current_item.kind.clone())) } else { None }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ead69473b00d1..3cd5c827693a4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -247,7 +247,8 @@ enum ResolutionError<'ra> { outer_res: Res, has_generic_params: HasGenericParams, def_kind: DefKind, - inner_item: Option<(Span, ast::ItemKind)>, + /// 1. label span, 2. item span, 3. item kind + inner_item: Option<(Span, Span, ast::ItemKind)>, current_self_ty: Option, }, /// Error E0403: the name is already used for a type or const parameter in this generic diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr index 8827d1bbb49d3..21f80198f1978 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr @@ -10,9 +10,14 @@ LL | const K: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const K: u32 = T::C; +LL + let K: u32 = T::C; + | error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:20:24 | LL | impl Tr for T { // outer impl block | - type parameter from outer item @@ -24,9 +29,14 @@ LL | const I: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const I: u32 = T::C; +LL + let I: u32 = T::C; + | error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:29:20 | LL | struct S(U32<{ // outer struct | - type parameter from outer item @@ -37,6 +47,11 @@ LL | const _: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const _: u32 = T::C; +LL + let _: u32 = T::C; + | error: aborting due to 3 previous errors diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr index 8ff9771b9ade6..54a53a097bcbe 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr @@ -10,13 +10,18 @@ LL | const K: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const K: u32 = T::C; +LL + let K: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const K: u32 = T::C; | +++ error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:19:24 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:20:24 | LL | impl Tr for T { // outer impl block | - type parameter from outer item @@ -28,13 +33,18 @@ LL | const I: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const I: u32 = T::C; +LL + let I: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const I: u32 = T::C; | +++ error[E0401]: can't use generic parameters from outer item - --> $DIR/generic-params-from-outer-item-in-const-item.rs:27:20 + --> $DIR/generic-params-from-outer-item-in-const-item.rs:29:20 | LL | struct S(U32<{ // outer struct | - type parameter from outer item @@ -45,6 +55,11 @@ LL | const _: u32 = T::C; | = note: nested items are independent from their parent item for everything except for privacy and name resolution = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const _: u32 = T::C; +LL + let _: u32 = T::C; + | help: try introducing a local generic parameter here | LL | const _: u32 = T::C; diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs index c9a64de7f6bba..9616144ec3103 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.rs @@ -11,6 +11,7 @@ fn outer() { // outer function const K: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here } @@ -18,6 +19,7 @@ impl Tr for T { // outer impl block const C: u32 = { const I: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here I }; @@ -26,6 +28,7 @@ impl Tr for T { // outer impl block struct S(U32<{ // outer struct const _: u32 = T::C; //~^ ERROR can't use generic parameters from outer item + //~| HELP try using a local `let` binding instead //[generic_const_items]~| HELP try introducing a local generic parameter here 0 }>); diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed b/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed new file mode 100644 index 0000000000000..fea9f7a6f8516 --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.fixed @@ -0,0 +1,39 @@ +// Regression test for . +// Ensure we provide a suggestion to change from `const` to `let` +// on the generic params from outer item errors. + +//@ run-rustfix + +#![allow(unused, non_snake_case)] + +const fn size_plus_one() -> usize { + //~^ NOTE type parameter from outer item + let size: usize = core::mem::size_of::(); + //~^ ERROR can't use generic parameters from outer item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| NOTE use of generic parameter from outer item + //~| NOTE generic parameter used in this inner constant item + //~| HELP try using a local `let` binding instead + size + 1 +} + +struct A; + +impl A { + //~^ NOTE `Self` type implicitly declared here, by this `impl` + const VALUE: u32 = 1; + + fn f() { + let K: u32 = A::VALUE; + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item + //~| NOTE `Self` used in this inner constant item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| HELP refer to the type directly here instead + //~| HELP try using a local `let` binding instead + } +} + +fn main() {} diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs b/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs new file mode 100644 index 0000000000000..3f87f3e2a2ae8 --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.rs @@ -0,0 +1,39 @@ +// Regression test for . +// Ensure we provide a suggestion to change from `const` to `let` +// on the generic params from outer item errors. + +//@ run-rustfix + +#![allow(unused, non_snake_case)] + +const fn size_plus_one() -> usize { + //~^ NOTE type parameter from outer item + const size: usize = core::mem::size_of::(); + //~^ ERROR can't use generic parameters from outer item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| NOTE use of generic parameter from outer item + //~| NOTE generic parameter used in this inner constant item + //~| HELP try using a local `let` binding instead + size + 1 +} + +struct A; + +impl A { + //~^ NOTE `Self` type implicitly declared here, by this `impl` + const VALUE: u32 = 1; + + fn f() { + const K: u32 = Self::VALUE; + //~^ ERROR can't use `Self` from outer item + //~| NOTE use of `Self` from outer item + //~| NOTE `Self` used in this inner constant item + //~| NOTE nested items are independent + //~| NOTE a `const` is a separate item + //~| HELP refer to the type directly here instead + //~| HELP try using a local `let` binding instead + } +} + +fn main() {} diff --git a/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr b/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr new file mode 100644 index 0000000000000..3d3280cfbbb4b --- /dev/null +++ b/tests/ui/resolve/generic-params-from-outer-item-suggestion.stderr @@ -0,0 +1,46 @@ +error[E0401]: can't use generic parameters from outer item + --> $DIR/generic-params-from-outer-item-suggestion.rs:11:46 + | +LL | const fn size_plus_one() -> usize { + | - type parameter from outer item +LL | +LL | const size: usize = core::mem::size_of::(); + | ---- ^ use of generic parameter from outer item + | | + | generic parameter used in this inner constant item + | + = note: nested items are independent from their parent item for everything except for privacy and name resolution + = note: a `const` is a separate item from the item that contains it +help: try using a local `let` binding instead + | +LL - const size: usize = core::mem::size_of::(); +LL + let size: usize = core::mem::size_of::(); + | + +error[E0401]: can't use `Self` from outer item + --> $DIR/generic-params-from-outer-item-suggestion.rs:28:24 + | +LL | impl A { + | ---- `Self` type implicitly declared here, by this `impl` +... +LL | const K: u32 = Self::VALUE; + | - ^^^^ use of `Self` from outer item + | | + | `Self` used in this inner constant item + | + = note: nested items are independent from their parent item for everything except for privacy and name resolution + = note: a `const` is a separate item from the item that contains it +help: refer to the type directly here instead + | +LL - const K: u32 = Self::VALUE; +LL + const K: u32 = A::VALUE; + | +help: try using a local `let` binding instead + | +LL - const K: u32 = Self::VALUE; +LL + let K: u32 = Self::VALUE; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0401`. From 3f7c6455178d2918803dde16bb5ed1b47c327c2b Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Mon, 30 Mar 2026 17:41:22 +0100 Subject: [PATCH 02/23] Suggest public re-exports when a private module blocks an import path When an import like `use crate::a::b::Item` fails because module `b` is private, the resolver now looks up public re-export paths for `Item` and suggests them to the user. --- compiler/rustc_resolve/src/diagnostics.rs | 111 +++++++++++++++++++++- compiler/rustc_resolve/src/imports.rs | 21 ++++ 2 files changed, 131 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 97c88064e9799..e16645ec0df45 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2116,6 +2116,111 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()` } + /// Returns the path segments (as symbols) of a module, including `kw::Crate` at the start. + /// For example, for `crate::foo::bar`, returns `[Crate, foo, bar]`. + /// Returns `None` for block modules that don't have a `DefId`. + fn module_path_names(&self, module: Module<'ra>) -> Option> { + let mut path = Vec::new(); + let mut def_id = module.opt_def_id()?; + while let Some(parent) = self.tcx.opt_parent(def_id) { + if let Some(name) = self.tcx.opt_item_name(def_id) { + path.push(name); + } + if parent.is_top_level_module() { + break; + } + def_id = parent; + } + path.reverse(); + path.insert(0, kw::Crate); + Some(path) + } + + /// Shortens a candidate import path to use `super::` (up to 1 level) or `self::` (same module) + /// relative to the current scope, if possible. Only applies to crate-local items and + /// only when the resulting path is actually shorter than the original. + fn shorten_candidate_path( + &self, + suggestion: &mut ImportSuggestion, + current_module: Module<'ra>, + ) { + const MAX_SUPER_PATH_ITEMS_IN_SUGGESTION: usize = 1; + + // Only shorten local items. + if suggestion.did.is_none_or(|did| !did.is_local()) { + return; + } + + // Build current module path: [Crate, foo, bar, ...]. + let Some(current_mod_path) = self.module_path_names(current_module) else { + return; + }; + + // Normalise candidate path: filter out `PathRoot` (`::`), and if the path + // doesn't start with `Crate`, prepend it (edition 2015 paths are relative + // to the crate root without an explicit `crate::` prefix). + let candidate_names = { + let filtered_segments: Vec<_> = suggestion + .path + .segments + .iter() + .filter(|segment| segment.ident.name != kw::PathRoot) + .collect(); + + let mut candidate_names: Vec = + filtered_segments.iter().map(|segment| segment.ident.name).collect(); + if candidate_names.first() != Some(&kw::Crate) { + candidate_names.insert(0, kw::Crate); + } + if candidate_names.len() < 2 { + return; + } + candidate_names + }; + + // The candidate's module path is everything except the last segment (the item name). + let candidate_mod_names = &candidate_names[..candidate_names.len() - 1]; + + // Find the longest common prefix between the current module and candidate module paths. + let common_prefix_length = current_mod_path + .iter() + .zip(candidate_mod_names.iter()) + .take_while(|(current, candidate)| current == candidate) + .count(); + + // Non-crate-local item; keep the full absolute path. + if common_prefix_length == 0 { + return; + } + + let super_count = current_mod_path.len() - common_prefix_length; + + // At the crate root, `use` paths resolve from the crate root anyway, so we can + // drop the `crate::` prefix entirely instead of replacing it with `self::`. + let at_crate_root = current_mod_path.len() == 1; + + let mut new_segments = if super_count == 0 && at_crate_root { + ThinVec::new() + } else { + let prefix_keyword = match super_count { + 0 => kw::SelfLower, + 1..=MAX_SUPER_PATH_ITEMS_IN_SUGGESTION => kw::Super, + _ => return, // Too many `super` levels; keep the full absolute path. + }; + thin_vec![ast::PathSegment::from_ident(Ident::with_dummy_span(prefix_keyword),)] + }; + for &name in &candidate_names[common_prefix_length..] { + new_segments.push(ast::PathSegment::from_ident(Ident::with_dummy_span(name))); + } + + // Only apply if the result is strictly shorter than the original path. + if new_segments.len() >= suggestion.path.segments.len() { + return; + } + + suggestion.path = Path { span: suggestion.path.span, segments: new_segments, tokens: None }; + } + fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { let PrivacyError { ident, @@ -2144,12 +2249,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut not_publicly_reexported = false; if let Some((this_res, outer_ident)) = outermost_res { - let import_suggestions = self.lookup_import_candidates( + let mut import_suggestions = self.lookup_import_candidates( outer_ident, this_res.ns().unwrap_or(Namespace::TypeNS), &parent_scope, &|res: Res| res == this_res, ); + // Shorten candidate paths using `super::` or `self::` when possible. + for suggestion in &mut import_suggestions { + self.shorten_candidate_path(suggestion, parent_scope.module); + } let point_to_def = !show_candidates( self.tcx, &mut err, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 6507ee3477379..db098b4a14bc4 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1188,6 +1188,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for error in &mut self.privacy_errors[privacy_errors_len..] { error.outermost_res = res; } + } else { + // The final item is not a module (e.g., a struct, function, or macro). + // Resolve it directly in the parent module to get its Res, so + // `report_privacy_error()` can search for public re-export paths. + for ns in [TypeNS, ValueNS, MacroNS] { + if let Ok(binding) = self.cm().resolve_ident_in_module( + module, + ident, + ns, + &import.parent_scope, + None, + ignore_decl, + None, + ) { + let res = binding.res(); + for error in &mut self.privacy_errors[privacy_errors_len..] { + error.outermost_res = Some((res, ident)); + } + break; + } + } } } From 70fd887aa2c6a7a5dad1a3a635526e6b2d89097e Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Mon, 30 Mar 2026 17:41:33 +0100 Subject: [PATCH 03/23] Add and update tests for public re-export suggestions on private module errors --- tests/ui/imports/reexports.stderr | 8 +- .../suggest-public-reexport-for-use.rs | 49 ++++++++ .../suggest-public-reexport-for-use.stderr | 119 ++++++++++++++++++ tests/ui/privacy/privacy1.stderr | 17 ++- 4 files changed, 189 insertions(+), 4 deletions(-) create mode 100644 tests/ui/imports/suggest-public-reexport-for-use.rs create mode 100644 tests/ui/imports/suggest-public-reexport-for-use.stderr diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr index 0ebcf8e58d627..cb3836305c1ab 100644 --- a/tests/ui/imports/reexports.stderr +++ b/tests/ui/imports/reexports.stderr @@ -14,7 +14,9 @@ error[E0603]: module import `foo` is private --> $DIR/reexports.rs:36:22 | LL | use crate::b::a::foo::S; - | ^^^ private module import + | ^^^ - struct `S` is not publicly re-exported + | | + | private module import | note: the module import `foo` is defined here... --> $DIR/reexports.rs:24:17 @@ -31,7 +33,9 @@ error[E0603]: module import `foo` is private --> $DIR/reexports.rs:37:22 | LL | use crate::b::b::foo::S as T; - | ^^^ private module import + | ^^^ - struct `S` is not publicly re-exported + | | + | private module import | note: the module import `foo` is defined here... --> $DIR/reexports.rs:29:17 diff --git a/tests/ui/imports/suggest-public-reexport-for-use.rs b/tests/ui/imports/suggest-public-reexport-for-use.rs new file mode 100644 index 0000000000000..161d257510d26 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.rs @@ -0,0 +1,49 @@ +//@ edition:2021 + +// When a `use` statement accesses an item through a private module, +// the compiler should suggest a public re-export if one exists. + +mod outer { + pub use self::inner::MyStruct; + pub use self::inner::my_function; + pub use self::inner::MyTrait; + pub use self::inner::MyEnum; + + mod inner { + pub struct MyStruct; + pub fn my_function() {} + pub trait MyTrait {} + pub enum MyEnum { + Variant, + } + } +} + +// Accessing items through a private module should suggest the public re-export. +use outer::inner::MyStruct; //~ ERROR module `inner` is private +use outer::inner::my_function; //~ ERROR module `inner` is private +use outer::inner::MyTrait; //~ ERROR module `inner` is private +use outer::inner::MyEnum; //~ ERROR module `inner` is private + +// From a sibling module, the suggestion should use `super::`. +mod sibling { + use crate::outer::inner::MyStruct; //~ ERROR module `inner` is private +} + +// From a deeply nested module, the suggestion should keep the full path. +mod deep { + mod nested { + use crate::outer::inner::MyStruct; //~ ERROR module `inner` is private + } +} + +// Items with no public re-export should say "not publicly re-exported". +mod no_reexport { + mod hidden { + pub struct Secret; + } +} + +use no_reexport::hidden::Secret; //~ ERROR module `hidden` is private + +fn main() {} diff --git a/tests/ui/imports/suggest-public-reexport-for-use.stderr b/tests/ui/imports/suggest-public-reexport-for-use.stderr new file mode 100644 index 0000000000000..2a86e52155ed0 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:23:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:12:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:24:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:12:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use crate::outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:25:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:12:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use crate::outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:26:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:12:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use crate::outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:23 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:12:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:36:27 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:12:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:47:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:42:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/privacy/privacy1.stderr b/tests/ui/privacy/privacy1.stderr index f62ef3ae2e4cc..5d1e003c703b4 100644 --- a/tests/ui/privacy/privacy1.stderr +++ b/tests/ui/privacy/privacy1.stderr @@ -4,6 +4,12 @@ error[E0603]: module `baz` is private LL | use bar::baz::{foo, bar}; | ^^^ private module | +help: consider importing this function through its public re-export instead: + bar::foo + --> $DIR/privacy1.rs:139:24 + | +LL | use bar::baz::{foo, bar}; + | ^^^ note: the module `baz` is defined here --> $DIR/privacy1.rs:57:5 | @@ -16,12 +22,17 @@ error[E0603]: module `baz` is private LL | use bar::baz::{foo, bar}; | ^^^ private module | +help: consider importing this function through its public re-export instead: + bar::bar + --> $DIR/privacy1.rs:139:29 + | +LL | use bar::baz::{foo, bar}; + | ^^^ note: the module `baz` is defined here --> $DIR/privacy1.rs:57:5 | LL | mod baz { | ^^^^^^^ - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0603]: module `baz` is private --> $DIR/privacy1.rs:148:18 @@ -39,7 +50,9 @@ error[E0603]: module `i` is private --> $DIR/privacy1.rs:172:20 | LL | use self::foo::i::A; - | ^ private module + | ^ - struct `A` is not publicly re-exported + | | + | private module | note: the module `i` is defined here --> $DIR/privacy1.rs:177:9 From d4617fa747d99d7eab4a0f9f98ddd806b597044d Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Mon, 30 Mar 2026 22:09:47 +0100 Subject: [PATCH 04/23] Parametrise the newly added test by all four editions --- ...public-reexport-for-use.edition2015.stderr | 119 ++++++++++++++++++ ...ublic-reexport-for-use.edition2018.stderr} | 36 +++--- ...public-reexport-for-use.edition2021.stderr | 119 ++++++++++++++++++ ...public-reexport-for-use.edition2024.stderr | 119 ++++++++++++++++++ .../suggest-public-reexport-for-use.rs | 21 +++- 5 files changed, 392 insertions(+), 22 deletions(-) create mode 100644 tests/ui/imports/suggest-public-reexport-for-use.edition2015.stderr rename tests/ui/imports/{suggest-public-reexport-for-use.stderr => suggest-public-reexport-for-use.edition2018.stderr} (74%) create mode 100644 tests/ui/imports/suggest-public-reexport-for-use.edition2021.stderr create mode 100644 tests/ui/imports/suggest-public-reexport-for-use.edition2024.stderr diff --git a/tests/ui/imports/suggest-public-reexport-for-use.edition2015.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2015.stderr new file mode 100644 index 0000000000000..815f91a0b6c8a --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2015.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:27:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:28:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:29:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:36:16 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:46:20 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:60:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:55:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/suggest-public-reexport-for-use.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2018.stderr similarity index 74% rename from tests/ui/imports/suggest-public-reexport-for-use.stderr rename to tests/ui/imports/suggest-public-reexport-for-use.edition2018.stderr index 2a86e52155ed0..0295cb29ca3e2 100644 --- a/tests/ui/imports/suggest-public-reexport-for-use.stderr +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2018.stderr @@ -1,79 +1,79 @@ error[E0603]: module `inner` is private - --> $DIR/suggest-public-reexport-for-use.rs:23:12 + --> $DIR/suggest-public-reexport-for-use.rs:27:12 | LL | use outer::inner::MyStruct; | ^^^^^ private module | note: the module `inner` is defined here - --> $DIR/suggest-public-reexport-for-use.rs:12:5 + --> $DIR/suggest-public-reexport-for-use.rs:16:5 | LL | mod inner { | ^^^^^^^^^ help: consider importing this struct through its public re-export instead | LL - use outer::inner::MyStruct; -LL + use crate::outer::MyStruct; +LL + use outer::MyStruct; | error[E0603]: module `inner` is private - --> $DIR/suggest-public-reexport-for-use.rs:24:12 + --> $DIR/suggest-public-reexport-for-use.rs:28:12 | LL | use outer::inner::my_function; | ^^^^^ private module | note: the module `inner` is defined here - --> $DIR/suggest-public-reexport-for-use.rs:12:5 + --> $DIR/suggest-public-reexport-for-use.rs:16:5 | LL | mod inner { | ^^^^^^^^^ help: consider importing this function through its public re-export instead | LL - use outer::inner::my_function; -LL + use crate::outer::my_function; +LL + use outer::my_function; | error[E0603]: module `inner` is private - --> $DIR/suggest-public-reexport-for-use.rs:25:12 + --> $DIR/suggest-public-reexport-for-use.rs:29:12 | LL | use outer::inner::MyTrait; | ^^^^^ private module | note: the module `inner` is defined here - --> $DIR/suggest-public-reexport-for-use.rs:12:5 + --> $DIR/suggest-public-reexport-for-use.rs:16:5 | LL | mod inner { | ^^^^^^^^^ help: consider importing this trait through its public re-export instead | LL - use outer::inner::MyTrait; -LL + use crate::outer::MyTrait; +LL + use outer::MyTrait; | error[E0603]: module `inner` is private - --> $DIR/suggest-public-reexport-for-use.rs:26:12 + --> $DIR/suggest-public-reexport-for-use.rs:30:12 | LL | use outer::inner::MyEnum; | ^^^^^ private module | note: the module `inner` is defined here - --> $DIR/suggest-public-reexport-for-use.rs:12:5 + --> $DIR/suggest-public-reexport-for-use.rs:16:5 | LL | mod inner { | ^^^^^^^^^ help: consider importing this enum through its public re-export instead | LL - use outer::inner::MyEnum; -LL + use crate::outer::MyEnum; +LL + use outer::MyEnum; | error[E0603]: module `inner` is private - --> $DIR/suggest-public-reexport-for-use.rs:30:23 + --> $DIR/suggest-public-reexport-for-use.rs:39:23 | LL | use crate::outer::inner::MyStruct; | ^^^^^ private module | note: the module `inner` is defined here - --> $DIR/suggest-public-reexport-for-use.rs:12:5 + --> $DIR/suggest-public-reexport-for-use.rs:16:5 | LL | mod inner { | ^^^^^^^^^ @@ -84,13 +84,13 @@ LL + use crate::outer::MyStruct; | error[E0603]: module `inner` is private - --> $DIR/suggest-public-reexport-for-use.rs:36:27 + --> $DIR/suggest-public-reexport-for-use.rs:49:27 | LL | use crate::outer::inner::MyStruct; | ^^^^^ private module | note: the module `inner` is defined here - --> $DIR/suggest-public-reexport-for-use.rs:12:5 + --> $DIR/suggest-public-reexport-for-use.rs:16:5 | LL | mod inner { | ^^^^^^^^^ @@ -101,7 +101,7 @@ LL + use crate::outer::MyStruct; | error[E0603]: module `hidden` is private - --> $DIR/suggest-public-reexport-for-use.rs:47:18 + --> $DIR/suggest-public-reexport-for-use.rs:60:18 | LL | use no_reexport::hidden::Secret; | ^^^^^^ ------ struct `Secret` is not publicly re-exported @@ -109,7 +109,7 @@ LL | use no_reexport::hidden::Secret; | private module | note: the module `hidden` is defined here - --> $DIR/suggest-public-reexport-for-use.rs:42:5 + --> $DIR/suggest-public-reexport-for-use.rs:55:5 | LL | mod hidden { | ^^^^^^^^^^ diff --git a/tests/ui/imports/suggest-public-reexport-for-use.edition2021.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2021.stderr new file mode 100644 index 0000000000000..0295cb29ca3e2 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2021.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:27:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:28:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:29:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:39:23 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:49:27 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:60:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:55:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/suggest-public-reexport-for-use.edition2024.stderr b/tests/ui/imports/suggest-public-reexport-for-use.edition2024.stderr new file mode 100644 index 0000000000000..0295cb29ca3e2 --- /dev/null +++ b/tests/ui/imports/suggest-public-reexport-for-use.edition2024.stderr @@ -0,0 +1,119 @@ +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:27:12 + | +LL | use outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use outer::inner::MyStruct; +LL + use outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:28:12 + | +LL | use outer::inner::my_function; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use outer::inner::my_function; +LL + use outer::my_function; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:29:12 + | +LL | use outer::inner::MyTrait; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this trait through its public re-export instead + | +LL - use outer::inner::MyTrait; +LL + use outer::MyTrait; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:30:12 + | +LL | use outer::inner::MyEnum; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this enum through its public re-export instead + | +LL - use outer::inner::MyEnum; +LL + use outer::MyEnum; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:39:23 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `inner` is private + --> $DIR/suggest-public-reexport-for-use.rs:49:27 + | +LL | use crate::outer::inner::MyStruct; + | ^^^^^ private module + | +note: the module `inner` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:16:5 + | +LL | mod inner { + | ^^^^^^^^^ +help: consider importing this struct through its public re-export instead + | +LL - use crate::outer::inner::MyStruct; +LL + use crate::outer::MyStruct; + | + +error[E0603]: module `hidden` is private + --> $DIR/suggest-public-reexport-for-use.rs:60:18 + | +LL | use no_reexport::hidden::Secret; + | ^^^^^^ ------ struct `Secret` is not publicly re-exported + | | + | private module + | +note: the module `hidden` is defined here + --> $DIR/suggest-public-reexport-for-use.rs:55:5 + | +LL | mod hidden { + | ^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0603`. diff --git a/tests/ui/imports/suggest-public-reexport-for-use.rs b/tests/ui/imports/suggest-public-reexport-for-use.rs index 161d257510d26..1658735e36cf9 100644 --- a/tests/ui/imports/suggest-public-reexport-for-use.rs +++ b/tests/ui/imports/suggest-public-reexport-for-use.rs @@ -1,4 +1,8 @@ -//@ edition:2021 +//@ revisions: edition2015 edition2018 edition2021 edition2024 +//@ [edition2015] edition:2015 +//@ [edition2018] edition:2018 +//@ [edition2021] edition:2021 +//@ [edition2024] edition:2024 // When a `use` statement accesses an item through a private module, // the compiler should suggest a public re-export if one exists. @@ -25,15 +29,24 @@ use outer::inner::my_function; //~ ERROR module `inner` is private use outer::inner::MyTrait; //~ ERROR module `inner` is private use outer::inner::MyEnum; //~ ERROR module `inner` is private -// From a sibling module, the suggestion should use `super::`. +// From a sibling module, the suggestion should keep the full path +// (shortening to `super::` would not reduce the segment count here). mod sibling { - use crate::outer::inner::MyStruct; //~ ERROR module `inner` is private + #[cfg(edition2015)] + use outer::inner::MyStruct; //[edition2015]~ ERROR module `inner` is private + + #[cfg(not(edition2015))] + use crate::outer::inner::MyStruct; //[edition2018,edition2021,edition2024]~ ERROR module `inner` is private } // From a deeply nested module, the suggestion should keep the full path. mod deep { mod nested { - use crate::outer::inner::MyStruct; //~ ERROR module `inner` is private + #[cfg(edition2015)] + use outer::inner::MyStruct; //[edition2015]~ ERROR module `inner` is private + + #[cfg(not(edition2015))] + use crate::outer::inner::MyStruct; //[edition2018,edition2021,edition2024]~ ERROR module `inner` is private } } From d09d4c999dc0796b820dcdb4d77eb1e10343a18d Mon Sep 17 00:00:00 2001 From: Jacob Adam Date: Mon, 30 Mar 2026 23:19:55 +0100 Subject: [PATCH 05/23] Update the expected results for two other tests --- tests/ui/shadowed/shadowed-use-visibility.stderr | 10 ++++++++++ tests/ui/use/use-mod/use-mod-3.stderr | 2 ++ 2 files changed, 12 insertions(+) diff --git a/tests/ui/shadowed/shadowed-use-visibility.stderr b/tests/ui/shadowed/shadowed-use-visibility.stderr index b062341dc8be8..bbec8380fd032 100644 --- a/tests/ui/shadowed/shadowed-use-visibility.stderr +++ b/tests/ui/shadowed/shadowed-use-visibility.stderr @@ -14,6 +14,11 @@ note: ...and refers to the module `foo` which is defined here | LL | mod foo { | ^^^^^^^ +help: consider importing this function instead + | +LL - use crate::foo::bar::f as g; +LL + use foo::f as g; + | error[E0603]: module import `f` is private --> $DIR/shadowed-use-visibility.rs:15:10 @@ -31,6 +36,11 @@ note: ...and refers to the module `foo` which is defined here | LL | mod foo { | ^^^^^^^ +help: consider importing this function through its public re-export instead + | +LL - use bar::f::f; +LL + use bar::f; + | error: aborting due to 2 previous errors diff --git a/tests/ui/use/use-mod/use-mod-3.stderr b/tests/ui/use/use-mod/use-mod-3.stderr index 1b12b3c6fa09a..2143d09f6b983 100644 --- a/tests/ui/use/use-mod/use-mod-3.stderr +++ b/tests/ui/use/use-mod/use-mod-3.stderr @@ -15,6 +15,8 @@ error[E0603]: module `bar` is private | LL | use foo::bar::{ | ^^^ private module +LL | Bar + | --- type alias `Bar` is not publicly re-exported | note: the module `bar` is defined here --> $DIR/use-mod-3.rs:9:5 From 526f3d9bbe8927f9862a23f45c3d06aa3761b89b Mon Sep 17 00:00:00 2001 From: ujjwalVishwakarma2006 <2023ucs0116@iitjammu.ac.in> Date: Sun, 19 Apr 2026 23:44:20 +0530 Subject: [PATCH 06/23] Move test files from issues/ to appropriate subdirectories --- .../dont-allow-inline-and-repr-at-invalid-positions.rs} | 0 .../dont-allow-inline-and-repr-at-invalid-positions.stderr} | 0 .../issue-33202.rs => attributes/repr-on-single-variant-Enum.rs} | 0 .../foreign-fn-with-more-than-8-byte-arg-size.rs} | 0 .../recursive-struct-with-raw-pointer-field.rs} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-31769.rs => attributes/dont-allow-inline-and-repr-at-invalid-positions.rs} (100%) rename tests/ui/{issues/issue-31769.stderr => attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr} (100%) rename tests/ui/{issues/issue-33202.rs => attributes/repr-on-single-variant-Enum.rs} (100%) rename tests/ui/{issues/issue-38763.rs => foreign/foreign-fn-with-more-than-8-byte-arg-size.rs} (100%) rename tests/ui/{issues/issue-19001.rs => recursion/recursive-struct-with-raw-pointer-field.rs} (100%) diff --git a/tests/ui/issues/issue-31769.rs b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs similarity index 100% rename from tests/ui/issues/issue-31769.rs rename to tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs diff --git a/tests/ui/issues/issue-31769.stderr b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr similarity index 100% rename from tests/ui/issues/issue-31769.stderr rename to tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr diff --git a/tests/ui/issues/issue-33202.rs b/tests/ui/attributes/repr-on-single-variant-Enum.rs similarity index 100% rename from tests/ui/issues/issue-33202.rs rename to tests/ui/attributes/repr-on-single-variant-Enum.rs diff --git a/tests/ui/issues/issue-38763.rs b/tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs similarity index 100% rename from tests/ui/issues/issue-38763.rs rename to tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs diff --git a/tests/ui/issues/issue-19001.rs b/tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs similarity index 100% rename from tests/ui/issues/issue-19001.rs rename to tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs From c4f6148fd9556c46ad7cc490e0b204c4dfb98c73 Mon Sep 17 00:00:00 2001 From: ujjwalVishwakarma2006 <2023ucs0116@iitjammu.ac.in> Date: Sun, 19 Apr 2026 23:51:38 +0530 Subject: [PATCH 07/23] Add issue links --- .../dont-allow-inline-and-repr-at-invalid-positions.rs | 1 + .../dont-allow-inline-and-repr-at-invalid-positions.stderr | 4 ++-- tests/ui/attributes/repr-on-single-variant-Enum.rs | 1 + tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs | 1 + tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs | 1 + 5 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs index 354c1be9ed554..f295ecf302598 100644 --- a/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs +++ b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.rs @@ -1,3 +1,4 @@ +//! Regression test for fn main() { #[inline] struct Foo; //~ ERROR attribute cannot be used on #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to a struct, enum, or union diff --git a/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr index 0f75e84f2a704..fc8e22f171c20 100644 --- a/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr +++ b/tests/ui/attributes/dont-allow-inline-and-repr-at-invalid-positions.stderr @@ -1,5 +1,5 @@ error: `#[inline]` attribute cannot be used on structs - --> $DIR/issue-31769.rs:2:5 + --> $DIR/dont-allow-inline-and-repr-at-invalid-positions.rs:3:5 | LL | #[inline] struct Foo; | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[inline] struct Foo; = help: `#[inline]` can only be applied to functions error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-31769.rs:3:12 + --> $DIR/dont-allow-inline-and-repr-at-invalid-positions.rs:4:12 | LL | #[repr(C)] fn foo() {} | ^ ----------- not a struct, enum, or union diff --git a/tests/ui/attributes/repr-on-single-variant-Enum.rs b/tests/ui/attributes/repr-on-single-variant-Enum.rs index 3fef98606afab..ab45c76ef5aae 100644 --- a/tests/ui/attributes/repr-on-single-variant-Enum.rs +++ b/tests/ui/attributes/repr-on-single-variant-Enum.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass #[repr(C)] pub enum CPOption { diff --git a/tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs b/tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs index 87c758db1723c..4bd78a423cd2c 100644 --- a/tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs +++ b/tests/ui/foreign/foreign-fn-with-more-than-8-byte-arg-size.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass //@ needs-threads diff --git a/tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs b/tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs index 51aebf88c95fb..97fa08fab1d93 100644 --- a/tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs +++ b/tests/ui/recursion/recursive-struct-with-raw-pointer-field.rs @@ -1,3 +1,4 @@ +//! Regression test for //@ run-pass #![allow(dead_code)] // check that we handle recursive arrays correctly in `type_of` From 1a681b03162b141fe75eaf146e38a25e486dbe7f Mon Sep 17 00:00:00 2001 From: lapla Date: Mon, 27 Apr 2026 11:06:54 +0900 Subject: [PATCH 08/23] Use `_mcount` as the mcount symbol name on RISC-V Linux GNU targets --- .../rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs | 1 + .../src/spec/targets/riscv64a23_unknown_linux_gnu.rs | 1 + .../rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs index c11edf7c618c2..b936a2ba2570d 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32gc_unknown_linux_gnu.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { llvm_abiname: LlvmAbi::Ilp32d, max_atomic_width: Some(32), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "\u{1}_mcount".into(), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs index f9a7d307c74a3..74a8a88dff674 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64a23_unknown_linux_gnu.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "\u{1}_mcount".into(), ..base::linux_gnu::opts() }, } diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs index 76c9ad65700c2..f362e694db4d2 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_linux_gnu.rs @@ -23,6 +23,7 @@ pub(crate) fn target() -> Target { llvm_abiname: LlvmAbi::Lp64d, max_atomic_width: Some(64), supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), + mcount: "\u{1}_mcount".into(), ..base::linux_gnu::opts() }, } From c13cfc627efadd44664104ed5cbafb776273a745 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 15 Apr 2026 12:10:16 +0000 Subject: [PATCH 09/23] move `AstFragment::to_string` out of `ast_fragments!` --- compiler/rustc_expand/src/expand.rs | 82 +++++++++++++++++------------ compiler/rustc_expand/src/stats.rs | 4 -- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 804d3c02b413d..861af0fd74203 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -57,12 +57,10 @@ macro_rules! ast_fragments { $(one fn $mut_visit_ast:ident; fn $visit_ast:ident; - fn $ast_to_string:path; )? $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*); - fn $ast_to_string_elt:path; )? fn $make_ast:ident; })* @@ -166,21 +164,6 @@ macro_rules! ast_fragments { } V::Result::output() } - - pub(crate) fn to_string(&self) -> String { - match self { - AstFragment::OptExpr(Some(expr)) => pprust::expr_to_string(expr), - AstFragment::OptExpr(None) => unreachable!(), - AstFragment::MethodReceiverExpr(expr) => pprust::expr_to_string(expr), - $($(AstFragment::$Kind(ast) => $ast_to_string(ast),)?)* - $($( - AstFragment::$Kind(ast) => { - // The closure unwraps a `P` if present, or does nothing otherwise. - elems_to_string(&*ast, |ast| $ast_to_string_elt(&*ast)) - } - )?)* - } - } } impl<'a, 'b> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a, 'b> { @@ -195,98 +178,127 @@ macro_rules! ast_fragments { ast_fragments! { Expr(Box) { "expression"; - one fn visit_expr; fn visit_expr; fn pprust::expr_to_string; + one fn visit_expr; fn visit_expr; fn make_expr; } Pat(Box) { "pattern"; - one fn visit_pat; fn visit_pat; fn pprust::pat_to_string; + one fn visit_pat; fn visit_pat; fn make_pat; } Ty(Box) { "type"; - one fn visit_ty; fn visit_ty; fn pprust::ty_to_string; + one fn visit_ty; fn visit_ty; fn make_ty; } Stmts(SmallVec<[ast::Stmt; 1]>) { "statement"; - many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string; + many fn flat_map_stmt; fn visit_stmt(); fn make_stmts; } Items(SmallVec<[Box; 1]>) { "item"; - many fn flat_map_item; fn visit_item(); fn pprust::item_to_string; + many fn flat_map_item; fn visit_item(); fn make_items; } TraitItems(SmallVec<[Box; 1]>) { "trait item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait); - fn pprust::assoc_item_to_string; fn make_trait_items; } ImplItems(SmallVec<[Box; 1]>) { "impl item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); - fn pprust::assoc_item_to_string; fn make_impl_items; } TraitImplItems(SmallVec<[Box; 1]>) { "impl item"; many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); - fn pprust::assoc_item_to_string; fn make_trait_impl_items; } ForeignItems(SmallVec<[Box; 1]>) { "foreign item"; - many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string; + many fn flat_map_foreign_item; fn visit_foreign_item(); fn make_foreign_items; } Arms(SmallVec<[ast::Arm; 1]>) { "match arm"; - many fn flat_map_arm; fn visit_arm(); fn unreachable_to_string; + many fn flat_map_arm; fn visit_arm(); fn make_arms; } ExprFields(SmallVec<[ast::ExprField; 1]>) { "field expression"; - many fn flat_map_expr_field; fn visit_expr_field(); fn unreachable_to_string; + many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields; } PatFields(SmallVec<[ast::PatField; 1]>) { "field pattern"; - many fn flat_map_pat_field; fn visit_pat_field(); fn unreachable_to_string; + many fn flat_map_pat_field; fn visit_pat_field(); fn make_pat_fields; } GenericParams(SmallVec<[ast::GenericParam; 1]>) { "generic parameter"; - many fn flat_map_generic_param; fn visit_generic_param(); fn unreachable_to_string; + many fn flat_map_generic_param; fn visit_generic_param(); fn make_generic_params; } Params(SmallVec<[ast::Param; 1]>) { "function parameter"; - many fn flat_map_param; fn visit_param(); fn unreachable_to_string; + many fn flat_map_param; fn visit_param(); fn make_params; } FieldDefs(SmallVec<[ast::FieldDef; 1]>) { "field"; - many fn flat_map_field_def; fn visit_field_def(); fn unreachable_to_string; + many fn flat_map_field_def; fn visit_field_def(); fn make_field_defs; } Variants(SmallVec<[ast::Variant; 1]>) { - "variant"; many fn flat_map_variant; fn visit_variant(); fn unreachable_to_string; + "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; } WherePredicates(SmallVec<[ast::WherePredicate; 1]>) { "where predicate"; - many fn flat_map_where_predicate; fn visit_where_predicate(); fn unreachable_to_string; + many fn flat_map_where_predicate; fn visit_where_predicate(); fn make_where_predicates; } Crate(ast::Crate) { "crate"; - one fn visit_crate; fn visit_crate; fn unreachable_to_string; + one fn visit_crate; fn visit_crate; fn make_crate; } } +impl AstFragment { + pub(crate) fn to_string(&self) -> String { + match self { + AstFragment::OptExpr(Some(expr)) + | AstFragment::MethodReceiverExpr(expr) + | AstFragment::Expr(expr) => pprust::expr_to_string(expr), + AstFragment::Pat(ast) => pprust::pat_to_string(ast), + AstFragment::Ty(ast) => pprust::ty_to_string(ast), + AstFragment::Stmts(ast) => elems_to_string(ast, pprust::stmt_to_string), + AstFragment::Items(ast) => elems_to_string(ast, |ast| pprust::item_to_string(ast)), + AstFragment::TraitItems(ast) + | AstFragment::ImplItems(ast) + | AstFragment::TraitImplItems(ast) => { + elems_to_string(ast, |ast| pprust::assoc_item_to_string(ast)) + } + AstFragment::ForeignItems(ast) => { + elems_to_string(ast, |ast| pprust::foreign_item_to_string(ast)) + } + AstFragment::OptExpr(None) + | AstFragment::Crate(_) + | AstFragment::Arms(_) + | AstFragment::ExprFields(_) + | AstFragment::PatFields(_) + | AstFragment::GenericParams(_) + | AstFragment::Params(_) + | AstFragment::FieldDefs(_) + | AstFragment::Variants(_) + | AstFragment::WherePredicates(_) => unreachable!(), + } + } +} + pub enum SupportsMacroExpansion { No, Yes { supports_inner_attrs: bool }, diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs index 0d60141f274ec..ef1668e4af25c 100644 --- a/compiler/rustc_expand/src/stats.rs +++ b/compiler/rustc_expand/src/stats.rs @@ -32,10 +32,6 @@ pub(crate) fn elems_to_string(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> Str s } -pub(crate) fn unreachable_to_string(_: &T) -> String { - unreachable!() -} - pub(crate) fn update_bang_macro_stats( ecx: &mut ExtCtxt<'_>, fragment_kind: AstFragmentKind, From 712d30f79f37d3f6520e8f0521580ff871610b81 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 15 Apr 2026 12:21:14 +0000 Subject: [PATCH 10/23] merge `$mut_visit_ast` and `$visit_ast` --- compiler/rustc_expand/src/expand.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 861af0fd74203..762f293c1e443 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -55,7 +55,6 @@ macro_rules! ast_fragments { $($Kind:ident($AstTy:ty) { $kind_name:expr; $(one - fn $mut_visit_ast:ident; fn $visit_ast:ident; )? $(many @@ -148,7 +147,7 @@ macro_rules! ast_fragments { } } AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr), - $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)* + $($(AstFragment::$Kind(ast) => vis.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ast) => ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)* } @@ -178,17 +177,17 @@ macro_rules! ast_fragments { ast_fragments! { Expr(Box) { "expression"; - one fn visit_expr; fn visit_expr; + one fn visit_expr; fn make_expr; } Pat(Box) { "pattern"; - one fn visit_pat; fn visit_pat; + one fn visit_pat; fn make_pat; } Ty(Box) { "type"; - one fn visit_ty; fn visit_ty; + one fn visit_ty; fn make_ty; } Stmts(SmallVec<[ast::Stmt; 1]>) { @@ -262,7 +261,7 @@ ast_fragments! { } Crate(ast::Crate) { "crate"; - one fn visit_crate; fn visit_crate; + one fn visit_crate; fn make_crate; } } From 210f03a1cfb1a44a48df67ce070576e9098ae876 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Sun, 19 Apr 2026 20:53:05 +0000 Subject: [PATCH 11/23] smaller tweaks --- compiler/rustc_expand/src/expand.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 762f293c1e443..baabc6ebd75fc 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -117,21 +117,21 @@ macro_rules! ast_fragments { pub(crate) fn make_opt_expr(self) -> Option> { match self { AstFragment::OptExpr(expr) => expr, - _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), + _ => panic!("AstFragment::make_opt_expr called on the wrong kind of fragment"), } } pub(crate) fn make_method_receiver_expr(self) -> Box { match self { AstFragment::MethodReceiverExpr(expr) => expr, - _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), + _ => panic!("AstFragment::make_method_receiver_expr called on the wrong kind of fragment"), } } $(pub fn $make_ast(self) -> $AstTy { match self { AstFragment::$Kind(ast) => ast, - _ => panic!("AstFragment::make_* called on the wrong kind of fragment"), + _ => panic!("AstFragment::{} called on the wrong kind of fragment", stringify!($make_ast)), } })* @@ -251,7 +251,8 @@ ast_fragments! { fn make_field_defs; } Variants(SmallVec<[ast::Variant; 1]>) { - "variant"; many fn flat_map_variant; fn visit_variant(); + "variant"; + many fn flat_map_variant; fn visit_variant(); fn make_variants; } WherePredicates(SmallVec<[ast::WherePredicate; 1]>) { From 5ad560f7ec96bd42f003abe9842abe6e5643817e Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 28 Apr 2026 10:26:46 +0000 Subject: [PATCH 12/23] remove `MethodReceiverExpr` special-casing --- compiler/rustc_expand/src/base.rs | 4 ++++ compiler/rustc_expand/src/expand.rs | 19 +++++-------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b8325f7ba3987..e50c232df2d86 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -423,6 +423,10 @@ pub trait MacResult { None } + fn make_method_receiver_expr(self: Box) -> Option> { + self.make_expr() + } + /// Creates zero or more items. fn make_items(self: Box) -> Option; 1]>> { None diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index baabc6ebd75fc..53bb7c9c03857 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -68,7 +68,6 @@ macro_rules! ast_fragments { /// Can also serve as an input and intermediate result for macro expansion operations. pub enum AstFragment { OptExpr(Option>), - MethodReceiverExpr(Box), $($Kind($AstTy),)* } @@ -76,7 +75,6 @@ macro_rules! ast_fragments { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum AstFragmentKind { OptExpr, - MethodReceiverExpr, $($Kind,)* } @@ -84,7 +82,6 @@ macro_rules! ast_fragments { pub fn name(self) -> &'static str { match self { AstFragmentKind::OptExpr => "expression", - AstFragmentKind::MethodReceiverExpr => "expression", $(AstFragmentKind::$Kind => $kind_name,)* } } @@ -93,8 +90,6 @@ macro_rules! ast_fragments { match self { AstFragmentKind::OptExpr => result.make_expr().map(Some).map(AstFragment::OptExpr), - AstFragmentKind::MethodReceiverExpr => - result.make_expr().map(AstFragment::MethodReceiverExpr), $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)* } } @@ -121,13 +116,6 @@ macro_rules! ast_fragments { } } - pub(crate) fn make_method_receiver_expr(self) -> Box { - match self { - AstFragment::MethodReceiverExpr(expr) => expr, - _ => panic!("AstFragment::make_method_receiver_expr called on the wrong kind of fragment"), - } - } - $(pub fn $make_ast(self) -> $AstTy { match self { AstFragment::$Kind(ast) => ast, @@ -146,7 +134,6 @@ macro_rules! ast_fragments { *opt_expr = vis.filter_map_expr(expr) } } - AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr), $($(AstFragment::$Kind(ast) => vis.$visit_ast(ast),)?)* $($(AstFragment::$Kind(ast) => ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast, $($args)*)),)?)* @@ -157,7 +144,6 @@ macro_rules! ast_fragments { match self { AstFragment::OptExpr(Some(expr)) => try_visit!(visitor.visit_expr(expr)), AstFragment::OptExpr(None) => {} - AstFragment::MethodReceiverExpr(expr) => try_visit!(visitor.visit_method_receiver_expr(expr)), $($(AstFragment::$Kind(ast) => try_visit!(visitor.$visit_ast(ast)),)?)* $($(AstFragment::$Kind(ast) => walk_list!(visitor, $visit_ast_elt, &ast[..], $($args)*),)?)* } @@ -180,6 +166,11 @@ ast_fragments! { one fn visit_expr; fn make_expr; } + MethodReceiverExpr(Box) { + "expression"; + one fn visit_method_receiver_expr; + fn make_method_receiver_expr; + } Pat(Box) { "pattern"; one fn visit_pat; From b072d24e268d5d0121cfc29f3fcb0714408281e5 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Mon, 26 Jan 2026 16:58:31 -0800 Subject: [PATCH 13/23] Fix: On wasm targets, call `panic_in_cleanup` if panic occurs in cleanup Previously this was not correctly implemented. Each funclet may need its own terminate block, so this changes the `terminate_block` into a `terminate_blocks` `IndexVec` which can have a terminate_block for each funclet. We key on the first basic block of the funclet -- in particular, this is the start block for the old case of the top level terminate function. Rather than using a catchswitch/catchpad pair, I used a cleanuppad. The reason for the pair is to avoid catching foreign exceptions on MSVC. On wasm, it seems that the catchswitch/catchpad pair is optimized back into a single cleanuppad and a catch_all instruction is emitted which will catch foreign exceptions. Because the new logic is only used on wasm, it seemed better to take the simpler approach seeing as they do the same thing. --- compiler/rustc_codegen_gcc/src/builder.rs | 4 + compiler/rustc_codegen_llvm/src/builder.rs | 4 + compiler/rustc_codegen_ssa/src/mir/block.rs | 96 +++++++++++++++---- compiler/rustc_codegen_ssa/src/mir/mod.rs | 9 +- .../rustc_codegen_ssa/src/traits/builder.rs | 5 +- tests/codegen-llvm/double_panic_wasm.rs | 34 +++++++ tests/codegen-llvm/terminating-catchpad.rs | 10 ++ 7 files changed, 138 insertions(+), 24 deletions(-) create mode 100644 tests/codegen-llvm/double_panic_wasm.rs diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 3cffd862b9b98..08964113b944a 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1657,6 +1657,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { unimplemented!(); } + fn get_funclet_cleanuppad(&self, _funclet: &Funclet) -> RValue<'gcc> { + unimplemented!(); + } + // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 056a0763087a2..9e59d7aa7c20a 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1289,6 +1289,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ret } + fn get_funclet_cleanuppad(&self, funclet: &Funclet<'ll>) -> &'ll Value { + funclet.cleanuppad() + } + // Atomic Operations fn atomic_cmpxchg( &mut self, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 06c81662d6018..2967db9df787c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -214,19 +214,18 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, mir::UnwindAction::Terminate(reason) => { - if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) { + if fx.mir[self.bb].is_cleanup && base::wants_wasm_eh(fx.cx.tcx().sess) { + // For wasm, we need to generate a nested `cleanuppad within %outer_pad` + // to catch exceptions during cleanup and call `panic_in_cleanup`. + Some(fx.terminate_block(reason, Some(self.bb))) + } else if fx.mir[self.bb].is_cleanup + && base::wants_new_eh_instructions(fx.cx.tcx().sess) + { // MSVC SEH will abort automatically if an exception tries to // propagate out from cleanup. - - // FIXME(@mirkootter): For wasm, we currently do not support terminate during - // cleanup, because this requires a few more changes: The current code - // caches the `terminate_block` for each function; funclet based code - however - - // requires a different terminate_block for each funclet - // Until this is implemented, we just do not unwind inside cleanup blocks - None } else { - Some(fx.terminate_block(reason)) + Some(fx.terminate_block(reason, None)) } } }; @@ -238,7 +237,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some(unwind_block) = unwind_block { let ret_llbb = if let Some((_, target)) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -309,7 +308,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { ) -> MergingSucc { let unwind_target = match unwind { mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)), - mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)), + mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason, None)), mir::UnwindAction::Continue => None, mir::UnwindAction::Unreachable => None, }; @@ -317,7 +316,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) { assert!(unwind_target.is_none()); let ret_llbb = if let Some(target) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -334,7 +333,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { MergingSucc::False } else if let Some(cleanup) = unwind_target { let ret_llbb = if let Some(target) = destination { - fx.llbb(target) + self.llbb_with_cleanup(fx, target) } else { fx.unreachable_block() }; @@ -1906,8 +1905,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) } - fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock { - if let Some((cached_bb, cached_reason)) = self.terminate_block + fn terminate_block( + &mut self, + reason: UnwindTerminateReason, + outer_catchpad_bb: Option, + ) -> Bx::BasicBlock { + // mb_funclet_bb should be present if and only if the target is wasm and + // we're terminating because of an unwind in a cleanup block. In that + // case we have nested funclets and the inner catch_switch needs to know + // what outer catch_pad it is contained in. + debug_assert!( + outer_catchpad_bb.is_some() + == (base::wants_wasm_eh(self.cx.tcx().sess) + && reason == UnwindTerminateReason::InCleanup) + ); + + // When we aren't in a wasm InCleanup block, there's only one terminate + // block needed so we cache at START_BLOCK index. + let mut cache_bb = mir::START_BLOCK; + // In wasm eh InCleanup, use the outer funclet's cleanup BB as the cache + // key. + if let Some(outer_bb) = outer_catchpad_bb { + let cleanup_kinds = + self.cleanup_kinds.as_ref().expect("cleanup_kinds required for funclets"); + cache_bb = cleanup_kinds[outer_bb] + .funclet_bb(outer_bb) + .expect("funclet_bb should be in a funclet"); + + // Ensure the outer funclet is created first + if self.funclets[cache_bb].is_none() { + self.landing_pad_for(cache_bb); + } + } + if let Some((cached_bb, cached_reason)) = self.terminate_blocks[cache_bb] && reason == cached_reason { return cached_bb; @@ -1945,12 +1975,35 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // cp_terminate: // %cp = catchpad within %cs [null, i32 64, null] // ... + // + // By contrast, on WebAssembly targets, we specifically _do_ want to + // catch foreign exceptions. The situation with MSVC is a + // regrettable hack which we don't want to extend to other targets + // unless necessary. For WebAssembly, to generate catch(...) and + // catch only C++ exception instead of generating a catch_all, we + // need to call the intrinsics @llvm.wasm.get.exception and + // @llvm.wasm.get.ehselector in the catch pad. Since we don't do + // this, we generate a catch_all. We originally got this behavior + // by accident but it luckily matches our intention. llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate"); - let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); let mut cs_bx = Bx::build(self.cx, llbb); - let cs = cs_bx.catch_switch(None, None, &[cp_llbb]); + + // For wasm InCleanup blocks, our catch_switch is nested within the + // outer catchpad, so we need to provide it as the parent value to + // catch_switch. + let mut outer_cleanuppad = None; + if outer_catchpad_bb.is_some() { + // Get the outer funclet's catchpad + let outer_funclet = self.funclets[cache_bb] + .as_ref() + .expect("landing_pad_for didn't create funclet"); + outer_cleanuppad = Some(cs_bx.get_funclet_cleanuppad(outer_funclet)); + } + let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate"); + let cs = cs_bx.catch_switch(outer_cleanuppad, None, &[cp_llbb]); + drop(cs_bx); bx = Bx::build(self.cx, cp_llbb); let null = @@ -1971,13 +2024,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } else { // Specifying more arguments than necessary usually doesn't // hurt, but the `WasmEHPrepare` LLVM pass does not recognize - // anything other than a single `null` as a `catch (...)` block, + // anything other than a single `null` as a `catch_all` block, // leading to problems down the line during instruction // selection. &[null] as &[_] }; funclet = Some(bx.catch_pad(cs, args)); + // On wasm, if we wanted to generate a catch(...) and only catch C++ + // exceptions, we'd call @llvm.wasm.get.exception and + // @llvm.wasm.get.ehselector selectors here. We want a catch_all so + // we leave them out. This is intentionally diverging from the MSVC + // behavior. } else { llbb = Bx::append_block(self.cx, self.llfn, "terminate"); bx = Bx::build(self.cx, llbb); @@ -2003,7 +2061,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.unreachable(); - self.terminate_block = Some((llbb, reason)); + self.terminate_blocks[cache_bb] = Some((llbb, reason)); llbb } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 93da12107bab0..5c14d6f2c0930 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -90,8 +90,11 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// Cached unreachable block unreachable_block: Option, - /// Cached terminate upon unwinding block and its reason - terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>, + /// Cached terminate upon unwinding block and its reason. For non-wasm + /// targets, there is at most one such block per function, stored at index + /// `START_BLOCK`. For wasm targets, each funclet needs its own terminate + /// block, indexed by the cleanup block that is the funclet's head. + terminate_blocks: IndexVec>, /// A bool flag for each basic block indicating whether it is a cold block. /// A cold block is a block that is unlikely to be executed at runtime. @@ -227,7 +230,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( personality_slot: None, cached_llbbs, unreachable_block: None, - terminate_block: None, + terminate_blocks: IndexVec::from_elem(None, &mir.basic_blocks), cleanup_kinds, landing_pads: IndexVec::from_elem(None, &mir.basic_blocks), funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()), diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index c222aef4574bf..5092f28a33f7b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -552,12 +552,12 @@ pub trait BuilderMethods<'a, 'tcx>: fn set_personality_fn(&mut self, personality: Self::Function); - // These are used by everyone except msvc + // These are used by everyone except msvc and wasm EH fn cleanup_landing_pad(&mut self, pers_fn: Self::Function) -> (Self::Value, Self::Value); fn filter_landing_pad(&mut self, pers_fn: Self::Function); fn resume(&mut self, exn0: Self::Value, exn1: Self::Value); - // These are used only by msvc + // These are used by msvc and wasm EH fn cleanup_pad(&mut self, parent: Option, args: &[Self::Value]) -> Self::Funclet; fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option); fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet; @@ -567,6 +567,7 @@ pub trait BuilderMethods<'a, 'tcx>: unwind: Option, handlers: &[Self::BasicBlock], ) -> Self::Value; + fn get_funclet_cleanuppad(&self, funclet: &Self::Funclet) -> Self::Value; fn atomic_cmpxchg( &mut self, diff --git a/tests/codegen-llvm/double_panic_wasm.rs b/tests/codegen-llvm/double_panic_wasm.rs new file mode 100644 index 0000000000000..1eafe60503809 --- /dev/null +++ b/tests/codegen-llvm/double_panic_wasm.rs @@ -0,0 +1,34 @@ +//@ compile-flags: -C panic=unwind -Copt-level=0 +//@ needs-unwind +//@ only-wasm32 + +#![crate_type = "lib"] + +// Test that `panic_in_cleanup` is called on webassembly targets when a panic +// occurs in a destructor during unwinding. + +extern "Rust" { + fn may_panic(); +} + +struct PanicOnDrop; + +impl Drop for PanicOnDrop { + fn drop(&mut self) { + unsafe { may_panic() } + } +} + +// CHECK-LABEL: @double_panic +// CHECK: invoke void @may_panic() +// CHECK: invoke void @{{.+}}drop_in_place{{.+}} +// CHECK: unwind label %[[TERMINATE:.*]] +// +// CHECK: [[TERMINATE]]: +// CHECK: call void @{{.*panic_in_cleanup}} +// CHECK: unreachable +#[no_mangle] +pub fn double_panic() { + let _guard = PanicOnDrop; + unsafe { may_panic() } +} diff --git a/tests/codegen-llvm/terminating-catchpad.rs b/tests/codegen-llvm/terminating-catchpad.rs index a2ec19871d1fc..7c98ea94fdc13 100644 --- a/tests/codegen-llvm/terminating-catchpad.rs +++ b/tests/codegen-llvm/terminating-catchpad.rs @@ -9,6 +9,10 @@ // Ensure a catch-all generates: // - `catchpad ... [ptr null]` on Wasm (otherwise LLVM gets confused) // - `catchpad ... [ptr null, i32 64, ptr null]` on Windows (otherwise we catch SEH exceptions) +// +// Unlike on windows, on Wasm, we specifically do want to catch foreign +// exceptions. To catch only C++ exceptions we'd need to call +// @llvm.wasm.get.exception and @llvm.wasm.get.ehselector in the catchpad. #![feature(no_core, lang_items, rustc_attrs)] #![crate_type = "lib"] @@ -36,8 +40,14 @@ fn panic_cannot_unwind() -> ! { #[no_mangle] #[rustc_nounwind] pub fn doesnt_unwind() { + // CHECK: catchswitch within none [label %{{.*}}] unwind to caller // emscripten: %catchpad = catchpad within %catchswitch [ptr null] // wasi: %catchpad = catchpad within %catchswitch [ptr null] // seh: %catchpad = catchpad within %catchswitch [ptr null, i32 64, ptr null] + // + // We don't call these intrinsics on wasm targets so we generate a catch_all + // instruction which also picks up foreign exceptions + // NOT: @llvm.wasm.get.exception + // NOT: @llvm.wasm.get.ehselector unwinds(); } From d3992fac9491d397f8d41d7f34f98f1420d7728f Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Tue, 28 Apr 2026 18:01:12 +0000 Subject: [PATCH 14/23] Add feature gate for view_types --- compiler/rustc_feature/src/unstable.rs | 2 + compiler/rustc_span/src/symbol.rs | 1 + .../feature-gates/feature-gate-view-types.rs | 16 ++++++ .../feature-gate-view-types.stderr | 49 +++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 tests/ui/feature-gates/feature-gate-view-types.rs create mode 100644 tests/ui/feature-gates/feature-gate-view-types.stderr diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3bb4bc863def2..9712879fce6f7 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -723,6 +723,8 @@ declare_features! ( (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), + /// Allows view types. + (unstable, view_types, "CURRENT_RUSTC_VERSION", Some(155938)), /// Target features on wasm. (unstable, wasm_target_feature, "1.30.0", Some(150260)), /// Allows use of attributes in `where` clauses. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4cacdbd3408a5..3db4921d6ec0a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2232,6 +2232,7 @@ symbols! { verbatim, version, vfp2, + view_types, vis, visible_private_types, volatile, diff --git a/tests/ui/feature-gates/feature-gate-view-types.rs b/tests/ui/feature-gates/feature-gate-view-types.rs new file mode 100644 index 0000000000000..26ca0ee4206b2 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-view-types.rs @@ -0,0 +1,16 @@ +//@ known-bug: #155938 + +struct Foo { + a: usize, + b: usize, +} + +fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + a.a += 1; + b.b += 1; +} + +fn main() { + let mut foo = Foo { a: 0, b: 0 }; + bar(&mut foo, &mut foo); +} diff --git a/tests/ui/feature-gates/feature-gate-view-types.stderr b/tests/ui/feature-gates/feature-gate-view-types.stderr new file mode 100644 index 0000000000000..436b7ea769ed3 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-view-types.stderr @@ -0,0 +1,49 @@ +error: expected parameter name, found `{` + --> $DIR/feature-gate-view-types.rs:8:20 + | +LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + | ^ expected parameter name + +error: expected one of `!`, `(`, `)`, `,`, `::`, or `<`, found `.` + --> $DIR/feature-gate-view-types.rs:8:19 + | +LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + | ^ + | | + | expected one of `!`, `(`, `)`, `,`, `::`, or `<` + | help: missing `,` + +error: expected parameter name, found `{` + --> $DIR/feature-gate-view-types.rs:8:39 + | +LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + | ^ expected parameter name + +error: expected one of `!`, `(`, `)`, `,`, `::`, or `<`, found `.` + --> $DIR/feature-gate-view-types.rs:8:38 + | +LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + | ^ + | | + | expected one of `!`, `(`, `)`, `,`, `::`, or `<` + | help: missing `,` + +error[E0061]: this function takes 4 arguments but 2 arguments were supplied + --> $DIR/feature-gate-view-types.rs:15:5 + | +LL | bar(&mut foo, &mut foo); + | ^^^-------------------- two arguments are missing + | +note: function defined here + --> $DIR/feature-gate-view-types.rs:8:4 + | +LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + | ^^^ ----------------- +help: provide the arguments + | +LL | bar(&mut foo, &mut foo, /* &mut Foo */, /* _ */); + | +++++++++++++++++++++++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0061`. From 72a59e73d87f7219ad4a865f0ed28e3e55060b22 Mon Sep 17 00:00:00 2001 From: cyrgani Date: Wed, 29 Apr 2026 11:17:05 +0000 Subject: [PATCH 15/23] move fragment printing code --- compiler/rustc_expand/src/expand.rs | 32 --------------------------- compiler/rustc_expand/src/stats.rs | 34 +++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 53bb7c9c03857..7dbf6e113c53a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -258,38 +258,6 @@ ast_fragments! { } } -impl AstFragment { - pub(crate) fn to_string(&self) -> String { - match self { - AstFragment::OptExpr(Some(expr)) - | AstFragment::MethodReceiverExpr(expr) - | AstFragment::Expr(expr) => pprust::expr_to_string(expr), - AstFragment::Pat(ast) => pprust::pat_to_string(ast), - AstFragment::Ty(ast) => pprust::ty_to_string(ast), - AstFragment::Stmts(ast) => elems_to_string(ast, pprust::stmt_to_string), - AstFragment::Items(ast) => elems_to_string(ast, |ast| pprust::item_to_string(ast)), - AstFragment::TraitItems(ast) - | AstFragment::ImplItems(ast) - | AstFragment::TraitImplItems(ast) => { - elems_to_string(ast, |ast| pprust::assoc_item_to_string(ast)) - } - AstFragment::ForeignItems(ast) => { - elems_to_string(ast, |ast| pprust::foreign_item_to_string(ast)) - } - AstFragment::OptExpr(None) - | AstFragment::Crate(_) - | AstFragment::Arms(_) - | AstFragment::ExprFields(_) - | AstFragment::PatFields(_) - | AstFragment::GenericParams(_) - | AstFragment::Params(_) - | AstFragment::FieldDefs(_) - | AstFragment::Variants(_) - | AstFragment::WherePredicates(_) => unreachable!(), - } - } -} - pub enum SupportsMacroExpansion { No, Yes { supports_inner_attrs: bool }, diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs index ef1668e4af25c..d7bd5329da8b3 100644 --- a/compiler/rustc_expand/src/stats.rs +++ b/compiler/rustc_expand/src/stats.rs @@ -32,6 +32,36 @@ pub(crate) fn elems_to_string(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> Str s } +fn fragment_to_string(fragment: &AstFragment) -> String { + match fragment { + AstFragment::OptExpr(Some(expr)) + | AstFragment::MethodReceiverExpr(expr) + | AstFragment::Expr(expr) => pprust::expr_to_string(expr), + AstFragment::Pat(ast) => pprust::pat_to_string(ast), + AstFragment::Ty(ast) => pprust::ty_to_string(ast), + AstFragment::Stmts(ast) => elems_to_string(ast, pprust::stmt_to_string), + AstFragment::Items(ast) => elems_to_string(ast, |ast| pprust::item_to_string(ast)), + AstFragment::TraitItems(ast) + | AstFragment::ImplItems(ast) + | AstFragment::TraitImplItems(ast) => { + elems_to_string(ast, |ast| pprust::assoc_item_to_string(ast)) + } + AstFragment::ForeignItems(ast) => { + elems_to_string(ast, |ast| pprust::foreign_item_to_string(ast)) + } + AstFragment::OptExpr(None) + | AstFragment::Crate(_) + | AstFragment::Arms(_) + | AstFragment::ExprFields(_) + | AstFragment::PatFields(_) + | AstFragment::GenericParams(_) + | AstFragment::Params(_) + | AstFragment::FieldDefs(_) + | AstFragment::Variants(_) + | AstFragment::WherePredicates(_) => unreachable!(), + } +} + pub(crate) fn update_bang_macro_stats( ecx: &mut ExtCtxt<'_>, fragment_kind: AstFragmentKind, @@ -94,7 +124,7 @@ pub(crate) fn update_attr_macro_stats( let input = format!( "{}\n{}", pprust::attribute_to_string(attr), - fragment_kind.expect_from_annotatables(iter::once(item)).to_string(), + fragment_to_string(&fragment_kind.expect_from_annotatables(iter::once(item))), ); update_macro_stats(ecx, MacroKind::Attr, fragment_kind, span, path, &input, fragment); } @@ -125,7 +155,7 @@ pub(crate) fn update_macro_stats( // Measure the size of the output by pretty-printing it and counting // the lines and bytes. let name = Symbol::intern(&pprust::path_to_string(path)); - let output = fragment.to_string(); + let output = fragment_to_string(fragment); let num_lines = output.trim_end().split('\n').count(); let num_bytes = output.len(); From 77fb8d1d5c5f5e2058049b3b90abde3f8bccef4f Mon Sep 17 00:00:00 2001 From: Sasha Pourcelot Date: Wed, 29 Apr 2026 09:03:26 +0000 Subject: [PATCH 16/23] Parse view type syntax, mark it as unstable --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_parse/src/parser/ty.rs | 21 ++++++- .../feature-gates/feature-gate-view-types.rs | 5 +- .../feature-gate-view-types.stderr | 58 +++++++------------ 4 files changed, 45 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5831636a81b2c..3d51770f6ba79 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -510,6 +510,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(try_blocks_heterogeneous, "`try bikeshed` expression is experimental"); gate_all!(unsafe_binders, "unsafe binder types are experimental"); gate_all!(unsafe_fields, "`unsafe` fields are experimental"); + gate_all!(view_types, "view types are experimental"); gate_all!(where_clause_attrs, "attributes in `where` clause are unstable"); gate_all!(yeet_expr, "`do yeet` expression is experimental"); // tidy-alphabetical-end diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 072975f445bf4..b5151cf20ab02 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -19,7 +19,7 @@ use crate::errors::{ NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; -use crate::parser::{FnContext, FnParseMode}; +use crate::parser::{ExpTokenPair, FnContext, FnParseMode}; use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; /// Signals whether parsing a type should allow `+`. @@ -768,6 +768,25 @@ impl<'a> Parser<'a> { self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; + if self.token == TokenKind::Dot && self.look_ahead(1, |t| t.kind == TokenKind::OpenBrace) { + // & [mut] . { } + // ^ + // we are here + let view_start_span = self.token.span; + self.bump(); + let fields = self + .parse_delim_comma_seq( + ExpTokenPair { tok: TokenKind::OpenBrace, token_type: TokenType::OpenBrace }, + ExpTokenPair { tok: TokenKind::CloseBrace, token_type: TokenType::CloseBrace }, + |p| p.parse_ident(), + )? + .0; + // FIXME(scrabsha): actually propagate field view in the AST. + let _ = fields; + let view_end_span = self.prev_token.span; + let span = view_start_span.to(view_end_span); + self.psess.gated_spans.gate(sym::view_types, span); + } Ok(match pinned { Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }), diff --git a/tests/ui/feature-gates/feature-gate-view-types.rs b/tests/ui/feature-gates/feature-gate-view-types.rs index 26ca0ee4206b2..eb0c26d61db4a 100644 --- a/tests/ui/feature-gates/feature-gate-view-types.rs +++ b/tests/ui/feature-gates/feature-gate-view-types.rs @@ -1,11 +1,11 @@ -//@ known-bug: #155938 - struct Foo { a: usize, b: usize, } fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { + //~^ ERROR view types are experimental + //~| ERROR view types are experimental a.a += 1; b.b += 1; } @@ -13,4 +13,5 @@ fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { fn main() { let mut foo = Foo { a: 0, b: 0 }; bar(&mut foo, &mut foo); + //~^ ERROR cannot borrow `foo` as mutable more than once at a time } diff --git a/tests/ui/feature-gates/feature-gate-view-types.stderr b/tests/ui/feature-gates/feature-gate-view-types.stderr index 436b7ea769ed3..661783ec59202 100644 --- a/tests/ui/feature-gates/feature-gate-view-types.stderr +++ b/tests/ui/feature-gates/feature-gate-view-types.stderr @@ -1,49 +1,33 @@ -error: expected parameter name, found `{` - --> $DIR/feature-gate-view-types.rs:8:20 +error[E0658]: view types are experimental + --> $DIR/feature-gate-view-types.rs:6:19 | LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^ expected parameter name - -error: expected one of `!`, `(`, `)`, `,`, `::`, or `<`, found `.` - --> $DIR/feature-gate-view-types.rs:8:19 + | ^^^^^^ | -LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^ - | | - | expected one of `!`, `(`, `)`, `,`, `::`, or `<` - | help: missing `,` + = note: see issue #155938 for more information + = help: add `#![feature(view_types)]` 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: expected parameter name, found `{` - --> $DIR/feature-gate-view-types.rs:8:39 +error[E0658]: view types are experimental + --> $DIR/feature-gate-view-types.rs:6:38 | LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^ expected parameter name - -error: expected one of `!`, `(`, `)`, `,`, `::`, or `<`, found `.` - --> $DIR/feature-gate-view-types.rs:8:38 + | ^^^^^^ | -LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^ - | | - | expected one of `!`, `(`, `)`, `,`, `::`, or `<` - | help: missing `,` + = note: see issue #155938 for more information + = help: add `#![feature(view_types)]` 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[E0061]: this function takes 4 arguments but 2 arguments were supplied - --> $DIR/feature-gate-view-types.rs:15:5 +error[E0499]: cannot borrow `foo` as mutable more than once at a time + --> $DIR/feature-gate-view-types.rs:15:19 | LL | bar(&mut foo, &mut foo); - | ^^^-------------------- two arguments are missing - | -note: function defined here - --> $DIR/feature-gate-view-types.rs:8:4 - | -LL | fn bar(a: &mut Foo.{ a }, b: &mut Foo.{ b }) { - | ^^^ ----------------- -help: provide the arguments - | -LL | bar(&mut foo, &mut foo, /* &mut Foo */, /* _ */); - | +++++++++++++++++++++++++ + | --- -------- ^^^^^^^^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0061`. +Some errors have detailed explanations: E0499, E0658. +For more information about an error, try `rustc --explain E0499`. From 41796ecf1c75fc00119097b4545939f21979e01a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 29 Apr 2026 21:54:15 +0200 Subject: [PATCH 17/23] add `c_variadic_experimental_arch` feature --- compiler/rustc_abi/src/extern_abi.rs | 1 + .../rustc_ast_passes/src/ast_validation.rs | 23 ++++++--- compiler/rustc_codegen_llvm/src/va_arg.rs | 10 +++- compiler/rustc_feature/src/unstable.rs | 3 ++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 49 ++++++++++++++----- ...te-c_variadic_experimental_arch.avr.stderr | 23 +++++++++ ...c_variadic_experimental_arch.custom.stderr | 14 ++++++ ...e-c_variadic_experimental_arch.m68k.stderr | 23 +++++++++ ...c_variadic_experimental_arch.msp430.stderr | 23 +++++++++ ...variadic_experimental_arch.riscv32e.stderr | 23 +++++++++ ...ature-gate-c_variadic_experimental_arch.rs | 45 +++++++++++++++++ ...-c_variadic_experimental_arch.sparc.stderr | 23 +++++++++ 13 files changed, 242 insertions(+), 19 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs create mode 100644 tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 95ba2ee3b78f8..0a7519625efb6 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -259,6 +259,7 @@ impl StableOrd for ExternAbi { rustc_error_messages::into_diag_arg_using_display!(ExternAbi); #[cfg(feature = "nightly")] +#[derive(Debug)] pub enum CVariadicStatus { NotSupported, Stable, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 770189d8c7999..cdcef59419f6f 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -762,12 +762,23 @@ impl<'a> AstValidator<'a> { match fn_ctxt { FnCtxt::Foreign => return, FnCtxt::Free | FnCtxt::Assoc(_) => { - if !self.sess.target.supports_c_variadic_definitions() { - self.dcx().emit_err(errors::CVariadicNotSupported { - variadic_span: variadic_param.span, - target: &*self.sess.target.llvm_target, - }); - return; + match self.sess.target.supports_c_variadic_definitions() { + CVariadicStatus::NotSupported => { + self.dcx().emit_err(errors::CVariadicNotSupported { + variadic_span: variadic_param.span, + target: &*self.sess.target.llvm_target, + }); + return; + } + CVariadicStatus::Unstable { feature } if !self.features.enabled(feature) => { + let msg = + format!("C-variadic function definitions on this target are unstable"); + feature_err(&self.sess, feature, variadic_param.span, msg).emit(); + return; + } + CVariadicStatus::Unstable { .. } | CVariadicStatus::Stable => { + /* fall through */ + } } match sig.header.ext { diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index cfdd47b3a8c8c..09d3a5a3f040f 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -1,4 +1,4 @@ -use rustc_abi::{Align, BackendRepr, Endian, HasDataLayout, Primitive, Size}; +use rustc_abi::{Align, BackendRepr, CVariadicStatus, Endian, HasDataLayout, Primitive, Size}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::common::IntPredicate; use rustc_codegen_ssa::mir::operand::OperandRef; @@ -1038,6 +1038,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( assert!(!bx.layout_of(target_ty).is_zst()); let target = &bx.cx.tcx.sess.target; + let stability = target.supports_c_variadic_definitions(); + match target.arch { Arch::X86 => emit_ptr_va_arg( bx, @@ -1094,6 +1096,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( ForceRightAdjust::Yes, ), Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); // FIXME: clang manually adjusts the alignment for this ABI. It notes: // // > To be compatible with GCC's behaviors, we force arguments with @@ -1215,10 +1218,15 @@ pub(super) fn emit_va_arg<'ll, 'tcx>( Arch::SpirV => bug!("spirv does not support c-variadic functions"), Arch::Sparc | Arch::Avr | Arch::M68k | Arch::Msp430 => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); + // Clang uses the LLVM implementation for these architectures. bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx)) } + Arch::Other(ref arch) => { + std::assert_matches!(stability, CVariadicStatus::Unstable { .. }); + // Just to be safe we error out explicitly here, instead of crossing our fingers that // the default LLVM implementation has the correct behavior for this target. bug!("c-variadic functions are not currently implemented for custom target {arch}") diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 3bb4bc863def2..13ef1da6a8060 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -393,6 +393,9 @@ declare_features! ( (unstable, bpf_target_feature, "1.54.0", Some(150247)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), + /// Allows defining c-variadic functions on targets where this feature has not yet + /// undergone sufficient testing for stabilization. + (unstable, c_variadic_experimental_arch, "CURRENT_RUSTC_VERSION", Some(155973)), /// Allows defining c-variadic naked functions with any extern ABI that is allowed /// on c-variadic foreign functions. (unstable, c_variadic_naked_functions, "1.93.0", Some(148767)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4cacdbd3408a5..64a1890726309 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -548,6 +548,7 @@ symbols! { c_str_literals, c_unwind, c_variadic, + c_variadic_experimental_arch, c_variadic_naked_functions, c_void, call, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 768e43146a0c1..9da621c300d8f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -47,7 +47,8 @@ use std::str::FromStr; use std::{fmt, io}; use rustc_abi::{ - Align, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutError, + Align, CVariadicStatus, CanonAbi, Endian, ExternAbi, Integer, Size, TargetDataLayout, + TargetDataLayoutError, }; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_error_messages::{DiagArgValue, IntoDiagArg, into_diag_arg_using_display}; @@ -2208,10 +2209,13 @@ impl Target { Ok(dl) } - pub fn supports_c_variadic_definitions(&self) -> bool { + pub fn supports_c_variadic_definitions(&self) -> CVariadicStatus { use Arch::*; match self.arch { + // These targets just inherently do not support c-variadic definitions. + Bpf | SpirV => CVariadicStatus::NotSupported, + // The c-variadic ABI for this target may change in the future, per this comment in // clang: // @@ -2219,19 +2223,40 @@ impl Target { // > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`, // > `unsigned long long` and `double` to have 4-byte alignment. This // > behavior may be changed when RV32E/ILP32E is ratified. - RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => false, - - // These targets just do not support c-variadic definitions. - Bpf | SpirV => false, + RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => { + CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch } + } // We don't know how c-variadics work for this target. Using the default LLVM - // fallback implementation may work, but just to be safe we disallow this. - Other(_) => false, + // fallback implementation probably works, but we can't guarantee it. + Other(_) => CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch }, - AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64 - | M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC - | PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86 - | X86_64 | Xtensa => true, + // These targets require more testing before we commit to c-variadic definitions + // being stable. + // + // To stabilize c-variadic functions for one of these targets, the following + // requirements must be met: + // + // - Check that `core::ffi::VaArgSafe` is (un)implemented for all the correct types. + // - Add an assembly test to `tests/assembly-llvm/c-variadic` that tests the assembly + // for all implementers of `VaArgSafe`. The generated assembly should either match + // `clang`, or we should understand and document why it deviates. + // - Ensure that `va_arg` is implemented in rustc. For stable targets we don't rely on + // the LLVM implementation, it has historically caused miscompilations. + // - The `tests/ui/c-variadic/roundtrip.rs` test must pass for the target. It may + // need slight modifications for embedded targets, that's fine. + // - Check that calling c-variadic functions defined in Rust can be called from C. + // For most targets `tests/run-make/c-link-to-rust-va-list-fn` can be used here. + // For no_std targets a manual setup may be needed. + Sparc | Avr | M68k | Msp430 => { + CVariadicStatus::Unstable { feature: sym::c_variadic_experimental_arch } + } + + AArch64 | AmdGpu | Arm | Arm64EC | CSky | Hexagon | LoongArch32 | LoongArch64 + | Mips | Mips32r6 | Mips64 | Mips64r6 | Nvptx64 | PowerPC | PowerPC64 | RiscV32 + | RiscV64 | S390x | Sparc64 | Wasm32 | Wasm64 | X86 | X86_64 | Xtensa => { + CVariadicStatus::Stable + } } } } diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.avr.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr new file mode 100644 index 0000000000000..fd9d7777a3886 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.custom.stderr @@ -0,0 +1,14 @@ +error: requires `va_list` lang_item + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:26:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + +error: requires `va_list` lang_item + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:30:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.m68k.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.msp430.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.riscv32e.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs new file mode 100644 index 0000000000000..98b5f063d5844 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.rs @@ -0,0 +1,45 @@ +//@ add-minicore +//@ ignore-backends: gcc +// +//@ revisions: riscv32e sparc avr m68k msp430 +// +//@[riscv32e] compile-flags: --target riscv32e-unknown-none-elf +//@[riscv32e] needs-llvm-components: riscv +// +//@[sparc] compile-flags: --target sparc-unknown-none-elf +//@[sparc] needs-llvm-components: sparc +// +//@[avr] compile-flags: --target avr-none -Ctarget-cpu=atmega328p +//@[avr] needs-llvm-components: avr +// +//@[m68k] compile-flags: --target m68k-unknown-none-elf -Ctarget-cpu=M68020 +//@[m68k] needs-llvm-components: m68k +// +//@[msp430] compile-flags: --target msp430-none-elf -Ctarget-cpu=msp430 +//@[msp430] needs-llvm-components: msp430 +#![feature(no_core, lang_items, rustc_attrs, c_variadic)] +#![crate_type = "rlib"] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[repr(transparent)] +struct VaListInner { + ptr: *const c_void, +} + +#[repr(transparent)] +#[lang = "va_list"] +pub struct VaList<'a> { + inner: VaListInner, + _marker: PhantomData<&'a mut ()>, +} + +pub unsafe extern "C" fn test(_: i32, ap: ...) {} +//~^ ERROR C-variadic function definitions on this target are unstable + +trait Trait { + unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + //~^ ERROR C-variadic function definitions on this target are unstable +} diff --git a/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr new file mode 100644 index 0000000000000..df7697845814e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-c_variadic_experimental_arch.sparc.stderr @@ -0,0 +1,23 @@ +error[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:39:39 + | +LL | pub unsafe extern "C" fn test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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[E0658]: C-variadic function definitions on this target are unstable + --> $DIR/feature-gate-c_variadic_experimental_arch.rs:43:45 + | +LL | unsafe extern "C" fn trait_test(_: i32, ap: ...) {} + | ^^^^^^^ + | + = note: see issue #155973 for more information + = help: add `#![feature(c_variadic_experimental_arch)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. From 6d79bc6f0153a9784520667e8b7ad5a9ed6ff942 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 28 Apr 2026 10:46:27 +1000 Subject: [PATCH 18/23] Move `feature*` methods from `parse` mod to `errors` mod. As the FIXME comment says, these no longer use `ParseSess` and so the `parse` mod is not a good place for them. The `errors` mod is a better home. --- compiler/rustc_ast_lowering/src/asm.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_lowering/src/path.rs | 2 +- compiler/rustc_ast_lowering/src/stability.rs | 2 +- .../rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_passes/src/feature_gate.rs | 2 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 3 +- .../src/attributes/codegen_attrs.rs | 2 +- .../rustc_attr_parsing/src/attributes/doc.rs | 2 +- .../src/attributes/link_attrs.rs | 2 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- .../rustc_codegen_ssa/src/target_features.rs | 2 +- .../rustc_const_eval/src/check_consts/ops.rs | 2 +- compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_expand/src/expand.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 3 +- compiler/rustc_expand/src/mbe/quoted.rs | 2 +- compiler/rustc_hir_analysis/src/check/mod.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 2 +- .../rustc_hir_analysis/src/coherence/mod.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 2 +- .../src/hir_ty_lowering/errors.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 5 +- compiler/rustc_hir_typeck/src/pat.rs | 2 +- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_lint/src/levels.rs | 2 +- compiler/rustc_lint/src/lints.rs | 2 +- compiler/rustc_middle/src/middle/stability.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 2 +- compiler/rustc_resolve/src/imports.rs | 2 +- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 2 +- compiler/rustc_session/src/errors.rs | 169 ++++++++++++++++- compiler/rustc_session/src/parse.rs | 176 +----------------- compiler/rustc_session/src/session.rs | 4 +- .../src/error_reporting/traits/ambiguity.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 2 +- .../passes/collect_intra_doc_links.rs | 2 +- 43 files changed, 216 insertions(+), 220 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 46d7beae8fe58..e8df8ce6e6dc3 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::msg; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{Span, sym}; use rustc_target::asm; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4e1b46d568099..86eb721ad284c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1693,7 +1693,7 @@ impl<'hir> LoweringContext<'_, 'hir> { && !self.tcx.features().coroutines() && !self.tcx.features().gen_blocks() { - rustc_session::parse::feature_err( + rustc_session::errors::feature_err( &self.tcx.sess, sym::yield_expr, span, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6ca6bf3e1f6dc..49790c2da6de4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -62,7 +62,7 @@ use rustc_macros::extension; use rustc_middle::hir::{self as mid_hir}; use rustc_middle::span_bug; use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt}; -use rustc_session::parse::add_feature_diagnostics; +use rustc_session::errors::add_feature_diagnostics; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use smallvec::SmallVec; diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 49c5f060e2a1e..ef60dc6fc4f1c 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -6,7 +6,7 @@ use rustc_hir::def::{DefKind, PartialRes, PerNS, 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_session::errors::add_feature_diagnostics; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use smallvec::smallvec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index d185cc9163eb6..326576bb14881 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -3,7 +3,7 @@ use std::fmt; use rustc_abi::ExternAbi; use rustc_feature::Features; use rustc_session::Session; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 770189d8c7999..8ba2d955a80ad 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -30,11 +30,11 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{DiagCtxtHandle, Diagnostic, LintBuffer}; use rustc_feature::Features; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES, }; -use rustc_session::parse::feature_err; use rustc_span::{Ident, Span, kw, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; use thin_vec::thin_vec; diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5831636a81b2c..54de8965e6a03 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -6,7 +6,7 @@ use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Feat use rustc_hir::Attribute; use rustc_hir::attrs::AttributeKind; use rustc_session::Session; -use rustc_session::parse::{feature_err, feature_warn}; +use rustc_session::errors::{feature_err, feature_warn}; use rustc_span::{Span, Spanned, Symbol, sym}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 80a1d9aa5defd..4cc07ceaf231f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -13,8 +13,9 @@ use rustc_parse::parser::{ForceCollect, Parser, Recovery}; use rustc_parse::{exp, parse_in}; use rustc_session::Session; use rustc_session::config::ExpectedValues; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::UNEXPECTED_CFGS; -use rustc_session::parse::{ParseSess, feature_err}; +use rustc_session::parse::ParseSess; use rustc_span::{ErrorGuaranteed, Span, Symbol, sym}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index a20813406b024..a6cf25330b557 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,5 +1,5 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::edition::Edition::Edition2024; use super::prelude::*; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index c0b90c2c6d97f..ecb136edad5fc 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -5,7 +5,7 @@ use rustc_hir::Target; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, }; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 0ca059bf4030b..039977c74c1bb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -3,8 +3,8 @@ use rustc_feature::Features; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; use rustc_hir::attrs::*; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; -use rustc_session::parse::feature_err; use rustc_span::edition::Edition::Edition2024; use rustc_span::kw; use rustc_target::spec::{Arch, BinaryFormat}; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 820436bb6a265..3e19f7f95470f 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -12,8 +12,8 @@ use rustc_middle::middle::codegen_fn_attrs::{ use rustc_middle::mono::Visibility; use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; +use rustc_session::errors::feature_err; use rustc_session::lint; -use rustc_session::parse::feature_err; use rustc_span::{Span, sym}; use rustc_target::spec::Os; diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 4b1b0866f2eb9..b7d09d69aaecd 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -7,8 +7,8 @@ use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; -use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, edit_distance, sym}; use rustc_target::spec::{Arch, SanitizerSet}; use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability}; diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index d64cf8e032935..c776fa69ba5c1 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, AssocContainer, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, suggest_constraining_type_param, }; -use rustc_session::parse::add_feature_diagnostics; +use rustc_session::errors::add_feature_diagnostics; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::traits::call_kind::{ CallDesugaringKind, CallKind, call_kind, diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b5f85536d9cac..2b914a2664fe5 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -27,7 +27,7 @@ use rustc_hir::{ }; use rustc_parse::parser::Recovery; use rustc_session::Session; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::instrument; diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index fe363e7d4a511..3629b72a93ec2 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -30,8 +30,8 @@ use rustc_parse::parser::{ RecoverColon, RecoverComma, Recovery, token_descr, }; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; -use rustc_session::parse::feature_err; use rustc_span::hygiene::SyntaxContext; use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym}; use smallvec::SmallVec; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index eed13a13fa911..cb22ad136645b 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -23,7 +23,8 @@ use rustc_lint_defs::builtin::{ use rustc_parse::exp; use rustc_parse::parser::{Parser, Recovery}; use rustc_session::Session; -use rustc_session::parse::{ParseSess, feature_err}; +use rustc_session::errors::feature_err; +use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::hygiene::Transparency; use rustc_span::{Ident, Span, Symbol, kw, sym}; diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 92d19820848b4..443a17287d734 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::Applicability; use rustc_feature::Features; use rustc_session::Session; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::edition::Edition; use rustc_span::{Ident, Span, kw, sym}; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index fcdbb11b297c1..3225e00b24b26 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -92,7 +92,7 @@ use rustc_middle::ty::{ Unnormalized, }; use rustc_middle::{bug, span_bug}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; @@ -312,7 +312,7 @@ fn default_body_is_unstable( }); let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span()); - rustc_session::parse::add_feature_diagnostics_for_issue( + rustc_session::errors::add_feature_diagnostics_for_issue( &mut err, &tcx.sess, feature, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 05d16d2ddb49c..d0277d2e24264 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -27,7 +27,7 @@ use rustc_middle::ty::{ Unnormalized, Upcast, }; use rustc_middle::{bug, span_bug}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::{InferCtxtRegionExt, OutlivesEnvironmentBuildExt}; diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 07ad5db47b6d8..05a9f68131819 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -11,7 +11,7 @@ use rustc_hir::LangItem; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, elaborate}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{ErrorGuaranteed, sym}; use tracing::debug; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 3a2f3948f0abc..d8cf13db265fd 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1272,7 +1272,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { && !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async() && !self.tcx.features().anonymous_lifetime_in_impl_trait() { - let mut diag: rustc_errors::Diag<'_> = rustc_session::parse::feature_err( + let mut diag: rustc_errors::Diag<'_> = rustc_session::errors::feature_err( &self.tcx.sess, sym::anonymous_lifetime_in_impl_trait, lifetime_ref.ident.span, diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 41b1ec91e0e75..3ac603fc715f3 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -505,7 +505,7 @@ fn infer_placeholder_type<'tcx>( fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) { if !tcx.features().inherent_associated_types() { - use rustc_session::parse::feature_err; + use rustc_session::errors::feature_err; use rustc_span::sym; feature_err( &tcx.sess, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 0aa478f99200b..5e11819805e15 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_param, }; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 5096e5ef76f0d..75ea42a38ff4c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -43,8 +43,8 @@ use rustc_middle::ty::{ const_lit_matches_ty, fold_regions, }; use rustc_middle::{bug, span_bug}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; -use rustc_session::parse::feature_err; use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 0721bfcab519a..9cadaef8f886b 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -89,7 +89,7 @@ use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{Const, Ty, TyCtxt}; use rustc_middle::{middle, ty}; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 71c02dc32f6b5..664c3c457876c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -30,8 +30,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TypeVisitableExt, Unnormalized}; use rustc_middle::{bug, span_bug}; -use rustc_session::errors::ExprParenthesesNeeded; -use rustc_session::parse::feature_err; +use rustc_session::errors::{ExprParenthesesNeeded, feature_err}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::{Ident, Span, Spanned, Symbol, kw, sym}; @@ -3767,7 +3766,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); if !self.tcx.features().offset_of_enum() { - rustc_session::parse::feature_err( + rustc_session::errors::feature_err( &self.tcx.sess, sym::offset_of_enum, ident.span, diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 5a4cd6d24a8b6..d7f15222376c8 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -21,8 +21,8 @@ use rustc_infer::infer::RegionVariableOrigin; use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::{self, Pinnedness, Ty, TypeVisitableExt, Unnormalized}; use rustc_middle::{bug, span_bug}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; -use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym}; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 38d899853cd5b..cc05fffa1daa2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -39,8 +39,8 @@ use rustc_resolve::{Resolver, ResolverOutputs}; use rustc_session::Session; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; +use rustc_session::errors::feature_err; use rustc_session::output::{filename_for_input, invalid_output_for_target}; -use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; use rustc_span::{ DUMMY_SP, ErrorGuaranteed, ExpnKind, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 2b859b65c9f8f..0c308e18b1533 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -966,7 +966,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { let mut lint = Diag::new(dcx, level, msg!("unknown lint: `{$name}`")) .with_arg("name", lint_id.lint.name_lower()) .with_note(msg!("the `{$name}` lint is unstable")); - rustc_session::parse::add_feature_diagnostics_for_issue( + rustc_session::errors::add_feature_diagnostics_for_issue( &mut lint, sess, feature, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1e3ce972a3667..6d9f486f627f6 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -306,7 +306,7 @@ impl<'a> Diagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { let mut diag = Diag::new(dcx, level, "`#[track_caller]` on async functions is a no-op") .with_span_label(self.label, "this function will not propagate the caller location"); - rustc_session::parse::add_feature_diagnostics( + rustc_session::errors::add_feature_diagnostics( &mut diag, self.session, sym::async_fn_track_caller, diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index f9821c92df369..2c59517847370 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -11,9 +11,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, ConstStability, DefaultBodyStability, HirId, Stability}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; +use rustc_session::errors::feature_err_issue; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE}; use rustc_session::lint::{DeprecatedSinceKind, Level, Lint}; -use rustc_session::parse::feature_err_issue; use rustc_span::{Span, Symbol, sym}; use tracing::debug; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 831199a59a432..2817cf3020ff9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -36,12 +36,12 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized}; use rustc_middle::{bug, span_bug}; use rustc_session::config::CrateType; +use rustc_session::errors::feature_err; use rustc_session::lint; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; -use rustc_session::parse::feature_err; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 5fae50041a02d..febdb085f7ee1 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -6,8 +6,8 @@ use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS}; use rustc_middle::{bug, span_bug}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; -use rustc_session::parse::feature_err; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::{Ident, Span, kw, sym}; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 2695655278fb4..5a98a17add701 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -18,11 +18,11 @@ use rustc_hir::def_id::{DefId, LocalDefIdMap}; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::span_bug; use rustc_middle::ty::{TyCtxt, Visibility}; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ AMBIGUOUS_GLOB_REEXPORTS, EXPORTED_PRIVATE_DEPENDENCIES, HIDDEN_GLOB_REEXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, UNUSED_IMPORTS, }; -use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Ident, Span, Symbol, kw, sym}; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6eb5fe17bc169..014a472c2c1bb 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -32,8 +32,8 @@ use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::ty::{AssocTag, DelegationInfo, Visibility}; use rustc_middle::{bug, span_bug}; use rustc_session::config::{CrateType, ResolveDocLinks}; +use rustc_session::errors::feature_err; use rustc_session::lint; -use rustc_session::parse::feature_err; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Spanned, Symbol, kw, respan, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index dc20d4fcf36b7..998cf27a85de1 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -23,11 +23,11 @@ use rustc_hir::{Attribute, StabilityLevel}; use rustc_middle::middle::stability; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::Session; +use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACRO_RULES, UNUSED_MACROS, }; -use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; use rustc_span::hygiene::{self, AstPass, ExpnData, ExpnKind, LocalExpnId, MacroKind}; diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 54f88aa22bdc4..bc4c5e98282a5 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -5,14 +5,179 @@ use rustc_ast::util::literal::LitError; use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, - MultiSpan, + MultiSpan, StashKey, }; +use rustc_feature::{GateIssue, find_feature_issue}; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTuple}; +use crate::Session; +use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION; use crate::parse::ParseSess; +/// Construct a diagnostic for a language feature error due to the given `span`. +/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbol`. +#[track_caller] +pub fn feature_err( + sess: &Session, + feature: Symbol, + span: impl Into, + explain: impl Into, +) -> Diag<'_> { + feature_err_issue(sess, feature, span, GateIssue::Language, explain) +} + +/// Construct a diagnostic for a feature gate error. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. +#[track_caller] +pub fn feature_err_issue( + sess: &Session, + feature: Symbol, + span: impl Into, + issue: GateIssue, + explain: impl Into, +) -> Diag<'_> { + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() + && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) + { + err.cancel() + } + + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); + err +} + +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +#[track_caller] +pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) { + feature_warn_issue(sess, feature, span, GateIssue::Language, explain); +} + +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. +#[track_caller] +pub fn feature_warn_issue( + sess: &Session, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &'static str, +) { + let mut err = sess.dcx().struct_span_warn(span, explain); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); + + // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level + let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; + let future_incompatible = lint.future_incompatible.as_ref().unwrap(); + err.is_lint(lint.name_lower(), /* has_future_breakage */ false); + err.warn(lint.desc); + err.note(format!("for more information, see {}", future_incompatible.reason.reference())); + + // A later feature_err call can steal and cancel this warning. + err.stash(span, StashKey::EarlySyntaxWarning); +} + +/// Adds the diagnostics for a feature to an existing error. +/// Must be a language feature! +pub fn add_feature_diagnostics( + err: &mut Diag<'_, G>, + sess: &Session, + feature: Symbol, +) { + add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); +} + +/// Adds the diagnostics for a feature to an existing error. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer +/// `add_feature_diagnostics`. +pub fn add_feature_diagnostics_for_issue( + err: &mut Diag<'_, G>, + sess: &Session, + feature: Symbol, + issue: GateIssue, + feature_from_cli: bool, + inject_span: Option, +) { + if let Some(n) = find_feature_issue(feature, issue) { + err.subdiagnostic(FeatureDiagnosticForIssue { n }); + } + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.unstable_features.is_nightly_build() { + if feature_from_cli { + err.subdiagnostic(CliFeatureDiagnosticHelp { feature }); + } else if let Some(span) = inject_span { + err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span }); + } else { + err.subdiagnostic(FeatureDiagnosticHelp { feature }); + } + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); + } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { + err.subdiagnostic(suggestion); + } + } +} + +/// This is only used by unstable_feature_bound as it does not have issue number information for now. +/// This is basically the same as `feature_err_issue` +/// but without the feature issue note. If we can do a lookup for issue number from feature name, +/// then we should directly use `feature_err_issue` for ambiguity error of +/// `#[unstable_feature_bound]`. +#[track_caller] +pub fn feature_err_unstable_feature_bound( + sess: &Session, + feature: Symbol, + span: impl Into, + explain: impl Into, +) -> Diag<'_> { + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() { + if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { + err.cancel() + } + } + + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.unstable_features.is_nightly_build() { + err.subdiagnostic(FeatureDiagnosticHelp { feature }); + + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); + } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { + err.subdiagnostic(suggestion); + } + } + err +} + #[derive(Diagnostic)] pub(crate) enum AppleDeploymentTarget { #[diag("failed to parse deployment target specified in {$env_var}: {$error}")] diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index c09e3eed37125..54058e9f5f046 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -1,7 +1,6 @@ //! Contains `ParseSess` which holds state living beyond what one `Parser` might. //! It also serves as an input to the parser itself. -use std::str; use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; @@ -11,21 +10,15 @@ use rustc_data_structures::sync::{AppendOnlyVec, DynSend, DynSync, Lock}; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitter; use rustc_errors::emitter::{EmitterWithNote, stderr_destination}; use rustc_errors::{ - BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle, - DiagMessage, EmissionGuarantee, Level, MultiSpan, StashKey, + BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle, Level, + MultiSpan, }; -use rustc_feature::{GateIssue, find_feature_issue}; use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use crate::Session; -use crate::errors::{ - CliFeatureDiagnosticHelp, FeatureDiagnosticForIssue, FeatureDiagnosticHelp, - FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler, -}; -use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION; use crate::lint::{Lint, LintId}; /// Collected spans during parsing for places where a certain feature was @@ -78,169 +71,6 @@ impl SymbolGallery { } } -// FIXME: this function now accepts `Session` instead of `ParseSess` and should be relocated -/// Construct a diagnostic for a language feature error due to the given `span`. -/// The `feature`'s `Symbol` is the one you used in `unstable.rs` and `rustc_span::symbol`. -#[track_caller] -pub fn feature_err( - sess: &Session, - feature: Symbol, - span: impl Into, - explain: impl Into, -) -> Diag<'_> { - feature_err_issue(sess, feature, span, GateIssue::Language, explain) -} - -/// Construct a diagnostic for a feature gate error. -/// -/// This variant allows you to control whether it is a library or language feature. -/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`. -#[track_caller] -pub fn feature_err_issue( - sess: &Session, - feature: Symbol, - span: impl Into, - issue: GateIssue, - explain: impl Into, -) -> Diag<'_> { - let span = span.into(); - - // Cancel an earlier warning for this same error, if it exists. - if let Some(span) = span.primary_span() - && let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) - { - err.cancel() - } - - let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); - add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); - err -} - -/// Construct a future incompatibility diagnostic for a feature gate. -/// -/// This diagnostic is only a warning and *does not cause compilation to fail*. -#[track_caller] -pub fn feature_warn(sess: &Session, feature: Symbol, span: Span, explain: &'static str) { - feature_warn_issue(sess, feature, span, GateIssue::Language, explain); -} - -/// Construct a future incompatibility diagnostic for a feature gate. -/// -/// This diagnostic is only a warning and *does not cause compilation to fail*. -/// -/// This variant allows you to control whether it is a library or language feature. -/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. -#[track_caller] -pub fn feature_warn_issue( - sess: &Session, - feature: Symbol, - span: Span, - issue: GateIssue, - explain: &'static str, -) { - let mut err = sess.dcx().struct_span_warn(span, explain); - add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false, None); - - // Decorate this as a future-incompatibility lint as in rustc_middle::lint::lint_level - let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; - let future_incompatible = lint.future_incompatible.as_ref().unwrap(); - err.is_lint(lint.name_lower(), /* has_future_breakage */ false); - err.warn(lint.desc); - err.note(format!("for more information, see {}", future_incompatible.reason.reference())); - - // A later feature_err call can steal and cancel this warning. - err.stash(span, StashKey::EarlySyntaxWarning); -} - -/// Adds the diagnostics for a feature to an existing error. -/// Must be a language feature! -pub fn add_feature_diagnostics( - err: &mut Diag<'_, G>, - sess: &Session, - feature: Symbol, -) { - add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language, false, None); -} - -/// Adds the diagnostics for a feature to an existing error. -/// -/// This variant allows you to control whether it is a library or language feature. -/// Almost always, you want to use this for a language feature. If so, prefer -/// `add_feature_diagnostics`. -pub fn add_feature_diagnostics_for_issue( - err: &mut Diag<'_, G>, - sess: &Session, - feature: Symbol, - issue: GateIssue, - feature_from_cli: bool, - inject_span: Option, -) { - if let Some(n) = find_feature_issue(feature, issue) { - err.subdiagnostic(FeatureDiagnosticForIssue { n }); - } - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if sess.unstable_features.is_nightly_build() { - if feature_from_cli { - err.subdiagnostic(CliFeatureDiagnosticHelp { feature }); - } else if let Some(span) = inject_span { - err.subdiagnostic(FeatureDiagnosticSuggestion { feature, span }); - } else { - err.subdiagnostic(FeatureDiagnosticHelp { feature }); - } - if feature == sym::rustc_attrs { - // We're unlikely to stabilize something out of `rustc_attrs` - // without at least renaming it, so pointing out how old - // the compiler is will do little good. - } else if sess.opts.unstable_opts.ui_testing { - err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); - } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { - err.subdiagnostic(suggestion); - } - } -} - -/// This is only used by unstable_feature_bound as it does not have issue number information for now. -/// This is basically the same as `feature_err_issue` -/// but without the feature issue note. If we can do a lookup for issue number from feature name, -/// then we should directly use `feature_err_issue` for ambiguity error of -/// `#[unstable_feature_bound]`. -#[track_caller] -pub fn feature_err_unstable_feature_bound( - sess: &Session, - feature: Symbol, - span: impl Into, - explain: impl Into, -) -> Diag<'_> { - let span = span.into(); - - // Cancel an earlier warning for this same error, if it exists. - if let Some(span) = span.primary_span() { - if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { - err.cancel() - } - } - - let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); - - // #23973: do not suggest `#![feature(...)]` if we are in beta/stable - if sess.unstable_features.is_nightly_build() { - err.subdiagnostic(FeatureDiagnosticHelp { feature }); - - if feature == sym::rustc_attrs { - // We're unlikely to stabilize something out of `rustc_attrs` - // without at least renaming it, so pointing out how old - // the compiler is will do little good. - } else if sess.opts.unstable_opts.ui_testing { - err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); - } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { - err.subdiagnostic(suggestion); - } - } - err -} - /// Info about a parsing session. pub struct ParseSess { dcx: DiagCtxt, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 623a246dc1b59..21583a5416277 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -45,7 +45,7 @@ use crate::config::{ }; use crate::filesearch::FileSearch; use crate::lint::LintId; -use crate::parse::{ParseSess, add_feature_diagnostics}; +use crate::parse::ParseSess; use crate::search_paths::SearchPath; use crate::{errors, filesearch, lint}; @@ -282,7 +282,7 @@ impl Session { if err.code.is_none() { err.code(E0658); } - add_feature_diagnostics(&mut err, self, feature); + errors::add_feature_diagnostics(&mut err, self, feature); err } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 1a308ee334d3b..108262d507ef7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -13,7 +13,7 @@ use rustc_infer::traits::{ }; use rustc_middle::ty::print::PrintPolyTraitPredicateExt; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _, Unnormalized}; -use rustc_session::parse::feature_err_unstable_feature_bound; +use rustc_session::errors::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use tracing::{debug, instrument}; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 66a2fcaa562d1..57b14e93e277c 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, GenericArgsRef, Term, TermKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_session::parse::feature_err; +use rustc_session::errors::feature_err; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{Span, sym}; use tracing::{debug, instrument, trace}; diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 45061a02e7525..eb1dee2e16d7b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1492,7 +1492,7 @@ impl LinkCollector<'_, '_> { Some((sp, _)) => sp, None => item.attr_span(self.cx.tcx), }; - rustc_session::parse::feature_err( + rustc_session::errors::feature_err( self.cx.tcx.sess, sym::intra_doc_pointers, span, From ee7e4309bea4096c8169f3716fd6a0fb7f9bbbae Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 28 Apr 2026 16:48:50 +1000 Subject: [PATCH 19/23] Remove unnecessary `lift` calls. Various places where `lift` just isn't necessary. Either because we're not within a closure passed to `tls::with`, or because the type being lifted doesn't have a `'tcx` lifetime. --- compiler/rustc_middle/src/mir/pretty.rs | 5 ----- .../rustc_public/src/unstable/convert/internal.rs | 15 +++++++-------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index d160aada80a83..26c4d5fbe249d 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1911,8 +1911,6 @@ fn pretty_print_const_value_tcx<'tcx>( // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` // to be able to destructure the tuple into `(0u8, *mut T)` (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_non_region_param() => { - let ct = tcx.lift(ct).unwrap(); - let ty = tcx.lift(ty).unwrap(); if let Some(contents) = tcx.try_destructure_mir_constant_for_user_output(ct, ty) { let fields: Vec<(ConstValue, Ty<'_>)> = contents.fields.to_vec(); match *ty.kind() { @@ -1937,7 +1935,6 @@ fn pretty_print_const_value_tcx<'tcx>( .variant .expect("destructed mir constant of adt without variant idx"); let variant_def = &def.variant(variant_idx); - let args = tcx.lift(args).unwrap(); let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; p.pretty_print_value_path(variant_def.def_id, args)?; @@ -1974,7 +1971,6 @@ fn pretty_print_const_value_tcx<'tcx>( (ConstValue::Scalar(scalar), _) => { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; - let ty = tcx.lift(ty).unwrap(); p.pretty_print_const_scalar(scalar, ty)?; fmt.write_str(&p.into_buffer())?; return Ok(()); @@ -2000,7 +1996,6 @@ pub(crate) fn pretty_print_const_value<'tcx>( fmt: &mut Formatter<'_>, ) -> fmt::Result { ty::tls::with(|tcx| { - let ct = tcx.lift(ct).unwrap(); let ty = tcx.lift(ty).unwrap(); pretty_print_const_value_tcx(tcx, ct, ty, fmt) }) diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index dc41bb1f687fe..67099c1cf1c12 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -49,9 +49,9 @@ impl RustcInternal for DefId { fn internal<'tcx>( &self, tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, + _tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.def_ids[*self]).unwrap() + tables.def_ids[*self] } } @@ -78,7 +78,7 @@ impl RustcInternal for GenericArgKind { GenericArgKind::Type(ty) => ty.internal(tables, tcx).into(), GenericArgKind::Const(cnst) => cnst.internal(tables, tcx).into(), }; - tcx.lift(arg).unwrap() + arg } } @@ -316,11 +316,10 @@ impl RustcInternal for FnSig { .set_abi(self.abi.internal(tables, tcx)) .set_safety(self.safety.internal(tables, tcx)) .set_c_variadic(self.c_variadic); - tcx.lift(rustc_ty::FnSig { + rustc_ty::FnSig { inputs_and_output: tcx.mk_type_list(&self.inputs_and_output.internal(tables, tcx)), fn_sig_kind, - }) - .unwrap() + } } } @@ -553,9 +552,9 @@ impl RustcInternal for AllocId { fn internal<'tcx>( &self, tables: &mut Tables<'_, BridgeTys>, - tcx: impl InternalCx<'tcx>, + _tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.alloc_ids[*self]).unwrap() + tables.alloc_ids[*self] } } From a762dbfe76f7bd81d6a8c6623b496329bb0b14b1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 30 Apr 2026 11:16:30 +1000 Subject: [PATCH 20/23] Make lifting infallible. Every lifting root calls `unwrap`/`expect` on the result, except for `ImmTy::fmt` but there's no good reason for that exception. Making lifting infallible is sensible because it should only fail if the wrong interner is somehow used, which indicates a major bug in rustc rather than an error condition. --- .../rustc_const_eval/src/interpret/operand.rs | 13 ++++----- compiler/rustc_macros/src/lift.rs | 17 +++++++----- compiler/rustc_middle/src/macros.rs | 4 +-- compiler/rustc_middle/src/mir/consts.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 6 ++--- .../rustc_middle/src/ty/consts/valtree.rs | 3 +-- compiler/rustc_middle/src/ty/context.rs | 27 +++++++++---------- compiler/rustc_middle/src/ty/error.rs | 17 ++++-------- compiler/rustc_middle/src/ty/generic_args.rs | 8 +++--- compiler/rustc_middle/src/ty/instance.rs | 3 +-- compiler/rustc_middle/src/ty/print/mod.rs | 2 +- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +-- .../rustc_middle/src/ty/structural_impls.rs | 13 ++++----- .../src/unstable/convert/internal.rs | 17 +++++------- .../src/unstable/convert/stable/abi.rs | 2 +- .../src/unstable/convert/stable/mir.rs | 6 ++--- .../src/unstable/convert/stable/ty.rs | 6 ++--- .../src/unstable/internal_cx/mod.rs | 2 +- compiler/rustc_public/src/unstable/mod.rs | 2 +- .../rustc_public_bridge/src/context/impls.rs | 2 +- compiler/rustc_type_ir/src/binder.rs | 22 +++++++-------- compiler/rustc_type_ir/src/lift.rs | 6 ++--- compiler/rustc_type_ir/src/predicate.rs | 4 +-- compiler/rustc_type_ir/src/ty_kind.rs | 4 +-- compiler/rustc_type_ir_macros/src/lib.rs | 6 ++--- 25 files changed, 90 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 6c9cd2e608ae1..7b2983620d420 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -216,14 +216,11 @@ impl std::fmt::Display for ImmTy<'_, Prov> { ty::tls::with(|tcx| { match self.imm { Immediate::Scalar(s) => { - if let Some(ty) = tcx.lift(self.layout.ty) { - let s = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { - print_scalar(p, s, ty) - })?; - f.write_str(&s)?; - return Ok(()); - } - write!(f, "{:x}: {}", s, self.layout.ty) + let ty = tcx.lift(self.layout.ty); + let s = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { + print_scalar(p, s, ty) + })?; + f.write_str(&s) } Immediate::ScalarPair(a, b) => { // FIXME(oli-obk): at least print tuples and slices nicely diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index 03ea396a42c75..9affbf5f1583b 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -34,16 +34,19 @@ pub(super) fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::To let bindings = &vi.bindings(); vi.construct(|_, index| { let bi = &bindings[index]; - quote! { __tcx.lift(#bi)? } + quote! { __tcx.lift(#bi) } }) }); s.add_impl_generic(newtcx); - s.bound_impl(quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), quote! { - type Lifted = #lifted; + s.bound_impl( + quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), + quote! { + type Lifted = #lifted; - fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> Option<#lifted> { - Some(match self { #body }) - } - }) + fn lift_to_interner(self, __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>) -> #lifted { + match self { #body } + } + }, + ) } diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index 0ae774ebee795..3d0971ed1ffd9 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -46,8 +46,8 @@ macro_rules! TrivialLiftImpls { $( impl<'tcx> $crate::ty::Lift<$crate::ty::TyCtxt<'tcx>> for $ty { type Lifted = Self; - fn lift_to_interner(self, _: $crate::ty::TyCtxt<'tcx>) -> Option { - Some(self) + fn lift_to_interner(self, _: $crate::ty::TyCtxt<'tcx>) -> Self { + self } } )+ diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index de3ef6deca1fc..c3dd68fdd9187 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -493,7 +493,7 @@ impl<'tcx> Display for Const<'tcx> { // FIXME(valtrees): Correctly print mir constants. Const::Unevaluated(c, _ty) => { ty::tls::with(move |tcx| { - let c = tcx.lift(c).unwrap(); + let c = tcx.lift(c); // Matches `GlobalId` printing. let instance = with_no_trimmed_paths!(tcx.def_path_str_with_args(c.def, c.args)); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 26c4d5fbe249d..c59e6b6fa2151 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1165,7 +1165,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Adt(adt_did, variant, args, _user_ty, _) => { ty::tls::with(|tcx| { let variant_def = &tcx.adt_def(adt_did).variant(variant); - let args = tcx.lift(args).expect("could not lift for printing"); + let args = tcx.lift(args); let name = FmtPrinter::print_string(tcx, Namespace::ValueNS, |p| { p.print_def_path(variant_def.def_id, args) })?; @@ -1187,7 +1187,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Closure(def_id, args) | AggregateKind::CoroutineClosure(def_id, args) => ty::tls::with(|tcx| { let name = if tcx.sess.opts.unstable_opts.span_free_formats { - let args = tcx.lift(args).unwrap(); + let args = tcx.lift(args); format!("{{closure@{}}}", tcx.def_path_str_with_args(def_id, args),) } else { let span = tcx.def_span(def_id); @@ -1996,7 +1996,7 @@ pub(crate) fn pretty_print_const_value<'tcx>( fmt: &mut Formatter<'_>, ) -> fmt::Result { ty::tls::with(|tcx| { - let ty = tcx.lift(ty).unwrap(); + let ty = tcx.lift(ty); pretty_print_const_value_tcx(tcx, ct, ty, fmt) }) } diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 50242613b3e7f..8866860661c41 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -238,9 +238,8 @@ impl<'tcx> rustc_type_ir::inherent::ValueConst> for Value<'tcx> { impl<'tcx> fmt::Display for Value<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(move |tcx| { - let cv = tcx.lift(*self).unwrap(); let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); - p.pretty_print_const_valtree(cv, /*print_ty*/ true)?; + p.pretty_print_const_valtree(tcx.lift(*self), /*print_ty*/ true)?; f.write_str(&p.into_buffer()) }) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e26eb13243762..e394076ea7c5a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -958,7 +958,7 @@ impl<'tcx> TyCtxt<'tcx> { (start, end) } - pub fn lift>>(self, value: T) -> Option { + pub fn lift>>(self, value: T) -> T::Lifted { value.lift_to_interner(self) } @@ -1689,7 +1689,8 @@ macro_rules! nop_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift> for $ty { type Lifted = $lifted; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + #[track_caller] + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { // Assert that the set has the right type. // Given an argument that has an interned type, the return type has the type of // the corresponding interner set. This won't actually return anything, we're @@ -1709,12 +1710,10 @@ macro_rules! nop_lift { _type_eq(&interner, &tcx.interners.$set); } - tcx.interners - .$set - .contains_pointer_to(&InternedInSet(&*self.0.0)) - // SAFETY: `self` is interned and therefore valid - // for the entire lifetime of the `TyCtxt`. - .then(|| unsafe { mem::transmute(self) }) + assert!(tcx.interners.$set.contains_pointer_to(&InternedInSet(&*self.0.0))); + // SAFETY: we just checked that `self` is interned and therefore is valid for the + // entire lifetime of the `TyCtxt`. + unsafe { mem::transmute(self) } } } }; @@ -1724,19 +1723,19 @@ macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { impl<'a, 'tcx> Lift> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { // Assert that the set has the right type. if false { let _x: &InternedSet<'tcx, List<$lifted>> = &tcx.interners.$set; } if self.is_empty() { - return Some(List::empty()); + return List::empty(); } - tcx.interners - .$set - .contains_pointer_to(&InternedInSet(self)) - .then(|| unsafe { mem::transmute(self) }) + assert!(tcx.interners.$set.contains_pointer_to(&InternedInSet(self))); + // SAFETY: we just checked that `self` is interned and therefore is valid for the + // entire lifetime of the `TyCtxt`. + unsafe { mem::transmute(self) } } } }; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index a4c30f1f88434..082e5de16cf98 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -223,10 +223,8 @@ impl<'tcx> TyCtxt<'tcx> { T: Copy + for<'a, 'b> Lift, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { let mut type_limit = 50; - let regular = FmtPrinter::print_string(self, ns, |p| { - self.lift(t).expect("could not lift for printing").print(p) - }) - .expect("could not write to `String`"); + let regular = FmtPrinter::print_string(self, ns, |p| self.lift(t).print(p)) + .expect("could not write to `String`"); if regular.len() <= length_limit { return regular; } @@ -235,10 +233,7 @@ impl<'tcx> TyCtxt<'tcx> { // Look for the longest properly trimmed path that still fits in length_limit. short = with_forced_trimmed_paths!({ let mut p = FmtPrinter::new_with_limit(self, ns, Limit(type_limit)); - self.lift(t) - .expect("could not lift for printing") - .print(&mut p) - .expect("could not print type"); + self.lift(t).print(&mut p).expect("could not print type"); p.into_buffer() }); if short.len() <= length_limit || type_limit == 0 { @@ -273,10 +268,8 @@ impl<'tcx> TyCtxt<'tcx> { where T: Copy + Hash + for<'a, 'b> Lift, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { - let regular = FmtPrinter::print_string(self, namespace, |p| { - self.lift(t).expect("could not lift for printing").print(p) - }) - .expect("could not write to `String`"); + let regular = FmtPrinter::print_string(self, namespace, |p| self.lift(t).print(p)) + .expect("could not write to `String`"); if !self.sess.opts.unstable_opts.write_long_types_to_disk || self.sess.opts.verbose { return regular; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index daeabf24d749f..c57c0851d8a49 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -320,11 +320,11 @@ impl<'tcx> GenericArg<'tcx> { impl<'a, 'tcx> Lift> for GenericArg<'a> { type Lifted = GenericArg<'tcx>; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { match self.kind() { - GenericArgKind::Lifetime(lt) => tcx.lift(lt).map(|lt| lt.into()), - GenericArgKind::Type(ty) => tcx.lift(ty).map(|ty| ty.into()), - GenericArgKind::Const(ct) => tcx.lift(ct).map(|ct| ct.into()), + GenericArgKind::Lifetime(lt) => tcx.lift(lt).into(), + GenericArgKind::Type(ty) => tcx.lift(ty).into(), + GenericArgKind::Const(ct) => tcx.lift(ct).into(), } } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 408edf19dbf23..8166053f9bd5f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -381,8 +381,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); - let instance = tcx.lift(*self).expect("could not lift for printing"); - instance.print(&mut p)?; + tcx.lift(*self).print(&mut p)?; let s = p.into_buffer(); f.write_str(&s) }) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index d2ae226c4d8dc..d5d1c3634c7d1 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -418,7 +418,7 @@ where fn print(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { ty::tls::with(|tcx| { let mut p = FmtPrinter::new(tcx, Namespace::TypeNS); - tcx.lift(*t).expect("could not lift for printing").print(&mut p)?; + tcx.lift(*t).print(&mut p)?; fmt.write_str(&p.into_buffer())?; Ok(()) }) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index f997e49868ba8..04d76e4304fe9 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2082,10 +2082,9 @@ pub(crate) fn pretty_print_const<'tcx>( print_types: bool, ) -> fmt::Result { ty::tls::with(|tcx| { - let literal = tcx.lift(c).unwrap(); let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; - p.pretty_print_const(literal, print_types)?; + p.pretty_print_const(tcx.lift(c), print_types)?; fmt.write_str(&p.into_buffer())?; Ok(()) }) @@ -3098,7 +3097,6 @@ macro_rules! forward_display_to_print { ty::tls::with(|tcx| { let mut p = FmtPrinter::new(tcx, Namespace::TypeNS); tcx.lift(*self) - .expect("could not lift for printing") .print(&mut p)?; f.write_str(&p.into_buffer())?; Ok(()) diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 29b784e837954..bc53fc18b41b6 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -271,20 +271,17 @@ TrivialTypeTraversalAndLiftImpls! { impl<'tcx, T: Lift>> Lift> for Option { type Lifted = Option; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { - Some(match self { - Some(x) => Some(tcx.lift(x)?), - None => None, - }) + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { + self.map(|x| tcx.lift(x)) } } impl<'a, 'tcx> Lift> for Term<'a> { type Lifted = ty::Term<'tcx>; - fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Option { + fn lift_to_interner(self, tcx: TyCtxt<'tcx>) -> Self::Lifted { match self.kind() { - TermKind::Ty(ty) => tcx.lift(ty).map(Into::into), - TermKind::Const(c) => tcx.lift(c).map(Into::into), + TermKind::Ty(ty) => tcx.lift(ty).into(), + TermKind::Const(c) => tcx.lift(c).into(), } } } diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs index 67099c1cf1c12..165ad737fccb8 100644 --- a/compiler/rustc_public/src/unstable/convert/internal.rs +++ b/compiler/rustc_public/src/unstable/convert/internal.rs @@ -101,7 +101,7 @@ impl RustcInternal for Ty { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.types[*self]).unwrap() + tcx.lift(tables.types[*self]) } } @@ -112,7 +112,7 @@ impl RustcInternal for TyConst { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.ty_consts[self.id]).unwrap() + tcx.lift(tables.ty_consts[self.id]) } } @@ -357,16 +357,13 @@ impl RustcInternal for MirConst { let constant = tables.mir_consts[self.id]; match constant { rustc_middle::mir::Const::Ty(ty, ct) => { - rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap(), tcx.lift(ct).unwrap()) + rustc_middle::mir::Const::Ty(tcx.lift(ty), tcx.lift(ct)) } rustc_middle::mir::Const::Unevaluated(uneval, ty) => { - rustc_middle::mir::Const::Unevaluated( - tcx.lift(uneval).unwrap(), - tcx.lift(ty).unwrap(), - ) + rustc_middle::mir::Const::Unevaluated(tcx.lift(uneval), tcx.lift(ty)) } rustc_middle::mir::Const::Val(const_val, ty) => { - rustc_middle::mir::Const::Val(tcx.lift(const_val).unwrap(), tcx.lift(ty).unwrap()) + rustc_middle::mir::Const::Val(tcx.lift(const_val), tcx.lift(ty)) } } } @@ -399,7 +396,7 @@ impl RustcInternal for Instance { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.instances[self.def]).unwrap() + tcx.lift(tables.instances[self.def]) } } @@ -690,7 +687,7 @@ impl RustcInternal for Layout { tables: &mut Tables<'_, BridgeTys>, tcx: impl InternalCx<'tcx>, ) -> Self::T<'tcx> { - tcx.lift(tables.layouts[*self]).unwrap() + tcx.lift(tables.layouts[*self]) } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index d8c4cee7abbe4..56fbd8108786a 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -58,7 +58,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Layout<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - tables.layout_id(cx.lift(*self).unwrap()) + tables.layout_id(cx.lift(*self)) } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 0d04053aab76b..2bc23e2837048 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -864,7 +864,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - let id = tables.intern_mir_const(cx.lift(*self).unwrap()); + let id = tables.intern_mir_const(cx.lift(*self)); match *self { mir::Const::Ty(ty, c) => MirConst::new( crate::ty::ConstantKind::Ty(c.stable(tables, cx)), @@ -885,8 +885,8 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { MirConst::new(ConstantKind::ZeroSized, ty, id) } mir::Const::Val(val, ty) => { - let ty = cx.lift(ty).unwrap(); - let val = cx.lift(val).unwrap(); + let ty = cx.lift(ty); + let val = cx.lift(val); let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables, cx)); let ty = ty.stable(tables, cx); MirConst::new(kind, ty, id) diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 4c4a51f7444bb..80453d838b880 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -408,7 +408,7 @@ impl<'tcx> Stable<'tcx> for Ty<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - tables.intern_ty(cx.lift(*self).unwrap()) + tables.intern_ty(cx.lift(*self)) } } @@ -526,7 +526,7 @@ impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - let ct = cx.lift(*self).unwrap(); + let ct = cx.lift(*self); let kind = match ct.kind() { ty::ConstKind::Value(cv) => { let const_val = cx.valtree_to_const_val(cv); @@ -967,7 +967,7 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { tables: &mut Tables<'cx, BridgeTys>, cx: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - let def = tables.instance_def(cx.lift(*self).unwrap()); + let def = tables.instance_def(cx.lift(*self)); let kind = match self.def { ty::InstanceKind::Item(..) => crate::mir::mono::InstanceKind::Item, ty::InstanceKind::Intrinsic(..) => crate::mir::mono::InstanceKind::Intrinsic, diff --git a/compiler/rustc_public/src/unstable/internal_cx/mod.rs b/compiler/rustc_public/src/unstable/internal_cx/mod.rs index 161f2754bed87..f178ced7224c1 100644 --- a/compiler/rustc_public/src/unstable/internal_cx/mod.rs +++ b/compiler/rustc_public/src/unstable/internal_cx/mod.rs @@ -44,7 +44,7 @@ impl<'tcx> InternalCx<'tcx> for TyCtxt<'tcx> { self } - fn lift>>(self, value: T) -> Option { + fn lift>>(self, value: T) -> T::Lifted { TyCtxt::lift(self, value) } diff --git a/compiler/rustc_public/src/unstable/mod.rs b/compiler/rustc_public/src/unstable/mod.rs index ec979eef40cd1..8c20a54018553 100644 --- a/compiler/rustc_public/src/unstable/mod.rs +++ b/compiler/rustc_public/src/unstable/mod.rs @@ -26,7 +26,7 @@ mod internal_cx; pub trait InternalCx<'tcx>: Copy + Clone { fn tcx(self) -> TyCtxt<'tcx>; - fn lift>>(self, value: T) -> Option; + fn lift>>(self, value: T) -> T::Lifted; fn mk_args_from_iter(self, iter: I) -> T::Output where diff --git a/compiler/rustc_public_bridge/src/context/impls.rs b/compiler/rustc_public_bridge/src/context/impls.rs index bb504bd0017a0..260b9cd2198cf 100644 --- a/compiler/rustc_public_bridge/src/context/impls.rs +++ b/compiler/rustc_public_bridge/src/context/impls.rs @@ -53,7 +53,7 @@ impl<'tcx, B: Bridge> AllocRangeHelpers<'tcx> for CompilerCtxt<'tcx, B> { } impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> { - pub fn lift>>(&self, value: T) -> Option { + pub fn lift>>(&self, value: T) -> T::Lifted { self.tcx.lift(value) } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 2b0dc221844ec..14ad3373b2c8f 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -45,11 +45,11 @@ where { type Lifted = Binder; - fn lift_to_interner(self, cx: U) -> Option { - Some(Binder { - value: self.value.lift_to_interner(cx)?, - bound_vars: self.bound_vars.lift_to_interner(cx)?, - }) + fn lift_to_interner(self, cx: U) -> Self::Lifted { + Binder { + value: self.value.lift_to_interner(cx), + bound_vars: self.bound_vars.lift_to_interner(cx), + } } } @@ -994,12 +994,12 @@ where { type Lifted = Placeholder; - fn lift_to_interner(self, cx: U) -> Option { - Some(Placeholder { + fn lift_to_interner(self, cx: U) -> Self::Lifted { + Placeholder { universe: self.universe, - bound: self.bound.lift_to_interner(cx)?, + bound: self.bound.lift_to_interner(cx), _tcx: PhantomData, - }) + } } } @@ -1190,8 +1190,8 @@ where { type Lifted = BoundTy; - fn lift_to_interner(self, cx: U) -> Option { - Some(BoundTy { var: self.var, kind: self.kind.lift_to_interner(cx)? }) + fn lift_to_interner(self, cx: U) -> Self::Lifted { + BoundTy { var: self.var, kind: self.kind.lift_to_interner(cx) } } } diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs index e5a099d1f5042..739d3a8512329 100644 --- a/compiler/rustc_type_ir/src/lift.rs +++ b/compiler/rustc_type_ir/src/lift.rs @@ -9,13 +9,13 @@ /// It would be more efficient if `TypedArena` provided a way to /// determine whether the address is in the allocated range. /// -/// `None` is returned if the value or one of the components is not part +/// Panics if the value or one of the components is not part /// of the provided context. -/// For `Ty`, `None` can be returned if either the type interner doesn't +/// For `Ty`, this can happen if either the type interner doesn't /// contain the `TyKind` key or if the address of the interned /// pointer differs. The latter case is possible if a primitive type, /// e.g., `()` or `u8`, was interned in a different context. pub trait Lift: std::fmt::Debug { type Lifted: std::fmt::Debug; - fn lift_to_interner(self, cx: I) -> Option; + fn lift_to_interner(self, cx: I) -> Self::Lifted; } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 0545fbfda6e41..7a1798e439d16 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -35,8 +35,8 @@ where { type Lifted = OutlivesPredicate; - fn lift_to_interner(self, cx: U) -> Option { - Some(OutlivesPredicate(self.0.lift_to_interner(cx)?, self.1.lift_to_interner(cx)?)) + fn lift_to_interner(self, cx: U) -> Self::Lifted { + OutlivesPredicate(self.0.lift_to_interner(cx), self.1.lift_to_interner(cx)) } } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index e136257a5b248..e58de0c947cd2 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -782,8 +782,8 @@ pub struct FnSigKind { impl crate::lift::Lift for FnSigKind { type Lifted = FnSigKind; - fn lift_to_interner(self, _cx: J) -> Option { - Some(FnSigKind { flags: self.flags, _marker: PhantomData }) + fn lift_to_interner(self, _cx: J) -> Self::Lifted { + FnSigKind { flags: self.flags, _marker: PhantomData } } } diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 8df10b6a9eccd..7ea8bd384e3cf 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -168,7 +168,7 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift }); let bind = &bindings[index]; quote! { - #bind.lift_to_interner(interner)? + #bind.lift_to_interner(interner) } }) }); @@ -189,8 +189,8 @@ fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { fn lift_to_interner( self, interner: J, - ) -> Option { - Some(match self { #body_fold }) + ) -> Self::Lifted { + match self { #body_fold } } }, ) From ef93fbbc9d208d5dbf7658fe79d373931d0b2480 Mon Sep 17 00:00:00 2001 From: Vastargazing Date: Thu, 30 Apr 2026 10:24:54 +0300 Subject: [PATCH 21/23] tests/run-make/print-cfg: add Android target_env case Android targets must not inherit `target_env="gnu"` from the Linux GNU base. Cover this in the existing print-cfg run-make test so a future target-spec refactor cannot silently re-introduce it. --- tests/run-make/print-cfg/rmake.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index a5df237b7fddc..b516bb1508ec4 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -48,6 +48,12 @@ fn main() { includes: &["unix", "target_abi=\"eabihf\""], disallow: &["windows"], }); + // Regression test for #90834: Android must not have `target_env="gnu"`. + check(PrintCfg { + target: "i686-linux-android", + includes: &["unix", "target_os=\"android\""], + disallow: &["windows", "target_env=\"gnu\""], + }); } fn check(PrintCfg { target, includes, disallow }: PrintCfg) { From e4eb91ca0fb9b176be4e2cdd0a3a5e08eb472fc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 29 Apr 2026 23:23:28 +0200 Subject: [PATCH 22/23] catch callback unwinding to finalize in-flight self-profiling events from queries fatal errors currently abort the compiler process without allocating the self-profile strings: query events aren't always correctly recorded, and will show up as in the data. catching the unwinding panic allows us to finalize the self-profiling process correctly before continuing unwinding as before. --- compiler/rustc_interface/src/passes.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 842cb1f041311..344090d1c147f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1016,9 +1016,24 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs)))); feed.output_filenames(Arc::new(outputs)); - let res = f(tcx); - // FIXME maybe run finish even when a fatal error occurred? or at least - // tcx.alloc_self_profile_query_strings()? + // There are two paths out of `f`. + // - Normal exit. + // - Panic, e.g. triggered by `abort_if_errors` or a fatal error. + // + // If a panic occurs, we still need to wind down the self-profiler to correctly record + // the query events that are still in flight. Otherwise, they will be invalid and will + // show up as "" in the profiling data. + let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(tcx))); + let res = match res { + Ok(res) => res, + Err(err) => { + tcx.alloc_self_profile_query_strings(); + + // Resume unwinding if a panic happened. + std::panic::resume_unwind(err); + } + }; + tcx.finish(); res }, From c5e38b741dcdd205bb36eb798590b9aacbfdb3da Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:18:33 +0000 Subject: [PATCH 23/23] Pass Session to optimize_and_codegen_fat_lto This is necessary to fix incremental LTO in cg_gcc as well as to do some LTO refactorings I want to do. The actual fix for cg_gcc will be done on the cg_gcc repo to test it in CI. --- compiler/rustc_codegen_gcc/src/lib.rs | 4 ++-- compiler/rustc_codegen_llvm/src/lib.rs | 8 ++++---- compiler/rustc_codegen_ssa/src/back/write.rs | 8 ++++---- compiler/rustc_codegen_ssa/src/traits/write.rs | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index d50968bad2501..4be25b3fb0934 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -430,8 +430,8 @@ impl WriteBackendMethods for GccCodegenBackend { } fn optimize_and_codegen_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, _tm_factory: TargetMachineFactoryFn, // FIXME(bjorn3): Limit LTO exports to these symbols @@ -439,7 +439,7 @@ impl WriteBackendMethods for GccCodegenBackend { each_linked_rlib_for_lto: &[PathBuf], modules: Vec>, ) -> CompiledModule { - back::lto::run_fat(cgcx, prof, shared_emitter, each_linked_rlib_for_lto, modules) + back::lto::run_fat(cgcx, &sess.prof, shared_emitter, each_linked_rlib_for_lto, modules) } fn run_thin_lto( diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 65c70c754918d..575e37d0b171d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -133,8 +133,8 @@ impl WriteBackendMethods for LlvmCodegenBackend { back::write::target_machine_factory(sess, optlvl, target_features) } fn optimize_and_codegen_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String], @@ -143,7 +143,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { ) -> CompiledModule { let mut module = back::lto::run_fat( cgcx, - prof, + &sess.prof, shared_emitter, tm_factory, exported_symbols_for_lto, @@ -153,9 +153,9 @@ impl WriteBackendMethods for LlvmCodegenBackend { let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); - back::lto::run_pass_manager(cgcx, prof, dcx, &mut module, false); + back::lto::run_pass_manager(cgcx, &sess.prof, dcx, &mut module, false); - back::write::codegen(cgcx, prof, shared_emitter, module, &cgcx.module_config) + back::write::codegen(cgcx, &sess.prof, shared_emitter, module, &cgcx.module_config) } fn run_thin_lto( cgcx: &CodegenContext, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index ff91a08de4de6..c48e8a58b6964 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -961,15 +961,15 @@ fn execute_copy_from_cache_work_item( } fn do_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: SharedEmitter, tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], needs_fat_lto: Vec>, ) -> CompiledModule { - let _timer = prof.verbose_generic_activity("LLVM_fatlto"); + let _timer = sess.prof.verbose_generic_activity("LLVM_fatlto"); let dcx = DiagCtxt::new(Box::new(shared_emitter.clone())); let dcx = dcx.handle(); @@ -977,8 +977,8 @@ fn do_fat_lto( check_lto_allowed(&cgcx, dcx); B::optimize_and_codegen_fat_lto( + sess, cgcx, - prof, &shared_emitter, tm_factory, exported_symbols_for_lto, @@ -2177,8 +2177,8 @@ impl OngoingCodegen { CompiledModules { modules: vec![do_fat_lto( + sess, &cgcx, - &sess.prof, shared_emitter, tm_factory, &exported_symbols_for_lto, diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index cca6db78e381e..9b8bf138e7a14 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -30,8 +30,8 @@ pub trait WriteBackendMethods: Clone + 'static { /// Performs fat LTO by merging all modules into a single one, running autodiff /// if necessary and running any further optimizations fn optimize_and_codegen_fat_lto( + sess: &Session, cgcx: &CodegenContext, - prof: &SelfProfilerRef, shared_emitter: &SharedEmitter, tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String],