Make missing_fragment_specifier an error in edition 2024

`missing_fragment_specifier` has been a future compatibility warning
since 2017. Uplifting it to an unconditional hard error was attempted in
2020, but eventually reverted due to fallout.

Make it an error only in edition >= 2024, leaving the lint for older
editions. This change will make it easier to support more macro syntax
that relies on usage of `$`.

Fixes <https://github.com/rust-lang/rust/issues/40107>
This commit is contained in:
Trevor Gross 2024-07-20 07:18:09 -05:00
parent a526d7ce45
commit 8c402f125c
7 changed files with 114 additions and 25 deletions

View file

@ -105,6 +105,11 @@ expand_meta_var_dif_seq_matchers = {$msg}
expand_meta_var_expr_unrecognized_var = expand_meta_var_expr_unrecognized_var =
variable `{$key}` is not recognized in meta-variable expression variable `{$key}` is not recognized in meta-variable expression
expand_missing_fragment_specifier = missing fragment specifier
.note = fragment specifiers must be specified in the 2024 edition
.suggestion_add_fragspec = try adding a specifier here
.valid = {$valid}
expand_module_circular = expand_module_circular =
circular modules: {$modules} circular modules: {$modules}

View file

@ -416,6 +416,23 @@ pub struct DuplicateMatcherBinding {
pub prev: Span, pub prev: Span,
} }
#[derive(Diagnostic)]
#[diag(expand_missing_fragment_specifier)]
#[note]
#[help(expand_valid)]
pub struct MissingFragmentSpecifier {
#[primary_span]
pub span: Span,
#[suggestion(
expand_suggestion_add_fragspec,
style = "verbose",
code = ":spec",
applicability = "maybe-incorrect"
)]
pub add_span: Span,
pub valid: &'static str,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(expand_invalid_fragment_specifier)] #[diag(expand_invalid_fragment_specifier)]
#[help] #[help]

View file

