diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 13742ad273b59..d64bd2d98892d 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -986,7 +986,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // should be fixed later. let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none() && tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable()); - if callee_is_unstable_unmarked { + let can_call_unmarked_function = + super::rustc_allow_const_fn_unstable(tcx, caller, sym::any_unmarked); + if callee_is_unstable_unmarked && !can_call_unmarked_function { trace!("callee_is_unstable_unmarked"); // We do not use `const` modifiers for intrinsic "functions", as intrinsics are // `extern` functions, and these have no way to get marked `const`. So instead we diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 40b0387424221..4aea5da7d9bb8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -397,6 +397,7 @@ symbols! { anon, anonymous_lifetime_in_impl_trait, any, + any_unmarked, append_const_msg, arbitrary_enum_discriminant, arbitrary_self_types, diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 39e94902cfe5f..2c7650503df38 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -279,7 +279,18 @@ impl HashMap { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575")] + #[cfg_attr( + bootstrap, + rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575") + )] + #[cfg_attr( + not(bootstrap), + rustc_const_stable( + feature = "const_collections_with_hasher", + since = "CURRENT_RUSTC_VERSION" + ) + )] + #[rustc_allow_const_fn_unstable(any_unmarked)] pub const fn with_hasher(hash_builder: S) -> HashMap { HashMap { base: base::HashMap::with_hasher(hash_builder) } } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 8bc5960829066..4bd04bfe4d5d3 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -369,7 +369,18 @@ impl HashSet { /// ``` #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575")] + #[cfg_attr( + bootstrap, + rustc_const_unstable(feature = "const_collections_with_hasher", issue = "102575") + )] + #[cfg_attr( + not(bootstrap), + rustc_const_stable( + feature = "const_collections_with_hasher", + since = "CURRENT_RUSTC_VERSION" + ) + )] + #[rustc_allow_const_fn_unstable(any_unmarked)] pub const fn with_hasher(hasher: S) -> HashSet { HashSet { base: base::HashSet::with_hasher(hasher) } } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d06012c14dcfe..26c8f63ceea61 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -297,6 +297,7 @@ #![feature(no_sanitize)] #![feature(platform_intrinsics)] #![feature(prelude_import)] +#![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(staged_api)] @@ -388,7 +389,7 @@ // // Only for const-ness: // tidy-alphabetical-start -#![feature(const_collections_with_hasher)] +#![cfg_attr(bootstrap, feature(const_collections_with_hasher))] #![feature(const_hash)] #![feature(const_io_structs)] #![feature(const_ip)] diff --git a/tests/ui/stability-attribute/auxiliary/const-unstable.rs b/tests/ui/stability-attribute/auxiliary/const-unstable.rs new file mode 100644 index 0000000000000..86d159c7c32a1 --- /dev/null +++ b/tests/ui/stability-attribute/auxiliary/const-unstable.rs @@ -0,0 +1,8 @@ +#![feature(staged_api)] +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_identity", issue = "1")] +pub const fn identity(x: i32) -> i32 { + x +} diff --git a/tests/ui/stability-attribute/auxiliary/normal-const-fn.rs b/tests/ui/stability-attribute/auxiliary/normal-const-fn.rs new file mode 100644 index 0000000000000..222063a55f887 --- /dev/null +++ b/tests/ui/stability-attribute/auxiliary/normal-const-fn.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zforce-unstable-if-unmarked + +// This emulates a dep-of-std (eg hashbrown), that has const functions it +// cannot mark as stable, and is build with force-unstable-if-unmarked. + +pub const fn do_something_else() {} diff --git a/tests/ui/stability-attribute/const-stable-cross-crate.rs b/tests/ui/stability-attribute/const-stable-cross-crate.rs new file mode 100644 index 0000000000000..d102979dd7d5d --- /dev/null +++ b/tests/ui/stability-attribute/const-stable-cross-crate.rs @@ -0,0 +1,22 @@ +// aux-build:normal-const-fn.rs +// check-pass +#![crate_type = "lib"] +#![feature(staged_api)] +#![feature(rustc_attrs)] +#![feature(rustc_private)] +#![allow(internal_features)] +#![feature(rustc_allow_const_fn_unstable)] +#![stable(feature = "stable_feature", since = "1.0.0")] + +extern crate normal_const_fn; + +// This ensures std can call const functions in it's deps that don't have +// access to rustc_const_stable annotations (and hense don't have a feature) +// gate. + +#[rustc_const_stable(feature = "stable_feature", since = "1.0.0")] +#[stable(feature = "stable_feature", since = "1.0.0")] +#[rustc_allow_const_fn_unstable(any_unmarked)] +pub const fn do_something() { + normal_const_fn::do_something_else() +} diff --git a/tests/ui/stability-attribute/const-unstable-from-unmarked.rs b/tests/ui/stability-attribute/const-unstable-from-unmarked.rs new file mode 100644 index 0000000000000..006768de95ed6 --- /dev/null +++ b/tests/ui/stability-attribute/const-unstable-from-unmarked.rs @@ -0,0 +1,16 @@ +// aux-build: const-unstable.rs +// compile-flags: -Zforce-unstable-if-unmarked +#![crate_type = "lib"] +extern crate const_unstable; + +// Check that crates build with `-Zforce-unstable-if-unmarked` can't call +// const-unstable functions, despite their functions sometimes being considerd +// unstable. +// +// See https://github.com/rust-lang/rust/pull/118427#discussion_r1409914941 for +// more context. + +pub const fn identity(x: i32) -> i32 { + const_unstable::identity(x) + //~^ ERROR `const_unstable::identity` is not yet stable as a const fn +} diff --git a/tests/ui/stability-attribute/const-unstable-from-unmarked.stderr b/tests/ui/stability-attribute/const-unstable-from-unmarked.stderr new file mode 100644 index 0000000000000..320fa210bfba8 --- /dev/null +++ b/tests/ui/stability-attribute/const-unstable-from-unmarked.stderr @@ -0,0 +1,10 @@ +error: `const_unstable::identity` is not yet stable as a const fn + --> $DIR/const-unstable-from-unmarked.rs:14:5 + | +LL | const_unstable::identity(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_identity)]` to the crate attributes to enable + +error: aborting due to 1 previous error +