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..3b039786eb5e7 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)]
@@ -117,7 +116,6 @@
#![feature(const_pin)]
#![feature(const_refs_to_cell)]
#![feature(const_size_of_val)]
-#![feature(const_waker)]
#![feature(core_intrinsics)]
#![feature(deprecated_suggestion)]
#![feature(deref_pure_trait)]
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/lib.rs b/library/core/src/lib.rs
index 9f0055d191134..c4d1351c4956d 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -162,7 +162,6 @@
#![feature(const_ub_checks)]
#![feature(const_unicode_case_lookup)]
#![feature(const_unsafecell_get_mut)]
-#![feature(const_waker)]
#![feature(coverage_attribute)]
#![feature(do_not_recommend)]
#![feature(duration_consts_float)]
@@ -225,6 +224,7 @@
#![feature(lang_items)]
#![feature(let_chains)]
#![feature(link_llvm_intrinsics)]
+#![feature(local_waker)]
#![feature(macro_metavar_expr)]
#![feature(marker_trait_attr)]
#![feature(min_exhaustive_patterns)]
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/src/task/wake.rs b/library/core/src/task/wake.rs
index d2b1d74ff6a02..3a3b6ddcede65 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -250,7 +250,8 @@ pub struct Context<'a> {
impl<'a> Context<'a> {
/// Create a new `Context` from a [`&Waker`](Waker).
#[stable(feature = "futures_api", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(local_waker)]
#[must_use]
#[inline]
pub const fn from_waker(waker: &'a Waker) -> Self {
@@ -261,7 +262,7 @@ impl<'a> Context<'a> {
#[inline]
#[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")]
pub const fn waker(&self) -> &'a Waker {
&self.waker
}
@@ -269,7 +270,7 @@ impl<'a> Context<'a> {
/// Returns a reference to the [`LocalWaker`] for the current task.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const fn local_waker(&self) -> &'a LocalWaker {
&self.local_waker
}
@@ -277,7 +278,7 @@ impl<'a> Context<'a> {
/// Returns a reference to the extension data for the current task.
#[inline]
#[unstable(feature = "context_ext", issue = "123392")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn ext(&mut self) -> &mut dyn Any {
// FIXME: this field makes Context extra-weird about unwind safety
// can we justify AssertUnwindSafe if we stabilize this? do we care?
@@ -336,8 +337,8 @@ pub struct ContextBuilder<'a> {
impl<'a> ContextBuilder<'a> {
/// Create a ContextBuilder from a Waker.
#[inline]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
#[unstable(feature = "local_waker", issue = "118959")]
+ #[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const fn from_waker(waker: &'a Waker) -> Self {
// SAFETY: LocalWaker is just Waker without thread safety
let local_waker = unsafe { transmute(waker) };
@@ -352,8 +353,8 @@ impl<'a> ContextBuilder<'a> {
/// Create a ContextBuilder from an existing Context.
#[inline]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
#[unstable(feature = "context_ext", issue = "123392")]
+ #[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn from(cx: &'a mut Context<'_>) -> Self {
let ext = match &mut cx.ext.0 {
ExtData::Some(ext) => ExtData::Some(*ext),
@@ -371,7 +372,7 @@ impl<'a> ContextBuilder<'a> {
/// This method is used to set the value for the waker on `Context`.
#[inline]
#[unstable(feature = "context_ext", issue = "123392")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn waker(self, waker: &'a Waker) -> Self {
Self { waker, ..self }
}
@@ -379,7 +380,7 @@ impl<'a> ContextBuilder<'a> {
/// This method is used to set the value for the local waker on `Context`.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self {
Self { local_waker, ..self }
}
@@ -387,7 +388,7 @@ impl<'a> ContextBuilder<'a> {
/// This method is used to set the value for the extension data on `Context`.
#[inline]
#[unstable(feature = "context_ext", issue = "123392")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_unstable(feature = "context_ext", issue = "123392")]
pub const fn ext(self, data: &'a mut dyn Any) -> Self {
Self { ext: ExtData::Some(data), ..self }
}
@@ -395,7 +396,7 @@ impl<'a> ContextBuilder<'a> {
/// Builds the `Context`.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const fn build(self) -> Context<'a> {
let ContextBuilder { waker, local_waker, ext, _marker, _marker2 } = self;
Context { waker, local_waker, ext: AssertUnwindSafe(ext), _marker, _marker2 }
@@ -521,7 +522,7 @@ impl Waker {
#[inline]
#[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_stable(feature = "const_waker", since = "CURRENT_RUSTC_VERSION")]
pub const unsafe fn from_raw(waker: RawWaker) -> Waker {
Waker { waker }
}
@@ -772,7 +773,7 @@ impl LocalWaker {
#[inline]
#[must_use]
#[unstable(feature = "local_waker", issue = "118959")]
- #[rustc_const_unstable(feature = "const_waker", issue = "102012")]
+ #[rustc_const_unstable(feature = "local_waker", issue = "118959")]
pub const unsafe fn from_raw(waker: RawWaker) -> LocalWaker {
Self { waker }
}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 4c22518788246..8910305315636 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)]
@@ -87,7 +86,6 @@
#![feature(const_ipv6)]
#![feature(const_mut_refs)]
#![feature(const_pin)]
-#![feature(const_waker)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(pointer_is_aligned_to)]
diff --git a/library/core/tests/waker.rs b/library/core/tests/waker.rs
index 2c66e0d7ad3a4..f8c91a72593f0 100644
--- a/library/core/tests/waker.rs
+++ b/library/core/tests/waker.rs
@@ -20,3 +20,35 @@ static WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
|_| {},
|_| {},
);
+
+// https://github.com/rust-lang/rust/issues/102012#issuecomment-1915282956
+mod nop_waker {
+ use core::{
+ future::{ready, Future},
+ pin::Pin,
+ task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
+ };
+
+ const NOP_RAWWAKER: RawWaker = {
+ fn nop(_: *const ()) {}
+ const VTAB: RawWakerVTable = RawWakerVTable::new(|_| NOP_RAWWAKER, nop, nop, nop);
+ RawWaker::new(&() as *const (), &VTAB)
+ };
+
+ const NOP_WAKER: &Waker = &unsafe { Waker::from_raw(NOP_RAWWAKER) };
+
+ const NOP_CONTEXT: Context<'static> = Context::from_waker(NOP_WAKER);
+
+ fn poll_once(f: &mut F) -> Poll
+ where
+ F: Future