Reenable early feature-gates as future-compat warnings

This commit is contained in:
Christopher Durham 2022-08-17 06:52:47 -05:00
parent e9e46c95ce
commit 767239f740
11 changed files with 224 additions and 34 deletions

View File

@ -2,10 +2,10 @@
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::{struct_span_err, Applicability};
use rustc_errors::{struct_span_err, Applicability, StashKey};
use rustc_feature::Features;
use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
use rustc_session::parse::{feature_err, feature_err_issue};
use rustc_session::parse::{feature_err, feature_warn};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
@ -20,9 +20,7 @@ macro_rules! gate_feature_fn {
let has_feature: bool = has_feature(visitor.features);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
if !has_feature && !span.allows_unstable($name) {
feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
.help(help)
.emit();
feature_err(&visitor.sess.parse_sess, name, span, explain).help(help).emit();
}
}};
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
@ -31,8 +29,19 @@ macro_rules! gate_feature_fn {
let has_feature: bool = has_feature(visitor.features);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
if !has_feature && !span.allows_unstable($name) {
feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
.emit();
feature_err(&visitor.sess.parse_sess, name, span, explain).emit();
}
}};
(future_incompatible; $visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
let (visitor, has_feature, span, name, explain) =
(&*$visitor, $has_feature, $span, $name, $explain);
let has_feature: bool = has_feature(visitor.features);
debug!(
"gate_feature(feature = {:?}, span = {:?}); has? {} (future_incompatible)",
name, span, has_feature
);
if !has_feature && !span.allows_unstable($name) {
feature_warn(&visitor.sess.parse_sess, name, span, explain);
}
}};
}
@ -44,6 +53,9 @@ macro_rules! gate_feature_post {
($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
};
(future_incompatible; $visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
gate_feature_fn!(future_incompatible; $visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
};
}
pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) {
@ -588,11 +600,10 @@ fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
{
// When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
// ascription error, but the likely intention was to write a `let` statement. (#78907).
feature_err_issue(
feature_err(
&self.sess.parse_sess,
sym::type_ascription,
lhs.span,
GateIssue::Language,
"type ascription is experimental",
).span_suggestion_verbose(
lhs.span.shrink_to_lo(),
@ -615,15 +626,22 @@ fn visit_expr(&mut self, e: &'a ast::Expr) {
);
}
ast::ExprKind::Type(..) => {
// To avoid noise about type ascription in common syntax errors, only emit if it
// is the *only* error.
if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
// To avoid noise about type ascription in common syntax errors,
// only emit if it is the *only* error.
gate_feature_post!(
&self,
type_ascription,
e.span,
"type ascription is experimental"
);
} else {
// And if it isn't, cancel the early-pass warning.
self.sess
.parse_sess
.span_diagnostic
.steal_diagnostic(e.span, StashKey::EarlySyntaxWarning)
.map(|err| err.cancel());
}
}
ast::ExprKind::TryBlock(_) => {
@ -789,14 +807,12 @@ macro_rules! gate_all {
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
// We emit an early future-incompatible warning for these.
// New syntax gates should go above here to get a hard error gate.
macro_rules! gate_all {
($gate:ident, $msg:literal) => {
// FIXME(eddyb) do something more useful than always
// disabling these uses of early feature-gatings.
if false {
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
gate_feature_post!(&visitor, $gate, *span, $msg);
}
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
gate_feature_post!(future_incompatible; &visitor, $gate, *span, $msg);
}
};
}
@ -809,11 +825,7 @@ macro_rules! gate_all {
gate_all!(try_blocks, "`try` blocks are unstable");
gate_all!(label_break_value, "labels on blocks are unstable");
gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
// To avoid noise about type ascription in common syntax errors,
// only emit if it is the *only* error. (Also check it last.)
if sess.parse_sess.span_diagnostic.err_count() == 0 {
gate_all!(type_ascription, "type ascription is experimental");
}
gate_all!(type_ascription, "type ascription is experimental");
visit::walk_crate(&mut visitor, krate);
}

View File

@ -458,6 +458,7 @@ struct HandlerInner {
pub enum StashKey {
ItemNoType,
UnderscoreForArrayLengths,
EarlySyntaxWarning,
}
fn default_track_diagnostic(_: &Diagnostic) {}

View File

@ -3212,6 +3212,56 @@
};
}
declare_lint! {
/// The `unstable_syntax_pre_expansion` lint detects the use of unstable
/// syntax that is discarded during attribute expansion.
///
/// ### Example
///
/// ```rust
/// #[cfg(FALSE)]
/// macro foo() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// The input to active attributes such as `#[cfg]` or procedural macro
/// attributes is required to be valid syntax. Previously, the compiler only
/// gated the use of unstable syntax features after resolving `#[cfg]` gates
/// and expanding procedural macros.
///
/// To avoid relying on unstable syntax, move the use of unstable syntax
/// into a position where the compiler does not parse the syntax, such as a
/// functionlike macro.
///
/// ```rust
/// # #![deny(unstable_syntax_pre_expansion)]
///
/// macro_rules! identity {
/// ( $($tokens:tt)* ) => { $($tokens)* }
/// }
///
/// #[cfg(FALSE)]
/// identity! {
/// macro foo() {}
/// }
/// ```
///
/// This is a [future-incompatible] lint to transition this
/// to a hard error in the future. See [issue #65860] for more details.
///
/// [issue #65860]: https://github.com/rust-lang/rust/issues/65860
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub UNSTABLE_SYNTAX_PRE_EXPANSION,
Warn,
"unstable syntax can change at any point in the future, causing a hard error!",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #65860 <https://github.com/rust-lang/rust/issues/65860>",
};
}
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
@ -3280,6 +3330,7 @@
POINTER_STRUCTURAL_MATCH,
NONTRIVIAL_STRUCTURAL_MATCH,
SOFT_UNSTABLE,
UNSTABLE_SYNTAX_PRE_EXPANSION,
INLINE_NO_SANITIZE,
BAD_ASM_STYLE,
ASM_SUB_REGISTER,

View File

@ -2,15 +2,17 @@
//! It also serves as an input to the parser itself.
use crate::config::CheckCfg;
use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId};
use crate::lint::{
builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId,
};
use crate::SessionDiagnostic;
use rustc_ast::node_id::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler};
use rustc_errors::{
error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder,
DiagnosticMessage, ErrorGuaranteed, MultiSpan,
error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
DiagnosticMessage, ErrorGuaranteed, MultiSpan, StashKey,
};
use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
use rustc_span::edition::Edition;
@ -101,11 +103,58 @@ pub fn feature_err_issue<'a>(
issue: GateIssue,
explain: &str,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let span = span.into();
// Cancel an earlier warning for this same error, if it exists.
if let Some(span) = span.primary_span() {
sess.span_diagnostic
.steal_diagnostic(span, StashKey::EarlySyntaxWarning)
.map(|err| err.cancel());
}
let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
err
}
/// Construct a future incompatibility diagnostic for a feature gate.
///
/// This diagnostic is only a warning and *does not cause compilation to fail*.
pub fn feature_warn<'a>(sess: &'a ParseSess, feature: Symbol, span: Span, explain: &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`.
pub fn feature_warn_issue<'a>(
sess: &'a ParseSess,
feature: Symbol,
span: Span,
issue: GateIssue,
explain: &str,
) {
let mut err = sess.span_diagnostic.struct_span_warn(span, explain);
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
// Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
let future_incompatible = lint.future_incompatible.as_ref().unwrap();
err.code(DiagnosticId::Lint {
name: lint.name_lower(),
has_future_breakage: false,
is_force_warn: false,
});
err.warn(lint.desc);
err.note(format!("for more information, see {}", future_incompatible.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.
pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);

View File

@ -3,11 +3,18 @@
// compile-flags: --test
#![feature(async_closure)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_trait_impl)]
#![feature(decl_macro)]
#![feature(generators)]
#![feature(half_open_range_patterns)]
#![feature(label_break_value)]
#![feature(more_qualified_paths)]
#![feature(raw_ref_op)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(type_ascription)]
#![deny(unused_macros)]
macro_rules! stringify_block {

View File

@ -7,7 +7,7 @@ fn main() {}
// Test the `pat` macro fragment parser:
macro_rules! accept_pat {
($p:pat) => {}
($p:pat) => {};
}
accept_pat!((p | q));
@ -21,28 +21,28 @@ macro_rules! accept_pat {
#[cfg(FALSE)]
fn or_patterns() {
// Top level of `let`:
let (| A | B);
let (A | B);
let (A | B);
let (A | B): u8;
let (A | B) = 0;
let (A | B): u8 = 0;
// Top level of `for`:
for | A | B in 0 {}
for A | B in 0 {}
for A | B in 0 {}
// Top level of `while`:
while let | A | B = 0 {}
while let A | B = 0 {}
while let A | B = 0 {}
// Top level of `if`:
if let | A | B = 0 {}
if let A | B = 0 {}
if let A | B = 0 {}
// Top level of `match` arms:
match 0 {
| A | B => {},
A | B => {},
A | B => {}
A | B => {}
}
// Functions:
@ -68,6 +68,8 @@ fn fun((A | B): _) {}
// These bind as `(prefix p) | q` as opposed to `prefix (p | q)`:
let (box 0 | 1); // Unstable; we *can* change the precedence if we want.
//~^ WARN box pattern syntax is experimental
//~| WARN unstable syntax
let (&0 | 1);
let (&mut 0 | 1);
let (x @ 0 | 1);

View File

@ -0,0 +1,13 @@
warning: box pattern syntax is experimental
--> $DIR/or-patterns-syntactic-pass.rs:70:10
|
LL | let (box 0 | 1); // Unstable; we *can* change the precedence if we want.
| ^^^^^
|
= note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
= help: add `#![feature(box_patterns)]` to the crate attributes to enable
= warning: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: 1 warning emitted

