diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index ffaca029a8a78..384bc87499887 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -1236,8 +1236,10 @@ pub(crate) mod builtin { pub macro test($item:item) { /* compiler built-in */ } /// Attribute macro applied to a function to turn it into a benchmark test. - #[unstable(feature = "test", issue = "50297", - reason = "`bench` is a part of custom test frameworks which are unstable")] + #[cfg_attr(not(boostrap_stdarch_ignore_this), unstable(soft, feature = "test", issue = "50297", + reason = "`bench` is a part of custom test frameworks which are unstable"))] + #[cfg_attr(boostrap_stdarch_ignore_this, unstable(feature = "test", issue = "50297", + reason = "`bench` is a part of custom test frameworks which are unstable"))] #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] pub macro bench($item:item) { /* compiler built-in */ } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 646060bc8be77..a33181e5925cd 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -115,9 +115,10 @@ for ::syntax::attr::StabilityLevel { hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { + ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue, ref is_soft } => { reason.hash_stable(hcx, hasher); issue.hash_stable(hcx, hasher); + is_soft.hash_stable(hcx, hasher); } ::syntax::attr::StabilityLevel::Stable { ref since } => { since.hash_stable(hcx, hasher); diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 6d9a6bb77dd55..dd290572d7bb7 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -395,6 +395,12 @@ declare_lint! { "reservation of a two-phased borrow conflicts with other shared borrows" } +declare_lint! { + pub SOFT_UNSTABLE, + Deny, + "a feature gate that doesn't break dependent crates" +} + declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. @@ -460,6 +466,7 @@ declare_lint_pass! { NESTED_IMPL_TRAIT, MUTABLE_BORROW_RESERVATION_CONFLICT, INDIRECT_STRUCTURAL_MATCH, + SOFT_UNSTABLE, ] } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index d02259bf3010b..c06a0feb6a993 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -438,6 +438,7 @@ impl<'tcx> Index<'tcx> { level: attr::StabilityLevel::Unstable { reason: Some(Symbol::intern(reason)), issue: 27812, + is_soft: false, }, feature: sym::rustc_private, rustc_depr: None, @@ -480,7 +481,7 @@ pub fn provide(providers: &mut Providers<'_>) { } pub fn report_unstable( - sess: &Session, feature: Symbol, reason: Option, issue: u32, span: Span + sess: &Session, feature: Symbol, reason: Option, issue: u32, is_soft: bool, span: Span ) { let msg = match reason { Some(r) => format!("use of unstable library feature '{}': {}", feature, r), @@ -505,7 +506,13 @@ pub fn report_unstable( let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone()); let fresh = sess.one_time_diagnostics.borrow_mut().insert(error_id); if fresh { - emit_feature_err(&sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg); + if is_soft { + sess.buffer_lint(lint::builtin::SOFT_UNSTABLE, CRATE_NODE_ID, span, &msg); + } else { + emit_feature_err( + &sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg + ); + } } } @@ -621,6 +628,7 @@ pub enum EvalResult { feature: Symbol, reason: Option, issue: u32, + is_soft: bool, }, /// The item does not have the `#[stable]` or `#[unstable]` marker assigned. Unmarked, @@ -720,7 +728,9 @@ impl<'tcx> TyCtxt<'tcx> { } match stability { - Some(&Stability { level: attr::Unstable { reason, issue }, feature, .. }) => { + Some(&Stability { + level: attr::Unstable { reason, issue, is_soft }, feature, .. + }) => { if span.allows_unstable(feature) { debug!("stability: skipping span={:?} since it is internal", span); return EvalResult::Allow; @@ -744,7 +754,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - EvalResult::Deny { feature, reason, issue } + EvalResult::Deny { feature, reason, issue, is_soft } } Some(_) => { // Stable APIs are always ok to call and deprecated APIs are @@ -767,8 +777,8 @@ impl<'tcx> TyCtxt<'tcx> { pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { match self.eval_stability(def_id, id, span) { EvalResult::Allow => {} - EvalResult::Deny { feature, reason, issue } => - report_unstable(self.sess, feature, reason, issue, span), + EvalResult::Deny { feature, reason, issue, is_soft } => + report_unstable(self.sess, feature, reason, issue, is_soft, span), EvalResult::Unmarked => { // The API could be uncallable for other reasons, for example when a private module // was referenced. diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4ee6551f78781..0e054013cd779 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -435,7 +435,12 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(INDIRECT_STRUCTURAL_MATCH), reference: "issue #62411 ", edition: None, - } + }, + FutureIncompatibleInfo { + id: LintId::of(SOFT_UNSTABLE), + reference: "issue #64266 ", + edition: None, + }, ]); // Register renamed and removed lints. diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 054b17fec7849..87439440463b3 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -774,10 +774,10 @@ impl<'a> Resolver<'a> { fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &ast::Path) { let span = path.span; if let Some(stability) = &ext.stability { - if let StabilityLevel::Unstable { reason, issue } = stability.level { + if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level { let feature = stability.feature; if !self.active_features.contains(&feature) && !span.allows_unstable(feature) { - stability::report_unstable(self.session, feature, reason, issue, span); + stability::report_unstable(self.session, feature, reason, issue, is_soft, span); } } if let Some(depr) = &stability.rustc_depr { diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 5fb513783fbaa..b5037b75f79e7 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -154,23 +154,10 @@ pub struct Stability { #[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)] pub enum StabilityLevel { // Reason for the current stability level and the relevant rust-lang issue - Unstable { reason: Option, issue: u32 }, + Unstable { reason: Option, issue: u32, is_soft: bool }, Stable { since: Symbol }, } -impl Stability { - pub fn unstable(feature: Symbol, reason: Option, issue: u32) -> Stability { - Stability { - level: StabilityLevel::Unstable { reason, issue }, - feature, - rustc_depr: None, - const_stability: None, - promotable: false, - allow_const_fn_ptr: false, - } - } -} - impl StabilityLevel { pub fn is_unstable(&self) -> bool { if let StabilityLevel::Unstable {..} = *self { @@ -356,19 +343,27 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let mut feature = None; let mut reason = None; let mut issue = None; + let mut is_soft = false; for meta in metas { if let Some(mi) = meta.meta_item() { match mi.name_or_empty() { sym::feature => if !get(mi, &mut feature) { continue 'outer }, sym::reason => if !get(mi, &mut reason) { continue 'outer }, sym::issue => if !get(mi, &mut issue) { continue 'outer }, + sym::soft => { + if !mi.is_word() { + let msg = "`soft` should not have any arguments"; + sess.span_diagnostic.span_err(mi.span, msg); + } + is_soft = true; + } _ => { handle_errors( sess, meta.span(), AttrError::UnknownMetaItem( mi.path.to_string(), - &["feature", "reason", "issue"] + &["feature", "reason", "issue", "soft"] ), ); continue 'outer @@ -400,7 +395,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, "incorrect 'issue'"); continue } - } + }, + is_soft, }, feature, rustc_depr: None, diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index ecc31cfeb3d1f..ab32d4461ef87 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -626,6 +626,7 @@ symbols! { size, slice_patterns, slicing_syntax, + soft, Some, specialization, speed, diff --git a/src/test/ui/feature-gates/bench.rs b/src/test/ui/feature-gates/bench.rs new file mode 100644 index 0000000000000..afe4dc7d54c9b --- /dev/null +++ b/src/test/ui/feature-gates/bench.rs @@ -0,0 +1,5 @@ +#[bench] //~ ERROR use of unstable library feature 'test' + //~| WARN this was previously accepted +fn bench() {} + +fn main() {} diff --git a/src/test/ui/feature-gates/bench.stderr b/src/test/ui/feature-gates/bench.stderr new file mode 100644 index 0000000000000..b9e24e931d42b --- /dev/null +++ b/src/test/ui/feature-gates/bench.stderr @@ -0,0 +1,12 @@ +error: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable + --> $DIR/bench.rs:1:3 + | +LL | #[bench] + | ^^^^^ + | + = note: `#[deny(soft_unstable)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #64266 + +error: aborting due to previous error +