@ -115,6 +115,7 @@ use rustc_errors::MultiSpan;
use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::BuiltinLintDiag;
use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_span::edition::Edition;
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
use rustc_span::{symbol::MacroRulesNormalizedIdent, ErrorGuaranteed, Span}; use rustc_span::{symbol::MacroRulesNormalizedIdent, ErrorGuaranteed, Span};
@ -122,6 +123,8 @@ use smallvec::SmallVec;
use std::iter; use std::iter;
use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021;
/// Stack represented as linked list. /// Stack represented as linked list.
/// ///
/// Those are used for environments because they grow incrementally and are not mutable. /// Those are used for environments because they grow incrementally and are not mutable.
@ -269,12 +272,20 @@ fn check_binders(
// FIXME: Report this as a hard error eventually and remove equivalent errors from // FIXME: Report this as a hard error eventually and remove equivalent errors from
// `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once // `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once
// as a hard error and then once as a buffered lint. // as a hard error and then once as a buffered lint.
psess.buffer_lint( if span.edition() >= Edition::Edition2024 {
MISSING_FRAGMENT_SPECIFIER, psess.dcx().emit_err(errors::MissingFragmentSpecifier {
span, span,
node_id, add_span: span.shrink_to_hi(),
BuiltinLintDiag::MissingFragmentSpecifier, valid: VALID_FRAGMENT_NAMES_MSG_2021,
); });
} else {
psess.buffer_lint(
MISSING_FRAGMENT_SPECIFIER,
span,
node_id,
BuiltinLintDiag::MissingFragmentSpecifier,
);
}
} }
if !macros.is_empty() { if !macros.is_empty() {
psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");

View file

@ -16,7 +16,7 @@ use rustc_span::Span;
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \ `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
`literal`, `path`, `meta`, `tt`, `item` and `vis`"; `literal`, `path`, `meta`, `tt`, `item` and `vis`";
const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \ pub const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \
`ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \ `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \
`ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \ `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
`item` and `vis`"; `item` and `vis`";

View file

@ -1,11 +1,11 @@
error: missing fragment specifier error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:4:20 --> $DIR/macro-missing-fragment.rs:9:20
| |
LL | ( $( any_token $field_rust_type )* ) => {}; LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
warning: missing fragment specifier warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:4:20 --> $DIR/macro-missing-fragment.rs:9:20
| |
LL | ( $( any_token $field_rust_type )* ) => {}; LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -13,13 +13,13 @@ LL | ( $( any_token $field_rust_type )* ) => {};
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:1:9 --> $DIR/macro-missing-fragment.rs:6:9
| |
LL | #![warn(missing_fragment_specifier)] LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: missing fragment specifier warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:12:7 --> $DIR/macro-missing-fragment.rs:19:7
| |
LL | ( $name ) => {}; LL | ( $name ) => {};
| ^^^^^ | ^^^^^
@ -28,7 +28,7 @@ LL | ( $name ) => {};
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107> = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
warning: missing fragment specifier warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:18:7 --> $DIR/macro-missing-fragment.rs:26:7
| |
LL | ( $name ) => {}; LL | ( $name ) => {};
| ^^^^^ | ^^^^^
@ -40,7 +40,7 @@ error: aborting due to 1 previous error; 3 warnings emitted
Future incompatibility report: Future breakage diagnostic: Future incompatibility report: Future breakage diagnostic:
warning: missing fragment specifier warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:4:20 --> $DIR/macro-missing-fragment.rs:9:20
| |
LL | ( $( any_token $field_rust_type )* ) => {}; LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^
@ -48,14 +48,14 @@ LL | ( $( any_token $field_rust_type )* ) => {};
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:1:9 --> $DIR/macro-missing-fragment.rs:6:9
| |
LL | #![warn(missing_fragment_specifier)] LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
Future breakage diagnostic: Future breakage diagnostic:
warning: missing fragment specifier warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:12:7 --> $DIR/macro-missing-fragment.rs:19:7
| |
LL | ( $name ) => {}; LL | ( $name ) => {};
| ^^^^^ | ^^^^^
@ -63,14 +63,14 @@ LL | ( $name ) => {};
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:1:9 --> $DIR/macro-missing-fragment.rs:6:9
| |
LL | #![warn(missing_fragment_specifier)] LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
Future breakage diagnostic: Future breakage diagnostic:
warning: missing fragment specifier warning: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:18:7 --> $DIR/macro-missing-fragment.rs:26:7
| |
LL | ( $name ) => {}; LL | ( $name ) => {};
| ^^^^^ | ^^^^^
@ -78,7 +78,7 @@ LL | ( $name ) => {};
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> = note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
note: the lint level is defined here note: the lint level is defined here
--> $DIR/macro-missing-fragment.rs:1:9 --> $DIR/macro-missing-fragment.rs:6:9
| |
LL | #![warn(missing_fragment_specifier)] LL | #![warn(missing_fragment_specifier)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -0,0 +1,47 @@
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:9:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^
|
= note: fragment specifiers must be specified in the 2024 edition
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
help: try adding a specifier here
|
LL | ( $( any_token $field_rust_type:spec )* ) => {};
| +++++
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:19:7
|
LL | ( $name ) => {};
| ^^^^^
|
= note: fragment specifiers must be specified in the 2024 edition
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
help: try adding a specifier here
|
LL | ( $name:spec ) => {};
| +++++
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:26:7
|
LL | ( $name ) => {};
| ^^^^^
|
= note: fragment specifiers must be specified in the 2024 edition
= help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
help: try adding a specifier here
|
LL | ( $name:spec ) => {};
| +++++
error: missing fragment specifier
--> $DIR/macro-missing-fragment.rs:9:20
|
LL | ( $( any_token $field_rust_type )* ) => {};
| ^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View file

@ -1,23 +1,32 @@
//@ revisions: e2015 e2024
//@[e2015] edition:2015
//@[e2024] edition:2024
//@[e2024] compile-flags: -Zunstable-options
#![warn(missing_fragment_specifier)] #![warn(missing_fragment_specifier)]
macro_rules! used_arm { macro_rules! used_arm {
( $( any_token $field_rust_type )* ) => {}; ( $( any_token $field_rust_type )* ) => {};
//~^ ERROR missing fragment //[e2015]~^ ERROR missing fragment
//~| WARN missing fragment //[e2015]~| WARN missing fragment
//~| WARN this was previously accepted //[e2015]~| WARN this was previously accepted
//[e2024]~^^^^ ERROR missing fragment
//[e2024]~| ERROR missing fragment
} }
macro_rules! used_macro_unused_arm { macro_rules! used_macro_unused_arm {
() => {}; () => {};
( $name ) => {}; ( $name ) => {};
//~^ WARN missing fragment //[e2015]~^ WARN missing fragment
//~| WARN this was previously accepted //[e2015]~| WARN this was previously accepted
//[e2024]~^^^ ERROR missing fragment
} }
macro_rules! unused_macro { macro_rules! unused_macro {
( $name ) => {}; ( $name ) => {};
//~^ WARN missing fragment //[e2015]~^ WARN missing fragment
//~| WARN this was previously accepted //[e2015]~| WARN this was previously accepted
//[e2024]~^^^ ERROR missing fragment
} }
fn main() { fn main() {