View File

@ -3,7 +3,11 @@
#[cfg(FALSE)]
fn syntax() {
foo::<T = u8, T: Ord, String>();
//~^ WARN associated type bounds are unstable
//~| WARN unstable syntax
foo::<T = u8, 'a, T: Ord>();
//~^ WARN associated type bounds are unstable
//~| WARN unstable syntax
}
fn main() {}

View File

@ -0,0 +1,24 @@
warning: associated type bounds are unstable
--> $DIR/constraints-before-generic-args-syntactic-pass.rs:5:19
|
LL | foo::<T = u8, T: Ord, String>();
| ^^^^^^
|
= note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
= help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
= warning: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: associated type bounds are unstable
--> $DIR/constraints-before-generic-args-syntactic-pass.rs:8:23
|
LL | foo::<T = u8, 'a, T: Ord>();
| ^^^^^^
|
= note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
= help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
= warning: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: 2 warnings emitted

View File

@ -19,6 +19,8 @@ fn foo(..: u8) {}
// Box patterns:
let box ..;
//~^ WARN box pattern syntax is experimental
//~| WARN unstable syntax
// In or-patterns:
match x {
@ -57,7 +59,7 @@ fn foo(..: u8) {}
.. |
[
(
box ..,
box .., //~ WARN box pattern syntax is experimental
&(..),
&mut ..,
x @ ..
@ -67,4 +69,5 @@ fn foo(..: u8) {}
ref mut x @ ..
=> {}
}
//~| WARN unstable syntax
}

View File

@ -0,0 +1,24 @@
warning: box pattern syntax is experimental
--> $DIR/rest-pat-syntactic.rs:21:9
|
LL | let box ..;
| ^^^^^^
|
= note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
= help: add `#![feature(box_patterns)]` to the crate attributes to enable
= warning: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: box pattern syntax is experimental
--> $DIR/rest-pat-syntactic.rs:62:17
|
LL | box ..,
| ^^^^^^
|
= note: see issue #29641 <https://github.com/rust-lang/rust/issues/29641> for more information
= help: add `#![feature(box_patterns)]` to the crate attributes to enable
= warning: unstable syntax can change at any point in the future, causing a hard error!
= note: for more information, see issue #65860 <https://github.com/rust-lang/rust/issues/65860>
warning: 2 warnings emitted