From 39bff4bf9c998ba77d12b36b26c604340638fa73 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 6 Apr 2022 21:27:46 -0700 Subject: [PATCH 01/15] don't report int/float ambiguity when we have previous errors --- .../src/traits/error_reporting/mod.rs | 22 +++++++++++-- .../ui/traits/no-fallback-multiple-impls.rs | 16 ++++++++++ .../traits/no-fallback-multiple-impls.stderr | 9 ++++++ src/test/ui/traits/test-2.rs | 4 +-- src/test/ui/traits/test-2.stderr | 32 ++----------------- 5 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 src/test/ui/traits/no-fallback-multiple-impls.rs create mode 100644 src/test/ui/traits/no-fallback-multiple-impls.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9998c5bb087e1..ac98dd5801e40 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -36,6 +36,7 @@ use rustc_span::symbol::{kw, sym}; use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; use std::iter; +use std::ops::ControlFlow; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::AtExt as _; @@ -2226,9 +2227,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { post.dedup(); if self.is_tainted_by_errors() - && crate_names.len() == 1 - && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) - && spans.len() == 0 + && (crate_names.len() == 1 + && spans.len() == 0 + && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str()) + || predicate.visit_with(&mut HasNumericInferVisitor).is_break()) { // Avoid complaining about other inference issues for expressions like // `42 >> 1`, where the types are still `{integer}`, but we want to @@ -2666,3 +2668,17 @@ impl ArgKind { } } } + +struct HasNumericInferVisitor; + +impl<'tcx> ty::TypeVisitor<'tcx> for HasNumericInferVisitor { + type BreakTy = (); + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) { + ControlFlow::Break(()) + } else { + ControlFlow::CONTINUE + } + } +} diff --git a/src/test/ui/traits/no-fallback-multiple-impls.rs b/src/test/ui/traits/no-fallback-multiple-impls.rs new file mode 100644 index 0000000000000..7ed3796f08b76 --- /dev/null +++ b/src/test/ui/traits/no-fallback-multiple-impls.rs @@ -0,0 +1,16 @@ +trait Fallback { + fn foo(&self) {} +} + +impl Fallback for i32 {} + +impl Fallback for u64 {} + +impl Fallback for usize {} + +fn main() { + missing(); + //~^ ERROR cannot find function `missing` in this scope + 0.foo(); + // But then we shouldn't report an inference ambiguity here... +} diff --git a/src/test/ui/traits/no-fallback-multiple-impls.stderr b/src/test/ui/traits/no-fallback-multiple-impls.stderr new file mode 100644 index 0000000000000..61c9e5aaabdb4 --- /dev/null +++ b/src/test/ui/traits/no-fallback-multiple-impls.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find function `missing` in this scope + --> $DIR/no-fallback-multiple-impls.rs:12:5 + | +LL | missing(); + | ^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/traits/test-2.rs b/src/test/ui/traits/test-2.rs index d062de25ac8c1..342928e882a55 100644 --- a/src/test/ui/traits/test-2.rs +++ b/src/test/ui/traits/test-2.rs @@ -6,9 +6,9 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } fn main() { - 10.dup::(); //~ ERROR type annotations needed + 10.dup::(); //~^ ERROR this associated function takes 0 generic arguments but 1 - 10.blah::(); //~ ERROR type annotations needed + 10.blah::(); //~^ ERROR this associated function takes 1 generic argument but 2 (Box::new(10) as Box).dup(); //~^ ERROR E0038 diff --git a/src/test/ui/traits/test-2.stderr b/src/test/ui/traits/test-2.stderr index 5eec012458450..77ea4e4e974eb 100644 --- a/src/test/ui/traits/test-2.stderr +++ b/src/test/ui/traits/test-2.stderr @@ -79,35 +79,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah(&self); } = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<{integer}>` = note: required by cast to type `Box` -error[E0283]: type annotations needed - --> $DIR/test-2.rs:9:8 - | -LL | 10.dup::(); - | ^^^ cannot infer type for type `{integer}` - | -note: multiple `impl`s satisfying `{integer}: bar` found - --> $DIR/test-2.rs:5:1 - | -LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ -LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ - -error[E0283]: type annotations needed - --> $DIR/test-2.rs:11:8 - | -LL | 10.blah::(); - | ^^^^ cannot infer type for type `{integer}` - | -note: multiple `impl`s satisfying `{integer}: bar` found - --> $DIR/test-2.rs:5:1 - | -LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ -LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } - | ^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0038, E0107, E0283. +Some errors have detailed explanations: E0038, E0107. For more information about an error, try `rustc --explain E0038`. From 2f46de216819cf3262af0a98a7ede764bd76b272 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 12:49:46 +0200 Subject: [PATCH 02/15] Add current_thread_unique_ptr() in std::sys_common. --- library/std/src/sys_common/thread_info.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs index 38c9e50009af5..cd570dca0ff57 100644 --- a/library/std/src/sys_common/thread_info.rs +++ b/library/std/src/sys_common/thread_info.rs @@ -30,6 +30,13 @@ impl ThreadInfo { } } +/// Get an address that is unique per running thread. +/// +/// This can be used as a non-null usize-sized ID. +pub fn current_thread_unique_ptr() -> usize { + THREAD_INFO.with(|info| <*const _>::addr(info)) +} + pub fn current_thread() -> Option { ThreadInfo::with(|info| info.thread.clone()) } From 619163e2673ba6641f88c8cc6d2a5adfd4ed5d98 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 12:50:02 +0200 Subject: [PATCH 03/15] Add futex-based ReentrantMutex on Linux. --- library/std/src/sys/unix/locks/futex.rs | 88 ++++++++++++++++++++++++- library/std/src/sys/unix/locks/mod.rs | 6 +- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs index 630351d0dc278..f49fbda0d82bd 100644 --- a/library/std/src/sys/unix/locks/futex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -1,8 +1,10 @@ +use crate::cell::UnsafeCell; use crate::sync::atomic::{ - AtomicI32, + AtomicI32, AtomicUsize, Ordering::{Acquire, Relaxed, Release}, }; use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all}; +use crate::sys_common::thread_info::current_thread_unique_ptr; use crate::time::Duration; pub type MovableMutex = Mutex; @@ -162,3 +164,87 @@ impl Condvar { r } } + +/// A reentrant mutex. Used by stdout().lock() and friends. +/// +/// The 'owner' field tracks which thread has locked the mutex. +/// +/// We use current_thread_unique_ptr() as the thread identifier, +/// which is just the address of a thread local variable. +/// +/// If `owner` is set to the identifier of the current thread, +/// we assume the mutex is already locked and instead of locking it again, +/// we increment `lock_count`. +/// +/// When unlocking, we decrement `lock_count`, and only unlock the mutex when +/// it reaches zero. +/// +/// `lock_count` is protected by the mutex and only accessed by the thread that has +/// locked the mutex, so needs no synchronization. +/// +/// `owner` can be checked by other threads that want to see if they already +/// hold the lock, so needs to be atomic. If it compares equal, we're on the +/// same thread that holds the mutex and memory access can use relaxed ordering +/// since we're not dealing with multiple threads. If it compares unequal, +/// synchronization is left to the mutex, making relaxed memory ordering for +/// the `owner` field fine in all cases. +pub struct ReentrantMutex { + mutex: Mutex, + owner: AtomicUsize, + lock_count: UnsafeCell, +} + +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + +impl ReentrantMutex { + #[inline] + pub const unsafe fn uninitialized() -> Self { + Self { mutex: Mutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0) } + } + + #[inline] + pub unsafe fn init(&self) {} + + #[inline] + pub unsafe fn destroy(&self) {} + + pub unsafe fn try_lock(&self) -> bool { + let this_thread = current_thread_unique_ptr(); + if self.owner.load(Relaxed) == this_thread { + self.increment_lock_count(); + true + } else if self.mutex.try_lock() { + self.owner.store(this_thread, Relaxed); + *self.lock_count.get() = 1; + true + } else { + false + } + } + + pub unsafe fn lock(&self) { + let this_thread = current_thread_unique_ptr(); + if self.owner.load(Relaxed) == this_thread { + self.increment_lock_count(); + } else { + self.mutex.lock(); + self.owner.store(this_thread, Relaxed); + *self.lock_count.get() = 1; + } + } + + unsafe fn increment_lock_count(&self) { + *self.lock_count.get() = (*self.lock_count.get()) + .checked_add(1) + .expect("lock count overflow in reentrant mutex"); + } + + pub unsafe fn unlock(&self) { + *self.lock_count.get() -= 1; + if *self.lock_count.get() == 0 { + self.owner.store(0, Relaxed); + self.mutex.unlock(); + } + } +} diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs index 2b8dd168068b5..e6b8438cff999 100644 --- a/library/std/src/sys/unix/locks/mod.rs +++ b/library/std/src/sys/unix/locks/mod.rs @@ -4,12 +4,8 @@ cfg_if::cfg_if! { target_os = "android", ))] { mod futex; - #[allow(dead_code)] - mod pthread_mutex; // Only used for PthreadMutexAttr, needed by pthread_remutex. - mod pthread_remutex; // FIXME: Implement this using a futex mod pthread_rwlock; // FIXME: Implement this using a futex - pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar}; - pub use pthread_remutex::ReentrantMutex; + pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar, ReentrantMutex}; pub use pthread_rwlock::{RwLock, MovableRwLock}; } else { mod pthread_mutex; From d5e0eafb7d43c33f192c2a462203ecfb1ec91b25 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 13:50:45 +0200 Subject: [PATCH 04/15] Make current_thread_unique_ptr work during thread destruction. Otherwise we can't use println!() within atexit handlers etc. --- library/std/src/sys_common/thread_info.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs index cd570dca0ff57..b8f2e658214b9 100644 --- a/library/std/src/sys_common/thread_info.rs +++ b/library/std/src/sys_common/thread_info.rs @@ -34,7 +34,9 @@ impl ThreadInfo { /// /// This can be used as a non-null usize-sized ID. pub fn current_thread_unique_ptr() -> usize { - THREAD_INFO.with(|info| <*const _>::addr(info)) + // Use a non-drop type to make sure it's still available during thread destruction. + thread_local! { static X: u8 = 0 } + X.with(|x| <*const _>::addr(x)) } pub fn current_thread() -> Option { From 6888fb1d6d68b62eda861cc0d3a7e11449c7bf77 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 22:12:47 +0200 Subject: [PATCH 05/15] Move current_thread_unique_ptr to the only module that uses it. --- library/std/src/sys/unix/locks/futex.rs | 10 +++++++++- library/std/src/sys_common/thread_info.rs | 9 --------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs index f49fbda0d82bd..1df7b53254654 100644 --- a/library/std/src/sys/unix/locks/futex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -4,7 +4,6 @@ use crate::sync::atomic::{ Ordering::{Acquire, Relaxed, Release}, }; use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all}; -use crate::sys_common::thread_info::current_thread_unique_ptr; use crate::time::Duration; pub type MovableMutex = Mutex; @@ -248,3 +247,12 @@ impl ReentrantMutex { } } } + +/// Get an address that is unique per running thread. +/// +/// This can be used as a non-null usize-sized ID. +pub fn current_thread_unique_ptr() -> usize { + // Use a non-drop type to make sure it's still available during thread destruction. + thread_local! { static X: u8 = 0 } + X.with(|x| <*const _>::addr(x)) +} diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs index b8f2e658214b9..38c9e50009af5 100644 --- a/library/std/src/sys_common/thread_info.rs +++ b/library/std/src/sys_common/thread_info.rs @@ -30,15 +30,6 @@ impl ThreadInfo { } } -/// Get an address that is unique per running thread. -/// -/// This can be used as a non-null usize-sized ID. -pub fn current_thread_unique_ptr() -> usize { - // Use a non-drop type to make sure it's still available during thread destruction. - thread_local! { static X: u8 = 0 } - X.with(|x| <*const _>::addr(x)) -} - pub fn current_thread() -> Option { ThreadInfo::with(|info| info.thread.clone()) } From dc827183cb48eae6a7fa69b85d0c804dac62531c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 22:14:43 +0200 Subject: [PATCH 06/15] Initialize thread local with const{}. --- library/std/src/sys/unix/locks/futex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs index 1df7b53254654..0c7fb098c5f63 100644 --- a/library/std/src/sys/unix/locks/futex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -253,6 +253,6 @@ impl ReentrantMutex { /// This can be used as a non-null usize-sized ID. pub fn current_thread_unique_ptr() -> usize { // Use a non-drop type to make sure it's still available during thread destruction. - thread_local! { static X: u8 = 0 } + thread_local! { static X: u8 = const { 0 } } X.with(|x| <*const _>::addr(x)) } From aeb01c319d8acc39eae72dfa6a48786031c9ab15 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 22:15:43 +0200 Subject: [PATCH 07/15] Add debug asserts to futex ReentrantMutex impl. --- library/std/src/sys/unix/locks/futex.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs index 0c7fb098c5f63..d97777e4da29d 100644 --- a/library/std/src/sys/unix/locks/futex.rs +++ b/library/std/src/sys/unix/locks/futex.rs @@ -215,6 +215,7 @@ impl ReentrantMutex { true } else if self.mutex.try_lock() { self.owner.store(this_thread, Relaxed); + debug_assert_eq!(*self.lock_count.get(), 0); *self.lock_count.get() = 1; true } else { @@ -229,6 +230,7 @@ impl ReentrantMutex { } else { self.mutex.lock(); self.owner.store(this_thread, Relaxed); + debug_assert_eq!(*self.lock_count.get(), 0); *self.lock_count.get() = 1; } } From 0664b8a6ea8d18332106b37ba46812c1fd48e2c2 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 22:22:43 +0200 Subject: [PATCH 08/15] Add #[deny(unsafe_op_in_unsafe_fn)] to thread_local!(const). This avoids 'unused unsafe' warnings when using this feature inside std. --- library/std/src/thread/local.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index a41cb02a6070d..dfd73148a4a24 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -179,6 +179,7 @@ macro_rules! __thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, const $init:expr) => {{ #[cfg_attr(not(windows), inline(always))] // see comments below + #[deny(unsafe_op_in_unsafe_fn)] unsafe fn __getit( _init: $crate::option::Option<&mut $crate::option::Option<$t>>, ) -> $crate::option::Option<&'static $t> { From 5974c18efba3bb2ed01082a6cc48c7cb954f8104 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 7 Apr 2022 09:32:02 -0300 Subject: [PATCH 09/15] [macro_metavar_expr] Add tests to ensure the feature requirement --- .../rfc-3086-metavar-expr/required-feature.rs | 35 ++++++++ .../required-feature.stderr | 83 ++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs index cff6f29a15386..b4fef11f1e29a 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs +++ b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.rs @@ -5,5 +5,40 @@ macro_rules! count { }; } +macro_rules! dollar_dollar { + () => { + macro_rules! bar { + ( $$( $$any:tt )* ) => { $$( $$any )* }; + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + } + }; +} + +macro_rules! index { + ( $( $e:stmt ),* ) => { + $( ${ignore(e)} ${index()} )* + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + }; +} + +macro_rules! ignore { + ( $( $i:stmt ),* ) => {{ + 0 $( + 1 ${ignore(i)} )* + //~^ ERROR meta-variable expressions are unstable + }}; +} + +macro_rules! length { + ( $( $e:stmt ),* ) => { + $( ${ignore(e)} ${length()} )* + //~^ ERROR meta-variable expressions are unstable + //~| ERROR meta-variable expressions are unstable + }; +} + fn main() { } diff --git a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr index f573194479314..ecf598b104d05 100644 --- a/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr +++ b/src/test/ui/macros/rfc-3086-metavar-expr/required-feature.stderr @@ -7,6 +7,87 @@ LL | ${ count(e) } = note: see issue #83527 for more information = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:16 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:20 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:39 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:11:43 + | +LL | ( $$( $$any:tt )* ) => { $$( $$any )* }; + | ^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:22:13 + | +LL | $( ${ignore(e)} ${index()} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:22:26 + | +LL | $( ${ignore(e)} ${index()} )* + | ^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:30:19 + | +LL | 0 $( + 1 ${ignore(i)} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:37:13 + | +LL | $( ${ignore(e)} ${length()} )* + | ^^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error[E0658]: meta-variable expressions are unstable + --> $DIR/required-feature.rs:37:26 + | +LL | $( ${ignore(e)} ${length()} )* + | ^^^^^^^^^^ + | + = note: see issue #83527 for more information + = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0658`. From d0cc98689e3db7841c54c0ad1104dea87f811ff5 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 5 Apr 2022 15:52:53 +0300 Subject: [PATCH 10/15] check_doc_keyword: don't alloc string for emptiness check check_doc_alias_value: get argument as Symbol to prevent needless string convertions check_doc_attrs: don't alloc vec, iterate over slice. Vec introduced in #83149, but no perf run posted on merge replace as_str() check with symbol check get_single_str_from_tts: don't prealloc string trivial string to str replace LifetimeScopeForPath::NonElided use Vec instead of Vec AssertModuleSource use BTreeSet instead of BTreeSet CrateInfo.crate_name replace FxHashMap with FxHashMap --- .../rustc_builtin_macros/src/compile_error.rs | 2 +- compiler/rustc_builtin_macros/src/env.rs | 4 +- .../rustc_builtin_macros/src/source_util.rs | 6 +- .../rustc_codegen_cranelift/src/driver/jit.rs | 4 +- compiler/rustc_codegen_ssa/src/back/link.rs | 4 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_expand/src/base.rs | 4 +- .../src/assert_module_sources.rs | 23 +++----- .../src/middle/resolve_lifetime.rs | 3 +- compiler/rustc_middle/src/mir/pretty.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 58 +++++++++---------- compiler/rustc_passes/src/stability.rs | 2 +- compiler/rustc_resolve/src/late/lifetimes.rs | 2 +- .../wrong_number_of_generic_args.rs | 2 +- 15 files changed, 56 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 990b88295690c..72397aa2500f9 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -13,7 +13,7 @@ pub fn expand_compile_error<'cx>( return DummyResult::any(sp); }; - cx.span_err(sp, &var); + cx.span_err(sp, var.as_str()); DummyResult::any(sp) } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 66ee93ce3c90e..b8828fa671a5d 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -21,8 +21,8 @@ pub fn expand_option_env<'cx>( }; let sp = cx.with_def_site_ctxt(sp); - let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern); - cx.sess.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value)); + let value = env::var(var.as_str()).ok().as_deref().map(Symbol::intern); + cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index be628c9202cbd..41871f303b0ee 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -104,7 +104,7 @@ pub fn expand_include<'cx>( return DummyResult::any(sp); }; // The file will be added to the code map by the parser - let file = match resolve_path(cx, file, sp) { + let file = match resolve_path(cx, file.as_str(), sp) { Ok(f) => f, Err(mut err) => { err.emit(); @@ -173,7 +173,7 @@ pub fn expand_include_str( let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else { return DummyResult::any(sp); }; - let file = match resolve_path(cx, file, sp) { + let file = match resolve_path(cx, file.as_str(), sp) { Ok(f) => f, Err(mut err) => { err.emit(); @@ -207,7 +207,7 @@ pub fn expand_include_bytes( let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else { return DummyResult::any(sp); }; - let file = match resolve_path(cx, file, sp) { + let file = match resolve_path(cx, file.as_str(), sp) { Ok(f) => f, Err(mut err) => { err.emit(); diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 6c22296db716d..7f15bc75fda23 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -288,8 +288,8 @@ fn load_imported_symbols_for_jit( match data[cnum.as_usize() - 1] { Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - let name = &crate_info.crate_name[&cnum]; - let mut err = sess.struct_err(&format!("Can't load static lib {}", name.as_str())); + let name = crate_info.crate_name[&cnum]; + let mut err = sess.struct_err(&format!("Can't load static lib {}", name)); err.note("rustc_codegen_cranelift can only load dylibs in JIT mode."); err.emit(); } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a727da0570449..cf32d558d4a51 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -216,7 +216,7 @@ pub fn each_linked_rlib( Some(_) => {} None => return Err("could not find formats for rlibs".to_string()), } - let name = &info.crate_name[&cnum]; + let name = info.crate_name[&cnum]; let used_crate_source = &info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.rlib { f(cnum, &path); @@ -467,7 +467,7 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( let mut all_native_libs = vec![]; let res = each_linked_rlib(&codegen_results.crate_info, &mut |cnum, path| { - let name = &codegen_results.crate_info.crate_name[&cnum]; + let name = codegen_results.crate_info.crate_name[&cnum]; let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; // Here when we include the rlib into our staticlib we need to make a diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 010560248054e..7933afb50e8ce 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -861,7 +861,7 @@ impl CrateInfo { for &cnum in crates.iter() { info.native_libraries .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect()); - info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); + info.crate_name.insert(cnum, tcx.crate_name(cnum)); info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum).clone()); if tcx.is_compiler_builtins(cnum) { info.compiler_builtins = Some(cnum); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index a2d60472ed9ed..5273b6cc83725 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -146,7 +146,7 @@ pub struct CrateInfo { pub profiler_runtime: Option, pub is_no_builtins: FxHashSet, pub native_libraries: FxHashMap>, - pub crate_name: FxHashMap, + pub crate_name: FxHashMap, pub used_libraries: Vec, pub used_crate_source: FxHashMap>, pub used_crates: Vec, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 556b2c6fbf368..6f57280abb250 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1215,7 +1215,7 @@ pub fn get_single_str_from_tts( sp: Span, tts: TokenStream, name: &str, -) -> Option { +) -> Option { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); @@ -1227,7 +1227,7 @@ pub fn get_single_str_from_tts( if p.token != token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); } - expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s.to_string()) + expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s) } /// Extracts comma-separated expressions from `tts`. diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs index 4b235213f7f5c..7569abfbb10e5 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_incremental/src/assert_module_sources.rs @@ -22,12 +22,12 @@ //! was re-used. use rustc_ast as ast; +use rustc_data_structures::stable_set::FxHashSet; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::ty::TyCtxt; use rustc_session::cgu_reuse_tracker::*; use rustc_span::symbol::{sym, Symbol}; -use std::collections::BTreeSet; #[allow(missing_docs)] pub fn assert_module_sources(tcx: TyCtxt<'_>) { @@ -36,12 +36,8 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { return; } - let available_cgus = tcx - .collect_and_partition_mono_items(()) - .1 - .iter() - .map(|cgu| cgu.name().to_string()) - .collect::>(); + let available_cgus = + tcx.collect_and_partition_mono_items(()).1.iter().map(|cgu| cgu.name()).collect(); let ams = AssertModuleSource { tcx, available_cgus }; @@ -53,7 +49,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { struct AssertModuleSource<'tcx> { tcx: TyCtxt<'tcx>, - available_cgus: BTreeSet, + available_cgus: FxHashSet, } impl<'tcx> AssertModuleSource<'tcx> { @@ -124,18 +120,17 @@ impl<'tcx> AssertModuleSource<'tcx> { debug!("mapping '{}' to cgu name '{}'", self.field(attr, sym::module), cgu_name); - if !self.available_cgus.contains(cgu_name.as_str()) { + if !self.available_cgus.contains(&cgu_name) { + let mut cgu_names: Vec<&str> = + self.available_cgus.iter().map(|cgu| cgu.as_str()).collect(); + cgu_names.sort(); self.tcx.sess.span_err( attr.span, &format!( "no module named `{}` (mangled: {}). Available modules: {}", user_path, cgu_name, - self.available_cgus - .iter() - .map(|cgu| cgu.to_string()) - .collect::>() - .join(", ") + cgu_names.join(", ") ), ); } diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 98375cbad9f9b..bc50730ab8b83 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -6,6 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::ItemLocalId; use rustc_macros::HashStable; +use rustc_span::symbol::Symbol; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum Region { @@ -23,7 +24,7 @@ pub enum Region { pub enum LifetimeScopeForPath { // Contains all lifetime names that are in scope and could possibly be used in generics // arguments of path. - NonElided(Vec), + NonElided(Vec), // Information that allows us to suggest args of the form `<'_>` in case // no generic arguments were provided for a path. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index b2dd67fb16dce..69dac03883940 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -561,8 +561,7 @@ fn write_scope_tree( } indented_decl.push(';'); - let local_name = - if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; + let local_name = if local == RETURN_PLACE { " return place" } else { "" }; writeln!( w, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1f12f99efb3d5..c45326e1e6e6c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -20,7 +20,7 @@ use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, }; use rustc_session::parse::feature_err; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::collections::hash_map::Entry; @@ -536,7 +536,7 @@ impl CheckAttrVisitor<'_> { fn check_doc_alias_value( &self, meta: &NestedMetaItem, - doc_alias: &str, + doc_alias: Symbol, hir_id: HirId, target: Target, is_list: bool, @@ -554,14 +554,17 @@ impl CheckAttrVisitor<'_> { ); false }; - if doc_alias.is_empty() { + if doc_alias == kw::Empty { return err_fn( meta.name_value_literal_span().unwrap_or_else(|| meta.span()), "attribute cannot have empty value", ); } - if let Some(c) = - doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) + + let doc_alias_str = doc_alias.as_str(); + if let Some(c) = doc_alias_str + .chars() + .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) { self.tcx.sess.span_err( meta.name_value_literal_span().unwrap_or_else(|| meta.span()), @@ -573,7 +576,7 @@ impl CheckAttrVisitor<'_> { ); return false; } - if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { + if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') { return err_fn( meta.name_value_literal_span().unwrap_or_else(|| meta.span()), "cannot start or end with ' '", @@ -608,11 +611,11 @@ impl CheckAttrVisitor<'_> { return err_fn(meta.span(), &format!("isn't allowed on {}", err)); } let item_name = self.tcx.hir().name(hir_id); - if item_name.as_str() == doc_alias { + if item_name == doc_alias { return err_fn(meta.span(), "is the same as the item's name"); } let span = meta.span(); - if let Err(entry) = aliases.try_insert(doc_alias.to_owned(), span) { + if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) { self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| { lint.build("doc alias is duplicated") .span_label(*entry.entry.get(), "first defined here") @@ -635,14 +638,7 @@ impl CheckAttrVisitor<'_> { match v.literal() { Some(l) => match l.kind { LitKind::Str(s, _) => { - if !self.check_doc_alias_value( - v, - s.as_str(), - hir_id, - target, - true, - aliases, - ) { + if !self.check_doc_alias_value(v, s, hir_id, target, true, aliases) { errors += 1; } } @@ -670,8 +666,8 @@ impl CheckAttrVisitor<'_> { } } errors == 0 - } else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) { - self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false, aliases) + } else if let Some(doc_alias) = meta.value_str() { + self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases) } else { self.tcx .sess @@ -686,8 +682,8 @@ impl CheckAttrVisitor<'_> { } fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { - let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); - if doc_keyword.is_empty() { + let doc_keyword = meta.value_str().unwrap_or(kw::Empty); + if doc_keyword == kw::Empty { self.doc_attr_str_error(meta, "keyword"); return false; } @@ -718,7 +714,7 @@ impl CheckAttrVisitor<'_> { return false; } } - if !rustc_lexer::is_ident(&doc_keyword) { + if !rustc_lexer::is_ident(doc_keyword.as_str()) { self.tcx .sess .struct_span_err( @@ -911,20 +907,20 @@ impl CheckAttrVisitor<'_> { ) -> bool { let mut is_valid = true; - if let Some(list) = attr.meta().and_then(|mi| mi.meta_item_list().map(|l| l.to_vec())) { - for meta in &list { + if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() { + for meta in list { if let Some(i_meta) = meta.meta_item() { match i_meta.name_or_empty() { sym::alias - if !self.check_attr_not_crate_level(&meta, hir_id, "alias") - || !self.check_doc_alias(&meta, hir_id, target, aliases) => + if !self.check_attr_not_crate_level(meta, hir_id, "alias") + || !self.check_doc_alias(meta, hir_id, target, aliases) => { is_valid = false } sym::keyword - if !self.check_attr_not_crate_level(&meta, hir_id, "keyword") - || !self.check_doc_keyword(&meta, hir_id) => + if !self.check_attr_not_crate_level(meta, hir_id, "keyword") + || !self.check_doc_keyword(meta, hir_id) => { is_valid = false } @@ -936,15 +932,15 @@ impl CheckAttrVisitor<'_> { | sym::html_root_url | sym::html_no_source | sym::test - if !self.check_attr_crate_level(&attr, &meta, hir_id) => + if !self.check_attr_crate_level(attr, meta, hir_id) => { is_valid = false; } sym::inline | sym::no_inline if !self.check_doc_inline( - &attr, - &meta, + attr, + meta, hir_id, target, specified_inline, @@ -976,7 +972,7 @@ impl CheckAttrVisitor<'_> { | sym::plugins => {} sym::test => { - if !self.check_test_attr(&meta, hir_id) { + if !self.check_test_attr(meta, hir_id) { is_valid = false; } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 84b4a803403f9..ff033cbb57299 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -696,7 +696,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { hir::ItemKind::ExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. // `std` is still checked for the `restricted-std` feature. - if item.span.is_dummy() && item.ident.as_str() != "std" { + if item.span.is_dummy() && item.ident.name != sym::std { return; } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index afb19d7df9fce..1460b5efbb058 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -587,7 +587,7 @@ fn get_lifetime_scopes_for_path(mut scope: &Scope<'_>) -> LifetimeScopeForPath { match scope { Scope::Binder { lifetimes, s, .. } => { available_lifetimes.extend(lifetimes.keys().filter_map(|p| match p { - hir::ParamName::Plain(ident) => Some(ident.name.to_string()), + hir::ParamName::Plain(ident) => Some(ident.name), _ => None, })); scope = s; diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 24b6639d7f275..1b1a2037d9eaa 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { param_names .iter() .take(num_params_to_take) - .map(|p| (*p).clone()) + .map(|p| p.as_str()) .collect::>() .join(", ") } else { From 43d0497824d3d1a6f0b15d865a00715537673af2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 8 Apr 2022 15:30:37 +0200 Subject: [PATCH 11/15] Fix invalid array access in `beautify_doc_string` --- compiler/rustc_ast/src/util/comments.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs index f51b0086dc8b6..8730aeb0f3bff 100644 --- a/compiler/rustc_ast/src/util/comments.rs +++ b/compiler/rustc_ast/src/util/comments.rs @@ -52,7 +52,10 @@ pub fn beautify_doc_string(data: Symbol, kind: CommentKind) -> Symbol { // when we try to compute the "horizontal trim". let lines = if kind == CommentKind::Block { // Whatever happens, we skip the first line. - let mut i = if lines[0].trim_start().starts_with('*') { 0 } else { 1 }; + let mut i = lines + .get(0) + .map(|l| if l.trim_start().starts_with('*') { 0 } else { 1 }) + .unwrap_or(0); let mut j = lines.len(); while i < j && lines[i].trim().is_empty() { From 5e8bd9bbaaaa842e96a3ddef3a75208d0c96ffe7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 8 Apr 2022 15:30:53 +0200 Subject: [PATCH 12/15] Add test for empty doc comments with a backline --- src/test/rustdoc/empty-doc-comment.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/rustdoc/empty-doc-comment.rs diff --git a/src/test/rustdoc/empty-doc-comment.rs b/src/test/rustdoc/empty-doc-comment.rs new file mode 100644 index 0000000000000..b1dae930e066b --- /dev/null +++ b/src/test/rustdoc/empty-doc-comment.rs @@ -0,0 +1,22 @@ +// Ensure that empty doc comments don't panic. + +/*! +*/ + +/// +/// +pub struct Foo; + +#[doc = " +"] +pub mod Mod { + //! + //! +} + +/** +*/ +pub mod Another { + #![doc = " +"] +} From 1040cab53b95aa47c2ea8e1a6de73eddadc57aa7 Mon Sep 17 00:00:00 2001 From: Aria Beingessner Date: Mon, 21 Mar 2022 19:25:44 -0400 Subject: [PATCH 13/15] WIP PROOF-OF-CONCEPT: Make the compiler complain about all int<->ptr casts. ALL OF THEM --- compiler/rustc_lint_defs/src/builtin.rs | 36 ++++++++++++++ compiler/rustc_typeck/src/check/cast.rs | 64 +++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5704c6ed3b25d..f9ac0a54a2f34 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2648,6 +2648,41 @@ declare_lint! { }; } +declare_lint! { + /// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer + /// and a pointer. + /// + /// ### Example + /// + /// fn main() { + /// let my_ref = &0; + /// let my_addr = my_ref as usize; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Casting a pointer to an integer or an integer to a pointer is a lossy operation, + /// because beyond just an *address* a pointer may be associated with a particular + /// *provenance* and *segment*. This information is required by both the compiler + /// and the hardware to correctly execute your code. If you need to do this kind + /// of operation, use ptr::addr and ptr::with_addr. + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #9999999] for more details. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + /// [issue #9999999]: https://github.com/rust-lang/rust/issues/9999999 + pub FUZZY_PROVENANCE_CASTS, + Warn, + "A lossy pointer-integer integer cast is used", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #9999999 ", + }; +} + declare_lint! { /// The `const_evaluatable_unchecked` lint detects a generic constant used /// in a type. @@ -3101,6 +3136,7 @@ declare_lint_pass! { UNSAFE_OP_IN_UNSAFE_FN, INCOMPLETE_INCLUDE, CENUM_IMPL_DROP_CAST, + FUZZY_PROVENANCE_CASTS, CONST_EVALUATABLE_UNCHECKED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, MUST_NOT_SUSPEND, diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7ce428ea12466..9b67fd54bd66f 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -807,11 +807,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { // ptr -> * (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast - (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast - (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast), - // * -> ptr - (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast + // ptr-addr-cast + (Ptr(m_expr), Int(_)) => { + self.fuzzy_provenance_ptr2int_lint(fcx, t_from); + self.check_ptr_addr_cast(fcx, m_expr) + } + (FnPtr, Int(_)) => { + self.fuzzy_provenance_ptr2int_lint(fcx, t_from); + Ok(CastKind::FnPtrAddrCast) + } + // addr-ptr-cast + (Int(_), Ptr(mt)) => { + self.fuzzy_provenance_int2ptr_lint(fcx); + self.check_addr_ptr_cast(fcx, mt) + } + // fn-ptr-cast (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt), // prim -> prim @@ -934,6 +945,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'tcx>, m_cast: TypeAndMut<'tcx>, ) -> Result { + self.fuzzy_provenance_int2ptr_lint(fcx); // ptr-addr cast. pointer must be thin. match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), @@ -973,6 +985,50 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } } + + fn fuzzy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_from: CastTy<'tcx>) { + fcx.tcx.struct_span_lint_hir( + lint::builtin::FUZZY_PROVENANCE_CASTS, + self.expr.hir_id, + self.span, + |err| { + let mut err = err.build(&format!( + "strict provenance disallows casting pointer `{}` to integer `{}`", + self.expr_ty, self.cast_ty + )); + + if let CastTy::FnPtr = t_from { + err.help( + "use `(... as *const u8).addr()` to obtain \ + the address of a function pointer", + ); + } else { + err.help("use `.addr()` to obtain the address of a pointer"); + } + + err.emit(); + }, + ); + } + + fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { + fcx.tcx.struct_span_lint_hir( + lint::builtin::FUZZY_PROVENANCE_CASTS, + self.expr.hir_id, + self.span, + |err| { + err.build(&format!( + "strict provenance disallows casting integer `{}` to pointer `{}`", + self.expr_ty, self.cast_ty + )) + .help( + "use `.with_addr(...)` to adjust a valid pointer \ + in the same allocation, to this address", + ) + .emit(); + }, + ); + } } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { From 98a483423720bda1f51a22f01b378fa8e8e8b9a3 Mon Sep 17 00:00:00 2001 From: niluxv Date: Sat, 2 Apr 2022 21:07:00 +0200 Subject: [PATCH 14/15] Split `fuzzy_provenance_casts` into lossy and fuzzy, feature gate and test it * split `fuzzy_provenance_casts` into a ptr2int and a int2ptr lint * feature gate both lints * update documentation to be more realistic short term * add tests for these lints --- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_lint_defs/src/builtin.rs | 88 +++++++++++++++---- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/cast.rs | 61 +++++++++---- .../language-features/strict-provenance.md | 22 +++++ .../feature-gate-strict_provenance.rs | 19 ++++ .../feature-gate-strict_provenance.stderr | 63 +++++++++++++ .../lint-strict-provenance-fuzzy-casts.rs | 7 ++ .../lint-strict-provenance-fuzzy-casts.stderr | 19 ++++ .../lint-strict-provenance-lossy-casts.rs | 11 +++ .../lint-strict-provenance-lossy-casts.stderr | 23 +++++ 11 files changed, 281 insertions(+), 35 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/strict-provenance.md create mode 100644 src/test/ui/feature-gates/feature-gate-strict_provenance.rs create mode 100644 src/test/ui/feature-gates/feature-gate-strict_provenance.stderr create mode 100644 src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs create mode 100644 src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr create mode 100644 src/test/ui/lint/lint-strict-provenance-lossy-casts.rs create mode 100644 src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 28466315c8687..8340a0b360ef7 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -505,6 +505,8 @@ declare_features! ( (active, static_nobundle, "1.16.0", Some(37403), None), /// Allows attributes on expressions and non-item statements. (active, stmt_expr_attributes, "1.6.0", Some(15701), None), + /// Allows lints part of the strict provenance effort. + (active, strict_provenance, "1.61.0", Some(95228), None), /// Allows the use of `#[target_feature]` on safe functions. (active, target_feature_11, "1.45.0", Some(69098), None), /// Allows using `#[thread_local]` on `static` items. diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index f9ac0a54a2f34..89ce307d12cd7 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2654,9 +2654,12 @@ declare_lint! { /// /// ### Example /// + /// ```rust + /// #![feature(strict_provenance)] + /// #![warn(fuzzy_provenance_casts)] + /// /// fn main() { - /// let my_ref = &0; - /// let my_addr = my_ref as usize; + /// let _dangling = 16_usize as *const u8; /// } /// ``` /// @@ -2664,23 +2667,75 @@ declare_lint! { /// /// ### Explanation /// - /// Casting a pointer to an integer or an integer to a pointer is a lossy operation, - /// because beyond just an *address* a pointer may be associated with a particular - /// *provenance* and *segment*. This information is required by both the compiler - /// and the hardware to correctly execute your code. If you need to do this kind - /// of operation, use ptr::addr and ptr::with_addr. + /// This lint is part of the strict provenance effort, see [issue #95228]. + /// Casting an integer to a pointer is considered bad style, as a pointer + /// contains, besides the *address* also a *provenance*, indicating what + /// memory the pointer is allowed to read/write. Casting an integer, which + /// doesn't have provenance, to a pointer requires the compiler to assign + /// (guess) provenance. The compiler assigns "all exposed valid" (see the + /// docs of [`ptr::from_exposed_addr`] for more information about this + /// "exposing"). This penalizes the optimiser and is not well suited for + /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI + /// platforms). /// - /// This is a [future-incompatible] lint to transition this to a hard error - /// in the future. See [issue #9999999] for more details. + /// It is much better to use [`ptr::with_addr`] instead to specify the + /// provenance you want. If using this function is not possible because the + /// code relies on exposed provenance then there is as an escape hatch + /// [`ptr::from_exposed_addr`]. /// - /// [future-incompatible]: ../index.md#future-incompatible-lints - /// [issue #9999999]: https://github.com/rust-lang/rust/issues/9999999 + /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 + /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/ptr/fn.with_addr + /// [`ptr::from_exposed_addr`]: https://doc.rust-lang.org/core/ptr/fn.from_exposed_addr pub FUZZY_PROVENANCE_CASTS, - Warn, - "A lossy pointer-integer integer cast is used", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #9999999 ", - }; + Allow, + "a fuzzy integer to pointer cast is used", + @feature_gate = sym::strict_provenance; +} + +declare_lint! { + /// The `lossy_provenance_casts` lint detects an `as` cast between a pointer + /// and an integer. + /// + /// ### Example + /// + /// ```rust + /// #![feature(strict_provenance)] + /// #![warn(lossy_provenance_casts)] + /// + /// fn main() { + /// let x: u8 = 37; + /// let _addr: usize = &x as *const u8 as usize; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is part of the strict provenance effort, see [issue #95228]. + /// Casting a pointer to an integer is a lossy operation, because beyond + /// just an *address* a pointer may be associated with a particular + /// *provenance*. This information is used by the optimiser and for dynamic + /// analysis/dynamic program verification (e.g. Miri or CHERI platforms). + /// + /// Since this cast is lossy, it is considered good style to use the + /// [`ptr::addr`] method instead, which has a similar effect, but doesn't + /// "expose" the pointer provenance. This improves optimisation potential. + /// See the docs of [`ptr::addr`] and [`ptr::expose_addr`] for more information + /// about exposing pointer provenance. + /// + /// If your code can't comply with strict provenance and needs to expose + /// the provenance, then there is [`ptr::expose_addr`] as an escape hatch, + /// which preserves the behaviour of `as usize` casts while being explicit + /// about the semantics. + /// + /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228 + /// [`ptr::addr`]: https://doc.rust-lang.org/core/ptr/fn.addr + /// [`ptr::expose_addr`]: https://doc.rust-lang.org/core/ptr/fn.expose_addr + pub LOSSY_PROVENANCE_CASTS, + Allow, + "a lossy pointer to integer cast is used", + @feature_gate = sym::strict_provenance; } declare_lint! { @@ -3137,6 +3192,7 @@ declare_lint_pass! { INCOMPLETE_INCLUDE, CENUM_IMPL_DROP_CAST, FUZZY_PROVENANCE_CASTS, + LOSSY_PROVENANCE_CASTS, CONST_EVALUATABLE_UNCHECKED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, MUST_NOT_SUSPEND, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f5803aaa0786e..dc4d10f699c75 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1348,6 +1348,7 @@ symbols! { str_trim, str_trim_end, str_trim_start, + strict_provenance, stringify, stringify_macro, struct_field_attributes, diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 9b67fd54bd66f..6091b8fee00b6 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -809,12 +809,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast // ptr-addr-cast - (Ptr(m_expr), Int(_)) => { - self.fuzzy_provenance_ptr2int_lint(fcx, t_from); + (Ptr(m_expr), Int(t_c)) => { + self.lossy_provenance_ptr2int_lint(fcx, t_c); self.check_ptr_addr_cast(fcx, m_expr) } (FnPtr, Int(_)) => { - self.fuzzy_provenance_ptr2int_lint(fcx, t_from); + // FIXME(#95489): there should eventually be a lint for these casts Ok(CastKind::FnPtrAddrCast) } // addr-ptr-cast @@ -945,7 +945,6 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx: &FnCtxt<'a, 'tcx>, m_cast: TypeAndMut<'tcx>, ) -> Result { - self.fuzzy_provenance_int2ptr_lint(fcx); // ptr-addr cast. pointer must be thin. match fcx.pointer_kind(m_cast.ty, self.span)? { None => Err(CastError::UnknownCastPtrKind), @@ -986,25 +985,36 @@ impl<'a, 'tcx> CastCheck<'tcx> { } } - fn fuzzy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_from: CastTy<'tcx>) { + fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::IntTy) { fcx.tcx.struct_span_lint_hir( - lint::builtin::FUZZY_PROVENANCE_CASTS, + lint::builtin::LOSSY_PROVENANCE_CASTS, self.expr.hir_id, self.span, |err| { let mut err = err.build(&format!( - "strict provenance disallows casting pointer `{}` to integer `{}`", + "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`", self.expr_ty, self.cast_ty )); - if let CastTy::FnPtr = t_from { - err.help( - "use `(... as *const u8).addr()` to obtain \ - the address of a function pointer", + let msg = "use `.addr()` to obtain the address of a pointer"; + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + let scalar_cast = match t_c { + ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(), + _ => format!(" as {}", self.cast_ty), + }; + err.span_suggestion( + self.span, + msg, + format!("({}).addr(){}", snippet, scalar_cast), + Applicability::MaybeIncorrect ); } else { - err.help("use `.addr()` to obtain the address of a pointer"); + err.help(msg); } + err.help( + "if you can't comply with strict provenance and need to expose the pointer\ + provenance you can use `.expose_addr()` instead" + ); err.emit(); }, @@ -1017,15 +1027,28 @@ impl<'a, 'tcx> CastCheck<'tcx> { self.expr.hir_id, self.span, |err| { - err.build(&format!( + + let mut err = err.build(&format!( "strict provenance disallows casting integer `{}` to pointer `{}`", self.expr_ty, self.cast_ty - )) - .help( - "use `.with_addr(...)` to adjust a valid pointer \ - in the same allocation, to this address", - ) - .emit(); + )); + let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address"; + if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) { + err.span_suggestion( + self.span, + msg, + format!("(...).with_addr({})", snippet), + Applicability::HasPlaceholders, + ); + } else { + err.help(msg); + } + err.help( + "if you can't comply with strict provenance and don't have a pointer with \ + the correct provenance you can use `std::ptr::from_exposed_addr()` instead" + ); + + err.emit(); }, ); } diff --git a/src/doc/unstable-book/src/language-features/strict-provenance.md b/src/doc/unstable-book/src/language-features/strict-provenance.md new file mode 100644 index 0000000000000..dc60f3f375d3c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/strict-provenance.md @@ -0,0 +1,22 @@ +# `strict_provenance` + +The tracking issue for this feature is: [#95228] + +[#95228]: https://github.com/rust-lang/rust/issues/95228 +----- + +The `strict_provenance` feature allows to enable the `fuzzy_provenance_casts` and `lossy_provenance_casts` lints. +These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model. +The same feature gate is also used for the experimental strict provenance API in `std` (actually `core`). + +## Example + +```rust +#![feature(strict_provenance)] +#![warn(fuzzy_provenance_casts)] + +fn main() { + let _dangling = 16_usize as *const u8; + //~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8` +} +``` diff --git a/src/test/ui/feature-gates/feature-gate-strict_provenance.rs b/src/test/ui/feature-gates/feature-gate-strict_provenance.rs new file mode 100644 index 0000000000000..75d0ee5700d07 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-strict_provenance.rs @@ -0,0 +1,19 @@ +// check-pass + +#![deny(fuzzy_provenance_casts)] +//~^ WARNING unknown lint: `fuzzy_provenance_casts` +//~| WARNING unknown lint: `fuzzy_provenance_casts` +//~| WARNING unknown lint: `fuzzy_provenance_casts` +#![deny(lossy_provenance_casts)] +//~^ WARNING unknown lint: `lossy_provenance_casts` +//~| WARNING unknown lint: `lossy_provenance_casts` +//~| WARNING unknown lint: `lossy_provenance_casts` + +fn main() { + // no warnings emitted since the lints are not activated + + let _dangling = 16_usize as *const u8; + + let x: u8 = 37; + let _addr: usize = &x as *const u8 as usize; +} diff --git a/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr b/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr new file mode 100644 index 0000000000000..34bd240c304a7 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-strict_provenance.stderr @@ -0,0 +1,63 @@ +warning: unknown lint: `fuzzy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:3:1 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unknown_lints)]` on by default + = note: the `fuzzy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `lossy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:7:1 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `lossy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `fuzzy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:3:1 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `fuzzy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `lossy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:7:1 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `lossy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `fuzzy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:3:1 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `fuzzy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: unknown lint: `lossy_provenance_casts` + --> $DIR/feature-gate-strict_provenance.rs:7:1 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the `lossy_provenance_casts` lint is unstable + = note: see issue #95228 for more information + = help: add `#![feature(strict_provenance)]` to the crate attributes to enable + +warning: 6 warnings emitted + diff --git a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs new file mode 100644 index 0000000000000..d2d72a68f1396 --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.rs @@ -0,0 +1,7 @@ +#![feature(strict_provenance)] +#![deny(fuzzy_provenance_casts)] + +fn main() { + let dangling = 16_usize as *const u8; + //~^ ERROR strict provenance disallows casting integer `usize` to pointer `*const u8` +} diff --git a/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr new file mode 100644 index 0000000000000..e50d243b6ad6d --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-fuzzy-casts.stderr @@ -0,0 +1,19 @@ +error: strict provenance disallows casting integer `usize` to pointer `*const u8` + --> $DIR/lint-strict-provenance-fuzzy-casts.rs:5:20 + | +LL | let dangling = 16_usize as *const u8; + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/lint-strict-provenance-fuzzy-casts.rs:2:9 + | +LL | #![deny(fuzzy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: if you can't comply with strict provenance and don't have a pointer with the correct provenance you can use `std::ptr::from_exposed_addr()` instead +help: use `.with_addr()` to adjust a valid pointer in the same allocation, to this address + | +LL | let dangling = (...).with_addr(16_usize); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs new file mode 100644 index 0000000000000..3690fbc904d99 --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.rs @@ -0,0 +1,11 @@ +#![feature(strict_provenance)] +#![deny(lossy_provenance_casts)] + +fn main() { + let x: u8 = 37; + let addr: usize = &x as *const u8 as usize; + //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` + + let addr_32bit = &x as *const u8 as u32; + //~^ ERROR under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` +} diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr new file mode 100644 index 0000000000000..489cb03ddd316 --- /dev/null +++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr @@ -0,0 +1,23 @@ +error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `usize` + --> $DIR/lint-strict-provenance-lossy-casts.rs:6:23 + | +LL | let addr: usize = &x as *const u8 as usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr()` + | +note: the lint level is defined here + --> $DIR/lint-strict-provenance-lossy-casts.rs:2:9 + | +LL | #![deny(lossy_provenance_casts)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + +error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` + --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22 + | +LL | let addr_32bit = &x as *const u8 as u32; + | ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32` + | + = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + +error: aborting due to 2 previous errors + From f6c7f109f8efa12d891b6c37baca5a3dec4e1b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20BRANSTETT?= Date: Fri, 8 Apr 2022 17:33:40 +0200 Subject: [PATCH 15/15] Remove extra space before a where clause in the documentation --- src/librustdoc/html/format.rs | 3 ++- src/test/rustdoc/where.SWhere_Simd_item-decl.html | 1 + .../rustdoc/where.SWhere_TraitWhere_item-decl.html | 3 +++ src/test/rustdoc/where.rs | 13 +++++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/where.SWhere_Simd_item-decl.html create mode 100644 src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 5c59609d5b8c6..228976cb171b5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -371,7 +371,8 @@ crate fn print_where_clause<'a, 'tcx: 'a>( clause = clause.replace("
", &format!("
{}", padding)); clause.insert_str(0, &" ".repeat(indent.saturating_sub(1))); if !end_newline { - clause.insert_str(0, "
"); + // we insert the
after a single space but before multiple spaces at the start + clause.insert_str(if indent == 0 { 1 } else { 0 }, "
"); } } write!(f, "{}", clause) diff --git a/src/test/rustdoc/where.SWhere_Simd_item-decl.html b/src/test/rustdoc/where.SWhere_Simd_item-decl.html new file mode 100644 index 0000000000000..d941ad7de4c48 --- /dev/null +++ b/src/test/rustdoc/where.SWhere_Simd_item-decl.html @@ -0,0 +1 @@ +
pub struct Simd<T, const LANES: usize>(_) 
where
    T: Sized
;
\ No newline at end of file diff --git a/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html new file mode 100644 index 0000000000000..54026ff034e00 --- /dev/null +++ b/src/test/rustdoc/where.SWhere_TraitWhere_item-decl.html @@ -0,0 +1,3 @@ +
pub trait TraitWhere {
+    type Item<'a>
    where
        Self: 'a
; +}
\ No newline at end of file diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 549cfff96cb6d..73c75fdb61bcd 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -1,3 +1,4 @@ +#![feature(generic_associated_types)] #![crate_name = "foo"] pub trait MyTrait { fn dummy(&self) { } } @@ -19,6 +20,18 @@ impl Delta where D: MyTrait { pub struct Echo(E); +// @has 'foo/struct.Simd.html' +// @snapshot SWhere_Simd_item-decl - '//div[@class="docblock item-decl"]' +pub struct Simd([T; LANES]) +where + T: Sized; + +// @has 'foo/trait.TraitWhere.html' +// @snapshot SWhere_TraitWhere_item-decl - '//div[@class="docblock item-decl"]' +pub trait TraitWhere { + type Item<'a> where Self: 'a; +} + // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ // "impl MyTrait for Echo where E: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \