diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 597622b2ebf90..8a5fc5feeb71b 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -3,7 +3,7 @@ pub use self::StabilityLevel::*; -use crate::ty::{self, TyCtxt}; +use crate::ty::{self, DefIdTree, TyCtxt}; use rustc_ast::NodeId; use rustc_attr::{self as attr, ConstStability, Deprecation, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -90,6 +90,7 @@ pub fn report_unstable( feature: Symbol, reason: Option, issue: Option, + suggestion: Option<(Span, String, String, Applicability)>, is_soft: bool, span: Span, soft_handler: impl FnOnce(&'static Lint, Span, &str), @@ -116,8 +117,12 @@ pub fn report_unstable( if is_soft { soft_handler(SOFT_UNSTABLE, span, &msg) } else { - feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg) - .emit(); + let mut err = + feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg); + if let Some((inner_types, ref msg, sugg, applicability)) = suggestion { + err.span_suggestion(inner_types, msg, sugg, applicability); + } + err.emit(); } } } @@ -271,7 +276,13 @@ pub enum EvalResult { Allow, /// We cannot use the item because it is unstable and we did not provide the /// corresponding feature gate. - Deny { feature: Symbol, reason: Option, issue: Option, is_soft: bool }, + Deny { + feature: Symbol, + reason: Option, + issue: Option, + suggestion: Option<(Span, String, String, Applicability)>, + is_soft: bool, + }, /// The item does not have the `#[stable]` or `#[unstable]` marker assigned. Unmarked, } @@ -292,6 +303,32 @@ fn skip_stability_check_due_to_privacy(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } +// See issue #83250. +fn suggestion_for_allocator_api( + tcx: TyCtxt<'_>, + def_id: DefId, + span: Span, + feature: Symbol, +) -> Option<(Span, String, String, Applicability)> { + if feature == sym::allocator_api { + if let Some(trait_) = tcx.parent(def_id) { + if tcx.is_diagnostic_item(sym::Vec, trait_) { + let sm = tcx.sess.parse_sess.source_map(); + let inner_types = sm.span_extend_to_prev_char(span, '<', true); + if let Ok(snippet) = sm.span_to_snippet(inner_types) { + return Some(( + inner_types, + "consider wrapping the inner types in tuple".to_string(), + format!("({})", snippet), + Applicability::MaybeIncorrect, + )); + } + } + } + } + None +} + impl<'tcx> TyCtxt<'tcx> { /// Evaluates the stability of an item. /// @@ -406,7 +443,8 @@ impl<'tcx> TyCtxt<'tcx> { } } - EvalResult::Deny { feature, reason, issue, is_soft } + let suggestion = suggestion_for_allocator_api(self, def_id, span, feature); + EvalResult::Deny { feature, reason, issue, suggestion, is_soft } } Some(_) => { // Stable APIs are always ok to call and deprecated APIs are @@ -457,9 +495,16 @@ impl<'tcx> TyCtxt<'tcx> { }; match self.eval_stability(def_id, id, span, method_span) { EvalResult::Allow => {} - EvalResult::Deny { feature, reason, issue, is_soft } => { - report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler) - } + EvalResult::Deny { feature, reason, issue, suggestion, is_soft } => report_unstable( + self.sess, + feature, + reason, + issue, + suggestion, + is_soft, + span, + soft_handler, + ), EvalResult::Unmarked => unmarked(span, def_id), } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 31fd9b989e1c8..28dbce0471eaf 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -1133,6 +1133,7 @@ impl<'a> Resolver<'a> { feature, reason, issue, + None, is_soft, span, soft_handler, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 0d556b5eda609..9064d0c4969ec 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -307,6 +307,7 @@ symbols! { alloc_layout, alloc_zeroed, allocator, + allocator_api, allocator_internals, allow, allow_fail, diff --git a/src/test/ui/stability-attribute/suggest-vec-allocator-api.rs b/src/test/ui/stability-attribute/suggest-vec-allocator-api.rs new file mode 100644 index 0000000000000..fac52ab77c68c --- /dev/null +++ b/src/test/ui/stability-attribute/suggest-vec-allocator-api.rs @@ -0,0 +1,9 @@ +fn main() { + let _: Vec = vec![]; //~ ERROR use of unstable library feature 'allocator_api' + #[rustfmt::skip] + let _: Vec< + String, + _> = vec![]; //~ ERROR use of unstable library feature 'allocator_api' + let _ = Vec::::new(); //~ ERROR use of unstable library feature 'allocator_api' + let _boxed: Box = Box::new(10); //~ ERROR use of unstable library feature 'allocator_api' +} diff --git a/src/test/ui/stability-attribute/suggest-vec-allocator-api.stderr b/src/test/ui/stability-attribute/suggest-vec-allocator-api.stderr new file mode 100644 index 0000000000000..41e5787b8c2de --- /dev/null +++ b/src/test/ui/stability-attribute/suggest-vec-allocator-api.stderr @@ -0,0 +1,49 @@ +error[E0658]: use of unstable library feature 'allocator_api' + --> $DIR/suggest-vec-allocator-api.rs:2:20 + | +LL | let _: Vec = vec![]; + | ----^ + | | + | help: consider wrapping the inner types in tuple: `(u8, _)` + | + = note: see issue #32838 for more information + = help: add `#![feature(allocator_api)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'allocator_api' + --> $DIR/suggest-vec-allocator-api.rs:6:9 + | +LL | _> = vec![]; + | ^ + | + = note: see issue #32838 for more information + = help: add `#![feature(allocator_api)]` to the crate attributes to enable +help: consider wrapping the inner types in tuple + | +LL ~ let _: Vec<( +LL + String, +LL ~ _)> = vec![]; + | + +error[E0658]: use of unstable library feature 'allocator_api' + --> $DIR/suggest-vec-allocator-api.rs:8:26 + | +LL | let _boxed: Box = Box::new(10); + | ^ + | + = note: see issue #32838 for more information + = help: add `#![feature(allocator_api)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'allocator_api' + --> $DIR/suggest-vec-allocator-api.rs:7:24 + | +LL | let _ = Vec::::new(); + | -----^ + | | + | help: consider wrapping the inner types in tuple: `(u16, _)` + | + = note: see issue #32838 for more information + = help: add `#![feature(allocator_api)]` to the crate attributes to enable + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0658`.