From d3858f7465a711852e162b42e7cb2a2a53cf1e83 Mon Sep 17 00:00:00 2001 From: Folkert Date: Thu, 25 Jul 2024 10:05:31 +0200 Subject: [PATCH 1/6] improve error message when `global_asm!` uses `asm!` options --- compiler/rustc_ast/src/ast.rs | 5 ++ compiler/rustc_builtin_macros/messages.ftl | 4 ++ compiler/rustc_builtin_macros/src/asm.rs | 61 +++++++++++++------- compiler/rustc_builtin_macros/src/errors.rs | 11 ++++ compiler/rustc_parse/src/parser/mod.rs | 7 ++- compiler/rustc_passes/src/naked_functions.rs | 5 +- tests/ui/asm/parse-error.rs | 10 +++- tests/ui/asm/parse-error.stderr | 58 ++++++++++++------- tests/ui/asm/x86_64/bad-options.rs | 12 ++-- tests/ui/asm/x86_64/bad-options.stderr | 24 ++++---- 10 files changed, 128 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 411fc8311a08f..1c917651e2778 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2265,6 +2265,11 @@ bitflags::bitflags! { } impl InlineAsmOptions { + pub const COUNT: usize = Self::all().bits().count_ones() as usize; + + pub const GLOBAL_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW); + pub const NAKED_OPTIONS: Self = Self::ATT_SYNTAX.union(Self::RAW).union(Self::NORETURN); + pub fn human_readable_names(&self) -> Vec<&'static str> { let mut options = vec![]; diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index b56bfa98357b3..876f3c2b13518 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -199,6 +199,10 @@ builtin_macros_format_use_positional = consider using a positional formatting ar builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!` +builtin_macros_global_asm_unsupported_option = the `{$symbol}` option cannot be used with `global_asm!` + .label = the `{$symbol}` option is not meaningful for global-scoped inline assembly + .suggestion = remove this option + builtin_macros_invalid_crate_attribute = invalid crate attribute builtin_macros_multiple_default_attrs = multiple `#[default]` attributes diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index dd0f9aaf22104..96fc40ed1eb6a 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -310,6 +310,16 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span }); } +/// Report an invalid option error. +/// +/// This function must be called immediately after the option token is parsed. +/// Otherwise, the suggestion will be incorrect. +fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) { + // Tool-only output + let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span }; + p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span }); +} + /// Try to set the provided option in the provided `AsmArgs`. /// If it is already set, report a duplicate option error. /// @@ -318,13 +328,16 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) { fn try_set_option<'a>( p: &Parser<'a>, args: &mut AsmArgs, + is_global_asm: bool, symbol: Symbol, option: ast::InlineAsmOptions, ) { - if !args.options.contains(option) { - args.options |= option; - } else { + if is_global_asm && !ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { + err_unsupported_option(p, symbol, p.prev_token.span); + } else if args.options.contains(option) { err_duplicate_option(p, symbol, p.prev_token.span); + } else { + args.options |= option; } } @@ -338,25 +351,29 @@ fn parse_options<'a>( p.expect(&token::OpenDelim(Delimiter::Parenthesis))?; while !p.eat(&token::CloseDelim(Delimiter::Parenthesis)) { - if !is_global_asm && p.eat_keyword(sym::pure) { - try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE); - } else if !is_global_asm && p.eat_keyword(sym::nomem) { - try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM); - } else if !is_global_asm && p.eat_keyword(sym::readonly) { - try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY); - } else if !is_global_asm && p.eat_keyword(sym::preserves_flags) { - try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS); - } else if !is_global_asm && p.eat_keyword(sym::noreturn) { - try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN); - } else if !is_global_asm && p.eat_keyword(sym::nostack) { - try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK); - } else if !is_global_asm && p.eat_keyword(sym::may_unwind) { - try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND); - } else if p.eat_keyword(sym::att_syntax) { - try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX); - } else if p.eat_keyword(kw::Raw) { - try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW); - } else { + const OPTIONS: [(Symbol, ast::InlineAsmOptions); ast::InlineAsmOptions::COUNT] = [ + (sym::pure, ast::InlineAsmOptions::PURE), + (sym::nomem, ast::InlineAsmOptions::NOMEM), + (sym::readonly, ast::InlineAsmOptions::READONLY), + (sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS), + (sym::noreturn, ast::InlineAsmOptions::NORETURN), + (sym::nostack, ast::InlineAsmOptions::NOSTACK), + (sym::may_unwind, ast::InlineAsmOptions::MAY_UNWIND), + (sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX), + (kw::Raw, ast::InlineAsmOptions::RAW), + ]; + + 'blk: { + for (symbol, option) in OPTIONS { + let expect = + !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option); + + if if expect { p.eat_keyword(symbol) } else { p.eat_keyword_noexpect(symbol) } { + try_set_option(p, args, is_global_asm, symbol, option); + break 'blk; + } + } + return p.unexpected(); } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 49d640436c2f3..2e6bdae14a8bb 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -845,6 +845,17 @@ pub(crate) struct AsmOptAlreadyprovided { pub(crate) full_span: Span, } +#[derive(Diagnostic)] +#[diag(builtin_macros_global_asm_unsupported_option)] +pub(crate) struct GlobalAsmUnsupportedOption { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) symbol: Symbol, + #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] + pub(crate) full_span: Span, +} + #[derive(Diagnostic)] #[diag(builtin_macros_test_runner_invalid)] pub(crate) struct TestRunnerInvalid { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7326b9ec51f2b..e7240869a394a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -599,7 +599,7 @@ impl<'a> Parser<'a> { /// If the next token is the given keyword, eats it and returns `true`. /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. - // Public for rustfmt usage. + // Public for rustc_builtin_macros and rustfmt usage. #[inline] pub fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { @@ -631,8 +631,11 @@ impl<'a> Parser<'a> { false } + /// If the next token is the given keyword, eats it and returns `true`. + /// Otherwise, returns `false`. No expectation is added. + // Public for rustc_builtin_macros usage. #[inline] - fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { + pub fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { if self.token.is_keyword(kw) { self.bump(); true diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index dbbf802c920d4..4c5089b86762c 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -244,10 +244,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> { self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands }); } - let supported_options = - InlineAsmOptions::RAW | InlineAsmOptions::NORETURN | InlineAsmOptions::ATT_SYNTAX; - let unsupported_options = asm.options.difference(supported_options); - + let unsupported_options = asm.options.difference(InlineAsmOptions::NAKED_OPTIONS); if !unsupported_options.is_empty() { self.tcx.dcx().emit_err(NakedFunctionsAsmOptions { span, diff --git a/tests/ui/asm/parse-error.rs b/tests/ui/asm/parse-error.rs index a0251c6763ba4..9dec3a1c394ef 100644 --- a/tests/ui/asm/parse-error.rs +++ b/tests/ui/asm/parse-error.rs @@ -111,11 +111,15 @@ global_asm!("{}", const); global_asm!("{}", const(reg) FOO); //~^ ERROR expected one of global_asm!("", options(FOO)); -//~^ ERROR expected one of +//~^ ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO` +global_asm!("", options(FOO,)); +//~^ ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO` global_asm!("", options(nomem FOO)); -//~^ ERROR expected one of +//~^ ERROR the `nomem` option cannot be used with `global_asm!` +//~| ERROR expected one of `)` or `,`, found `FOO` global_asm!("", options(nomem, FOO)); -//~^ ERROR expected one of +//~^ ERROR the `nomem` option cannot be used with `global_asm!` +//~| ERROR expected one of `)`, `att_syntax`, or `raw`, found `FOO` global_asm!("{}", options(), const FOO); global_asm!("", clobber_abi(FOO)); //~^ ERROR expected string literal diff --git a/tests/ui/asm/parse-error.stderr b/tests/ui/asm/parse-error.stderr index 1999cd09aa3b5..e9ecd712bc367 100644 --- a/tests/ui/asm/parse-error.stderr +++ b/tests/ui/asm/parse-error.stderr @@ -264,62 +264,80 @@ error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` LL | global_asm!("", options(FOO)); | ^^^ expected one of `)`, `att_syntax`, or `raw` -error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` +error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` --> $DIR/parse-error.rs:115:25 | -LL | global_asm!("", options(nomem FOO)); - | ^^^^^ expected one of `)`, `att_syntax`, or `raw` +LL | global_asm!("", options(FOO,)); + | ^^^ expected one of `)`, `att_syntax`, or `raw` -error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` +error: the `nomem` option cannot be used with `global_asm!` --> $DIR/parse-error.rs:117:25 | +LL | global_asm!("", options(nomem FOO)); + | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly + +error: expected one of `)` or `,`, found `FOO` + --> $DIR/parse-error.rs:117:31 + | +LL | global_asm!("", options(nomem FOO)); + | ^^^ expected one of `)` or `,` + +error: the `nomem` option cannot be used with `global_asm!` + --> $DIR/parse-error.rs:120:25 + | +LL | global_asm!("", options(nomem, FOO)); + | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly + +error: expected one of `)`, `att_syntax`, or `raw`, found `FOO` + --> $DIR/parse-error.rs:120:32 + | LL | global_asm!("", options(nomem, FOO)); - | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + | ^^^ expected one of `)`, `att_syntax`, or `raw` error: expected string literal - --> $DIR/parse-error.rs:120:29 + --> $DIR/parse-error.rs:124:29 | LL | global_asm!("", clobber_abi(FOO)); | ^^^ not a string literal error: expected one of `)` or `,`, found `FOO` - --> $DIR/parse-error.rs:122:33 + --> $DIR/parse-error.rs:126:33 | LL | global_asm!("", clobber_abi("C" FOO)); | ^^^ expected one of `)` or `,` error: expected string literal - --> $DIR/parse-error.rs:124:34 + --> $DIR/parse-error.rs:128:34 | LL | global_asm!("", clobber_abi("C", FOO)); | ^^^ not a string literal error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:126:19 + --> $DIR/parse-error.rs:130:19 | LL | global_asm!("{}", clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:128:28 + --> $DIR/parse-error.rs:132:28 | LL | global_asm!("", options(), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:130:30 + --> $DIR/parse-error.rs:134:30 | LL | global_asm!("{}", options(), clobber_abi("C"), const FOO); | ^^^^^^^^^^^^^^^^ error: `clobber_abi` cannot be used with `global_asm!` - --> $DIR/parse-error.rs:132:17 + --> $DIR/parse-error.rs:136:17 | LL | global_asm!("", clobber_abi("C"), clobber_abi("C")); | ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ error: duplicate argument named `a` - --> $DIR/parse-error.rs:134:35 + --> $DIR/parse-error.rs:138:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -327,7 +345,7 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); | previously here error: argument never used - --> $DIR/parse-error.rs:134:35 + --> $DIR/parse-error.rs:138:35 | LL | global_asm!("{a}", a = const FOO, a = const BAR); | ^^^^^^^^^^^^^ argument never used @@ -335,19 +353,19 @@ LL | global_asm!("{a}", a = const FOO, a = const BAR); = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `""` - --> $DIR/parse-error.rs:137:28 + --> $DIR/parse-error.rs:141:28 | LL | global_asm!("", options(), ""); | ^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: expected one of `clobber_abi`, `const`, `options`, or `sym`, found `"{}"` - --> $DIR/parse-error.rs:139:30 + --> $DIR/parse-error.rs:143:30 | LL | global_asm!("{}", const FOO, "{}", const FOO); | ^^^^ expected one of `clobber_abi`, `const`, `options`, or `sym` error: asm template must be a string literal - --> $DIR/parse-error.rs:141:13 + --> $DIR/parse-error.rs:145:13 | LL | global_asm!(format!("{{{}}}", 0), const FOO); | ^^^^^^^^^^^^^^^^^^^^ @@ -355,7 +373,7 @@ LL | global_asm!(format!("{{{}}}", 0), const FOO); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: asm template must be a string literal - --> $DIR/parse-error.rs:143:20 + --> $DIR/parse-error.rs:147:20 | LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); | ^^^^^^^^^^^^^^^^^^^^ @@ -363,7 +381,7 @@ LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR); = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) error: expected operand, options, or additional template string - --> $DIR/parse-error.rs:145:19 + --> $DIR/parse-error.rs:149:19 | LL | global_asm!("{}", label {}); | ^^^^^^^^ expected operand, options, or additional template string @@ -423,6 +441,6 @@ help: consider using `const` instead of `let` LL | const bar: /* Type */ = 0; | ~~~~~ ++++++++++++ -error: aborting due to 64 previous errors +error: aborting due to 67 previous errors For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/asm/x86_64/bad-options.rs b/tests/ui/asm/x86_64/bad-options.rs index f9cc13cfc5a8b..6424a1b1d421b 100644 --- a/tests/ui/asm/x86_64/bad-options.rs +++ b/tests/ui/asm/x86_64/bad-options.rs @@ -33,14 +33,14 @@ fn main() { } global_asm!("", options(nomem)); -//~^ ERROR expected one of +//~^ ERROR the `nomem` option cannot be used with `global_asm!` global_asm!("", options(readonly)); -//~^ ERROR expected one of +//~^ ERROR the `readonly` option cannot be used with `global_asm!` global_asm!("", options(noreturn)); -//~^ ERROR expected one of +//~^ ERROR the `noreturn` option cannot be used with `global_asm!` global_asm!("", options(pure)); -//~^ ERROR expected one of +//~^ ERROR the `pure` option cannot be used with `global_asm!` global_asm!("", options(nostack)); -//~^ ERROR expected one of +//~^ ERROR the `nostack` option cannot be used with `global_asm!` global_asm!("", options(preserves_flags)); -//~^ ERROR expected one of +//~^ ERROR the `preserves_flags` option cannot be used with `global_asm!` diff --git a/tests/ui/asm/x86_64/bad-options.stderr b/tests/ui/asm/x86_64/bad-options.stderr index aa167e7913c3e..366eb7cb90f39 100644 --- a/tests/ui/asm/x86_64/bad-options.stderr +++ b/tests/ui/asm/x86_64/bad-options.stderr @@ -51,41 +51,41 @@ LL | asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C")); | | clobber_abi | generic outputs -error: expected one of `)`, `att_syntax`, or `raw`, found `nomem` +error: the `nomem` option cannot be used with `global_asm!` --> $DIR/bad-options.rs:35:25 | LL | global_asm!("", options(nomem)); - | ^^^^^ expected one of `)`, `att_syntax`, or `raw` + | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly -error: expected one of `)`, `att_syntax`, or `raw`, found `readonly` +error: the `readonly` option cannot be used with `global_asm!` --> $DIR/bad-options.rs:37:25 | LL | global_asm!("", options(readonly)); - | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly -error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn` +error: the `noreturn` option cannot be used with `global_asm!` --> $DIR/bad-options.rs:39:25 | LL | global_asm!("", options(noreturn)); - | ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly -error: expected one of `)`, `att_syntax`, or `raw`, found `pure` +error: the `pure` option cannot be used with `global_asm!` --> $DIR/bad-options.rs:41:25 | LL | global_asm!("", options(pure)); - | ^^^^ expected one of `)`, `att_syntax`, or `raw` + | ^^^^ the `pure` option is not meaningful for global-scoped inline assembly -error: expected one of `)`, `att_syntax`, or `raw`, found `nostack` +error: the `nostack` option cannot be used with `global_asm!` --> $DIR/bad-options.rs:43:25 | LL | global_asm!("", options(nostack)); - | ^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + | ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly -error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags` +error: the `preserves_flags` option cannot be used with `global_asm!` --> $DIR/bad-options.rs:45:25 | LL | global_asm!("", options(preserves_flags)); - | ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw` + | ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly error: invalid ABI for `clobber_abi` --> $DIR/bad-options.rs:24:18 From 73fde1701762e82227cd9fe588b06ee15719d252 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 26 Jul 2024 00:08:22 +0200 Subject: [PATCH 2/6] refactor the `if if` --- compiler/rustc_builtin_macros/src/asm.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 96fc40ed1eb6a..218529b9ed75d 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -365,10 +365,14 @@ fn parse_options<'a>( 'blk: { for (symbol, option) in OPTIONS { - let expect = - !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option); + let kw_matched = + if !is_global_asm || ast::InlineAsmOptions::GLOBAL_OPTIONS.contains(option) { + p.eat_keyword(symbol) + } else { + p.eat_keyword_noexpect(symbol) + }; - if if expect { p.eat_keyword(symbol) } else { p.eat_keyword_noexpect(symbol) } { + if kw_matched { try_set_option(p, args, is_global_asm, symbol, option); break 'blk; } From 8859da0bf2f1f3d447ce1939647e88a0302afb99 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 26 Jul 2024 00:20:59 +0200 Subject: [PATCH 3/6] add `run-rustfix` test for machine-applicable suggestion --- tests/ui/asm/unsupported-option.fixed | 10 ++++++++++ tests/ui/asm/unsupported-option.rs | 10 ++++++++++ tests/ui/asm/unsupported-option.stderr | 20 ++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 tests/ui/asm/unsupported-option.fixed create mode 100644 tests/ui/asm/unsupported-option.rs create mode 100644 tests/ui/asm/unsupported-option.stderr diff --git a/tests/ui/asm/unsupported-option.fixed b/tests/ui/asm/unsupported-option.fixed new file mode 100644 index 0000000000000..c2ff13bbc5516 --- /dev/null +++ b/tests/ui/asm/unsupported-option.fixed @@ -0,0 +1,10 @@ +//@ run-rustfix + +use std::arch::global_asm; + +fn main() {} + +global_asm!("", options(att_syntax, raw)); +//~^ ERROR the `nomem` option cannot be used with `global_asm!` +//~| ERROR the `readonly` option cannot be used with `global_asm!` +//~| ERROR the `noreturn` option cannot be used with `global_asm!` diff --git a/tests/ui/asm/unsupported-option.rs b/tests/ui/asm/unsupported-option.rs new file mode 100644 index 0000000000000..672aedf230ca7 --- /dev/null +++ b/tests/ui/asm/unsupported-option.rs @@ -0,0 +1,10 @@ +//@ run-rustfix + +use std::arch::global_asm; + +fn main() {} + +global_asm!("", options(att_syntax, nomem, readonly, noreturn, raw)); +//~^ ERROR the `nomem` option cannot be used with `global_asm!` +//~| ERROR the `readonly` option cannot be used with `global_asm!` +//~| ERROR the `noreturn` option cannot be used with `global_asm!` diff --git a/tests/ui/asm/unsupported-option.stderr b/tests/ui/asm/unsupported-option.stderr new file mode 100644 index 0000000000000..c040b0364d7b7 --- /dev/null +++ b/tests/ui/asm/unsupported-option.stderr @@ -0,0 +1,20 @@ +error: the `nomem` option cannot be used with `global_asm!` + --> $DIR/unsupported-option.rs:7:37 + | +LL | global_asm!("", options(att_syntax, nomem, readonly, noreturn, raw)); + | ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly + +error: the `readonly` option cannot be used with `global_asm!` + --> $DIR/unsupported-option.rs:7:44 + | +LL | global_asm!("", options(att_syntax, nomem, readonly, noreturn, raw)); + | ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly + +error: the `noreturn` option cannot be used with `global_asm!` + --> $DIR/unsupported-option.rs:7:54 + | +LL | global_asm!("", options(att_syntax, nomem, readonly, noreturn, raw)); + | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly + +error: aborting due to 3 previous errors + From 1140750f6eff7ad09ea675cf48d66418a62bcdd5 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 27 Jul 2024 11:05:03 +0300 Subject: [PATCH 4/6] update `rust.channel` documentation Signed-off-by: onur-ozkan --- config.example.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config.example.toml b/config.example.toml index 8800c85db3258..45faa66ec114f 100644 --- a/config.example.toml +++ b/config.example.toml @@ -578,7 +578,10 @@ # The "channel" for the Rust build to produce. The stable/beta channels only # allow using stable features, whereas the nightly and dev channels allow using # nightly features -#channel = "dev" +# +# If using tarball sources, default value for `channel` is taken from the `src/ci/channel` file; +# otherwise, it's "dev". +#channel = if "is a tarball source" { content of `src/ci/channel` file } else { "dev" } # A descriptive string to be appended to `rustc --version` output, which is # also used in places like debuginfo `DW_AT_producer`. This may be useful for From 139a713dc0451589ef6bfb04451ab638065d7ca4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 27 Jul 2024 11:05:36 +0300 Subject: [PATCH 5/6] add change entry for `rust.channel` defaults Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 879cc079c6b2b..b8f70fdf6a805 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -215,4 +215,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Removed android-ndk r25b support in favor of android-ndk r26d.", }, + ChangeInfo { + change_id: 125181, + severity: ChangeSeverity::Warning, + summary: "For tarball sources, default value for `rust.channel` will be taken from `src/ci/channel` file.", + }, ]; From 8c402f125ccb3d8ccbabef40694482d481fc28b8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Sat, 20 Jul 2024 07:18:09 -0500 Subject: [PATCH 6/6] 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 --- compiler/rustc_expand/messages.ftl | 5 ++ compiler/rustc_expand/src/errors.rs | 17 +++++++ compiler/rustc_expand/src/mbe/macro_check.rs | 23 ++++++--- compiler/rustc_expand/src/mbe/quoted.rs | 2 +- ...rr => macro-missing-fragment.e2015.stderr} | 22 ++++----- .../macro-missing-fragment.e2024.stderr | 47 +++++++++++++++++++ tests/ui/macros/macro-missing-fragment.rs | 23 ++++++--- 7 files changed, 114 insertions(+), 25 deletions(-) rename tests/ui/macros/{macro-missing-fragment.stderr => macro-missing-fragment.e2015.stderr} (86%) create mode 100644 tests/ui/macros/macro-missing-fragment.e2024.stderr diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index cc0b110d2bc6f..18d95a398fd4f 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -105,6 +105,11 @@ expand_meta_var_dif_seq_matchers = {$msg} expand_meta_var_expr_unrecognized_var = 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 = circular modules: {$modules} diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 0be7403f25b17..6f1a0f16c49ff 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -416,6 +416,23 @@ pub struct DuplicateMatcherBinding { 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)] #[diag(expand_invalid_fragment_specifier)] #[help] diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 4b730d307fd6c..161e27fe02c61 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -115,6 +115,7 @@ use rustc_errors::MultiSpan; use rustc_lint_defs::BuiltinLintDiag; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; use rustc_span::symbol::kw; use rustc_span::{symbol::MacroRulesNormalizedIdent, ErrorGuaranteed, Span}; @@ -122,6 +123,8 @@ use smallvec::SmallVec; use std::iter; +use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021; + /// Stack represented as linked list. /// /// 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 // `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. - psess.buffer_lint( - MISSING_FRAGMENT_SPECIFIER, - span, - node_id, - BuiltinLintDiag::MissingFragmentSpecifier, - ); + if span.edition() >= Edition::Edition2024 { + psess.dcx().emit_err(errors::MissingFragmentSpecifier { + span, + add_span: span.shrink_to_hi(), + valid: VALID_FRAGMENT_NAMES_MSG_2021, + }); + } else { + psess.buffer_lint( + MISSING_FRAGMENT_SPECIFIER, + span, + node_id, + BuiltinLintDiag::MissingFragmentSpecifier, + ); + } } if !macros.is_empty() { psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 9c480f17b4215..57b6947316d65 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -16,7 +16,7 @@ use rustc_span::Span; const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \ `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`, \ `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \ `item` and `vis`"; diff --git a/tests/ui/macros/macro-missing-fragment.stderr b/tests/ui/macros/macro-missing-fragment.e2015.stderr similarity index 86% rename from tests/ui/macros/macro-missing-fragment.stderr rename to tests/ui/macros/macro-missing-fragment.e2015.stderr index abe4d4cd68a2b..a068dc5c054f0 100644 --- a/tests/ui/macros/macro-missing-fragment.stderr +++ b/tests/ui/macros/macro-missing-fragment.e2015.stderr @@ -1,11 +1,11 @@ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:4:20 + --> $DIR/macro-missing-fragment.rs:9:20 | LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:4:20 + --> $DIR/macro-missing-fragment.rs:9:20 | 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! = note: for more information, see issue #40107 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)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:12:7 + --> $DIR/macro-missing-fragment.rs:19:7 | LL | ( $name ) => {}; | ^^^^^ @@ -28,7 +28,7 @@ LL | ( $name ) => {}; = note: for more information, see issue #40107 warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 + --> $DIR/macro-missing-fragment.rs:26:7 | LL | ( $name ) => {}; | ^^^^^ @@ -40,7 +40,7 @@ error: aborting due to 1 previous error; 3 warnings emitted Future incompatibility report: Future breakage diagnostic: warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:4:20 + --> $DIR/macro-missing-fragment.rs:9:20 | 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! = note: for more information, see issue #40107 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)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Future breakage diagnostic: warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:12:7 + --> $DIR/macro-missing-fragment.rs:19:7 | 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! = note: for more information, see issue #40107 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)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Future breakage diagnostic: warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 + --> $DIR/macro-missing-fragment.rs:26:7 | 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! = note: for more information, see issue #40107 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)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.e2024.stderr new file mode 100644 index 0000000000000..3afa069c170e4 --- /dev/null +++ b/tests/ui/macros/macro-missing-fragment.e2024.stderr @@ -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 + diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs index 210c85ebbf2f3..b7da87ae610f2 100644 --- a/tests/ui/macros/macro-missing-fragment.rs +++ b/tests/ui/macros/macro-missing-fragment.rs @@ -1,23 +1,32 @@ +//@ revisions: e2015 e2024 +//@[e2015] edition:2015 +//@[e2024] edition:2024 +//@[e2024] compile-flags: -Zunstable-options + #![warn(missing_fragment_specifier)] macro_rules! used_arm { ( $( any_token $field_rust_type )* ) => {}; - //~^ ERROR missing fragment - //~| WARN missing fragment - //~| WARN this was previously accepted + //[e2015]~^ ERROR missing fragment + //[e2015]~| WARN missing fragment + //[e2015]~| WARN this was previously accepted + //[e2024]~^^^^ ERROR missing fragment + //[e2024]~| ERROR missing fragment } macro_rules! used_macro_unused_arm { () => {}; ( $name ) => {}; - //~^ WARN missing fragment - //~| WARN this was previously accepted + //[e2015]~^ WARN missing fragment + //[e2015]~| WARN this was previously accepted + //[e2024]~^^^ ERROR missing fragment } macro_rules! unused_macro { ( $name ) => {}; - //~^ WARN missing fragment - //~| WARN this was previously accepted + //[e2015]~^ WARN missing fragment + //[e2015]~| WARN this was previously accepted + //[e2024]~^^^ ERROR missing fragment } fn main() {