From 3948b054dc8e598b83a194056dc4d3a0852dc79e Mon Sep 17 00:00:00 2001 From: Florian Warzecha Date: Wed, 21 Oct 2020 12:36:07 +0200 Subject: [PATCH 01/15] add rustc_allow_const_fn_unstable attribute allow_internal_unstable is currently used to side-step feature gate and stability checks. While it was originally only meant to be used only on macros, its use was expanded to const functions. This commit prepares stricter checks for the usage of allow_internal_unstable (only on macros) and introduces the rustc_allow_const_fn_unstable attribute for usage on functions. See rust-lang/rust#69399 --- compiler/rustc_feature/src/active.rs | 5 +++++ compiler/rustc_feature/src/builtin_attrs.rs | 4 ++++ compiler/rustc_span/src/symbol.rs | 1 + .../feature-gate-rustc-allow-const-fn-unstable.rs | 6 ++++++ ...feature-gate-rustc-allow-const-fn-unstable.stderr | 12 ++++++++++++ 5 files changed, 28 insertions(+) create mode 100644 src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.rs create mode 100644 src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index c13fe2ae2806b..90fed862b9993 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -210,6 +210,11 @@ declare_features! ( /// it is not on path for eventual stabilization). (active, no_niche, "1.42.0", None, None), + /// Allows using `#[rustc_allow_const_fn_unstable]`. + /// This is an attribute on `const fn` for the same + /// purpose as `#[allow_internal_unstable]`. + (active, rustc_allow_const_fn_unstable, "1.49.0", Some(69399), None), + // no-tracking-issue-end // ------------------------------------------------------------------------- diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 83aa1f62106cb..f73363cbccc25 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -379,6 +379,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ allow_internal_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."), "allow_internal_unstable side-steps feature gating and stability checks", ), + gated!( + rustc_allow_const_fn_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."), + "rustc_allow_const_fn_unstable side-steps feature gating and stability checks" + ), gated!( allow_internal_unsafe, Normal, template!(Word), "allow_internal_unsafe side-steps the unsafe_code lint", diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9cf530d57c0b1..13864f6d0ea8d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -893,6 +893,7 @@ symbols! { rustc, rustc_allocator, rustc_allocator_nounwind, + rustc_allow_const_fn_unstable, rustc_args_required_const, rustc_attrs, rustc_builtin_macro, diff --git a/src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.rs b/src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.rs new file mode 100644 index 0000000000000..19d8fa87f5536 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.rs @@ -0,0 +1,6 @@ +#![allow(unused_macros)] + +#[rustc_allow_const_fn_unstable()] //~ ERROR rustc_allow_const_fn_unstable side-steps +const fn foo() { } + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.stderr b/src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.stderr new file mode 100644 index 0000000000000..a549cb64e0cb6 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-rustc-allow-const-fn-unstable.stderr @@ -0,0 +1,12 @@ +error[E0658]: rustc_allow_const_fn_unstable side-steps feature gating and stability checks + --> $DIR/feature-gate-rustc-allow-const-fn-unstable.rs:3:1 + | +LL | #[rustc_allow_const_fn_unstable()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #69399 for more information + = help: add `#![feature(rustc_allow_const_fn_unstable)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 05f4a9a42abbbdb64d3ec4ed0ae6883c10c66e3f Mon Sep 17 00:00:00 2001 From: Florian Warzecha Date: Wed, 21 Oct 2020 20:54:20 +0200 Subject: [PATCH 02/15] switch allow_internal_unstable const fns to rustc_allow_const_fn_unstable --- compiler/rustc_attr/src/builtin.rs | 25 ++++++++++++++++--- compiler/rustc_expand/src/base.rs | 9 +++++-- .../src/transform/check_consts/mod.rs | 2 +- .../src/transform/check_consts/validation.rs | 6 ++--- compiler/rustc_passes/src/check_const.rs | 6 ++--- library/alloc/src/lib.rs | 1 + library/alloc/src/raw_vec.rs | 3 ++- library/core/src/lib.rs | 1 + library/core/src/num/int_macros.rs | 6 +++-- library/core/src/num/uint_macros.rs | 6 +++-- library/core/src/slice/mod.rs | 3 ++- library/core/src/str/converts.rs | 3 ++- library/core/src/str/mod.rs | 3 ++- library/core/src/task/wake.rs | 3 ++- library/proc_macro/src/bridge/client.rs | 15 +++++++---- library/proc_macro/src/bridge/scoped_cell.rs | 3 ++- library/proc_macro/src/lib.rs | 1 + library/std/src/lib.rs | 1 + library/std/src/net/ip.rs | 3 ++- .../consts/min_const_fn/allow_const_fn_ptr.rs | 4 +-- .../min_const_fn/allow_const_fn_ptr.stderr | 4 +-- .../allow_const_fn_ptr_run_pass.rs | 4 +-- .../min_const_fn_libstd_stability.stderr | 4 +-- ...in_const_unsafe_fn_libstd_stability.stderr | 4 +-- 24 files changed, 81 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 9c309345000bb..218a9b229e0df 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1013,13 +1013,28 @@ pub fn allow_internal_unstable<'a>( sess: &'a Session, attrs: &'a [Attribute], ) -> Option + 'a> { - let attrs = sess.filter_by_name(attrs, sym::allow_internal_unstable); + allow_unstable(sess, attrs, sym::allow_internal_unstable) +} + +pub fn rustc_allow_const_fn_unstable<'a>( + sess: &'a Session, + attrs: &'a [Attribute], +) -> Option + 'a> { + allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable) +} + +fn allow_unstable<'a>( + sess: &'a Session, + attrs: &'a [Attribute], + symbol: Symbol, +) -> Option + 'a> { + let attrs = sess.filter_by_name(attrs, symbol); let list = attrs .filter_map(move |attr| { attr.meta_item_list().or_else(|| { sess.diagnostic().span_err( attr.span, - "`allow_internal_unstable` expects a list of feature names", + &format!("`{}` expects a list of feature names", symbol.to_ident_string()), ); None }) @@ -1029,8 +1044,10 @@ pub fn allow_internal_unstable<'a>( Some(list.into_iter().filter_map(move |it| { let name = it.ident().map(|ident| ident.name); if name.is_none() { - sess.diagnostic() - .span_err(it.span(), "`allow_internal_unstable` expects feature names"); + sess.diagnostic().span_err( + it.span(), + &format!("`{}` expects feature names", symbol.to_ident_string()), + ); } name })) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b0e43a260e91d..e5bb213b51412 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -768,8 +768,13 @@ impl SyntaxExtension { name: Symbol, attrs: &[ast::Attribute], ) -> SyntaxExtension { - let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs) - .map(|features| features.collect::>().into()); + let allow_internal_unstable = { + let mut feat_list = Vec::new(); + attr::allow_internal_unstable(sess, &attrs).map(|features| feat_list.extend(features)); + attr::rustc_allow_const_fn_unstable(sess, &attrs) + .map(|features| feat_list.extend(features)); + Some(feat_list.into()) + }; let mut local_inner_macros = false; if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) { diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index 33815ceba620b..11e389cbe4464 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -79,7 +79,7 @@ pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { let attrs = tcx.get_attrs(def_id); - attr::allow_internal_unstable(&tcx.sess, attrs) + attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs) .map_or(false, |mut features| features.any(|name| name == feature_gate)) } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 587b5b381288a..e23fb453c5ae0 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -805,7 +805,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } // Calling an unstable function *always* requires that the corresponding gate - // be enabled, even if the function has `#[allow_internal_unstable(the_gate)]`. + // be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) { self.check_op(ops::FnCallUnstable(callee, Some(gate))); return; @@ -965,8 +965,8 @@ fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol ) .span_suggestion( attr_span, - "otherwise `#[allow_internal_unstable]` can be used to bypass stability checks", - format!("#[allow_internal_unstable({})]\n", gate), + "otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks", + format!("#[rustc_allow_const_fn_unstable({})]\n", gate), Applicability::MaybeIncorrect, ) .emit(); diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index dd0bcbf208d7c..b24c62b971a46 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -87,7 +87,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { let is_feature_allowed = |feature_gate| { // All features require that the corresponding gate be enabled, - // even if the function has `#[allow_internal_unstable(the_gate)]`. + // even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`. if !tcx.features().enabled(feature_gate) { return false; } @@ -105,8 +105,8 @@ impl<'tcx> CheckConstVisitor<'tcx> { } // However, we cannot allow stable `const fn`s to use unstable features without an explicit - // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) + // opt-in via `rustc_allow_const_fn_unstable`. + attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id)) .map_or(false, |mut features| features.any(|name| name == feature_gate)) }; diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b69e19072af44..ccabc336acc16 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -72,6 +72,7 @@ #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] #![deny(unsafe_op_in_unsafe_fn)] +#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] #![cfg_attr(test, feature(new_uninit))] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 1844d3ae004f4..43628259ba32a 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -150,7 +150,8 @@ impl RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. - #[allow_internal_unstable(const_fn)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr: Unique::dangling(), cap: 0, alloc } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index af4b7199397b3..6cb240d1730ed 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -63,6 +63,7 @@ #![warn(missing_debug_implementations)] #![allow(explicit_outlives_requirements)] #![allow(incomplete_features)] +#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(asm)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 33fa26675f610..295a876773c48 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2045,7 +2045,8 @@ assert_eq!( #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[allow_internal_unstable(const_fn_transmute)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -2193,7 +2194,8 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[allow_internal_unstable(const_fn_transmute)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 0de1cc6b1654a..bdea0ea3b08c0 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1803,7 +1803,8 @@ assert_eq!( #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes - #[allow_internal_unstable(const_fn_transmute)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] #[inline] pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to @@ -1951,7 +1952,8 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them - #[allow_internal_unstable(const_fn_transmute)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] #[inline] pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d32e7d4355161..007c75dd07647 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -88,7 +88,8 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[allow_internal_unstable(const_fn_union)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_union))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_union))] pub const fn len(&self) -> usize { // SAFETY: this is safe because `&[T]` and `FatPtr` have the same layout. // Only `std` can make this guarantee. diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index de2a93f735032..952d0598a7c5b 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -157,7 +157,8 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")] -#[allow_internal_unstable(const_fn_transmute)] +#[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] +#[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { // SAFETY: the caller must guarantee that the bytes `v` are valid UTF-8. // Also relies on `&str` and `&[u8]` having the same layout. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 3e18a4e70627d..ee9c09fe186c7 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -219,7 +219,8 @@ impl str { #[rustc_const_stable(feature = "str_as_bytes", since = "1.32.0")] #[inline(always)] #[allow(unused_attributes)] - #[allow_internal_unstable(const_fn_transmute)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] pub const fn as_bytes(&self) -> &[u8] { // SAFETY: const sound because we transmute two types with the same layout unsafe { mem::transmute(self) } diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 8cca9dc904293..d3c0d9b784139 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -130,7 +130,8 @@ impl RawWakerVTable { #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] - #[allow_internal_unstable(const_fn_fn_ptr_basics)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_fn_ptr_basics))] pub const fn new( clone: unsafe fn(*const ()) -> RawWaker, wake: unsafe fn(*const ()), diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index ba3d4c075e11f..dfe5df965cfac 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -401,7 +401,8 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( } impl Client crate::TokenStream> { - #[allow_internal_unstable(const_fn)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, @@ -414,7 +415,8 @@ impl Client crate::TokenStream> { } impl Client crate::TokenStream> { - #[allow_internal_unstable(const_fn)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] pub const fn expand2( f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { @@ -459,7 +461,8 @@ impl ProcMacro { } } - #[allow_internal_unstable(const_fn)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], @@ -468,7 +471,8 @@ impl ProcMacro { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } - #[allow_internal_unstable(const_fn)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] pub const fn attr( name: &'static str, expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, @@ -476,7 +480,8 @@ impl ProcMacro { ProcMacro::Attr { name, client: Client::expand2(expand) } } - #[allow_internal_unstable(const_fn)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] pub const fn bang( name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream, diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs index daa577f74bac3..e7c32b10384d4 100644 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ b/library/proc_macro/src/bridge/scoped_cell.rs @@ -35,7 +35,8 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { pub struct ScopedCell(Cell<>::Out>); impl ScopedCell { - #[allow_internal_unstable(const_fn)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn))] pub const fn new(value: >::Out) -> Self { ScopedCell(Cell::new(value)) } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 139b3591206e7..5a4b69cf6fc1b 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -18,6 +18,7 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) )] +#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] #![feature(nll)] #![feature(staged_api)] #![feature(const_fn)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 30e7a7f3c3b10..7aac411b63307 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -206,6 +206,7 @@ #![needs_panic_runtime] // std may use features in a platform-specific way #![allow(unused_features)] +#![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))] #![cfg_attr(test, feature(print_internals, set_stdio, update_panic_count))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 8089d7a8ba6f1..bb3ece4c2739f 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1043,7 +1043,8 @@ impl Ipv6Addr { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")] - #[allow_internal_unstable(const_fn_transmute)] + #[cfg_attr(not(bootstrap), rustc_allow_const_fn_unstable(const_fn_transmute))] + #[cfg_attr(bootstrap, allow_internal_unstable(const_fn_transmute))] pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr { let addr16 = [ a.to_be(), diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs index dc10db177ed69..53ade85bfd2e7 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, staged_api, allow_internal_unstable)] +#![feature(rustc_attrs, staged_api, rustc_allow_const_fn_unstable)] #![feature(const_fn_fn_ptr_basics)] #[stable(feature = "rust1", since = "1.0.0")] @@ -8,7 +8,7 @@ const fn error(_: fn()) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(since="1.0.0", feature = "mep")] -#[allow_internal_unstable(const_fn_fn_ptr_basics)] +#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] const fn compiles(_: fn()) {} fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr index a08d57b6043d7..6f89225719f84 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr @@ -8,9 +8,9 @@ help: if it is not part of the public API, make this function unstably const | LL | #[rustc_const_unstable(feature = "...", issue = "...")] | -help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks +help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks | -LL | #[allow_internal_unstable(const_fn_fn_ptr_basics)] +LL | #[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] | error: aborting due to previous error diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs index b4e836bbc9540..430e911aacdee 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(allow_internal_unstable)] +#![feature(rustc_allow_const_fn_unstable)] #![feature(const_fn_fn_ptr_basics)] #![feature(rustc_attrs, staged_api)] @@ -7,7 +7,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(since="1.0.0", feature = "mep")] -#[allow_internal_unstable(const_fn_fn_ptr_basics)] +#[rustc_allow_const_fn_unstable(const_fn_fn_ptr_basics)] const fn takes_fn_ptr(_: fn()) {} const FN: fn() = || (); diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index de6a9a19269b1..d3017c5602a8c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -24,9 +24,9 @@ help: if it is not part of the public API, make this function unstably const | LL | #[rustc_const_unstable(feature = "...", issue = "...")] | -help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks +help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks | -LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)] +LL | #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] | error: `foo2_gated` is not yet stable as a const fn diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index f258deb12a9d9..53a59467e3d20 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -24,9 +24,9 @@ help: if it is not part of the public API, make this function unstably const | LL | #[rustc_const_unstable(feature = "...", issue = "...")] | -help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks +help: otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks | -LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)] +LL | #[rustc_allow_const_fn_unstable(const_fn_floating_point_arithmetic)] | error: `foo2_gated` is not yet stable as a const fn From 7258740509877ff97c32c52cea7ac236ba80c51a Mon Sep 17 00:00:00 2001 From: Florian Warzecha Date: Wed, 21 Oct 2020 22:49:08 +0200 Subject: [PATCH 03/15] validate allow_internal_unstable target Adds a check to make sure `#[allow_internal_unstable]` can be applied only to macro definitions. --- compiler/rustc_passes/src/check_attr.rs | 29 +++++++++++++++++++ ...ure-gate-allow-internal-unstable-struct.rs | 1 + ...gate-allow-internal-unstable-struct.stderr | 11 ++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1acaa4c6eff5d..95e6cc3b863c4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -85,6 +85,8 @@ impl CheckAttrVisitor<'tcx> { self.check_export_name(&attr, span, target) } else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) { self.check_rustc_args_required_const(&attr, span, target, item) + } else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) { + self.check_allow_internal_unstable(&attr, span, target, &attrs) } else { // lint-only checks if self.tcx.sess.check_name(attr, sym::cold) { @@ -762,6 +764,33 @@ impl CheckAttrVisitor<'tcx> { } } } + + /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. + /// (Allows proc_macro functions) + fn check_allow_internal_unstable( + &self, + attr: &Attribute, + span: &Span, + target: Target, + attrs: &[Attribute], + ) -> bool { + debug!("Checking target: {:?}", target); + if target == Target::Fn { + for attr in attrs { + if self.tcx.sess.is_proc_macro_attr(attr) { + debug!("Is proc macro attr"); + return true; + } + } + debug!("Is not proc macro attr"); + } + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a macro") + .span_label(*span, "not a macro") + .emit(); + false + } } impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { diff --git a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs index ede969097d5ae..8b13f1bf2788e 100644 --- a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs +++ b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs @@ -2,6 +2,7 @@ // this needs a different test since this is done after expansion #[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps +//~| ERROR attribute should struct S; fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr index a1acfd553738f..df7773ba4fb65 100644 --- a/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr @@ -6,6 +6,15 @@ LL | #[allow_internal_unstable()] | = help: add `#![feature(allow_internal_unstable)]` to the crate attributes to enable -error: aborting due to previous error +error: attribute should be applied to a macro + --> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1 + | +LL | #[allow_internal_unstable()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | struct S; + | --------- not a macro + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 3a63bf02998f7b5e040a4b87e049d03ddd144f74 Mon Sep 17 00:00:00 2001 From: Florian Warzecha Date: Thu, 22 Oct 2020 00:02:26 +0200 Subject: [PATCH 04/15] validate rustc_allow_const_fn_unstable targets Adds a check to make sure `#[rustc_allow_const_fn_unstable]` can be applied only to functions. --- compiler/rustc_passes/src/check_attr.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 95e6cc3b863c4..d6936ae942cdd 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -87,6 +87,8 @@ impl CheckAttrVisitor<'tcx> { self.check_rustc_args_required_const(&attr, span, target, item) } else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) { self.check_allow_internal_unstable(&attr, span, target, &attrs) + } else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) { + self.check_rustc_allow_const_fn_unstable(&attr, span, target) } else { // lint-only checks if self.tcx.sess.check_name(attr, sym::cold) { @@ -791,6 +793,26 @@ impl CheckAttrVisitor<'tcx> { .emit(); false } + + /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. + /// (Allows proc_macro functions) + fn check_rustc_allow_const_fn_unstable( + &self, + attr: &Attribute, + span: &Span, + target: Target, + ) -> bool { + if let Target::Fn | Target::Method(_) = target { + // FIXME Check that this isn't just a function, but a const fn + return true; + } + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to `const fn`") + .span_label(*span, "not a `const fn`") + .emit(); + false + } } impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { From 3a58ad91f68c0715301b9f0272954a18b72eb6bb Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 22 Oct 2020 07:10:25 +0900 Subject: [PATCH 05/15] Update `compiler_builtins` to 0.1.36 --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d2170a992747..b70e3e89b1a94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -626,9 +626,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455" +checksum = "7cd0782e0a7da7598164153173e5a5d4d9b1da094473c98dce0ff91406112369" dependencies = [ "cc", "rustc-std-workspace-core", From 7d30c53656395695a2c638694f0a13c3ac743ce8 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 23 Oct 2020 13:47:09 +0200 Subject: [PATCH 06/15] Bump backtrace-rs to enable Mach-O support on iOS. --- library/backtrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/backtrace b/library/backtrace index a6dd47bd588c8..8b8ea53b56f51 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit a6dd47bd588c882e735675a1379d2b61719fa380 +Subproject commit 8b8ea53b56f519dd7780defdd4254daaec892584 From 83fbdddc99f5fc4f76e144c6d86184dd09169287 Mon Sep 17 00:00:00 2001 From: Florian Warzecha Date: Fri, 23 Oct 2020 16:54:25 +0200 Subject: [PATCH 07/15] ignore #[rustc_allow_const_fn_unstable] for macro expansion Recognition for `rustc_allow_const_fn_unstable` attribute was errorneously added in 05f4a9a42abbbdb64d3ec4ed0ae6883c10c66e3f. --- compiler/rustc_expand/src/base.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e5bb213b51412..b0e43a260e91d 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -768,13 +768,8 @@ impl SyntaxExtension { name: Symbol, attrs: &[ast::Attribute], ) -> SyntaxExtension { - let allow_internal_unstable = { - let mut feat_list = Vec::new(); - attr::allow_internal_unstable(sess, &attrs).map(|features| feat_list.extend(features)); - attr::rustc_allow_const_fn_unstable(sess, &attrs) - .map(|features| feat_list.extend(features)); - Some(feat_list.into()) - }; + let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs) + .map(|features| features.collect::>().into()); let mut local_inner_macros = false; if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) { From 13b481b247fe472ccf75b4fb13f3a46ac8f9ecaf Mon Sep 17 00:00:00 2001 From: Florian Warzecha Date: Fri, 23 Oct 2020 17:11:08 +0200 Subject: [PATCH 08/15] rename allow_internal_unstable() to rustc_allow_const_fn_unstable() in rustc_mir Followup rename from 05f4a9a42abbbdb64d3ec4ed0ae6883c10c66e3f, which introduced `#[rustc_allow_const_fn_unstable]` for `const fn`s. --- compiler/rustc_mir/src/transform/check_consts/mod.rs | 6 +++++- .../rustc_mir/src/transform/check_consts/validation.rs | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index 11e389cbe4464..1eb06c0ef65e2 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -77,7 +77,11 @@ pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() } -pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { +pub fn rustc_allow_const_fn_unstable( + tcx: TyCtxt<'tcx>, + def_id: DefId, + feature_gate: Symbol, +) -> bool { let attrs = tcx.get_attrs(def_id); attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs) .map_or(false, |mut features| features.any(|name| name == feature_gate)) diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index e23fb453c5ae0..30e1d0d8adc04 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -292,7 +292,11 @@ impl Validator<'mir, 'tcx> { Status::Unstable(gate) if self.tcx.features().enabled(gate) => { let unstable_in_stable = self.ccx.is_const_stable_const_fn() - && !super::allow_internal_unstable(self.tcx, self.def_id().to_def_id(), gate); + && !super::rustc_allow_const_fn_unstable( + self.tcx, + self.def_id().to_def_id(), + gate, + ); if unstable_in_stable { emit_unstable_in_stable_error(self.ccx, span, gate); } @@ -819,7 +823,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { // Otherwise, we are something const-stable calling a const-unstable fn. - if super::allow_internal_unstable(tcx, caller, gate) { + if super::rustc_allow_const_fn_unstable(tcx, caller, gate) { return; } From ac2c599f23d6c8b5d3413febde4c6febff68062e Mon Sep 17 00:00:00 2001 From: Florian Warzecha Date: Fri, 23 Oct 2020 17:54:48 +0200 Subject: [PATCH 09/15] fix validation for rustc_allow_const_fn_unstable targets The validation was introduced in 3a63bf02998f7b5e040a4b87e049d03ddd144f74 without strict validation of functions, e. g. all function types were allowed. Now the validation only allows `const fn`s. --- compiler/rustc_passes/src/check_attr.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d6936ae942cdd..920c69cb619b5 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -88,7 +88,7 @@ impl CheckAttrVisitor<'tcx> { } else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) { self.check_allow_internal_unstable(&attr, span, target, &attrs) } else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) { - self.check_rustc_allow_const_fn_unstable(&attr, span, target) + self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target) } else { // lint-only checks if self.tcx.sess.check_name(attr, sym::cold) { @@ -798,13 +798,15 @@ impl CheckAttrVisitor<'tcx> { /// (Allows proc_macro functions) fn check_rustc_allow_const_fn_unstable( &self, + hir_id: HirId, attr: &Attribute, span: &Span, target: Target, ) -> bool { if let Target::Fn | Target::Method(_) = target { - // FIXME Check that this isn't just a function, but a const fn - return true; + if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) { + return true; + } } self.tcx .sess From 11a7087cc18cce879a1f4728de7e86c5a989136d Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 24 Oct 2020 14:30:45 +0200 Subject: [PATCH 10/15] Link to cargo's `build-std` feature instead of `xargo` in custom target docs The `xargo` tool is in maintenance mode since 2018 and the `build-std` feature of cargo already works reasonably well for most use cases. --- src/doc/rustc/src/targets/custom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md index 0691afc60eae1..a53e1b017df4f 100644 --- a/src/doc/rustc/src/targets/custom.md +++ b/src/doc/rustc/src/targets/custom.md @@ -14,4 +14,4 @@ To see it for a different target, add the `--target` flag: $ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json ``` -To use a custom target, see [`xargo`](https://github.com/japaric/xargo). \ No newline at end of file +To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html) of `cargo`. From 3b6c4fe465bcb8c47a6b6530d7687a19e78b2f41 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sat, 24 Oct 2020 13:04:52 +0200 Subject: [PATCH 11/15] BTreeMap: stop mistaking node::MIN_LEN as a node level constraint --- library/alloc/src/collections/btree/map.rs | 8 ++- .../alloc/src/collections/btree/map/tests.rs | 21 ++++++- library/alloc/src/collections/btree/node.rs | 2 +- .../alloc/src/collections/btree/node/tests.rs | 56 ++++++------------- library/alloc/src/collections/btree/remove.rs | 5 +- library/alloc/src/collections/btree/split.rs | 18 +++--- 6 files changed, 55 insertions(+), 55 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 20c6ebd22928b..4f9aa44b6b510 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -17,6 +17,10 @@ mod entry; pub use entry::{Entry, OccupiedEntry, VacantEntry}; use Entry::*; +/// Minimum number of elements in nodes that are not a root. +/// We might temporarily have fewer elements during methods. +pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; + /// A map based on a B-Tree. /// /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing @@ -1094,13 +1098,13 @@ impl BTreeMap { // Check if right-most child is underfull. let mut last_edge = internal.last_edge(); let right_child_len = last_edge.reborrow().descend().len(); - if right_child_len < node::MIN_LEN { + if right_child_len < MIN_LEN { // We need to steal. let mut last_kv = match last_edge.left_kv() { Ok(left) => left, Err(_) => unreachable!(), }; - last_kv.bulk_steal_left(node::MIN_LEN - right_child_len); + last_kv.bulk_steal_left(MIN_LEN - right_child_len); last_edge = last_kv.right_edge(); } diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index b51b95a635c87..adb94972f5bb6 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -50,10 +50,15 @@ impl<'a, K: 'a, V: 'a> BTreeMap { { if let Some(root) = &self.root { let root_node = root.node_as_ref(); + assert!(root_node.ascend().is_err()); root_node.assert_back_pointers(); - root_node.assert_ascending(); - assert_eq!(self.length, root_node.assert_and_add_lengths()); + + let counted = root_node.assert_ascending(); + assert_eq!(self.length, counted); + assert_eq!(self.length, root_node.calc_length()); + + root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 }); } else { assert_eq!(self.length, 0); } @@ -76,6 +81,18 @@ impl<'a, K: 'a, V: 'a> BTreeMap { } } +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + pub fn assert_min_len(self, min_len: usize) { + assert!(self.len() >= min_len, "{} < {}", self.len(), min_len); + if let node::ForceResult::Internal(node) = self.force() { + for idx in 0..=node.len() { + let edge = unsafe { Handle::new_edge(node, idx) }; + edge.descend().assert_min_len(MIN_LEN); + } + } + } +} + // Test our value of MIN_INSERTS_HEIGHT_2. It may change according to the // implementation of insertion, but it's best to be aware of when it does. #[test] diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 886d8abd030bf..f5aff9bf494e9 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -38,8 +38,8 @@ use crate::alloc::{AllocRef, Global, Layout}; use crate::boxed::Box; const B: usize = 6; -pub const MIN_LEN: usize = B - 1; pub const CAPACITY: usize = 2 * B - 1; +pub const MIN_LEN_AFTER_SPLIT: usize = B - 1; const KV_IDX_CENTER: usize = B - 1; const EDGE_IDX_LEFT_OF_CENTER: usize = B - 1; const EDGE_IDX_RIGHT_OF_CENTER: usize = B; diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index e56fc2aa51e7c..d6527057c5d77 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -5,25 +5,26 @@ use crate::string::String; use core::cmp::Ordering::*; impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + /// Asserts that the back pointer in each reachable node points to its parent. pub fn assert_back_pointers(self) { - match self.force() { - ForceResult::Leaf(_) => {} - ForceResult::Internal(node) => { - for idx in 0..=node.len() { - let edge = unsafe { Handle::new_edge(node, idx) }; - let child = edge.descend(); - assert!(child.ascend().ok() == Some(edge)); - child.assert_back_pointers(); - } + if let ForceResult::Internal(node) = self.force() { + for idx in 0..=node.len() { + let edge = unsafe { Handle::new_edge(node, idx) }; + let child = edge.descend(); + assert!(child.ascend().ok() == Some(edge)); + child.assert_back_pointers(); } } } - pub fn assert_ascending(self) + /// Asserts that the keys are in strictly ascending order. + /// Returns how many keys it encountered. + pub fn assert_ascending(self) -> usize where K: Copy + Debug + Ord, { struct SeriesChecker { + num_seen: usize, previous: Option, } impl SeriesChecker { @@ -32,10 +33,11 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> assert!(previous < next, "{:?} >= {:?}", previous, next); } self.previous = Some(next); + self.num_seen += 1; } } - let mut checker = SeriesChecker { previous: None }; + let mut checker = SeriesChecker { num_seen: 0, previous: None }; self.visit_nodes_in_order(|pos| match pos { navigate::Position::Leaf(node) => { for idx in 0..node.len() { @@ -49,33 +51,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> } navigate::Position::Internal(_) => {} }); - } - - pub fn assert_and_add_lengths(self) -> usize { - let mut internal_length = 0; - let mut internal_kv_count = 0; - let mut leaf_length = 0; - self.visit_nodes_in_order(|pos| match pos { - navigate::Position::Leaf(node) => { - let is_root = self.height() == 0; - let min_len = if is_root { 0 } else { MIN_LEN }; - assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); - leaf_length += node.len(); - } - navigate::Position::Internal(node) => { - let is_root = self.height() == node.height(); - let min_len = if is_root { 1 } else { MIN_LEN }; - assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); - internal_length += node.len(); - } - navigate::Position::InternalKV(_) => { - internal_kv_count += 1; - } - }); - assert_eq!(internal_length, internal_kv_count); - let total = internal_length + leaf_length; - assert_eq!(self.calc_length(), total); - total + checker.num_seen } pub fn dump_keys(self) -> String @@ -124,8 +100,8 @@ fn test_splitpoint() { right_len += 1; } } - assert!(left_len >= MIN_LEN); - assert!(right_len >= MIN_LEN); + assert!(left_len >= MIN_LEN_AFTER_SPLIT); + assert!(right_len >= MIN_LEN_AFTER_SPLIT); assert!(left_len + right_len == CAPACITY); } } diff --git a/library/alloc/src/collections/btree/remove.rs b/library/alloc/src/collections/btree/remove.rs index 9733b7d608425..99655d3e2bf64 100644 --- a/library/alloc/src/collections/btree/remove.rs +++ b/library/alloc/src/collections/btree/remove.rs @@ -1,4 +1,5 @@ -use super::node::{self, marker, ForceResult, Handle, NodeRef}; +use super::map::MIN_LEN; +use super::node::{marker, ForceResult, Handle, NodeRef}; use super::unwrap_unchecked; use core::mem; use core::ptr; @@ -40,7 +41,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter // Handle underflow let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() }; let mut at_leaf = true; - while cur_node.len() < node::MIN_LEN { + while cur_node.len() < MIN_LEN { match handle_underfull_node(cur_node) { UnderflowResult::AtRoot => break, UnderflowResult::Merged(edge, merged_with_left, offset) => { diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index 0e6e213f6e87d..5f00a5a25abad 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -1,5 +1,6 @@ -use super::node::{self, ForceResult::*, Root}; -use super::search::{self, SearchResult::*}; +use super::map::MIN_LEN; +use super::node::{ForceResult::*, Root}; +use super::search::{search_node, SearchResult::*}; use core::borrow::Borrow; impl Root { @@ -20,7 +21,7 @@ impl Root { let mut right_node = right_root.node_as_mut(); loop { - let mut split_edge = match search::search_node(left_node, key) { + let mut split_edge = match search_node(left_node, key) { // key is going to the right tree Found(handle) => handle.left_edge(), GoDown(handle) => handle, @@ -65,9 +66,9 @@ impl Root { cur_node = last_kv.merge().descend(); } else { let right_len = last_kv.reborrow().right_edge().descend().len(); - // `MINLEN + 1` to avoid readjust if merge happens on the next level. - if right_len < node::MIN_LEN + 1 { - last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len); + // `MIN_LEN + 1` to avoid readjust if merge happens on the next level. + if right_len < MIN_LEN + 1 { + last_kv.bulk_steal_left(MIN_LEN + 1 - right_len); } cur_node = last_kv.right_edge().descend(); } @@ -91,8 +92,9 @@ impl Root { cur_node = first_kv.merge().descend(); } else { let left_len = first_kv.reborrow().left_edge().descend().len(); - if left_len < node::MIN_LEN + 1 { - first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len); + // `MIN_LEN + 1` to avoid readjust if merge happens on the next level. + if left_len < MIN_LEN + 1 { + first_kv.bulk_steal_right(MIN_LEN + 1 - left_len); } cur_node = first_kv.left_edge().descend(); } From eb5db6ce4f7624ee63c0564f6fdaadc07d075d4c Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 24 Oct 2020 16:13:49 +0200 Subject: [PATCH 12/15] Link directly to `#build-std` anchor Co-authored-by: Jonas Schievink --- src/doc/rustc/src/targets/custom.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md index a53e1b017df4f..98e113a663b53 100644 --- a/src/doc/rustc/src/targets/custom.md +++ b/src/doc/rustc/src/targets/custom.md @@ -14,4 +14,4 @@ To see it for a different target, add the `--target` flag: $ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json ``` -To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html) of `cargo`. +To use a custom target, see the (unstable) [`build-std` feature](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std) of `cargo`. From ac384ac2dbb21c5a0f6189807edf4a4ac42383ed Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Fri, 23 Oct 2020 18:17:00 -0400 Subject: [PATCH 13/15] Fix inconsistencies in handling of inert attributes on statements When the 'early' and 'late' visitors visit an attribute target, they activate any lint attributes (e.g. `#[allow]`) that apply to it. This can affect warnings emitted on sibiling attributes. For example, the following code does not produce an `unused_attributes` for `#[inline]`, since the sibiling `#[allow(unused_attributes)]` suppressed the warning. ```rust trait Foo { #[allow(unused_attributes)] #[inline] fn first(); #[inline] #[allow(unused_attributes)] fn second(); } ``` However, we do not do this for statements - instead, the lint attributes only become active when we visit the struct nested inside `StmtKind` (e.g. `Item`). Currently, this is difficult to observe due to another issue - the `HasAttrs` impl for `StmtKind` ignores attributes for `StmtKind::Item`. As a result, the `unused_doc_comments` lint will never see attributes on item statements. This commit makes two interrelated fixes to the handling of inert (non-proc-macro) attributes on statements: * The `HasAttr` impl for `StmtKind` now returns attributes for `StmtKind::Item`, treating it just like every other `StmtKind` variant. The only place relying on the old behavior was macro which has been updated to explicitly ignore attributes on item statements. This allows the `unused_doc_comments` lint to fire for item statements. * The `early` and `late` lint visitors now activate lint attributes when invoking the callback for `Stmt`. This ensures that a lint attribute (e.g. `#[allow(unused_doc_comments)]`) can be applied to sibiling attributes on an item statement. For now, the `unused_doc_comments` lint is explicitly disabled on item statements, which preserves the current behavior. The exact locatiosn where this lint should fire are being discussed in PR #78306 --- compiler/rustc_ast/src/attr/mod.rs | 6 ++- compiler/rustc_expand/src/expand.rs | 3 +- compiler/rustc_hir/src/hir.rs | 6 +-- compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_lint/src/early.rs | 19 ++++++++- compiler/rustc_lint/src/late.rs | 13 +++--- compiler/rustc_lint/src/levels.rs | 7 ++++ compiler/rustc_middle/src/hir/map/mod.rs | 2 +- src/test/ui/lint/reasons-forbidden.rs | 12 ++++++ src/test/ui/lint/reasons-forbidden.stderr | 41 +++++++++++++++++-- .../clippy/clippy_lints/src/utils/author.rs | 2 +- .../clippy_lints/src/utils/inspector.rs | 2 +- 12 files changed, 94 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 8351be222f6bd..146948ed25d2f 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -623,7 +623,8 @@ impl HasAttrs for StmtKind { match *self { StmtKind::Local(ref local) => local.attrs(), StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), - StmtKind::Empty | StmtKind::Item(..) => &[], + StmtKind::Item(ref item) => item.attrs(), + StmtKind::Empty => &[], StmtKind::MacCall(ref mac) => mac.attrs.attrs(), } } @@ -632,7 +633,8 @@ impl HasAttrs for StmtKind { match self { StmtKind::Local(local) => local.visit_attrs(f), StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), - StmtKind::Empty | StmtKind::Item(..) => {} + StmtKind::Item(item) => item.visit_attrs(f), + StmtKind::Empty => {} StmtKind::MacCall(mac) => { mac.attrs.visit_attrs(f); } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 0b43225a242f7..a4154b12751fe 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1357,7 +1357,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { // we'll expand attributes on expressions separately if !stmt.is_expr() { let (attr, derives, after_derive) = if stmt.is_item() { - self.classify_item(&mut stmt) + // FIXME: Handle custom attributes on statements (#15701) + (None, vec![], false) } else { // ignore derives on non-item statements so it falls through // to the unused-attributes lint diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 65b96da95e972..56b5b5a1030c1 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1099,11 +1099,11 @@ pub enum StmtKind<'hir> { Semi(&'hir Expr<'hir>), } -impl StmtKind<'hir> { - pub fn attrs(&self) -> &'hir [Attribute] { +impl<'hir> StmtKind<'hir> { + pub fn attrs(&self, get_item: impl FnOnce(ItemId) -> &'hir Item<'hir>) -> &'hir [Attribute] { match *self { StmtKind::Local(ref l) => &l.attrs, - StmtKind::Item(_) => &[], + StmtKind::Item(ref item_id) => &get_item(*item_id).attrs, StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => &e.attrs, } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a964950f1df1b..e5f66611d0f9b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -994,7 +994,8 @@ impl EarlyLintPass for UnusedDocComment { fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) { let kind = match stmt.kind { ast::StmtKind::Local(..) => "statements", - ast::StmtKind::Item(..) => "inner items", + // Disabled pending discussion in #78306 + ast::StmtKind::Item(..) => return, // expressions will be reported by `check_expr`. ast::StmtKind::Empty | ast::StmtKind::Semi(_) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 4c8baa49edf61..9aeeb6277924e 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -18,6 +18,7 @@ use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; use rustc_ast as ast; use rustc_ast::visit as ast_visit; +use rustc_attr::HasAttrs; use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -119,8 +120,22 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> } fn visit_stmt(&mut self, s: &'a ast::Stmt) { - run_early_pass!(self, check_stmt, s); - self.check_id(s.id); + // Add the statement's lint attributes to our + // current state when checking the statement itself. + // This allows us to handle attributes like + // `#[allow(unused_doc_comments)]`, which apply to + // sibling attributes on the same target + // + // Note that statements get their attributes from + // the AST struct that they wrap (e.g. an item) + self.with_lint_attrs(s.id, s.attrs(), |cx| { + run_early_pass!(cx, check_stmt, s); + cx.check_id(s.id); + }); + // The visitor for the AST struct wrapped + // by the statement (e.g. `Item`) will call + // `with_lint_attrs`, so do this walk + // outside of the above `with_lint_attrs` call ast_visit::walk_stmt(self, s); } diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index a6c04fb0b4c84..015e109871182 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -174,12 +174,13 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas } fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { - // statement attributes are actually just attributes on one of - // - item - // - local - // - expression - // so we keep track of lint levels there - lint_callback!(self, check_stmt, s); + let get_item = |id: hir::ItemId| self.context.tcx.hir().item(id.id); + let attrs = &s.kind.attrs(get_item); + // See `EarlyContextAndPass::visit_stmt` for an explanation + // of why we call `walk_stmt` outside of `with_lint_attrs` + self.with_lint_attrs(s.hir_id, attrs, |cx| { + lint_callback!(cx, check_stmt, s); + }); hir_visit::walk_stmt(self, s); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 222333a578b7d..f36f598ade2de 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -562,6 +562,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> { }) } + fn visit_stmt(&mut self, e: &'tcx hir::Stmt<'tcx>) { + // We will call `with_lint_attrs` when we walk + // the `StmtKind`. The outer statement itself doesn't + // define the lint levels. + intravisit::walk_stmt(self, e); + } + fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { self.with_lint_attrs(e.hir_id, &e.attrs, |builder| { intravisit::walk_expr(builder, e); diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 57f03c2a5cf54..106fa8c78fa28 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -816,7 +816,7 @@ impl<'hir> Map<'hir> { Some(Node::Variant(ref v)) => Some(&v.attrs[..]), Some(Node::Field(ref f)) => Some(&f.attrs[..]), Some(Node::Expr(ref e)) => Some(&*e.attrs), - Some(Node::Stmt(ref s)) => Some(s.kind.attrs()), + Some(Node::Stmt(ref s)) => Some(s.kind.attrs(|id| self.item(id.id))), Some(Node::Arm(ref a)) => Some(&*a.attrs), Some(Node::GenericParam(param)) => Some(¶m.attrs[..]), // Unit/tuple structs/variants take the attributes straight from diff --git a/src/test/ui/lint/reasons-forbidden.rs b/src/test/ui/lint/reasons-forbidden.rs index 6a71176aabb15..5f6764c789d00 100644 --- a/src/test/ui/lint/reasons-forbidden.rs +++ b/src/test/ui/lint/reasons-forbidden.rs @@ -5,6 +5,9 @@ //~^ NOTE `forbid` level set here //~| NOTE `forbid` level set here //~| NOTE `forbid` level set here + //~| NOTE `forbid` level set here + //~| NOTE `forbid` level set here + //~| NOTE `forbid` level set here reason = "our errors & omissions insurance policy doesn't cover unsafe Rust" )] @@ -17,9 +20,18 @@ fn main() { //~^ ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) + //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) + //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) + //~| ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code) //~| NOTE overruled by previous forbid //~| NOTE overruled by previous forbid //~| NOTE overruled by previous forbid + //~| NOTE overruled by previous forbid + //~| NOTE overruled by previous forbid + //~| NOTE overruled by previous forbid + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust + //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust //~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust diff --git a/src/test/ui/lint/reasons-forbidden.stderr b/src/test/ui/lint/reasons-forbidden.stderr index 0954edea7378c..eed9c8d566ecd 100644 --- a/src/test/ui/lint/reasons-forbidden.stderr +++ b/src/test/ui/lint/reasons-forbidden.stderr @@ -1,5 +1,5 @@ error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:16:13 + --> $DIR/reasons-forbidden.rs:19:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -10,7 +10,7 @@ LL | #[allow(unsafe_code)] = note: our errors & omissions insurance policy doesn't cover unsafe Rust error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:16:13 + --> $DIR/reasons-forbidden.rs:19:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -21,7 +21,7 @@ LL | #[allow(unsafe_code)] = note: our errors & omissions insurance policy doesn't cover unsafe Rust error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) - --> $DIR/reasons-forbidden.rs:16:13 + --> $DIR/reasons-forbidden.rs:19:13 | LL | unsafe_code, | ----------- `forbid` level set here @@ -31,6 +31,39 @@ LL | #[allow(unsafe_code)] | = note: our errors & omissions insurance policy doesn't cover unsafe Rust -error: aborting due to 3 previous errors +error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) + --> $DIR/reasons-forbidden.rs:19:13 + | +LL | unsafe_code, + | ----------- `forbid` level set here +... +LL | #[allow(unsafe_code)] + | ^^^^^^^^^^^ overruled by previous forbid + | + = note: our errors & omissions insurance policy doesn't cover unsafe Rust + +error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) + --> $DIR/reasons-forbidden.rs:19:13 + | +LL | unsafe_code, + | ----------- `forbid` level set here +... +LL | #[allow(unsafe_code)] + | ^^^^^^^^^^^ overruled by previous forbid + | + = note: our errors & omissions insurance policy doesn't cover unsafe Rust + +error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code) + --> $DIR/reasons-forbidden.rs:19:13 + | +LL | unsafe_code, + | ----------- `forbid` level set here +... +LL | #[allow(unsafe_code)] + | ^^^^^^^^^^^ overruled by previous forbid + | + = note: our errors & omissions insurance policy doesn't cover unsafe Rust + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 89425437eeead..7250de3a41c04 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for Author { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) { - if !has_attr(cx.sess(), stmt.kind.attrs()) { + if !has_attr(cx.sess(), stmt.kind.attrs(|id| cx.tcx.hir().item(id.id))) { return; } prelude(); diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 93bd82994466a..4fbfb3be32cbf 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -109,7 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for DeepCodeInspector { } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx hir::Stmt<'_>) { - if !has_attr(cx.sess(), stmt.kind.attrs()) { + if !has_attr(cx.sess(), stmt.kind.attrs(|id| cx.tcx.hir().item(id.id))) { return; } match stmt.kind { From 283053a742277f9b949facdfc5f4996f503f3c4e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 15 Oct 2020 14:19:54 -0400 Subject: [PATCH 14/15] Compute proper module parent during resolution Fixes #75982 The direct parent of a module may not be a module (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`). To find the parent of a module for purposes of resolution, we need to walk up the tree until we hit a module or a crate root. --- .../src/rmeta/decoder/cstore_impl.rs | 5 ++ compiler/rustc_middle/src/middle/cstore.rs | 2 + .../rustc_resolve/src/build_reduced_graph.rs | 48 ++++++++++++++++--- src/test/ui/macros/auxiliary/issue-75982.rs | 12 +++++ .../issue-75982-foreign-macro-weird-mod.rs | 13 +++++ 5 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/macros/auxiliary/issue-75982.rs create mode 100644 src/test/ui/macros/issue-75982-foreign-macro-weird-mod.rs diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 05b8dad3097e4..68faf9c7a629d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -8,6 +8,7 @@ use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::svh::Svh; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::hir::exports::Export; @@ -487,6 +488,10 @@ impl CrateStore for CStore { self.get_crate_data(def.krate).def_key(def.index) } + fn def_kind(&self, def: DefId) -> DefKind { + self.get_crate_data(def.krate).def_kind(def.index) + } + fn def_path(&self, def: DefId) -> DefPath { self.get_crate_data(def.krate).def_path(def.index) } diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index f3d7c8506ab6f..ae9e4d364d3cb 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -8,6 +8,7 @@ use rustc_ast as ast; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{self, MetadataRef}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_macros::HashStable; @@ -185,6 +186,7 @@ pub trait CrateStore { // resolve fn def_key(&self, def: DefId) -> DefKey; + fn def_kind(&self, def: DefId) -> DefKind; fn def_path(&self, def: DefId) -> DefPath; fn def_path_hash(&self, def: DefId) -> DefPathHash; fn all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>; diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 02e31ade41f26..feeea726f4c1b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -95,6 +95,27 @@ impl<'a> Resolver<'a> { } } + /// Walks up the tree of definitions starting at `def_id`, + /// stopping at the first `DefKind::Mod` encountered + fn nearest_mod_parent(&mut self, def_id: DefId) -> Module<'a> { + let def_key = self.cstore().def_key(def_id); + + let mut parent_id = DefId { + krate: def_id.krate, + index: def_key.parent.expect("failed to get parent for module"), + }; + // The immediate parent may not be a module + // (e.g. `const _: () = { #[path = "foo.rs"] mod foo; };`) + // Walk up the tree until we hit a module or the crate root. + while parent_id.index != CRATE_DEF_INDEX + && self.cstore().def_kind(parent_id) != DefKind::Mod + { + let parent_def_key = self.cstore().def_key(parent_id); + parent_id.index = parent_def_key.parent.expect("failed to get parent for module"); + } + self.get_module(parent_id) + } + crate fn get_module(&mut self, def_id: DefId) -> Module<'a> { // If this is a local module, it will be in `module_map`, no need to recalculate it. if let Some(def_id) = def_id.as_local() { @@ -116,11 +137,8 @@ impl<'a> Resolver<'a> { .data .get_opt_name() .expect("given a DefId that wasn't a module"); - // This unwrap is safe since we know this isn't the root - let parent = Some(self.get_module(DefId { - index: def_key.parent.expect("failed to get parent for module"), - ..def_id - })); + + let parent = Some(self.nearest_mod_parent(def_id)); (name, parent) }; @@ -145,8 +163,24 @@ impl<'a> Resolver<'a> { if let Some(id) = def_id.as_local() { self.local_macro_def_scopes[&id] } else { - let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); - self.get_module(module_def_id) + // This is not entirely correct - a `macro_rules!` macro may occur + // inside a 'block' module: + // + // ```rust + // const _: () = { + // #[macro_export] + // macro_rules! my_macro { + // () => {}; + // } + // ` + // We don't record this information for external crates, so + // the module we compute here will be the closest 'mod' item + // (not necesssarily the actual parent of the `macro_rules!` + // macro). `macro_rules!` macros can't use def-site hygiene, + // so this hopefully won't be a problem. + // + // See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508 + self.nearest_mod_parent(def_id) } } diff --git a/src/test/ui/macros/auxiliary/issue-75982.rs b/src/test/ui/macros/auxiliary/issue-75982.rs new file mode 100644 index 0000000000000..1e1a6126a10cf --- /dev/null +++ b/src/test/ui/macros/auxiliary/issue-75982.rs @@ -0,0 +1,12 @@ +const _: () = { + #[macro_export] + macro_rules! first_macro { + () => {} + } + mod foo { + #[macro_export] + macro_rules! second_macro { + () => {} + } + } +}; diff --git a/src/test/ui/macros/issue-75982-foreign-macro-weird-mod.rs b/src/test/ui/macros/issue-75982-foreign-macro-weird-mod.rs new file mode 100644 index 0000000000000..e76b09d4bb947 --- /dev/null +++ b/src/test/ui/macros/issue-75982-foreign-macro-weird-mod.rs @@ -0,0 +1,13 @@ +// aux-build:issue-75982.rs +// check-pass + +// Regression test for issue #75982 +// Tests that don't ICE when invoking a foreign macro +// that occurs inside a module with a weird parent. + +extern crate issue_75982; + +fn main() { + issue_75982::first_macro!(); + issue_75982::second_macro!(); +} From dd683e5ab5d79782a484d919bb8de89764cf98d2 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Sun, 18 Oct 2020 16:32:25 -0400 Subject: [PATCH 15/15] MIR validation should check `SwitchInt` values are valid for the type --- compiler/rustc_mir/src/transform/validate.rs | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index beffffa727e7e..7b22d643ab646 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -5,13 +5,17 @@ use crate::dataflow::{Analysis, ResultsCursor}; use crate::util::storage::AlwaysLiveLocals; use super::MirPass; -use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{ + interpret::Scalar, + visit::{PlaceContext, Visitor}, +}; use rustc_middle::mir::{ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, }; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; +use rustc_target::abi::Size; #[derive(Copy, Clone, Debug)] enum EdgeKind { @@ -346,7 +350,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), ); } - for (_, target) in targets.iter() { + + let target_width = self.tcx.sess.target.pointer_width; + + let size = Size::from_bits(match switch_ty.kind() { + ty::Uint(uint) => uint.normalize(target_width).bit_width().unwrap(), + ty::Int(int) => int.normalize(target_width).bit_width().unwrap(), + ty::Char => 32, + ty::Bool => 1, + other => bug!("unhandled type: {:?}", other), + }); + + for (value, target) in targets.iter() { + if Scalar::<()>::try_from_uint(value, size).is_none() { + self.fail( + location, + format!("the value {:#x} is not a proper {:?}", value, switch_ty), + ) + } + self.check_edge(location, target, EdgeKind::Normal); } self.check_edge(location, targets.otherwise(), EdgeKind::Normal);