diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 876f3c2b13518..a30ab236213a0 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -220,6 +220,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 2e6bdae14a8bb..f17819474adcd 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -923,3 +923,13 @@ pub(crate) struct ExpectedItem<'a> { pub span: Span, pub token: &'a str, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_naked_functions_testing_attribute, code = E0736)] +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_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_error_codes/src/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md index 0f3d41ba66dc4..cb7633b7068a3 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0736.md +++ b/compiler/rustc_error_codes/src/error_codes/E0736.md @@ -1,14 +1,20 @@ -`#[track_caller]` and `#[naked]` cannot both be applied to the same function. +Functions marked with the `#[naked]` attribute are restricted in what other +attributes they may be marked with. + +Notable attributes that are incompatible with `#[naked]` are: + +* `#[inline]` +* `#[track_caller]` +* `#[test]`, `#[ignore]`, `#[should_panic]` 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. - -[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md +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. 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: 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/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 1d93cbaddd6fe..bfe0d54e64521 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_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 = 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 9cbd989cc0e9f..e0cf65d3f9830 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,71 @@ 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 { + // many attributes don't make sense in combination with #[naked]. + // Notable attributes that are incompatible with `#[naked]` are: + // + // * `#[inline]` + // * `#[track_caller]` + // * `#[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, + sym::target_feature, + // documentation + sym::doc, + ]; + 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 !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; + } + } + + 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 +547,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 +557,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..b195ba973ce29 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,17 @@ pub struct NakedFunctionsMustUseNoreturn { pub last_span: Span, } +#[derive(Diagnostic)] +#[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)] #[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 4c5089b86762c..b72ce239c4a96 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/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/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", } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e09e536722b11..8b502624176b6 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/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. 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/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`. 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/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs new file mode 100644 index 0000000000000..cfb38f2e73848 --- /dev/null +++ b/tests/ui/asm/naked-functions-inline.rs @@ -0,0 +1,38 @@ +//@ 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)); +} + +#[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 new file mode 100644 index 0000000000000..84a688f6f5382 --- /dev/null +++ b/tests/ui/asm/naked-functions-inline.stderr @@ -0,0 +1,35 @@ +error[E0736]: attribute incompatible with `#[naked]` + --> $DIR/naked-functions-inline.rs:13:1 + | +LL | #[naked] + | -------- function marked with `#[naked]` here +LL | #[inline] + | ^^^^^^^^^ the `inline` attribute is incompatible 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)] + | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible 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)] + | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]` + +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-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs new file mode 100644 index 0000000000000..12943ac0378b7 --- /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 [E0736] +fn test_naked() { + unsafe { asm!("", options(noreturn)) }; +} + +#[should_panic] +#[test] +#[naked] +//~^ ERROR [E0736] +fn test_naked_should_panic() { + unsafe { asm!("", options(noreturn)) }; +} + +#[ignore] +#[test] +#[naked] +//~^ ERROR [E0736] +fn test_naked_ignore() { + unsafe { asm!("", options(noreturn)) }; +} + +#[bench] +#[naked] +//~^ 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 new file mode 100644 index 0000000000000..4dabe41964a57 --- /dev/null +++ b/tests/ui/asm/naked-functions-testattrs.stderr @@ -0,0 +1,35 @@ +error[E0736]: 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[E0736]: 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[E0736]: 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[E0736]: 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 E0736`. diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 6b2d2aea238da..6d335ac2def1e 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; @@ -163,57 +163,89 @@ pub unsafe extern "C" fn valid_att_syntax() { } #[naked] -pub unsafe extern "C" fn inline_none() { - asm!("", options(noreturn)); +#[naked] +pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { + compile_error!("this is a user specified error") + //~^ ERROR this is a user specified error } #[naked] -#[inline] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_hint() { - asm!("", options(noreturn)); +pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { + compile_error!("this is a user specified error"); + //~^ ERROR this is a user specified error + asm!("", options(noreturn)) } #[naked] -#[inline(always)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_always() { - asm!("", options(noreturn)); +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] -#[inline(never)] -//~^ ERROR naked functions cannot be inlined -pub unsafe extern "C" fn inline_never() { - asm!("", options(noreturn)); +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] -#[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)); +pub unsafe extern "C" fn compatible_diagnostic_attributes() { + asm!("", options(noreturn, raw)); } +#[deprecated = "test"] #[naked] -pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 { - compile_error!("this is a user specified error") - //~^ ERROR this is a user specified error +pub unsafe extern "C" fn compatible_deprecated_attributes() { + asm!("", options(noreturn, raw)); } +#[cfg(target_arch = "x86_64")] +#[must_use] #[naked] -pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 { - compile_error!("this is a user specified error"); - //~^ ERROR this is a user specified error - asm!("", options(noreturn)) +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 invalid_asm_syntax(a: u32) -> u32 { - asm!(invalid_syntax) - //~^ ERROR asm template must be a string literal +pub unsafe extern "C" fn compatible_ffi_attributes_1() { + asm!("", options(noreturn, raw)); +} + +#[cold] +#[naked] +pub unsafe extern "C" fn compatible_codegen_attributes() { + asm!("", options(noreturn, raw)); +} + +#[cfg(target_arch = "x86_64")] +#[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() { + asm!("", options(noreturn, raw)); +} + +#[linkage = "external"] +#[naked] +pub unsafe extern "C" fn compatible_linkage() { + asm!("", options(noreturn, raw)); } diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr index 4dd9e29bdc6f8..93c02e2fbef82 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:168: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:174: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:181: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`. 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`. 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..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,14 +1,20 @@ -error[E0736]: cannot use `#[track_caller]` with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/error-with-naked.rs:6:1 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]` +LL | +LL | #[naked] + | -------- function marked with `#[naked]` here -error[E0736]: cannot use `#[track_caller]` with `#[naked]` +error[E0736]: attribute incompatible with `#[naked]` --> $DIR/error-with-naked.rs:18:5 | LL | #[track_caller] - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ the `track_caller` 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