From ceec6ddf9e2d4a41828fce4587180029588ae8eb Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 22:06:34 +0200 Subject: [PATCH 01/11] update text for E0736 and E0739 --- .../src/error_codes/E0736.md | 20 ++++++++++++++----- .../src/error_codes/E0739.md | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md index 0f3d41ba66dc4..08aa85e705d99 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0736.md +++ b/compiler/rustc_error_codes/src/error_codes/E0736.md @@ -1,14 +1,24 @@ -`#[track_caller]` and `#[naked]` cannot both be applied to the same function. +Functions marked with the `#[naked]` attribute are restricted in what other +code generation attributes they may be marked with. + +The following code generation attributes are incompatible with `#[naked]`: + + * `#[inline]` + * `#[track_caller]` + * `#[target_feature]` Erroneous code example: ```compile_fail,E0736 +#[inline] #[naked] -#[track_caller] fn foo() {} ``` -This is primarily due to ABI incompatibilities between the two attributes. -See [RFC 2091] for details on this and other limitations. +These incompatibilities are due to the fact that naked functions deliberately +impose strict restrictions regarding the code that the compiler is +allowed to produce for this function. + +See [the reference page for codegen attributes] for more information. -[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md +[the reference page for codegen attributes]: https://doc.rust-lang.org/reference/attributes/codegen.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0739.md b/compiler/rustc_error_codes/src/error_codes/E0739.md index 8d9039bef93f6..406d3d52779db 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0739.md +++ b/compiler/rustc_error_codes/src/error_codes/E0739.md @@ -1,4 +1,4 @@ -`#[track_caller]` can not be applied on struct. +`#[track_caller]` must be applied to a function Erroneous code example: From 4bd36324b6a19afdbcb53de1d41e65b0060a6dbb Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 23:03:13 +0200 Subject: [PATCH 02/11] improve error message when `#[naked]` is used with `#[inline]` --- compiler/rustc_passes/messages.ftl | 11 +++-- compiler/rustc_passes/src/check_attr.rs | 33 +++++++++++---- compiler/rustc_passes/src/errors.rs | 24 +++++------ compiler/rustc_passes/src/naked_functions.rs | 14 +------ tests/ui/asm/naked-functions-inline.rs | 31 ++++++++++++++ tests/ui/asm/naked-functions-inline.stderr | 27 ++++++++++++ tests/ui/asm/naked-functions.rs | 31 -------------- tests/ui/asm/naked-functions.stderr | 44 ++------------------ 8 files changed, 104 insertions(+), 111 deletions(-) create mode 100644 tests/ui/asm/naked-functions-inline.rs create mode 100644 tests/ui/asm/naked-functions-inline.stderr diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1d93cbaddd6fe..2b6841181a7ff 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -69,9 +69,6 @@ passes_break_non_loop = .suggestion = use `break` on its own without a value inside this `{$kind}` loop .break_expr_suggestion = alternatively, you might have meant to use the available loop label -passes_cannot_inline_naked_function = - naked functions cannot be inlined - passes_cannot_stabilize_deprecated = an API can't be stabilized after it is deprecated .label = invalid version @@ -485,6 +482,11 @@ passes_naked_functions_asm_block = passes_naked_functions_asm_options = asm options unsupported in naked functions: {$unsupported_options} +passes_naked_functions_codegen_attribute = + cannot use additional code generation attributes with `#[naked]` + .label = this attribute is incompatible with `#[naked]` + .label2 = function marked with `#[naked]` here + passes_naked_functions_must_use_noreturn = asm in naked functions must use `noreturn` option .suggestion = consider specifying that the asm block is responsible for returning from the function @@ -492,9 +494,6 @@ passes_naked_functions_must_use_noreturn = passes_naked_functions_operands = only `const` and `sym` operands are supported in naked functions -passes_naked_tracked_caller = - cannot use `#[track_caller]` with `#[naked]` - passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ce2fa83810fe8..739847d73d31c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -155,7 +155,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::rustc_std_internal_symbol] => { self.check_rustc_std_internal_symbol(attr, span, target) } - [sym::naked] => self.check_naked(hir_id, attr, span, target), + [sym::naked] => self.check_naked(hir_id, attr, span, target, attrs), [sym::rustc_never_returns_null_ptr] => { self.check_applied_to_fn_or_method(hir_id, attr, span, target) } @@ -410,12 +410,33 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool { + fn check_naked( + &self, + hir_id: HirId, + attr: &Attribute, + span: Span, + target: Target, + attrs: &[Attribute], + ) -> bool { + const FORBIDDEN: [rustc_span::Symbol; 3] = + [sym::track_caller, sym::inline, sym::target_feature]; + + for other_attr in attrs { + if FORBIDDEN.into_iter().any(|name| other_attr.has_name(name)) { + self.dcx().emit_err(errors::NakedFunctionCodegenAttribute { + span: other_attr.span, + naked_span: attr.span, + }); + + return false; + } + } + match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, // FIXME(#80564): We permit struct fields, match arms and macro defs to have an - // `#[allow_internal_unstable]` attribute with just a lint, because we previously + // `#[naked]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { @@ -488,7 +509,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. + /// Checks if a `#[track_caller]` is applied to a function. Returns `true` if valid. fn check_track_caller( &self, hir_id: HirId, @@ -498,10 +519,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: Target, ) -> bool { match target { - _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => { - self.dcx().emit_err(errors::NakedTrackedCaller { attr_span }); - false - } Target::Fn => { // `#[track_caller]` is not valid on weak lang items because they are called via // `extern` declarations and `#[track_caller]` would alter their ABI. diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 58d27d5b4bbaa..03105795bfcd9 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -79,13 +79,6 @@ pub struct AttrShouldBeAppliedToFn { pub on_crate: bool, } -#[derive(Diagnostic)] -#[diag(passes_naked_tracked_caller, code = E0736)] -pub struct NakedTrackedCaller { - #[primary_span] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[diag(passes_should_be_applied_to_fn, code = E0739)] pub struct TrackedCallerWrongLocation { @@ -1124,13 +1117,6 @@ pub struct UnlabeledCfInWhileCondition<'a> { pub cf_type: &'a str, } -#[derive(Diagnostic)] -#[diag(passes_cannot_inline_naked_function)] -pub struct CannotInlineNakedFunction { - #[primary_span] - pub span: Span, -} - #[derive(LintDiagnostic)] #[diag(passes_undefined_naked_function_abi)] pub struct UndefinedNakedFunctionAbi; @@ -1196,6 +1182,16 @@ pub struct NakedFunctionsMustUseNoreturn { pub last_span: Span, } +#[derive(Diagnostic)] +#[diag(passes_naked_functions_codegen_attribute, code = E0736)] +pub struct NakedFunctionCodegenAttribute { + #[primary_span] + #[label] + pub span: Span, + #[label(passes_label2)] + pub naked_span: Span, +} + #[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub struct AttrOnlyInFunctions { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index d45ee32a624de..4040fbd182ede 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -14,9 +14,8 @@ use rustc_span::Span; use rustc_target::spec::abi::Abi; use crate::errors::{ - CannotInlineNakedFunction, NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, - NakedFunctionsMustUseNoreturn, NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, - UndefinedNakedFunctionAbi, + NakedFunctionsAsmBlock, NakedFunctionsAsmOptions, NakedFunctionsMustUseNoreturn, + NakedFunctionsOperands, NoPatterns, ParamsNotAllowed, UndefinedNakedFunctionAbi, }; pub(crate) fn provide(providers: &mut Providers) { @@ -53,15 +52,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { check_no_patterns(tcx, body.params); check_no_parameters_use(tcx, body); check_asm(tcx, def_id, body); - check_inline(tcx, def_id); - } -} - -/// Check that the function isn't inlined. -fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let attrs = tcx.get_attrs(def_id, sym::inline); - for attr in attrs { - tcx.dcx().emit_err(CannotInlineNakedFunction { span: attr.span }); } } diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs new file mode 100644 index 0000000000000..9a4f754751842 --- /dev/null +++ b/tests/ui/asm/naked-functions-inline.rs @@ -0,0 +1,31 @@ +//@ needs-asm-support +#![feature(naked_functions)] +#![crate_type = "lib"] + +use std::arch::asm; + +#[naked] +pub unsafe extern "C" fn inline_none() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline] +//~^ ERROR [E0736] +pub unsafe extern "C" fn inline_hint() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(always)] +//~^ ERROR [E0736] +pub unsafe extern "C" fn inline_always() { + asm!("", options(noreturn)); +} + +#[naked] +#[inline(never)] +//~^ ERROR [E0736] +pub unsafe extern "C" fn inline_never() { + asm!("", options(noreturn)); +} diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr new file mode 100644 index 0000000000000..2496e942b17c8 --- /dev/null +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -0,0 +1,27 @@ +error[E0736]: cannot use additional code generation attributes with `#[naked]` + --> $DIR/naked-functions-inline.rs:13:1 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[inline] + | ^^^^^^^^^ this attribute is incompatible with `#[naked]` + +error[E0736]: cannot use additional code generation attributes with `#[naked]` + --> $DIR/naked-functions-inline.rs:20:1 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + +error[E0736]: cannot use additional code generation attributes with `#[naked]` + --> $DIR/naked-functions-inline.rs:27:1 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0736`. diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 1619ebfcf39f0..e6633ddd4f3e9 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -168,37 +168,6 @@ pub unsafe extern "C" fn inline_none() { } #[naked] -#[inline] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_hint() { - asm!("", options(noreturn)); -} - -#[naked] -#[inline(always)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_always() { - asm!("", options(noreturn)); -} - -#[naked] -#[inline(never)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_never() { - asm!("", options(noreturn)); -} - -#[naked] -#[inline] -//~^ ERROR naked functions cannot be inlined -#[inline(always)] -//~^ ERROR naked functions cannot be inlined -#[inline(never)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_all() { - asm!("", options(noreturn)); -} - #[naked] pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { compile_error!("this is a user specified error") diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 77bc80a101f02..736de85765e39 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -5,19 +5,19 @@ LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:204:5 + --> $DIR/naked-functions.rs:173:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:210:5 + --> $DIR/naked-functions.rs:179:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:217:10 + --> $DIR/naked-functions.rs:186:10 | LL | asm!(invalid_syntax) | ^^^^^^^^^^^^^^ @@ -249,42 +249,6 @@ warning: Rust ABI is unsupported in naked functions LL | pub unsafe fn rust_abi() { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:171:1 - | -LL | #[inline] - | ^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:178:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:185:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:192:1 - | -LL | #[inline] - | ^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:194:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - -error: naked functions cannot be inlined - --> $DIR/naked-functions.rs:196:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 33 previous errors; 2 warnings emitted +error: aborting due to 27 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0787`. From 7e6c083873b7b98aa52d47896107af11560aeaf5 Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 16 Jul 2024 23:35:02 +0200 Subject: [PATCH 03/11] improve error message when `#[naked]` is used with `#[track-caller] and `#[target-feature]`` --- compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/check_attr.rs | 26 ++++++++++--------- compiler/rustc_passes/src/errors.rs | 2 +- .../ui/asm/naked-functions-target-feature.rs | 13 ++++++++++ .../asm/naked-functions-target-feature.stderr | 12 +++++++++ .../rfc-2091-track-caller/error-with-naked.rs | 4 +-- .../error-with-naked.stderr | 14 +++++++--- 7 files changed, 53 insertions(+), 20 deletions(-) create mode 100644 tests/ui/asm/naked-functions-target-feature.rs create mode 100644 tests/ui/asm/naked-functions-target-feature.stderr diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 2b6841181a7ff..8dec24feebaeb 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -485,7 +485,7 @@ passes_naked_functions_asm_options = passes_naked_functions_codegen_attribute = cannot use additional code generation attributes with `#[naked]` .label = this attribute is incompatible with `#[naked]` - .label2 = function marked with `#[naked]` here + .naked_attribute = function marked with `#[naked]` here passes_naked_functions_must_use_noreturn = asm in naked functions must use `noreturn` option diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 739847d73d31c..311c11a03886e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -421,20 +421,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { const FORBIDDEN: [rustc_span::Symbol; 3] = [sym::track_caller, sym::inline, sym::target_feature]; - for other_attr in attrs { - if FORBIDDEN.into_iter().any(|name| other_attr.has_name(name)) { - self.dcx().emit_err(errors::NakedFunctionCodegenAttribute { - span: other_attr.span, - naked_span: attr.span, - }); - - return false; - } - } - match target { Target::Fn - | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { + for other_attr in attrs { + if FORBIDDEN.into_iter().any(|name| other_attr.has_name(name)) { + self.dcx().emit_err(errors::NakedFunctionCodegenAttribute { + span: other_attr.span, + naked_span: attr.span, + }); + + return false; + } + } + + true + } // FIXME(#80564): We permit struct fields, match arms and macro defs to have an // `#[naked]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 03105795bfcd9..b6be096b43b12 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1188,7 +1188,7 @@ pub struct NakedFunctionCodegenAttribute { #[primary_span] #[label] pub span: Span, - #[label(passes_label2)] + #[label(passes_naked_attribute)] pub naked_span: Span, } diff --git a/tests/ui/asm/naked-functions-target-feature.rs b/tests/ui/asm/naked-functions-target-feature.rs new file mode 100644 index 0000000000000..264e7e0976b1d --- /dev/null +++ b/tests/ui/asm/naked-functions-target-feature.rs @@ -0,0 +1,13 @@ +//@ only-x86_64 +//@ needs-asm-support +#![feature(naked_functions)] +#![crate_type = "lib"] + +use std::arch::asm; + +#[target_feature(enable = "sse2")] +//~^ ERROR [E0736] +#[naked] +pub unsafe extern "C" fn naked_target_feature() { + asm!("", options(noreturn)); +} diff --git a/tests/ui/asm/naked-functions-target-feature.stderr b/tests/ui/asm/naked-functions-target-feature.stderr new file mode 100644 index 0000000000000..1a8b59f61fe0a --- /dev/null +++ b/tests/ui/asm/naked-functions-target-feature.stderr @@ -0,0 +1,12 @@ +error[E0736]: cannot use additional code generation attributes with `#[naked]` + --> $DIR/naked-functions-target-feature.rs:8:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` +LL | +LL | #[naked] + | -------- function marked with `#[naked]` here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0736`. diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs index 6eaa7d4d9bc9f..0c73b9abf351d 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs @@ -3,7 +3,7 @@ use std::arch::asm; -#[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` +#[track_caller] //~ ERROR [E0736] //~^ ERROR `#[track_caller]` requires Rust ABI #[naked] extern "C" fn f() { @@ -15,7 +15,7 @@ extern "C" fn f() { struct S; impl S { - #[track_caller] //~ ERROR cannot use `#[track_caller]` with `#[naked]` + #[track_caller] //~ ERROR [E0736] //~^ ERROR `#[track_caller]` requires Rust ABI #[naked] extern "C" fn g() { diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr index 04c5c649d7fd8..7ab9f8b39ebda 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr @@ -1,14 +1,20 @@ -error[E0736]: cannot use `#[track_caller]` with `#[naked]` +error[E0736]: cannot use additional code generation attributes with `#[naked]` --> $DIR/error-with-naked.rs:6:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` +LL | +LL | #[naked] + | -------- function marked with `#[naked]` here -error[E0736]: cannot use `#[track_caller]` with `#[naked]` +error[E0736]: cannot use additional code generation attributes with `#[naked]` --> $DIR/error-with-naked.rs:18:5 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` +LL | +LL | #[naked] + | -------- function marked with `#[naked]` here error[E0737]: `#[track_caller]` requires Rust ABI --> $DIR/error-with-naked.rs:6:1 From 4d082b77af1f714df6c407785e1961a9dddd554c Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Jul 2024 00:03:33 +0200 Subject: [PATCH 04/11] add error message when `#[naked]` is used with `#[test]` --- compiler/rustc_builtin_macros/messages.ftl | 5 +++ compiler/rustc_builtin_macros/src/errors.rs | 10 +++++ compiler/rustc_builtin_macros/src/test.rs | 8 ++++ .../src/error_codes/E0798.md | 14 +++++++ compiler/rustc_error_codes/src/lib.rs | 1 + tests/ui/asm/naked-functions-testattrs.rs | 39 +++++++++++++++++++ tests/ui/asm/naked-functions-testattrs.stderr | 35 +++++++++++++++++ 7 files changed, 112 insertions(+) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0798.md create mode 100644 tests/ui/asm/naked-functions-testattrs.rs create mode 100644 tests/ui/asm/naked-functions-testattrs.stderr diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index b56bfa98357b3..21c0f0802f7c8 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -216,6 +216,11 @@ builtin_macros_multiple_defaults = multiple declared defaults .note = only one variant can be default .suggestion = make `{$ident}` default +builtin_macros_naked_functions_testing_attribute = + cannot use `#[naked]` with testing attributes + .label = function marked with testing attribute here + .naked_attribute = `#[naked]` is incompatible with testing attributes + builtin_macros_no_default_variant = no default declared .help = make a unit variant default by placing `#[default]` above it .suggestion = make `{$ident}` default diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 49d640436c2f3..24706a3b05445 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -912,3 +912,13 @@ pub(crate) struct ExpectedItem<'a> { pub span: Span, pub token: &'a str, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_naked_functions_testing_attribute, code = E0798)] +pub struct NakedFunctionTestingAttribute { + #[primary_span] + #[label(builtin_macros_naked_attribute)] + pub naked_span: Span, + #[label] + pub testing_span: Span, +} diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index c0310a2f4b003..bb00c8de1b808 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -133,6 +133,14 @@ pub(crate) fn expand_test_or_bench( }; }; + if let Some(attr) = attr::find_by_name(&item.attrs, sym::naked) { + cx.dcx().emit_err(errors::NakedFunctionTestingAttribute { + testing_span: attr_sp, + naked_span: attr.span, + }); + return vec![Annotatable::Item(item)]; + } + // check_*_signature will report any errors in the type so compilation // will fail. We shouldn't try to expand in this case because the errors // would be spurious. diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md new file mode 100644 index 0000000000000..96f25eb4f0e2c --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0798.md @@ -0,0 +1,14 @@ +Testing attributes cannot be applied to functions marked with `#[naked]`. + +Erroneous code example: + +```ignore (requires test runner) +#[test] +#[should_panic] +#[naked] +fn foo() {} +``` + +See [the reference page for testing attributes] for more information. + +[the reference page for testing attributes]: https://doc.rust-lang.org/reference/attributes/testing.html diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index d13d5e1bca219..2a7bc2501c081 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -536,6 +536,7 @@ E0794: 0794, E0795: 0795, E0796: 0796, E0797: 0797, +E0798: 0798, ); ) } diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs new file mode 100644 index 0000000000000..593cf3ad4595c --- /dev/null +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -0,0 +1,39 @@ +//@ needs-asm-support +//@ compile-flags: --test + +#![allow(undefined_naked_function_abi)] +#![feature(naked_functions)] +#![feature(test)] +#![crate_type = "lib"] + +use std::arch::asm; + +#[test] +#[naked] +//~^ ERROR [E0798] +fn test_naked() { + unsafe { asm!("", options(noreturn)) }; +} + +#[should_panic] +#[test] +#[naked] +//~^ ERROR [E0798] +fn test_naked_should_panic() { + unsafe { asm!("", options(noreturn)) }; +} + +#[ignore] +#[test] +#[naked] +//~^ ERROR [E0798] +fn test_naked_ignore() { + unsafe { asm!("", options(noreturn)) }; +} + +#[bench] +#[naked] +//~^ ERROR [E0798] +fn bench_naked() { + unsafe { asm!("", options(noreturn)) }; +} diff --git a/tests/ui/asm/naked-functions-testattrs.stderr b/tests/ui/asm/naked-functions-testattrs.stderr new file mode 100644 index 0000000000000..87647b0ca37df --- /dev/null +++ b/tests/ui/asm/naked-functions-testattrs.stderr @@ -0,0 +1,35 @@ +error[E0798]: cannot use `#[naked]` with testing attributes + --> $DIR/naked-functions-testattrs.rs:12:1 + | +LL | #[test] + | ------- function marked with testing attribute here +LL | #[naked] + | ^^^^^^^^ `#[naked]` is incompatible with testing attributes + +error[E0798]: cannot use `#[naked]` with testing attributes + --> $DIR/naked-functions-testattrs.rs:20:1 + | +LL | #[test] + | ------- function marked with testing attribute here +LL | #[naked] + | ^^^^^^^^ `#[naked]` is incompatible with testing attributes + +error[E0798]: cannot use `#[naked]` with testing attributes + --> $DIR/naked-functions-testattrs.rs:28:1 + | +LL | #[test] + | ------- function marked with testing attribute here +LL | #[naked] + | ^^^^^^^^ `#[naked]` is incompatible with testing attributes + +error[E0798]: cannot use `#[naked]` with testing attributes + --> $DIR/naked-functions-testattrs.rs:35:1 + | +LL | #[bench] + | -------- function marked with testing attribute here +LL | #[naked] + | ^^^^^^^^ `#[naked]` is incompatible with testing attributes + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0798`. From c6a166bac269eda77b595fdc8ff7290e1372c147 Mon Sep 17 00:00:00 2001 From: Folkert Date: Wed, 17 Jul 2024 10:42:24 +0200 Subject: [PATCH 05/11] switch to an allowlist approach - merge error codes - use attribute name that is incompatible in error message - add test for conditional incompatible attribute - add `linkage` to the allowlist --- compiler/rustc_builtin_macros/src/errors.rs | 2 +- .../src/error_codes/E0736.md | 15 ++-- .../src/error_codes/E0798.md | 14 ---- compiler/rustc_error_codes/src/lib.rs | 1 - compiler/rustc_passes/messages.ftl | 6 +- compiler/rustc_passes/src/check_attr.rs | 44 ++++++++++-- compiler/rustc_passes/src/errors.rs | 5 +- tests/ui/asm/naked-functions-inline.rs | 7 ++ tests/ui/asm/naked-functions-inline.stderr | 22 ++++-- .../ui/asm/naked-functions-instruction-set.rs | 30 ++++++++ .../asm/naked-functions-target-feature.stderr | 4 +- tests/ui/asm/naked-functions-testattrs.rs | 8 +-- tests/ui/asm/naked-functions-testattrs.stderr | 10 +-- tests/ui/asm/naked-functions.rs | 68 +++++++++++++++++-- tests/ui/asm/naked-functions.stderr | 6 +- .../error-with-naked.stderr | 8 +-- 16 files changed, 185 insertions(+), 65 deletions(-) delete mode 100644 compiler/rustc_error_codes/src/error_codes/E0798.md create mode 100644 tests/ui/asm/naked-functions-instruction-set.rs diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 24706a3b05445..daf40df46c308 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -914,7 +914,7 @@ pub(crate) struct ExpectedItem<'a> { } #[derive(Diagnostic)] -#[diag(builtin_macros_naked_functions_testing_attribute, code = E0798)] +#[diag(builtin_macros_naked_functions_testing_attribute, code = E0736)] pub struct NakedFunctionTestingAttribute { #[primary_span] #[label(builtin_macros_naked_attribute)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md index 08aa85e705d99..4660d6107448d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0736.md +++ b/compiler/rustc_error_codes/src/error_codes/E0736.md @@ -1,11 +1,12 @@ Functions marked with the `#[naked]` attribute are restricted in what other -code generation attributes they may be marked with. +attributes they may be marked with. -The following code generation attributes are incompatible with `#[naked]`: +Notable attributes that are incompatible with `#[naked]` are: - * `#[inline]` - * `#[track_caller]` - * `#[target_feature]` +* `#[inline]` +* `#[track_caller]` +* `#[target_feature]` +* `#[test]`, `#[ignore]`, `#[should_panic]` Erroneous code example: @@ -18,7 +19,3 @@ fn foo() {} These incompatibilities are due to the fact that naked functions deliberately impose strict restrictions regarding the code that the compiler is allowed to produce for this function. - -See [the reference page for codegen attributes] for more information. - -[the reference page for codegen attributes]: https://doc.rust-lang.org/reference/attributes/codegen.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0798.md b/compiler/rustc_error_codes/src/error_codes/E0798.md deleted file mode 100644 index 96f25eb4f0e2c..0000000000000 --- a/compiler/rustc_error_codes/src/error_codes/E0798.md +++ /dev/null @@ -1,14 +0,0 @@ -Testing attributes cannot be applied to functions marked with `#[naked]`. - -Erroneous code example: - -```ignore (requires test runner) -#[test] -#[should_panic] -#[naked] -fn foo() {} -``` - -See [the reference page for testing attributes] for more information. - -[the reference page for testing attributes]: https://doc.rust-lang.org/reference/attributes/testing.html diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 2a7bc2501c081..d13d5e1bca219 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -536,7 +536,6 @@ E0794: 0794, E0795: 0795, E0796: 0796, E0797: 0797, -E0798: 0798, ); ) } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 8dec24feebaeb..bfe0d54e64521 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -482,9 +482,9 @@ passes_naked_functions_asm_block = passes_naked_functions_asm_options = asm options unsupported in naked functions: {$unsupported_options} -passes_naked_functions_codegen_attribute = - cannot use additional code generation attributes with `#[naked]` - .label = this attribute is incompatible with `#[naked]` +passes_naked_functions_incompatible_attribute = + attribute incompatible with `#[naked]` + .label = the `{$attr}` attribute is incompatible with `#[naked]` .naked_attribute = function marked with `#[naked]` here passes_naked_functions_must_use_noreturn = diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 311c11a03886e..ba0dbfbac121c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -418,17 +418,53 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target: Target, attrs: &[Attribute], ) -> bool { - const FORBIDDEN: [rustc_span::Symbol; 3] = - [sym::track_caller, sym::inline, sym::target_feature]; + // many attributes don't make sense in combination with #[naked]. + // Notable attributes that are incompatible with `#[naked]` are: + // + // * `#[inline]` + // * `#[track_caller]` + // * `#[target_feature]` + // * `#[test]`, `#[ignore]`, `#[should_panic]` + // + // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate + const ALLOW_LIST: &[rustc_span::Symbol] = &[ + // conditional compilation + sym::cfg, + sym::cfg_attr, + // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`) + sym::test, + sym::ignore, + sym::should_panic, + sym::bench, + // diagnostics + sym::allow, + sym::warn, + sym::deny, + sym::forbid, + sym::deprecated, + sym::must_use, + // abi, linking and FFI + sym::export_name, + sym::link_section, + sym::linkage, + sym::no_mangle, + sym::naked, + sym::instruction_set, + // code generation + sym::cold, + // documentation + sym::doc, + ]; match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { for other_attr in attrs { - if FORBIDDEN.into_iter().any(|name| other_attr.has_name(name)) { - self.dcx().emit_err(errors::NakedFunctionCodegenAttribute { + if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { + self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: other_attr.span, naked_span: attr.span, + attr: other_attr.name_or_empty(), }); return false; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b6be096b43b12..b195ba973ce29 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1183,13 +1183,14 @@ pub struct NakedFunctionsMustUseNoreturn { } #[derive(Diagnostic)] -#[diag(passes_naked_functions_codegen_attribute, code = E0736)] -pub struct NakedFunctionCodegenAttribute { +#[diag(passes_naked_functions_incompatible_attribute, code = E0736)] +pub struct NakedFunctionIncompatibleAttribute { #[primary_span] #[label] pub span: Span, #[label(passes_naked_attribute)] pub naked_span: Span, + pub attr: Symbol, } #[derive(Diagnostic)] diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs index 9a4f754751842..cfb38f2e73848 100644 --- a/tests/ui/asm/naked-functions-inline.rs +++ b/tests/ui/asm/naked-functions-inline.rs @@ -29,3 +29,10 @@ pub unsafe extern "C" fn inline_always() { pub unsafe extern "C" fn inline_never() { asm!("", options(noreturn)); } + +#[naked] +#[cfg_attr(all(), inline(never))] +//~^ ERROR [E0736] +pub unsafe extern "C" fn conditional_inline_never() { + asm!("", options(noreturn)); +} diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr index 2496e942b17c8..84a688f6f5382 100644 --- a/tests/ui/asm/naked-functions-inline.stderr +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -1,27 +1,35 @@ -error[E0736]: cannot use additional code generation attributes with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/naked-functions-inline.rs:13:1 | LL | #[naked] | -------- function marked with `#[naked]` here LL | #[inline] - | ^^^^^^^^^ this attribute is incompatible with `#[naked]` + | ^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` -error[E0736]: cannot use additional code generation attributes with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/naked-functions-inline.rs:20:1 | LL | #[naked] | -------- function marked with `#[naked]` here LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` -error[E0736]: cannot use additional code generation attributes with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/naked-functions-inline.rs:27:1 | LL | #[naked] | -------- function marked with `#[naked]` here LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` -error: aborting due to 3 previous errors +error[E0736]: attribute incompatible with `#[naked]` + --> $DIR/naked-functions-inline.rs:34:19 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[cfg_attr(all(), inline(never))] + | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0736`. diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs new file mode 100644 index 0000000000000..b81b65cff74fc --- /dev/null +++ b/tests/ui/asm/naked-functions-instruction-set.rs @@ -0,0 +1,30 @@ +//@ compile-flags: --target armv5te-unknown-linux-gnueabi +//@ needs-llvm-components: arm +//@ needs-asm-support +//@ build-pass + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs, naked_functions)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +#[naked] +#[instruction_set(arm::t32)] +unsafe extern "C" fn test_thumb() { + asm!("bx lr", options(noreturn)); +} + +#[no_mangle] +#[naked] +#[instruction_set(arm::t32)] +unsafe extern "C" fn test_arm() { + asm!("bx lr", options(noreturn)); +} diff --git a/tests/ui/asm/naked-functions-target-feature.stderr b/tests/ui/asm/naked-functions-target-feature.stderr index 1a8b59f61fe0a..f215f99ab79ec 100644 --- a/tests/ui/asm/naked-functions-target-feature.stderr +++ b/tests/ui/asm/naked-functions-target-feature.stderr @@ -1,8 +1,8 @@ -error[E0736]: cannot use additional code generation attributes with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/naked-functions-target-feature.rs:8:1 | LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `target_feature` attribute is incompatible with `#[naked]` LL | LL | #[naked] | -------- function marked with `#[naked]` here diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs index 593cf3ad4595c..12943ac0378b7 100644 --- a/tests/ui/asm/naked-functions-testattrs.rs +++ b/tests/ui/asm/naked-functions-testattrs.rs @@ -10,7 +10,7 @@ use std::arch::asm; #[test] #[naked] -//~^ ERROR [E0798] +//~^ ERROR [E0736] fn test_naked() { unsafe { asm!("", options(noreturn)) }; } @@ -18,7 +18,7 @@ fn test_naked() { #[should_panic] #[test] #[naked] -//~^ ERROR [E0798] +//~^ ERROR [E0736] fn test_naked_should_panic() { unsafe { asm!("", options(noreturn)) }; } @@ -26,14 +26,14 @@ fn test_naked_should_panic() { #[ignore] #[test] #[naked] -//~^ ERROR [E0798] +//~^ ERROR [E0736] fn test_naked_ignore() { unsafe { asm!("", options(noreturn)) }; } #[bench] #[naked] -//~^ ERROR [E0798] +//~^ ERROR [E0736] fn bench_naked() { unsafe { asm!("", options(noreturn)) }; } diff --git a/tests/ui/asm/naked-functions-testattrs.stderr b/tests/ui/asm/naked-functions-testattrs.stderr index 87647b0ca37df..4dabe41964a57 100644 --- a/tests/ui/asm/naked-functions-testattrs.stderr +++ b/tests/ui/asm/naked-functions-testattrs.stderr @@ -1,4 +1,4 @@ -error[E0798]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[naked]` with testing attributes --> $DIR/naked-functions-testattrs.rs:12:1 | LL | #[test] @@ -6,7 +6,7 @@ LL | #[test] LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes -error[E0798]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[naked]` with testing attributes --> $DIR/naked-functions-testattrs.rs:20:1 | LL | #[test] @@ -14,7 +14,7 @@ LL | #[test] LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes -error[E0798]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[naked]` with testing attributes --> $DIR/naked-functions-testattrs.rs:28:1 | LL | #[test] @@ -22,7 +22,7 @@ LL | #[test] LL | #[naked] | ^^^^^^^^ `#[naked]` is incompatible with testing attributes -error[E0798]: cannot use `#[naked]` with testing attributes +error[E0736]: cannot use `#[naked]` with testing attributes --> $DIR/naked-functions-testattrs.rs:35:1 | LL | #[bench] @@ -32,4 +32,4 @@ LL | #[naked] error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0798`. +For more information about this error, try `rustc --explain E0736`. diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index e6633ddd4f3e9..23d5789ea8c78 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -3,7 +3,7 @@ //@ ignore-spirv #![feature(naked_functions)] -#![feature(asm_const, asm_unwind)] +#![feature(asm_const, asm_unwind, linkage)] #![crate_type = "lib"] use std::arch::asm; @@ -162,11 +162,6 @@ pub unsafe extern "C" fn valid_att_syntax() { asm!("", options(noreturn, att_syntax)); } -#[naked] -pub unsafe extern "C" fn inline_none() { - asm!("", options(noreturn)); -} - #[naked] #[naked] pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { @@ -186,3 +181,64 @@ pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 { asm!(invalid_syntax) //~^ ERROR asm template must be a string literal } + +#[cfg(target_arch = "x86_64")] +#[cfg_attr(target_pointer_width = "64", no_mangle)] +#[naked] +pub unsafe extern "C" fn compatible_cfg_attributes() { + asm!("", options(noreturn, att_syntax)); +} + +#[allow(dead_code)] +#[warn(dead_code)] +#[deny(dead_code)] +#[forbid(dead_code)] +#[naked] +pub unsafe extern "C" fn compatible_diagnostic_attributes() { + asm!("", options(noreturn, att_syntax)); +} + +#[deprecated = "test"] +#[naked] +pub unsafe extern "C" fn compatible_deprecated_attributes() { + asm!("", options(noreturn, att_syntax)); +} + +#[cfg(target_arch = "x86_64")] +#[must_use] +#[naked] +pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { + asm!( + " + mov rax, 42 + ret + ", + options(noreturn) + ) +} + +#[export_name = "exported_function_name"] +#[link_section = ".custom_section"] +#[no_mangle] +#[naked] +pub unsafe extern "C" fn compatible_ffi_attributes_1() { + asm!("", options(noreturn, att_syntax)); +} + +#[cold] +#[naked] +pub unsafe extern "C" fn compatible_codegen_attributes() { + asm!("", options(noreturn, att_syntax)); +} + +#[doc = "foo bar baz"] +#[naked] +pub unsafe extern "C" fn compatible_doc_attributes() { + asm!("", options(noreturn, att_syntax)); +} + +#[linkage = "external"] +#[naked] +pub unsafe extern "C" fn compatible_linkage() { + asm!("", options(noreturn, att_syntax)); +} diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 736de85765e39..357c365479467 100644 --- a/tests/ui/asm/naked-functions.stderr +++ b/tests/ui/asm/naked-functions.stderr @@ -5,19 +5,19 @@ LL | asm!("", options(readonly, nostack), options(pure)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:173:5 + --> $DIR/naked-functions.rs:168:5 | LL | compile_error!("this is a user specified error") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this is a user specified error - --> $DIR/naked-functions.rs:179:5 + --> $DIR/naked-functions.rs:174:5 | LL | compile_error!("this is a user specified error"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: asm template must be a string literal - --> $DIR/naked-functions.rs:186:10 + --> $DIR/naked-functions.rs:181:10 | LL | asm!(invalid_syntax) | ^^^^^^^^^^^^^^ diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr index 7ab9f8b39ebda..0625ed1183ba5 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr +++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr @@ -1,17 +1,17 @@ -error[E0736]: cannot use additional code generation attributes with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/error-with-naked.rs:6:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]` LL | LL | #[naked] | -------- function marked with `#[naked]` here -error[E0736]: cannot use additional code generation attributes with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/error-with-naked.rs:18:5 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ this attribute is incompatible with `#[naked]` + | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]` LL | LL | #[naked] | -------- function marked with `#[naked]` here From a3bb0104ff929674e9d315d9ebec8324f88f367f Mon Sep 17 00:00:00 2001 From: Folkert Date: Tue, 23 Jul 2024 16:02:32 +0200 Subject: [PATCH 06/11] allow `#[target_feature]` on `#[naked]` functions --- compiler/rustc_error_codes/src/error_codes/E0736.md | 1 - compiler/rustc_passes/src/check_attr.rs | 2 +- tests/ui/asm/naked-functions-target-feature.rs | 13 ------------- tests/ui/asm/naked-functions-target-feature.stderr | 12 ------------ tests/ui/asm/naked-functions.rs | 6 ++++++ 5 files changed, 7 insertions(+), 27 deletions(-) delete mode 100644 tests/ui/asm/naked-functions-target-feature.rs delete mode 100644 tests/ui/asm/naked-functions-target-feature.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md index 4660d6107448d..cb7633b7068a3 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0736.md +++ b/compiler/rustc_error_codes/src/error_codes/E0736.md @@ -5,7 +5,6 @@ Notable attributes that are incompatible with `#[naked]` are: * `#[inline]` * `#[track_caller]` -* `#[target_feature]` * `#[test]`, `#[ignore]`, `#[should_panic]` Erroneous code example: diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ba0dbfbac121c..879cae7a94c5a 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -423,7 +423,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // // * `#[inline]` // * `#[track_caller]` - // * `#[target_feature]` // * `#[test]`, `#[ignore]`, `#[should_panic]` // // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate @@ -452,6 +451,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::instruction_set, // code generation sym::cold, + sym::target_feature, // documentation sym::doc, ]; diff --git a/tests/ui/asm/naked-functions-target-feature.rs b/tests/ui/asm/naked-functions-target-feature.rs deleted file mode 100644 index 264e7e0976b1d..0000000000000 --- a/tests/ui/asm/naked-functions-target-feature.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ only-x86_64 -//@ needs-asm-support -#![feature(naked_functions)] -#![crate_type = "lib"] - -use std::arch::asm; - -#[target_feature(enable = "sse2")] -//~^ ERROR [E0736] -#[naked] -pub unsafe extern "C" fn naked_target_feature() { - asm!("", options(noreturn)); -} diff --git a/tests/ui/asm/naked-functions-target-feature.stderr b/tests/ui/asm/naked-functions-target-feature.stderr deleted file mode 100644 index f215f99ab79ec..0000000000000 --- a/tests/ui/asm/naked-functions-target-feature.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0736]: attribute incompatible with `#[naked]` - --> $DIR/naked-functions-target-feature.rs:8:1 - | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `target_feature` attribute is incompatible with `#[naked]` -LL | -LL | #[naked] - | -------- function marked with `#[naked]` here - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0736`. diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 23d5789ea8c78..33cdbd1adb62a 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -231,6 +231,12 @@ pub unsafe extern "C" fn compatible_codegen_attributes() { asm!("", options(noreturn, att_syntax)); } +#[target_feature(enable = "sse2")] +#[naked] +pub unsafe extern "C" fn compatible_target_feature() { + asm!("", options(noreturn)); +} + #[doc = "foo bar baz"] #[naked] pub unsafe extern "C" fn compatible_doc_attributes() { From bad25e3f2c44196ff1b1b42ced923f7d8cb19f1b Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 27 Jul 2024 08:51:12 -0700 Subject: [PATCH 07/11] Add a README to rustbook to explain its purpose --- src/tools/rustbook/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/tools/rustbook/README.md diff --git a/src/tools/rustbook/README.md b/src/tools/rustbook/README.md new file mode 100644 index 0000000000000..d9570c23ead17 --- /dev/null +++ b/src/tools/rustbook/README.md @@ -0,0 +1,34 @@ +# Rustbook + +This is a wrapper around [`mdbook`](https://github.com/rust-lang/mdBook/), which is used to generate the book-style documentation in the Rust project. This wrapper serves a few purposes: + +- Avoids some of mdbook's large, optional dependencies (like tokio, webserver, etc.). +- Makes it a little easier to customize and override some of mdbook's behaviors (like swapping in custom preprocessors). +- Supports vendoring of the source via Rust's normal release process. + +This is invoked automatically when building mdbook-style documentation, for example via `./x doc`. + +## Cargo workspace + +This package defines a separate cargo workspace from the main Rust workspace for a few reasons (ref [#127786](https://github.com/rust-lang/rust/pull/127786): + +- Avoids requiring checking out submodules for developers who are not working on the documentation. Otherwise, some submodules such as those that have custom preprocessors would be required for cargo to find the dependencies. +- Avoids problems with updating dependencies. Unfortunately this workspace has a rather large set of dependencies, which can make coordinating updates difficult (see [#127890](https://github.com/rust-lang/rust/issues/127890)). + +## Custom preprocessors + +Some books have custom mdbook preprocessors that need to be integrated with both the book's repository, and the build system here in the `rust-lang/rust` repository. To add a new preprocessor, there are few things to do: + +1. Implement the preprocessor as a cargo library in the book's repository. +2. Add the `[preprocessor]` table to the book's `book.toml` file. I recommend setting the command so that the preprocessor gets built automatically. It may look something like: + ```toml + [preprocessor.spec] + command = "cargo run --manifest-path my-cool-extension/Cargo.toml" + + [build] + extra-watch-dirs = ["my-cool-extension/src"] + ``` +3. Add the preprocessor as a dependency in rustbook's `Cargo.toml`. +4. Call `with_preprocessor` in `rustbook/src/main.rs`. +5. Be sure to test that it generates correctly, such as running `./x doc MY-BOOK-NAME --open` and verify the content looks correct. +6. Also test tidy and your book, such as running `./x test tidy` and `./x test MY-BOOK-NAME`. From c7e688eccd60ab05a00dea56ac9d984397a2d02e Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 27 Jul 2024 19:18:11 +0200 Subject: [PATCH 08/11] fix `tests/ui/asm/naked-functions.rs` for aarch64 --- tests/ui/asm/naked-functions.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 33cdbd1adb62a..b1f6e5d4fa9fd 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -195,13 +195,13 @@ pub unsafe extern "C" fn compatible_cfg_attributes() { #[forbid(dead_code)] #[naked] pub unsafe extern "C" fn compatible_diagnostic_attributes() { - asm!("", options(noreturn, att_syntax)); + asm!("", options(noreturn, raw)); } #[deprecated = "test"] #[naked] pub unsafe extern "C" fn compatible_deprecated_attributes() { - asm!("", options(noreturn, att_syntax)); + asm!("", options(noreturn, raw)); } #[cfg(target_arch = "x86_64")] @@ -222,15 +222,16 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[no_mangle] #[naked] pub unsafe extern "C" fn compatible_ffi_attributes_1() { - asm!("", options(noreturn, att_syntax)); + asm!("", options(noreturn, raw)); } #[cold] #[naked] pub unsafe extern "C" fn compatible_codegen_attributes() { - asm!("", options(noreturn, att_syntax)); + asm!("", options(noreturn, raw)); } +#[cfg(target_arch = "x86_64")] #[target_feature(enable = "sse2")] #[naked] pub unsafe extern "C" fn compatible_target_feature() { @@ -240,11 +241,11 @@ pub unsafe extern "C" fn compatible_target_feature() { #[doc = "foo bar baz"] #[naked] pub unsafe extern "C" fn compatible_doc_attributes() { - asm!("", options(noreturn, att_syntax)); + asm!("", options(noreturn, raw)); } #[linkage = "external"] #[naked] pub unsafe extern "C" fn compatible_linkage() { - asm!("", options(noreturn, att_syntax)); + asm!("", options(noreturn, raw)); } From c9e408e3f853253d0e3c48ecfab6c3ed9179d55e Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Sat, 27 Jul 2024 13:06:03 -0600 Subject: [PATCH 09/11] bitwise and bytewise methods on `NonZero` --- library/core/src/num/nonzero.rs | 433 +++++++++++++++++++++++++++++++- 1 file changed, 430 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index d80d3241b1eee..64985e216c451 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -455,6 +455,12 @@ macro_rules! nonzero_integer { UnsignedPrimitive = $Uint:ty, // Used in doc comments. + rot = $rot:literal, + rot_op = $rot_op:literal, + rot_result = $rot_result:literal, + swap_op = $swap_op:literal, + swapped = $swapped:literal, + reversed = $reversed:literal, leading_zeros_test = $leading_zeros_test:expr, ) => { /// An integer that is known not to equal zero. @@ -604,6 +610,270 @@ macro_rules! nonzero_integer { unsafe { NonZero::new_unchecked(self.get().count_ones()) } } + /// Shifts the bits to the left by a specified amount, `n`, + /// wrapping the truncated bits to the end of the resulting integer. + /// + /// Please note this isn't the same operation as the `<<` shifting operator! + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $rot_op, stringify!($Int), ")?;")] + #[doc = concat!("let m = NonZero::new(", $rot_result, ")?;")] + /// + #[doc = concat!("assert_eq!(n.rotate_left(", $rot, "), m);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn rotate_left(self, n: u32) -> Self { + let result = self.get().rotate_left(n); + // SAFETY: Rotating bits preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Shifts the bits to the right by a specified amount, `n`, + /// wrapping the truncated bits to the beginning of the resulting + /// integer. + /// + /// Please note this isn't the same operation as the `>>` shifting operator! + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $rot_result, stringify!($Int), ")?;")] + #[doc = concat!("let m = NonZero::new(", $rot_op, ")?;")] + /// + #[doc = concat!("assert_eq!(n.rotate_right(", $rot, "), m);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn rotate_right(self, n: u32) -> Self { + let result = self.get().rotate_right(n); + // SAFETY: Rotating bits preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Reverses the byte order of the integer. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $swap_op, stringify!($Int), ")?;")] + /// let m = n.swap_bytes(); + /// + #[doc = concat!("assert_eq!(m, NonZero::new(", $swapped, ")?);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn swap_bytes(self) -> Self { + let result = self.get().swap_bytes(); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit, + /// second least-significant bit becomes second most-significant bit, etc. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(", $swap_op, stringify!($Int), ")?;")] + /// let m = n.reverse_bits(); + /// + #[doc = concat!("assert_eq!(m, NonZero::new(", $reversed, ")?);")] + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn reverse_bits(self) -> Self { + let result = self.get().reverse_bits(); + // SAFETY: Reversing bits preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts an integer from big endian to the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "big") { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n)")] + /// } else { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_be(n), n.swap_bytes())")] + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use] + #[inline(always)] + pub const fn from_be(x: Self) -> Self { + let result = $Int::from_be(x.get()); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts an integer from little endian to the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + #[doc = concat!("use std::num::", stringify!($Ty), ";")] + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "little") { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_le(n), n)")] + /// } else { + #[doc = concat!(" assert_eq!(", stringify!($Ty), "::from_le(n), n.swap_bytes())")] + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use] + #[inline(always)] + pub const fn from_le(x: Self) -> Self { + let result = $Int::from_le(x.get()); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts `self` to big endian from the target's endianness. + /// + /// On big endian this is a no-op. On little endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "big") { + /// assert_eq!(n.to_be(), n) + /// } else { + /// assert_eq!(n.to_be(), n.swap_bytes()) + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn to_be(self) -> Self { + let result = self.get().to_be(); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + + /// Converts `self` to little endian from the target's endianness. + /// + /// On little endian this is a no-op. On big endian the bytes are + /// swapped. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(nonzero_bitwise)] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::new(0x1A", stringify!($Int), ")?;")] + /// + /// if cfg!(target_endian = "little") { + /// assert_eq!(n.to_le(), n) + /// } else { + /// assert_eq!(n.to_le(), n.swap_bytes()) + /// } + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "nonzero_bitwise", issue = "128281")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn to_le(self) -> Self { + let result = self.get().to_le(); + // SAFETY: Shuffling bytes preserves the property int > 0. + unsafe { Self::new_unchecked(result) } + } + nonzero_integer_signedness_dependent_methods! { Primitive = $signedness $Int, UnsignedPrimitive = $Uint, @@ -826,22 +1096,54 @@ macro_rules! nonzero_integer { nonzero_integer_signedness_dependent_impls!($signedness $Int); }; - (Self = $Ty:ident, Primitive = unsigned $Int:ident $(,)?) => { + ( + Self = $Ty:ident, + Primitive = unsigned $Int:ident, + rot = $rot:literal, + rot_op = $rot_op:literal, + rot_result = $rot_result:literal, + swap_op = $swap_op:literal, + swapped = $swapped:literal, + reversed = $reversed:literal, + $(,)? + ) => { nonzero_integer! { #[stable(feature = "nonzero", since = "1.28.0")] Self = $Ty, Primitive = unsigned $Int, UnsignedPrimitive = $Int, + rot = $rot, + rot_op = $rot_op, + rot_result = $rot_result, + swap_op = $swap_op, + swapped = $swapped, + reversed = $reversed, leading_zeros_test = concat!(stringify!($Int), "::MAX"), } }; - (Self = $Ty:ident, Primitive = signed $Int:ident, $($rest:tt)*) => { + ( + Self = $Ty:ident, + Primitive = signed $Int:ident, + UnsignedPrimitive = $UInt:ident, + rot = $rot:literal, + rot_op = $rot_op:literal, + rot_result = $rot_result:literal, + swap_op = $swap_op:literal, + swapped = $swapped:literal, + reversed = $reversed:literal, + ) => { nonzero_integer! { #[stable(feature = "signed_nonzero", since = "1.34.0")] Self = $Ty, Primitive = signed $Int, - $($rest)* + UnsignedPrimitive = $UInt, + rot = $rot, + rot_op = $rot_op, + rot_result = $rot_result, + swap_op = $swap_op, + swapped = $swapped, + reversed = $reversed, leading_zeros_test = concat!("-1", stringify!($Int)), } }; @@ -1241,6 +1543,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// assert_eq!(ten.isqrt(), three); /// # Some(()) /// # } + /// ``` #[unstable(feature = "isqrt", issue = "116226")] #[rustc_const_unstable(feature = "isqrt", issue = "116226")] #[must_use = "this returns the result of the operation, \ @@ -1704,65 +2007,189 @@ macro_rules! sign_dependent_expr { nonzero_integer! { Self = NonZeroU8, Primitive = unsigned u8, + rot = 2, + rot_op = "0x82", + rot_result = "0xa", + swap_op = "0x12", + swapped = "0x12", + reversed = "0x48", } nonzero_integer! { Self = NonZeroU16, Primitive = unsigned u16, + rot = 4, + rot_op = "0xa003", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", } nonzero_integer! { Self = NonZeroU32, Primitive = unsigned u32, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", } nonzero_integer! { Self = NonZeroU64, Primitive = unsigned u64, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } nonzero_integer! { Self = NonZeroU128, Primitive = unsigned u128, + rot = 16, + rot_op = "0x13f40000000000000000000000004f76", + rot_result = "0x4f7613f4", + swap_op = "0x12345678901234567890123456789012", + swapped = "0x12907856341290785634129078563412", + reversed = "0x48091e6a2c48091e6a2c48091e6a2c48", +} + +#[cfg(target_pointer_width = "16")] +nonzero_integer! { + Self = NonZeroUsize, + Primitive = unsigned usize, + rot = 4, + rot_op = "0xa003", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", } +#[cfg(target_pointer_width = "32")] nonzero_integer! { Self = NonZeroUsize, Primitive = unsigned usize, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", +} + +#[cfg(target_pointer_width = "64")] +nonzero_integer! { + Self = NonZeroUsize, + Primitive = unsigned usize, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } nonzero_integer! { Self = NonZeroI8, Primitive = signed i8, UnsignedPrimitive = u8, + rot = 2, + rot_op = "-0x7e", + rot_result = "0xa", + swap_op = "0x12", + swapped = "0x12", + reversed = "0x48", } nonzero_integer! { Self = NonZeroI16, Primitive = signed i16, UnsignedPrimitive = u16, + rot = 4, + rot_op = "-0x5ffd", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", } nonzero_integer! { Self = NonZeroI32, Primitive = signed i32, UnsignedPrimitive = u32, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", } nonzero_integer! { Self = NonZeroI64, Primitive = signed i64, UnsignedPrimitive = u64, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } nonzero_integer! { Self = NonZeroI128, Primitive = signed i128, UnsignedPrimitive = u128, + rot = 16, + rot_op = "0x13f40000000000000000000000004f76", + rot_result = "0x4f7613f4", + swap_op = "0x12345678901234567890123456789012", + swapped = "0x12907856341290785634129078563412", + reversed = "0x48091e6a2c48091e6a2c48091e6a2c48", +} + +#[cfg(target_pointer_width = "16")] +nonzero_integer! { + Self = NonZeroIsize, + Primitive = signed isize, + UnsignedPrimitive = usize, + rot = 4, + rot_op = "-0x5ffd", + rot_result = "0x3a", + swap_op = "0x1234", + swapped = "0x3412", + reversed = "0x2c48", +} + +#[cfg(target_pointer_width = "32")] +nonzero_integer! { + Self = NonZeroIsize, + Primitive = signed isize, + UnsignedPrimitive = usize, + rot = 8, + rot_op = "0x10000b3", + rot_result = "0xb301", + swap_op = "0x12345678", + swapped = "0x78563412", + reversed = "0x1e6a2c48", } +#[cfg(target_pointer_width = "64")] nonzero_integer! { Self = NonZeroIsize, Primitive = signed isize, UnsignedPrimitive = usize, + rot = 12, + rot_op = "0xaa00000000006e1", + rot_result = "0x6e10aa", + swap_op = "0x1234567890123456", + swapped = "0x5634129078563412", + reversed = "0x6a2c48091e6a2c48", } From ec0b3540925af3cab9c38b0344902d48edb9d5b8 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Sun, 28 Jul 2024 01:28:39 +0800 Subject: [PATCH 10/11] stabilize `is_sorted` --- .../example/std_example.rs | 1 - .../rustc_codegen_gcc/example/std_example.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 1 - compiler/rustc_lint_defs/src/builtin.rs | 12 ++++-- compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_monomorphize/src/lib.rs | 1 - library/alloc/src/lib.rs | 1 - library/core/src/iter/traits/iterator.rs | 12 ++---- library/core/src/slice/mod.rs | 11 ++--- library/core/tests/lib.rs | 1 - .../src/library-features/is-sorted.md | 11 ----- src/tools/clippy/clippy_lints/src/lib.rs | 1 - src/tools/clippy/tests/compile-test.rs | 1 - .../tests/ui/unit_return_expecting_ord.rs | 1 - .../tests/ui/unit_return_expecting_ord.stderr | 12 +++--- .../slice_is_sorted_by_borrow.rs | 2 - .../feature-gates/feature-gate-is_sorted.rs | 13 ------ .../feature-gate-is_sorted.stderr | 43 ------------------- 18 files changed, 21 insertions(+), 106 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/is-sorted.md delete mode 100644 tests/ui/feature-gates/feature-gate-is_sorted.rs delete mode 100644 tests/ui/feature-gates/feature-gate-is_sorted.stderr diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 6cedd84adfe52..e99763e272233 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -3,7 +3,6 @@ coroutines, stmt_expr_attributes, coroutine_trait, - is_sorted, repr_simd, tuple_trait, unboxed_closures diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs index 8ab8fcc525e5c..9e43b4635f0d3 100644 --- a/compiler/rustc_codegen_gcc/example/std_example.rs +++ b/compiler/rustc_codegen_gcc/example/std_example.rs @@ -1,5 +1,5 @@ #![allow(internal_features)] -#![feature(core_intrinsics, coroutines, coroutine_trait, is_sorted, stmt_expr_attributes)] +#![feature(core_intrinsics, coroutines, coroutine_trait, stmt_expr_attributes)] #[cfg(feature="master")] #[cfg(target_arch="x86_64")] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index dd7fbba753bdd..89b981ab80dd5 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -64,7 +64,6 @@ This API is completely unstable and subject to change. #![doc(rust_logo)] #![feature(control_flow_enum)] #![feature(if_let_guard)] -#![feature(is_sorted)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5d4cc7561a63d..c4158cccca4a3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1984,14 +1984,18 @@ declare_lint! { /// /// ```rust /// trait MyIterator : Iterator { - /// // is_sorted is an unstable method that already exists on the Iterator trait - /// fn is_sorted(self) -> bool where Self: Sized {true} + /// // is_partitioned is an unstable method that already exists on the Iterator trait + /// fn is_partitioned

(self, predicate: P) -> bool + /// where + /// Self: Sized, + /// P: FnMut(Self::Item) -> bool, + /// {true} /// } /// /// impl MyIterator for T where T: Iterator { } /// /// let x = vec![1, 2, 3]; - /// let _ = x.iter().is_sorted(); + /// let _ = x.iter().is_partitioned(|_| true); /// ``` /// /// {{produces}} @@ -2007,7 +2011,7 @@ declare_lint! { /// is an early-warning to let you know that there may be a collision in /// the future. This can be avoided by adding type annotations to /// disambiguate which trait method you intend to call, such as - /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method. + /// `MyIterator::is_partitioned(my_iter, my_predicate)` or renaming or removing the method. /// /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5d253d7384df4..243c9c6a2fd6f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -6,7 +6,6 @@ #![feature(decl_macro)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] -#![feature(is_sorted)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index fc6e8e0d14fd2..3b8f0a91e7463 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,6 +1,5 @@ // tidy-alphabetical-start #![feature(array_windows)] -#![feature(is_sorted)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4491a717dc2ea..49036077e2e67 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -92,7 +92,6 @@ // tidy-alphabetical-start #![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))] -#![cfg_attr(test, feature(is_sorted))] #![cfg_attr(test, feature(new_uninit))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 469097e484773..c85a61ada3d69 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3951,8 +3951,6 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!([1, 2, 2, 9].iter().is_sorted()); /// assert!(![1, 3, 2, 4].iter().is_sorted()); /// assert!([0].iter().is_sorted()); @@ -3960,7 +3958,7 @@ pub trait Iterator { /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[rustc_do_not_const_check] fn is_sorted(self) -> bool where @@ -3978,8 +3976,6 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!([1, 2, 2, 9].iter().is_sorted_by(|a, b| a <= b)); /// assert!(![1, 2, 2, 9].iter().is_sorted_by(|a, b| a < b)); /// @@ -3989,7 +3985,7 @@ pub trait Iterator { /// assert!(std::iter::empty::().is_sorted_by(|a, b| false)); /// assert!(std::iter::empty::().is_sorted_by(|a, b| true)); /// ``` - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[rustc_do_not_const_check] fn is_sorted_by(mut self, compare: F) -> bool where @@ -4030,13 +4026,11 @@ pub trait Iterator { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); /// assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[rustc_do_not_const_check] fn is_sorted_by_key(self, f: F) -> bool where diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 6d3e625bef428..201e1284b703f 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4069,7 +4069,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(is_sorted)] /// let empty: [i32; 0] = []; /// /// assert!([1, 2, 2, 9].is_sorted()); @@ -4079,7 +4078,7 @@ impl [T] { /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub fn is_sorted(&self) -> bool where @@ -4096,8 +4095,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b)); /// assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b)); /// @@ -4108,7 +4105,7 @@ impl [T] { /// assert!(empty.is_sorted_by(|a, b| false)); /// assert!(empty.is_sorted_by(|a, b| true)); /// ``` - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub fn is_sorted_by<'a, F>(&'a self, mut compare: F) -> bool where @@ -4128,13 +4125,11 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(is_sorted)] - /// /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); /// ``` #[inline] - #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + #[stable(feature = "is_sorted", since = "CURRENT_RUSTC_VERSION")] #[must_use] pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool where diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 4c22518788246..51d57c9e37d7c 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -44,7 +44,6 @@ #![feature(hasher_prefixfree_extras)] #![feature(hashmap_internals)] #![feature(try_find)] -#![feature(is_sorted)] #![feature(layout_for_ptr)] #![feature(pattern)] #![feature(slice_take)] diff --git a/src/doc/unstable-book/src/library-features/is-sorted.md b/src/doc/unstable-book/src/library-features/is-sorted.md deleted file mode 100644 index e3b7dc3b28eb2..0000000000000 --- a/src/doc/unstable-book/src/library-features/is-sorted.md +++ /dev/null @@ -1,11 +0,0 @@ -# `is_sorted` - -The tracking issue for this feature is: [#53485] - -[#53485]: https://github.com/rust-lang/rust/issues/53485 - ------------------------- - -Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`; -add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to -`Iterator`. diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 917d9d36076e4..22d23a175094a 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -5,7 +5,6 @@ #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] -#![feature(is_sorted)] #![feature(iter_intersperse)] #![feature(iter_partition_in_place)] #![feature(let_chains)] diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index ea3a0a93ecc0b..4e5120406b0d8 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -1,4 +1,3 @@ -#![feature(is_sorted)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] diff --git a/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs b/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs index 59b2f7e355b34..5f62157dd6d55 100644 --- a/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs +++ b/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs @@ -2,7 +2,6 @@ #![allow(clippy::needless_return)] #![allow(clippy::unused_unit)] #![allow(clippy::useless_vec)] -#![feature(is_sorted)] struct Struct { field: isize, diff --git a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr index b2fc885701582..329832048e88a 100644 --- a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr +++ b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr @@ -1,11 +1,11 @@ error: this closure returns the unit type which also implements Ord - --> tests/ui/unit_return_expecting_ord.rs:19:25 + --> tests/ui/unit_return_expecting_ord.rs:18:25 | LL | structs.sort_by_key(|s| { | ^^^ | help: probably caused by this trailing semicolon - --> tests/ui/unit_return_expecting_ord.rs:21:24 + --> tests/ui/unit_return_expecting_ord.rs:20:24 | LL | double(s.field); | ^ @@ -13,25 +13,25 @@ LL | double(s.field); = help: to override `-D warnings` add `#[allow(clippy::unit_return_expecting_ord)]` error: this closure returns the unit type which also implements PartialOrd - --> tests/ui/unit_return_expecting_ord.rs:24:30 + --> tests/ui/unit_return_expecting_ord.rs:23:30 | LL | structs.is_sorted_by_key(|s| { | ^^^ | help: probably caused by this trailing semicolon - --> tests/ui/unit_return_expecting_ord.rs:26:24 + --> tests/ui/unit_return_expecting_ord.rs:25:24 | LL | double(s.field); | ^ error: this closure returns the unit type which also implements PartialOrd - --> tests/ui/unit_return_expecting_ord.rs:28:30 + --> tests/ui/unit_return_expecting_ord.rs:27:30 | LL | structs.is_sorted_by_key(|s| { | ^^^ error: this closure returns the unit type which also implements Ord - --> tests/ui/unit_return_expecting_ord.rs:39:25 + --> tests/ui/unit_return_expecting_ord.rs:38:25 | LL | structs.sort_by_key(|s| unit(s.field)); | ^^^ diff --git a/tests/ui/array-slice-vec/slice_is_sorted_by_borrow.rs b/tests/ui/array-slice-vec/slice_is_sorted_by_borrow.rs index 31f59f8f7242d..6ac90953a059f 100644 --- a/tests/ui/array-slice-vec/slice_is_sorted_by_borrow.rs +++ b/tests/ui/array-slice-vec/slice_is_sorted_by_borrow.rs @@ -1,8 +1,6 @@ //@ check-pass // regression test for https://github.com/rust-lang/rust/issues/53485#issuecomment-885393452 -#![feature(is_sorted)] - struct A { name: String, } diff --git a/tests/ui/feature-gates/feature-gate-is_sorted.rs b/tests/ui/feature-gates/feature-gate-is_sorted.rs deleted file mode 100644 index 359ed835bcbb2..0000000000000 --- a/tests/ui/feature-gates/feature-gate-is_sorted.rs +++ /dev/null @@ -1,13 +0,0 @@ -fn main() { - // Assert `Iterator` methods are unstable - assert!([1, 2, 2, 9].iter().is_sorted()); - //~^ ERROR: use of unstable library feature 'is_sorted': new API - assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); - //~^ ERROR: use of unstable library feature 'is_sorted': new API - - // Assert `[T]` methods are unstable - assert!([1, 2, 2, 9].is_sorted()); - //~^ ERROR: use of unstable library feature 'is_sorted': new API - assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); - //~^ ERROR: use of unstable library feature 'is_sorted': new API -} diff --git a/tests/ui/feature-gates/feature-gate-is_sorted.stderr b/tests/ui/feature-gates/feature-gate-is_sorted.stderr deleted file mode 100644 index f3e87659b02f1..0000000000000 --- a/tests/ui/feature-gates/feature-gate-is_sorted.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0658]: use of unstable library feature 'is_sorted': new API - --> $DIR/feature-gate-is_sorted.rs:3:33 - | -LL | assert!([1, 2, 2, 9].iter().is_sorted()); - | ^^^^^^^^^ - | - = note: see issue #53485 for more information - = help: add `#![feature(is_sorted)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'is_sorted': new API - --> $DIR/feature-gate-is_sorted.rs:5:39 - | -LL | assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #53485 for more information - = help: add `#![feature(is_sorted)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'is_sorted': new API - --> $DIR/feature-gate-is_sorted.rs:9:26 - | -LL | assert!([1, 2, 2, 9].is_sorted()); - | ^^^^^^^^^ - | - = note: see issue #53485 for more information - = help: add `#![feature(is_sorted)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: use of unstable library feature 'is_sorted': new API - --> $DIR/feature-gate-is_sorted.rs:11:32 - | -LL | assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #53485 for more information - = help: add `#![feature(is_sorted)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. From 5eea6d75426badb7ce4a365ad7ea0cad88e0bdb0 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 27 Jul 2024 16:25:49 -0400 Subject: [PATCH 11/11] rustc book: document how the RUST_TARGET_PATH variable is used based on the module comment in rust/compiler/rustc_target/src/spec/mod.rs Fixes #128280 --- src/doc/rustc/src/targets/custom.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md index a67cb10fc75a8..a332d24c9f1fb 100644 --- a/src/doc/rustc/src/targets/custom.md +++ b/src/doc/rustc/src/targets/custom.md @@ -15,3 +15,16 @@ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print targe ``` To use a custom target, see the (unstable) [`build-std` feature](../../cargo/reference/unstable.html#build-std) of `cargo`. + +## Custom Target Lookup Path + +When `rustc` is given an option `--target=TARGET` (where `TARGET` is any string), it uses the following logic: +1. if `TARGET` is the name of a built-in target, use that +2. if `TARGET` is a path to a file, read that file as a json target +3. otherwise, search the colon-seperated list of directories found + in the `RUST_TARGET_PATH` environment variable from left to right + for a file named `TARGET.json`. + +These steps are tried in order, so if there are multple potentially valid +interpretations for a target, whichever is found first will take priority. +If none of these methods find a target, an error is thrown.