diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 97eee56f94807..68fca08101891 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -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); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6555b93ac0b1b..18e84b70b1b10 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -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> { - 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 { + let has_errors = self.has_errors(); let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::>(); 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 { + 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 { diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f00165cd3b370..95e34da734d6a 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -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 ", + }; +} + 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, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index f31d52147b47b..9f0886cb2089c 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -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); diff --git a/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs new file mode 100644 index 0000000000000..49f1cba7151ef --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.rs @@ -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() {} diff --git a/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr new file mode 100644 index 0000000000000..49550d811ba52 --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-with-errors.stderr @@ -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 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 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`. diff --git a/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs new file mode 100644 index 0000000000000..ca4ad2320f657 --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.rs @@ -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() {} diff --git a/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr new file mode 100644 index 0000000000000..3d9c22e548710 --- /dev/null +++ b/src/test/ui/feature-gates/soft-syntax-gates-without-errors.stderr @@ -0,0 +1,24 @@ +warning: `macro` is experimental + --> $DIR/soft-syntax-gates-without-errors.rs:6:1 + | +LL | macro b() {} + | ^^^^^^^^^^^^ + | + = note: see issue #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 + +warning: `macro` is experimental + --> $DIR/soft-syntax-gates-without-errors.rs:21:5 + | +LL | macro e() {} + | ^^^^^^^^^^^^ + | + = note: see issue #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 + +warning: 2 warnings emitted + diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index 8e71ed7c1120f..082c1abb8f2f4 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -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 { diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs index 6f9a631b092a7..dda5c0bb59d23 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.rs @@ -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); diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr new file mode 100644 index 0000000000000..c43fe192a73b8 --- /dev/null +++ b/src/test/ui/or-patterns/or-patterns-syntactic-pass.stderr @@ -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 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 + +warning: 1 warning emitted + diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs index afbd13e6fd9a8..d8346653c25aa 100644 --- a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs +++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.rs @@ -3,7 +3,11 @@ #[cfg(FALSE)] fn syntax() { foo::(); + //~^ WARN associated type bounds are unstable + //~| WARN unstable syntax foo::(); + //~^ WARN associated type bounds are unstable + //~| WARN unstable syntax } fn main() {} diff --git a/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr new file mode 100644 index 0000000000000..7e843c7f4d006 --- /dev/null +++ b/src/test/ui/parser/constraints-before-generic-args-syntactic-pass.stderr @@ -0,0 +1,24 @@ +warning: associated type bounds are unstable + --> $DIR/constraints-before-generic-args-syntactic-pass.rs:5:19 + | +LL | foo::(); + | ^^^^^^ + | + = note: see issue #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 + +warning: associated type bounds are unstable + --> $DIR/constraints-before-generic-args-syntactic-pass.rs:8:23 + | +LL | foo::(); + | ^^^^^^ + | + = note: see issue #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 + +warning: 2 warnings emitted + diff --git a/src/test/ui/pattern/rest-pat-syntactic.rs b/src/test/ui/pattern/rest-pat-syntactic.rs index 9656a0b5de9ce..4da5a2db76743 100644 --- a/src/test/ui/pattern/rest-pat-syntactic.rs +++ b/src/test/ui/pattern/rest-pat-syntactic.rs @@ -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 } diff --git a/src/test/ui/pattern/rest-pat-syntactic.stderr b/src/test/ui/pattern/rest-pat-syntactic.stderr new file mode 100644 index 0000000000000..37019b7d5ba7a --- /dev/null +++ b/src/test/ui/pattern/rest-pat-syntactic.stderr @@ -0,0 +1,24 @@ +warning: box pattern syntax is experimental + --> $DIR/rest-pat-syntactic.rs:21:9 + | +LL | let box ..; + | ^^^^^^ + | + = note: see issue #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 + +warning: box pattern syntax is experimental + --> $DIR/rest-pat-syntactic.rs:62:17 + | +LL | box .., + | ^^^^^^ + | + = note: see issue #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 + +warning: 2 warnings emitted + diff --git a/src/test/ui/suggestions/many-type-ascription.rs b/src/test/ui/suggestions/many-type-ascription.rs new file mode 100644 index 0000000000000..31ac556b9447c --- /dev/null +++ b/src/test/ui/suggestions/many-type-ascription.rs @@ -0,0 +1,4 @@ +fn main() { + let _ = 0: i32; //~ ERROR: type ascription is experimental + let _ = 0: i32; // (error only emitted once) +} diff --git a/src/test/ui/suggestions/many-type-ascription.stderr b/src/test/ui/suggestions/many-type-ascription.stderr new file mode 100644 index 0000000000000..3706bbae9df9f --- /dev/null +++ b/src/test/ui/suggestions/many-type-ascription.stderr @@ -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 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`. diff --git a/src/test/ui/suggestions/type-ascription-and-other-error.rs b/src/test/ui/suggestions/type-ascription-and-other-error.rs new file mode 100644 index 0000000000000..99ab2f3c858b9 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-and-other-error.rs @@ -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) +} diff --git a/src/test/ui/suggestions/type-ascription-and-other-error.stderr b/src/test/ui/suggestions/type-ascription-and-other-error.stderr new file mode 100644 index 0000000000000..eadf634bb14fd --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-and-other-error.stderr @@ -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 +