mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Rollup merge of #99935 - CAD97:unstable-syntax-lints, r=petrochenkov
Reenable disabled early syntax gates as future-incompatibility lints - MCP: https://github.com/rust-lang/compiler-team/issues/535 The approach taken by this PR is - Introduce a new lint, `unstable_syntax_pre_expansion`, and reenable the early syntax gates to emit it - Use the diagnostic stashing mechanism to stash warnings the early warnings - When the hard error occurs post expansion, steal and cancel the early warning - Don't display any stashed warnings if errors are present to avoid the same noise problem that hiding type ascription errors is avoiding Commits are working commits, but in a coherent steps-to-implement manner. Can be squashed if desired. The preexisting `soft_unstable` lint seems like it would've been a good fit, but it is deny-by-default (appropriate for `#[bench]`) and these gates should be introduced as warn-by-default. It may be desirable to change the stash mechanism's behavior to not flush lint errors in the presence of other errors either (like is done for warnings here), but upgrading a stash-using lint from warn to error perhaps is enough of a request to see the lint that they shouldn't be hidden; additionally, fixing the last error to get new errors thrown at you always feels bad, so if we know the lint errors are present, we should show them. Using a new flag/mechanism for a "weak diagnostic" which is suppressed by other errors may also be desirable over assuming any stashed warnings are "weak," but this is the first user of stashing warnings and seems an appropriate use of stashing (it follows the "know more later to refine the diagnostic" pattern; here we learn that it's in a compiled position) so we get to define what it means to stash a non-hard-error diagnostic. cc `````@petrochenkov````` (seconded MCP)
This commit is contained in:
commit
8828af4d88
@ -2,10 +2,10 @@ use rustc_ast as ast;
|
||||
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 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
{
|
||||
// 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 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
);
|
||||
}
|
||||
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 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
|
||||
// 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 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
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);
|
||||
}
|
||||
|
@ -459,6 +459,7 @@ struct HandlerInner {
|
||||
pub enum StashKey {
|
||||
ItemNoType,
|
||||
UnderscoreForArrayLengths,
|
||||
EarlySyntaxWarning,
|
||||
}
|
||||
|
||||
fn default_track_diagnostic(_: &Diagnostic) {}
|
||||
@ -626,19 +627,13 @@ impl Handler {
|
||||
/// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
|
||||
pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
|
||||
// if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
|
||||
// See the PR for a discussion.
|
||||
inner.stashed_diagnostics.insert((span, key), diag);
|
||||
inner.stash((span, key), diag);
|
||||
}
|
||||
|
||||
/// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
|
||||
pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_, ()>> {
|
||||
self.inner
|
||||
.borrow_mut()
|
||||
.stashed_diagnostics
|
||||
.remove(&(span, key))
|
||||
.map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
|
||||
let mut inner = self.inner.borrow_mut();
|
||||
inner.steal((span, key)).map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
|
||||
}
|
||||
|
||||
/// Emit all stashed diagnostics.
|
||||
@ -1106,13 +1101,31 @@ impl HandlerInner {
|
||||
|
||||
/// Emit all stashed diagnostics.
|
||||
fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
|
||||
let has_errors = self.has_errors();
|
||||
let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
|
||||
let mut reported = None;
|
||||
for mut diag in diags {
|
||||
// Decrement the count tracking the stash; emitting will increment it.
|
||||
if diag.is_error() {
|
||||
reported = Some(ErrorGuaranteed(()));
|
||||
if matches!(diag.level, Level::Error { lint: true }) {
|
||||
self.lint_err_count -= 1;
|
||||
} else {
|
||||
self.err_count -= 1;
|
||||
}
|
||||
} else {
|
||||
if diag.is_force_warn() {
|
||||
self.warn_count -= 1;
|
||||
} else {
|
||||
// Unless they're forced, don't flush stashed warnings when
|
||||
// there are errors, to avoid causing warning overload. The
|
||||
// stash would've been stolen already if it were important.
|
||||
if has_errors {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.emit_diagnostic(&mut diag);
|
||||
let reported_this = self.emit_diagnostic(&mut diag);
|
||||
reported = reported.or(reported_this);
|
||||
}
|
||||
reported
|
||||
}
|
||||
@ -1302,9 +1315,47 @@ impl HandlerInner {
|
||||
}
|
||||
}
|
||||
|
||||
fn stash(&mut self, key: (Span, StashKey), diagnostic: Diagnostic) {
|
||||
// Track the diagnostic for counts, but don't panic-if-treat-err-as-bug
|
||||
// yet; that happens when we actually emit the diagnostic.
|
||||
if diagnostic.is_error() {
|
||||
if matches!(diagnostic.level, Level::Error { lint: true }) {
|
||||
self.lint_err_count += 1;
|
||||
} else {
|
||||
self.err_count += 1;
|
||||
}
|
||||
} else {
|
||||
// Warnings are only automatically flushed if they're forced.
|
||||
if diagnostic.is_force_warn() {
|
||||
self.warn_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
|
||||
// if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
|
||||
// See the PR for a discussion.
|
||||
self.stashed_diagnostics.insert(key, diagnostic);
|
||||
}
|
||||
|
||||
fn steal(&mut self, key: (Span, StashKey)) -> Option<Diagnostic> {
|
||||
let diagnostic = self.stashed_diagnostics.remove(&key)?;
|
||||
if diagnostic.is_error() {
|
||||
if matches!(diagnostic.level, Level::Error { lint: true }) {
|
||||
self.lint_err_count -= 1;
|
||||
} else {
|
||||
self.err_count -= 1;
|
||||
}
|
||||
} else {
|
||||
if diagnostic.is_force_warn() {
|
||||
self.warn_count -= 1;
|
||||
}
|
||||
}
|
||||
Some(diagnostic)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn err_count(&self) -> usize {
|
||||
self.err_count + self.stashed_diagnostics.len()
|
||||
self.err_count
|
||||
}
|
||||
|
||||
fn has_errors(&self) -> bool {
|
||||
|
@ -3212,6 +3212,56 @@ declare_lint! {
|
||||
};
|
||||
}
|
||||
|
||||
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 @@ declare_lint_pass! {
|
||||
POINTER_STRUCTURAL_MATCH,
|
||||
NONTRIVIAL_STRUCTURAL_MATCH,
|
||||
SOFT_UNSTABLE,
|
||||
UNSTABLE_SYNTAX_PRE_EXPANSION,
|
||||
INLINE_NO_SANITIZE,
|
||||
BAD_ASM_STYLE,
|
||||
ASM_SUB_REGISTER,
|
||||
|
@ -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);
|
||||
|
30
src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs
Normal file
30
src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// check-fail
|
||||
// This file is used to test the behavior of the early-pass syntax warnings.
|
||||
// If macro syntax is stabilized, replace with a different unstable syntax.
|
||||
|
||||
macro a() {}
|
||||
//~^ ERROR: `macro` is experimental
|
||||
|
||||
#[cfg(FALSE)]
|
||||
macro b() {}
|
||||
|
||||
macro_rules! identity {
|
||||
($($x:tt)*) => ($($x)*);
|
||||
}
|
||||
|
||||
identity! {
|
||||
macro c() {}
|
||||
//~^ ERROR: `macro` is experimental
|
||||
}
|
||||
|
||||
#[cfg(FALSE)]
|
||||
identity! {
|
||||
macro d() {} // No error
|
||||
}
|
||||
|
||||
identity! {
|
||||
#[cfg(FALSE)]
|
||||
macro e() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,21 @@
|
||||
error[E0658]: `macro` is experimental
|
||||
--> $DIR/soft-syntax-gates-with-errors.rs:5:1
|
||||
|
|
||||
LL | macro a() {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
|
||||
= help: add `#![feature(decl_macro)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `macro` is experimental
|
||||
--> $DIR/soft-syntax-gates-with-errors.rs:16:5
|
||||
|
|
||||
LL | macro c() {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
|
||||
= help: add `#![feature(decl_macro)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,26 @@
|
||||
// check-pass
|
||||
// This file is used to test the behavior of the early-pass syntax warnings.
|
||||
// If macro syntax is stabilized, replace with a different unstable syntax.
|
||||
|
||||
#[cfg(FALSE)]
|
||||
macro b() {}
|
||||
//~^ WARN: `macro` is experimental
|
||||
//~| WARN: unstable syntax
|
||||
|
||||
macro_rules! identity {
|
||||
($($x:tt)*) => ($($x)*);
|
||||
}
|
||||
|
||||
#[cfg(FALSE)]
|
||||
identity! {
|
||||
macro d() {} // No error
|
||||
}
|
||||
|
||||
identity! {
|
||||
#[cfg(FALSE)]
|
||||
macro e() {}
|
||||
//~^ WARN: `macro` is experimental
|
||||
//~| WARN: unstable syntax
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,24 @@
|
||||
warning: `macro` is experimental
|
||||
--> $DIR/soft-syntax-gates-without-errors.rs:6:1
|
||||
|
|
||||
LL | macro b() {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
|
||||
= help: add `#![feature(decl_macro)]` 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: `macro` is experimental
|
||||
--> $DIR/soft-syntax-gates-without-errors.rs:21:5
|
||||
|
|
||||
LL | macro e() {}
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #39412 <https://github.com/rust-lang/rust/issues/39412> for more information
|
||||
= help: add `#![feature(decl_macro)]` 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
|
||||
|
@ -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 {
|
||||
|
@ -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 @@ accept_pat!([p | q]);
|
||||
#[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 or_patterns() {
|
||||
|
||||
// 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);
|
||||
|
13
src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr
Normal file
13
src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr
Normal 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
|
||||
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
@ -19,6 +19,8 @@ fn rest_patterns() {
|
||||
|
||||
// Box patterns:
|
||||
let box ..;
|
||||
//~^ WARN box pattern syntax is experimental
|
||||
//~| WARN unstable syntax
|
||||
|
||||
// In or-patterns:
|
||||
match x {
|
||||
@ -57,7 +59,7 @@ fn rest_patterns() {
|
||||
.. |
|
||||
[
|
||||
(
|
||||
box ..,
|
||||
box .., //~ WARN box pattern syntax is experimental
|
||||
&(..),
|
||||
&mut ..,
|
||||
x @ ..
|
||||
@ -67,4 +69,5 @@ fn rest_patterns() {
|
||||
ref mut x @ ..
|
||||
=> {}
|
||||
}
|
||||
//~| WARN unstable syntax
|
||||
}
|
||||
|
24
src/test/ui/pattern/rest-pat-syntactic.stderr
Normal file
24
src/test/ui/pattern/rest-pat-syntactic.stderr
Normal 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
|
||||
|
4
src/test/ui/suggestions/many-type-ascription.rs
Normal file
4
src/test/ui/suggestions/many-type-ascription.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
let _ = 0: i32; //~ ERROR: type ascription is experimental
|
||||
let _ = 0: i32; // (error only emitted once)
|
||||
}
|
12
src/test/ui/suggestions/many-type-ascription.stderr
Normal file
12
src/test/ui/suggestions/many-type-ascription.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0658]: type ascription is experimental
|
||||
--> $DIR/many-type-ascription.rs:2:13
|
||||
|
|
||||
LL | let _ = 0: i32;
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
|
||||
= help: add `#![feature(type_ascription)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,6 @@
|
||||
fn main() {
|
||||
not rust; //~ ERROR
|
||||
let _ = 0: i32; // (error hidden by existing error)
|
||||
#[cfg(FALSE)]
|
||||
let _ = 0: i32; // (warning hidden by existing error)
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `rust`
|
||||
--> $DIR/type-ascription-and-other-error.rs:2:9
|
||||
|
|
||||
LL | not rust;
|
||||
| ^^^^ expected one of 8 possible tokens
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user