From 99182dd8058f0a1153b8b7fcf873028caa6fbfa7 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 6 Oct 2022 22:46:15 +0200 Subject: [PATCH 01/21] std: use semaphore for thread parking on Apple platforms --- .../std/src/sys/unix/thread_parker/darwin.rs | 131 ++++++++++++++++++ library/std/src/sys/unix/thread_parker/mod.rs | 10 +- 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 library/std/src/sys/unix/thread_parker/darwin.rs diff --git a/library/std/src/sys/unix/thread_parker/darwin.rs b/library/std/src/sys/unix/thread_parker/darwin.rs new file mode 100644 index 0000000000000..510839d5dafbf --- /dev/null +++ b/library/std/src/sys/unix/thread_parker/darwin.rs @@ -0,0 +1,131 @@ +//! Thread parking for Darwin-based systems. +//! +//! Darwin actually has futex syscalls (`__ulock_wait`/`__ulock_wake`), but they +//! cannot be used in `std` because they are non-public (their use will lead to +//! rejection from the App Store) and because they are only available starting +//! with macOS version 10.12, even though the minimum target version is 10.7. +//! +//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin +//! supports semaphores, which allow us to implement the behaviour we need with +//! only one primitive (as opposed to a mutex-condvar pair). We use the semaphore +//! provided by libdispatch, as the underlying Mach semaphore is only dubiously +//! public. + +use crate::pin::Pin; +use crate::sync::atomic::{ + AtomicI8, + Ordering::{Acquire, Release}, +}; +use crate::time::Duration; + +type dispatch_semaphore_t = *mut crate::ffi::c_void; +type dispatch_time_t = u64; + +const DISPATCH_TIME_NOW: dispatch_time_t = 0; +const DISPATCH_TIME_FOREVER: dispatch_time_t = !0; + +#[link(name = "System", kind = "dylib")] +extern "C" { + fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t; + fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t; + fn dispatch_semaphore_wait(dsema: dispatch_semaphore_t, timeout: dispatch_time_t) -> isize; + fn dispatch_semaphore_signal(dsema: dispatch_semaphore_t) -> isize; + fn dispatch_release(object: *mut crate::ffi::c_void); +} + +const EMPTY: i8 = 0; +const NOTIFIED: i8 = 1; +const PARKED: i8 = -1; + +pub struct Parker { + semaphore: dispatch_semaphore_t, + state: AtomicI8, +} + +unsafe impl Sync for Parker {} +unsafe impl Send for Parker {} + +impl Parker { + pub unsafe fn new(parker: *mut Parker) { + let semaphore = dispatch_semaphore_create(0); + assert!( + !semaphore.is_null(), + "failed to create dispatch semaphore for thread synchronization" + ); + parker.write(Parker { semaphore, state: AtomicI8::new(EMPTY) }) + } + + // Does not need `Pin`, but other implementation do. + pub unsafe fn park(self: Pin<&Self>) { + // The semaphore counter must be zero at this point, because unparking + // threads will not actually increase it until we signalled that we + // are waiting. + + // Change NOTIFIED to EMPTY and EMPTY to PARKED. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + // Another thread may increase the semaphore counter from this point on. + // If it is faster than us, we will decrement it again immediately below. + // If we are faster, we wait. + + // Ensure that the semaphore counter has actually been decremented, even + // if the call timed out for some reason. + while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {} + + // At this point, the semaphore counter is zero again. + + // We were definitely woken up, so we don't need to check the state. + // Still, we need to reset the state using a swap to observe the state + // change with acquire ordering. + self.state.swap(EMPTY, Acquire); + } + + // Does not need `Pin`, but other implementation do. + pub unsafe fn park_timeout(self: Pin<&Self>, dur: Duration) { + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + + let nanos = dur.as_nanos().try_into().unwrap_or(i64::MAX); + let timeout = dispatch_time(DISPATCH_TIME_NOW, nanos); + + let timeout = dispatch_semaphore_wait(self.semaphore, timeout) != 0; + + let state = self.state.swap(EMPTY, Acquire); + if state == NOTIFIED && timeout { + // If the state was NOTIFIED but semaphore_wait returned without + // decrementing the count because of a timeout, it means another + // thread is about to call semaphore_signal. We must wait for that + // to happen to ensure the semaphore count is reset. + while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {} + } else { + // Either a timeout occurred and we reset the state before any thread + // tried to wake us up, or we were woken up and reset the state, + // making sure to observe the state change with acquire ordering. + // Either way, the semaphore counter is now zero again. + } + } + + // Does not need `Pin`, but other implementation do. + pub fn unpark(self: Pin<&Self>) { + let state = self.state.swap(NOTIFIED, Release); + if state == PARKED { + unsafe { + dispatch_semaphore_signal(self.semaphore); + } + } + } +} + +impl Drop for Parker { + fn drop(&mut self) { + // SAFETY: + // We always ensure that the semaphore count is reset, so this will + // never cause an exception. + unsafe { + dispatch_release(self.semaphore); + } + } +} diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs index e2453580dc72a..724ec2d482edb 100644 --- a/library/std/src/sys/unix/thread_parker/mod.rs +++ b/library/std/src/sys/unix/thread_parker/mod.rs @@ -11,7 +11,15 @@ )))] cfg_if::cfg_if! { - if #[cfg(target_os = "netbsd")] { + if #[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ))] { + mod darwin; + pub use darwin::Parker; + } else if #[cfg(target_os = "netbsd")] { mod netbsd; pub use netbsd::Parker; } else { From 0ad4dd494a67a0fffc5a3e4df08f0c26cf074c59 Mon Sep 17 00:00:00 2001 From: joboet Date: Thu, 6 Oct 2022 22:46:47 +0200 Subject: [PATCH 02/21] std: add thread parking tests --- library/std/src/thread/tests.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 130e47c8d44f0..dfb8765ab4eed 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -244,6 +244,28 @@ fn test_try_panic_any_message_unit_struct() { } } +#[test] +fn test_park_unpark_before() { + for _ in 0..10 { + thread::current().unpark(); + thread::park(); + } +} + +#[test] +fn test_park_unpark_called_other_thread() { + for _ in 0..10 { + let th = thread::current(); + + let _guard = thread::spawn(move || { + super::sleep(Duration::from_millis(50)); + th.unpark(); + }); + + thread::park(); + } +} + #[test] fn test_park_timeout_unpark_before() { for _ in 0..10 { From bf135de3bc451573e9f84703cf9dda2e669bb2a7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 13:57:32 +1100 Subject: [PATCH 03/21] Clean up rustdoc startup. rustc's startup has several layers, including: - `interface::run_compiler` passes a closure, `f`, to `run_in_thread_pool_with_globals`, which creates a thread pool, sets up session globals, and passes `f` to `create_compiler_and_run`. - `create_compiler_and_run` creates a `Session`, a `Compiler`, sets the source map, and calls `f`. rustdoc is a bit different. - `main_args` calls `main_options` via `run_in_thread_pool_with_globals`, which (again) creates a thread pool (hardcoded to a single thread!) and sets up session globals. - `main_options` has four different paths. - The second one calls `interface::run_compiler`, which redoes the `run_in_thread_pool_with_globals`! This is bad. - The fourth one calls `interface::create_compiler_and_run`, which is reasonable. - The first and third ones don't do anything of note involving the above functions, except for some symbol interning which requires session globals. In other words, rustdoc calls into `rustc_interface` at three different levels. It's a bit confused, and feels like code where functionality has been added by different people at different times without fully understanding how the globally accessible stuff is set up. This commit tidies things up. It removes the `run_in_thread_pool_with_globals` call in `main_args`, and adjust the four paths in `main_options` as follows. - `markdown::test` calls `test::test_main`, which provides its own parallelism and so doesn't need a thread pool. It had one small use of symbol interning, which required session globals, but the commit removes this. - `doctest::run` already calls `interface::run_compiler`, so it doesn't need further adjustment. - `markdown::render` is simple but needs session globals for interning (which can't easily be removed), so it's now wrapped in `create_session_globals_then`. - The fourth path now uses `interface::run_compiler`, which is equivalent to the old `run_in_thread_pool_with_globals` + `create_compiler_and_run` pairing. --- src/librustdoc/doctest.rs | 9 ++++----- src/librustdoc/lib.rs | 14 +++++++------- src/librustdoc/markdown.rs | 5 +++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f4ec60735a8dd..d9160e8abd4e3 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -18,7 +18,6 @@ use rustc_session::{lint, DiagnosticOutput, Session}; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; -use rustc_span::Symbol; use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP}; use rustc_target::spec::TargetTriple; use tempfile::Builder as TempFileBuilder; @@ -125,7 +124,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> { let opts = scrape_test_config(crate_attrs); let enable_per_target_ignores = options.enable_per_target_ignores; let mut collector = Collector::new( - tcx.crate_name(LOCAL_CRATE), + tcx.crate_name(LOCAL_CRATE).to_string(), options, false, opts, @@ -909,7 +908,7 @@ pub(crate) struct Collector { rustdoc_options: RustdocOptions, use_headers: bool, enable_per_target_ignores: bool, - crate_name: Symbol, + crate_name: String, opts: GlobalTestOptions, position: Span, source_map: Option>, @@ -921,7 +920,7 @@ pub(crate) struct Collector { impl Collector { pub(crate) fn new( - crate_name: Symbol, + crate_name: String, rustdoc_options: RustdocOptions, use_headers: bool, opts: GlobalTestOptions, @@ -984,7 +983,7 @@ impl Tester for Collector { fn add_test(&mut self, test: String, config: LangString, line: usize) { let filename = self.get_filename(); let name = self.generate_name(line, &filename); - let crate_name = self.crate_name.to_string(); + let crate_name = self.crate_name.clone(); let opts = self.opts.clone(); let edition = config.edition.unwrap_or(self.rustdoc_options.edition); let rustdoc_options = self.rustdoc_options.clone(); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ef01b854e5a69..ce6f7e817c620 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -700,11 +700,7 @@ fn main_args(at_args: &[String]) -> MainResult { }; } }; - rustc_interface::util::run_in_thread_pool_with_globals( - options.edition, - 1, // this runs single-threaded, even in a parallel compiler - move || main_options(options), - ) + main_options(options) } fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult { @@ -749,9 +745,12 @@ fn main_options(options: config::Options) -> MainResult { (true, true) => return wrap_return(&diag, markdown::test(options)), (true, false) => return doctest::run(options), (false, true) => { + // Session globals are required for symbol interning. return wrap_return( &diag, - markdown::render(&options.input, options.render_options, options.edition), + rustc_span::create_session_globals_then(options.edition, || { + markdown::render(&options.input, options.render_options, options.edition) + }), ); } (false, false) => {} @@ -777,9 +776,10 @@ fn main_options(options: config::Options) -> MainResult { let render_options = options.render_options.clone(); let scrape_examples_options = options.scrape_examples_options.clone(); let document_private = options.render_options.document_private; + let config = core::create_config(options); - interface::create_compiler_and_run(config, |compiler| { + interface::run_compiler(config, |compiler| { let sess = compiler.session(); if sess.opts.describe_lints { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 0b557ef244e94..eb64ac455dc4c 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -5,7 +5,6 @@ use std::path::Path; use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; -use rustc_span::Symbol; use crate::config::{Options, RenderOptions}; use crate::doctest::{Collector, GlobalTestOptions}; @@ -36,6 +35,8 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { /// Render `input` (e.g., "foo.md") into an HTML file in `output` /// (e.g., output = "bar" => "bar/foo.html"). +/// +/// Requires session globals to be available, for symbol interning. pub(crate) fn render>( input: P, options: RenderOptions, @@ -133,7 +134,7 @@ pub(crate) fn test(options: Options) -> Result<(), String> { let mut opts = GlobalTestOptions::default(); opts.no_crate_inject = true; let mut collector = Collector::new( - Symbol::intern(&options.input.display().to_string()), + options.input.display().to_string(), options.clone(), true, opts, From c461f3a760f4a7eeef82bd1a9389d68210abaf4a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 15:36:44 +1100 Subject: [PATCH 04/21] Merge `main_options` into `main_args`. There is no longer any need for them to be separate. --- src/librustdoc/lib.rs | 57 ++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ce6f7e817c620..7e0cc668d7b59 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -674,35 +674,6 @@ fn usage(argv0: &str) { /// A result type used by several functions under `main()`. type MainResult = Result<(), ErrorGuaranteed>; -fn main_args(at_args: &[String]) -> MainResult { - let args = rustc_driver::args::arg_expand_all(at_args); - - let mut options = getopts::Options::new(); - for option in opts() { - (option.apply)(&mut options); - } - let matches = match options.parse(&args[1..]) { - Ok(m) => m, - Err(err) => { - early_error(ErrorOutputType::default(), &err.to_string()); - } - }; - - // Note that we discard any distinction between different non-zero exit - // codes from `from_matches` here. - let options = match config::Options::from_matches(&matches, args) { - Ok(opts) => opts, - Err(code) => { - return if code == 0 { - Ok(()) - } else { - Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) - }; - } - }; - main_options(options) -} - fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult { match res { Ok(()) => Ok(()), @@ -733,7 +704,33 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( } } -fn main_options(options: config::Options) -> MainResult { +fn main_args(at_args: &[String]) -> MainResult { + let args = rustc_driver::args::arg_expand_all(at_args); + + let mut options = getopts::Options::new(); + for option in opts() { + (option.apply)(&mut options); + } + let matches = match options.parse(&args[1..]) { + Ok(m) => m, + Err(err) => { + early_error(ErrorOutputType::default(), &err.to_string()); + } + }; + + // Note that we discard any distinction between different non-zero exit + // codes from `from_matches` here. + let options = match config::Options::from_matches(&matches, args) { + Ok(opts) => opts, + Err(code) => { + return if code == 0 { + Ok(()) + } else { + Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) + }; + } + }; + let diag = core::new_handler( options.error_format, None, From d156a9092738b3f1fb5e665f532613ab06380162 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 11:57:25 +1100 Subject: [PATCH 05/21] Inline and remove `scoped_thread`. It has a single call site, and removing it slightly improves the confusing tangle of nested closures present at startup. --- compiler/rustc_interface/src/util.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index f7e70d355cf86..c07bfb9c23e4a 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -132,33 +132,27 @@ fn get_stack_size() -> Option { env::var_os("RUST_MIN_STACK").is_none().then_some(STACK_SIZE) } -/// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need -/// for `'static` bounds. -#[cfg(not(parallel_compiler))] -fn scoped_thread R + Send, R: Send>(cfg: thread::Builder, f: F) -> R { - // SAFETY: join() is called immediately, so any closure captures are still - // alive. - match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { - Ok(v) => v, - Err(e) => panic::resume_unwind(e), - } -} - #[cfg(not(parallel_compiler))] pub fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, _threads: usize, f: F, ) -> R { + // The thread pool is a single thread in the non-parallel compiler. let mut cfg = thread::Builder::new().name("rustc".to_string()); - if let Some(size) = get_stack_size() { cfg = cfg.stack_size(size); } - let main_handler = move || rustc_span::create_session_globals_then(edition, f); + let f = move || rustc_span::create_session_globals_then(edition, f); - scoped_thread(cfg, main_handler) + // This avoids the need for `'static` bounds. + // + // SAFETY: join() is called immediately, so any closure captures are still alive. + match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { + Ok(v) => v, + Err(e) => panic::resume_unwind(e), + } } /// Creates a new thread and forwards information in thread locals to it. From 226387a4039082b2df687c645acb4bde08f2939d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 15:35:42 +1100 Subject: [PATCH 06/21] Reduce visibility of some functions. --- compiler/rustc_interface/src/interface.rs | 2 +- compiler/rustc_interface/src/util.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 949bd02ad6839..d0555f3db0c9b 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -276,7 +276,7 @@ pub struct Config { pub registry: Registry, } -pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { +fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { crate::callbacks::setup_callbacks(); let registry = &config.registry; diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index c07bfb9c23e4a..7ec0d4d73f7a4 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -133,7 +133,7 @@ fn get_stack_size() -> Option { } #[cfg(not(parallel_compiler))] -pub fn run_in_thread_pool_with_globals R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, _threads: usize, f: F, @@ -171,7 +171,7 @@ unsafe fn handle_deadlock() { } #[cfg(parallel_compiler)] -pub fn run_in_thread_pool_with_globals R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( edition: Edition, threads: usize, f: F, From c00937f2d9b2ea994e5841c5f6047a603eeffe85 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 16:17:57 +1100 Subject: [PATCH 07/21] Inline and remove `create_compiler_and_run`. It has a single call site. --- compiler/rustc_interface/src/interface.rs | 106 +++++++++++----------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index d0555f3db0c9b..bee2e91c74730 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -276,59 +276,6 @@ pub struct Config { pub registry: Registry, } -fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R) -> R { - crate::callbacks::setup_callbacks(); - - let registry = &config.registry; - let (mut sess, codegen_backend) = util::create_session( - config.opts, - config.crate_cfg, - config.crate_check_cfg, - config.diagnostic_output, - config.file_loader, - config.input_path.clone(), - config.lint_caps, - config.make_codegen_backend, - registry.clone(), - ); - - if let Some(parse_sess_created) = config.parse_sess_created { - parse_sess_created( - &mut Lrc::get_mut(&mut sess) - .expect("create_session() should never share the returned session") - .parse_sess, - ); - } - - let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); - - let compiler = Compiler { - sess, - codegen_backend, - input: config.input, - input_path: config.input_path, - output_dir: config.output_dir, - output_file: config.output_file, - temps_dir, - register_lints: config.register_lints, - override_queries: config.override_queries, - }; - - rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { - let r = { - let _sess_abort_error = OnDrop(|| { - compiler.sess.finish_diagnostics(registry); - }); - - f(&compiler) - }; - - let prof = compiler.sess.prof.clone(); - prof.generic_activity("drop_compiler").run(move || drop(compiler)); - r - }) -} - // JUSTIFICATION: before session exists, only config #[allow(rustc::bad_opt_access)] pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { @@ -336,7 +283,58 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, - || create_compiler_and_run(config, f), + || { + crate::callbacks::setup_callbacks(); + + let registry = &config.registry; + let (mut sess, codegen_backend) = util::create_session( + config.opts, + config.crate_cfg, + config.crate_check_cfg, + config.diagnostic_output, + config.file_loader, + config.input_path.clone(), + config.lint_caps, + config.make_codegen_backend, + registry.clone(), + ); + + if let Some(parse_sess_created) = config.parse_sess_created { + parse_sess_created( + &mut Lrc::get_mut(&mut sess) + .expect("create_session() should never share the returned session") + .parse_sess, + ); + } + + let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); + + let compiler = Compiler { + sess, + codegen_backend, + input: config.input, + input_path: config.input_path, + output_dir: config.output_dir, + output_file: config.output_file, + temps_dir, + register_lints: config.register_lints, + override_queries: config.override_queries, + }; + + rustc_span::with_source_map(compiler.sess.parse_sess.clone_source_map(), move || { + let r = { + let _sess_abort_error = OnDrop(|| { + compiler.sess.finish_diagnostics(registry); + }); + + f(&compiler) + }; + + let prof = compiler.sess.prof.clone(); + prof.generic_activity("drop_compiler").run(move || drop(compiler)); + r + }) + }, ) } From 806701607285b6a61c6169797b5e22ef9a18d5de Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 7 Oct 2022 16:20:20 +1100 Subject: [PATCH 08/21] Apply `Lrc` later to `sess` and `codegen_backend`. This avoids the need for a degenerate `Lrc::get_mut` call. --- compiler/rustc_interface/src/interface.rs | 10 +++------- compiler/rustc_interface/src/util.rs | 5 ++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index bee2e91c74730..a697f8071b4b3 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -300,18 +300,14 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se ); if let Some(parse_sess_created) = config.parse_sess_created { - parse_sess_created( - &mut Lrc::get_mut(&mut sess) - .expect("create_session() should never share the returned session") - .parse_sess, - ); + parse_sess_created(&mut sess.parse_sess); } let temps_dir = sess.opts.unstable_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o)); let compiler = Compiler { - sess, - codegen_backend, + sess: Lrc::new(sess), + codegen_backend: Lrc::new(codegen_backend), input: config.input, input_path: config.input_path, output_dir: config.output_dir, diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 7ec0d4d73f7a4..ae7a240d81cb4 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,7 +5,6 @@ use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[cfg(parallel_compiler)] use rustc_data_structures::jobserver; -use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; #[cfg(parallel_compiler)] use rustc_middle::ty::tls; @@ -73,7 +72,7 @@ pub fn create_session( Box Box + Send>, >, descriptions: Registry, -) -> (Lrc, Lrc>) { +) -> (Session, Box) { let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { make_codegen_backend(&sopts) } else { @@ -121,7 +120,7 @@ pub fn create_session( sess.parse_sess.config = cfg; sess.parse_sess.check_config = check_cfg; - (Lrc::new(sess), Lrc::new(codegen_backend)) + (sess, codegen_backend) } const STACK_SIZE: usize = 8 * 1024 * 1024; From 1f0463a7b5ed89cedf25842e7c2917efc9200939 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 8 Oct 2022 07:43:15 +1100 Subject: [PATCH 09/21] Replace a `spawn_unchecked` with `spawn_scoped`. --- compiler/rustc_interface/src/util.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index ae7a240d81cb4..1bbfb9a415699 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -138,20 +138,24 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( f: F, ) -> R { // The thread pool is a single thread in the non-parallel compiler. - let mut cfg = thread::Builder::new().name("rustc".to_string()); - if let Some(size) = get_stack_size() { - cfg = cfg.stack_size(size); - } + thread::scope(|s| { + let mut builder = thread::Builder::new().name("rustc".to_string()); + if let Some(size) = get_stack_size() { + builder = builder.stack_size(size); + } - let f = move || rustc_span::create_session_globals_then(edition, f); + // `unwrap` is ok here because `spawn_scoped` only panics if the thread + // name contains null bytes. + let r = builder + .spawn_scoped(s, move || rustc_span::create_session_globals_then(edition, f)) + .unwrap() + .join(); - // This avoids the need for `'static` bounds. - // - // SAFETY: join() is called immediately, so any closure captures are still alive. - match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() { - Ok(v) => v, - Err(e) => panic::resume_unwind(e), - } + match r { + Ok(v) => v, + Err(e) => panic::resume_unwind(e), + } + }) } /// Creates a new thread and forwards information in thread locals to it. From b4c8a7b952de72bc70e798408efbd4124fa15c59 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 8 Oct 2022 09:07:28 +0200 Subject: [PATCH 10/21] std: remove unused linker attribute --- library/std/src/sys/unix/thread_parker/darwin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/thread_parker/darwin.rs b/library/std/src/sys/unix/thread_parker/darwin.rs index 510839d5dafbf..2f5356fe2276b 100644 --- a/library/std/src/sys/unix/thread_parker/darwin.rs +++ b/library/std/src/sys/unix/thread_parker/darwin.rs @@ -24,7 +24,7 @@ type dispatch_time_t = u64; const DISPATCH_TIME_NOW: dispatch_time_t = 0; const DISPATCH_TIME_FOREVER: dispatch_time_t = !0; -#[link(name = "System", kind = "dylib")] +// Contained in libSystem.dylib, which is linked by default. extern "C" { fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t; fn dispatch_semaphore_create(val: isize) -> dispatch_semaphore_t; From c320ab98ff1d4adb32cece206aa895e4effae175 Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 8 Oct 2022 09:12:06 +0200 Subject: [PATCH 11/21] std: do not use dispatch semaphore under miri (yet) --- library/std/src/sys/unix/thread_parker/mod.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/thread_parker/mod.rs b/library/std/src/sys/unix/thread_parker/mod.rs index 724ec2d482edb..35f1e68a87e5b 100644 --- a/library/std/src/sys/unix/thread_parker/mod.rs +++ b/library/std/src/sys/unix/thread_parker/mod.rs @@ -11,11 +11,14 @@ )))] cfg_if::cfg_if! { - if #[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "watchos", - target_os = "tvos", + if #[cfg(all( + any( + target_os = "macos", + target_os = "ios", + target_os = "watchos", + target_os = "tvos", + ), + not(miri), ))] { mod darwin; pub use darwin::Parker; From 76386bd65e650b5289b142daa310a4b98230c3db Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Sep 2022 23:20:03 +0000 Subject: [PATCH 12/21] Make dyn* cast into a coercion --- compiler/rustc_hir_analysis/src/check/cast.rs | 63 ++----------------- .../rustc_hir_analysis/src/check/coercion.rs | 50 +++++++++++++++ .../src/expr_use_visitor.rs | 4 +- .../src/mem_categorization.rs | 3 +- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_middle/src/ty/adjustment.rs | 3 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 1 + src/test/ui/dyn-star/const.rs | 2 +- src/test/ui/dyn-star/drop.rs | 2 +- src/test/ui/dyn-star/error.rs | 2 +- src/test/ui/dyn-star/error.stderr | 2 +- src/test/ui/dyn-star/make-dyn-star.rs | 2 +- src/test/ui/dyn-star/method.rs | 3 +- 13 files changed, 73 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs index 01badc133c918..7587283014069 100644 --- a/compiler/rustc_hir_analysis/src/check/cast.rs +++ b/compiler/rustc_hir_analysis/src/check/cast.rs @@ -35,13 +35,12 @@ use crate::type_error_struct; use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Binder, Ty, TypeAndMut, TypeVisitable, VariantDef}; +use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; @@ -218,58 +217,10 @@ pub fn check_cast<'tcx>( cast_span: Span, span: Span, ) -> CastCheckResult<'tcx> { - if cast_ty.is_dyn_star() { - check_dyn_star_cast(fcx, expr, expr_ty, cast_ty) - } else { - match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) { - Ok(check) => CastCheckResult::Deferred(check), - Err(e) => CastCheckResult::Err(e), - } - } -} - -fn check_dyn_star_cast<'tcx>( - fcx: &FnCtxt<'_, 'tcx>, - expr: &'tcx hir::Expr<'tcx>, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, -) -> CastCheckResult<'tcx> { - // Find the bounds in the dyn*. For eaxmple, if we have - // - // let x = 22_usize as dyn* (Clone + Debug + 'static) - // - // this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`. - let (existential_predicates, region) = match cast_ty.kind() { - ty::Dynamic(predicates, region, ty::DynStar) => (predicates, region), - _ => panic!("Invalid dyn* cast_ty"), - }; - - let cause = ObligationCause::new( - expr.span, - fcx.body_id, - // FIXME(dyn-star): Use a better obligation cause code - ObligationCauseCode::MiscObligation, - ); - - // For each existential predicate (e.g., `?Self: Clone`) substitute - // the type of the expression (e.g., `usize` in our example above) - // and then require that the resulting predicate (e.g., `usize: Clone`) - // holds (it does). - for existential_predicate in existential_predicates.iter() { - let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty); - fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate)); + match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) { + Ok(check) => CastCheckResult::Deferred(check), + Err(e) => CastCheckResult::Err(e), } - - // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example). - fcx.register_predicate(Obligation::new( - cause, - fcx.param_env, - fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives( - ty::OutlivesPredicate(expr_ty, *region), - ))), - )); - - CastCheckResult::Ok } impl<'a, 'tcx> CastCheck<'tcx> { @@ -934,11 +885,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), - // FIXME(dyn-star): this needs more conditions... - (_, DynStar) => Ok(CastKind::DynStarCast), - - // FIXME(dyn-star): do we want to allow dyn* upcasting or other casts? - (DynStar, _) => Err(CastError::IllegalCast), + (_, DynStar) | (DynStar, _) => bug!("should be handled by `try_coerce`"), } } diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs index cf87fe3c510a4..44e6438239774 100644 --- a/compiler/rustc_hir_analysis/src/check/coercion.rs +++ b/compiler/rustc_hir_analysis/src/check/coercion.rs @@ -216,6 +216,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::Ref(r_b, _, mutbl_b) => { return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); } + ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => { + return self.coerce_dyn_star(a, b, predicates, region); + } _ => {} } @@ -745,6 +748,53 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { Ok(coercion) } + fn coerce_dyn_star( + &self, + a: Ty<'tcx>, + b: Ty<'tcx>, + predicates: &'tcx ty::List>>, + b_region: ty::Region<'tcx>, + ) -> CoerceResult<'tcx> { + if !self.tcx.features().dyn_star { + return Err(TypeError::Mismatch); + } + + if let ty::Dynamic(a_data, _, _) = a.kind() + && let ty::Dynamic(b_data, _, _) = b.kind() + { + if a_data.principal_def_id() == b_data.principal_def_id() { + return self.unify_and(a, b, |_| vec![]); + } else { + bug!("dyn* trait upcasting is not supported"); + } + } + + let obligations = predicates + .iter() + .map(|predicate| { + // For each existential predicate (e.g., `?Self: Clone`) substitute + // the type of the expression (e.g., `usize` in our example above) + // and then require that the resulting predicate (e.g., `usize: Clone`) + // holds (it does). + let predicate = predicate.with_self_ty(self.tcx, a); + Obligation::new(self.cause.clone(), self.param_env, predicate) + }) + // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example). + .chain([Obligation::new( + self.cause.clone(), + self.param_env, + self.tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::TypeOutlives( + ty::OutlivesPredicate(a, b_region), + ))), + )]) + .collect(); + + Ok(InferOk { + value: (vec![Adjustment { kind: Adjust::DynStar, target: b }], b), + obligations, + }) + } + fn coerce_from_safe_fn( &self, a: Ty<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs index cbc3769901d72..039c653e5bc64 100644 --- a/compiler/rustc_hir_analysis/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_analysis/src/expr_use_visitor.rs @@ -583,7 +583,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { - adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) => { + adjustment::Adjust::NeverToAny + | adjustment::Adjust::Pointer(_) + | adjustment::Adjust::DynStar => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. self.delegate_consume(&place_with_id, place_with_id.hir_id); diff --git a/compiler/rustc_hir_analysis/src/mem_categorization.rs b/compiler/rustc_hir_analysis/src/mem_categorization.rs index b62c5b5e07783..362f1c3430041 100644 --- a/compiler/rustc_hir_analysis/src/mem_categorization.rs +++ b/compiler/rustc_hir_analysis/src/mem_categorization.rs @@ -292,7 +292,8 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { adjustment::Adjust::NeverToAny | adjustment::Adjust::Pointer(_) - | adjustment::Adjust::Borrow(_) => { + | adjustment::Adjust::Borrow(_) + | adjustment::Adjust::DynStar => { // Result is an rvalue. Ok(self.cat_rvalue(expr.hir_id, expr.span, target)) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d4258151ff3f3..c022ea9e5b470 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1824,7 +1824,6 @@ impl<'tcx> Rvalue<'tcx> { // While the model is undecided, we should be conservative. See // Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, - Rvalue::Cast(CastKind::DynStar, _, _) => false, Rvalue::Use(_) | Rvalue::CopyForDeref(_) @@ -1841,7 +1840,8 @@ impl<'tcx> Rvalue<'tcx> { | CastKind::FnPtrToPtr | CastKind::PtrToPtr | CastKind::Pointer(_) - | CastKind::PointerFromExposedAddress, + | CastKind::PointerFromExposedAddress + | CastKind::DynStar, _, _, ) diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index b809f176760d6..4682ac96b5297 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -101,6 +101,9 @@ pub enum Adjust<'tcx> { Borrow(AutoBorrow<'tcx>), Pointer(PointerCast), + + /// Cast into a dyn* object. + DynStar, } /// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)` diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index bcf2ed6817210..c7a7c3e3fa8ee 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -159,6 +159,7 @@ impl<'tcx> Cx<'tcx> { Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) } } + Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) }, }; Expr { temp_lifetime, ty: adjustment.target, span, kind } diff --git a/src/test/ui/dyn-star/const.rs b/src/test/ui/dyn-star/const.rs index e49caf649f892..67e3ab7ab35f1 100644 --- a/src/test/ui/dyn-star/const.rs +++ b/src/test/ui/dyn-star/const.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; fn make_dyn_star() { let i = 42usize; - let dyn_i: dyn* Debug = i as dyn* Debug; + let dyn_i: dyn* Debug = i; } fn main() { diff --git a/src/test/ui/dyn-star/drop.rs b/src/test/ui/dyn-star/drop.rs index 46b232f3dd399..1478498c0a9f3 100644 --- a/src/test/ui/dyn-star/drop.rs +++ b/src/test/ui/dyn-star/drop.rs @@ -15,7 +15,7 @@ impl Drop for Foo { } fn make_dyn_star(i: Foo) { - let _dyn_i: dyn* Debug = i as dyn* Debug; + let _dyn_i: dyn* Debug = i; } fn main() { diff --git a/src/test/ui/dyn-star/error.rs b/src/test/ui/dyn-star/error.rs index 33eff80a5fe70..d8261387efa9e 100644 --- a/src/test/ui/dyn-star/error.rs +++ b/src/test/ui/dyn-star/error.rs @@ -7,7 +7,7 @@ trait Foo {} fn make_dyn_star() { let i = 42; - let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied + let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied } fn main() {} diff --git a/src/test/ui/dyn-star/error.stderr b/src/test/ui/dyn-star/error.stderr index d612ccc630ea8..ae54b9ca707d0 100644 --- a/src/test/ui/dyn-star/error.stderr +++ b/src/test/ui/dyn-star/error.stderr @@ -1,7 +1,7 @@ error[E0277]: the trait bound `{integer}: Foo` is not satisfied --> $DIR/error.rs:10:27 | -LL | let dyn_i: dyn* Foo = i as dyn* Foo; +LL | let dyn_i: dyn* Foo = i; | ^ the trait `Foo` is not implemented for `{integer}` error: aborting due to previous error diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs index 708ffa25d6fee..4f9393abb30e2 100644 --- a/src/test/ui/dyn-star/make-dyn-star.rs +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -5,7 +5,7 @@ use std::fmt::Debug; fn make_dyn_star(i: usize) { - let _dyn_i: dyn* Debug = i as dyn* Debug; + let _dyn_i: dyn* Debug = i; } fn main() { diff --git a/src/test/ui/dyn-star/method.rs b/src/test/ui/dyn-star/method.rs index d04958ca2aac9..5a77640f0d932 100644 --- a/src/test/ui/dyn-star/method.rs +++ b/src/test/ui/dyn-star/method.rs @@ -1,4 +1,5 @@ // run-pass + #![feature(dyn_star)] #![allow(incomplete_features)] @@ -17,7 +18,7 @@ fn invoke_dyn_star(i: dyn* Foo) -> usize { } fn make_and_invoke_dyn_star(i: usize) -> usize { - let dyn_i: dyn* Foo = i as dyn* Foo; + let dyn_i: dyn* Foo = i; invoke_dyn_star(dyn_i) } From b8418485bc400d5a00f197ff328655bfa367835e Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 13 Oct 2022 13:07:56 +0900 Subject: [PATCH 13/21] check if the self type is `ty::Float` before getting second substs --- .../src/traits/error_reporting/suggestions.rs | 22 +++--- src/test/ui/traits/issue-102989.rs | 18 +++++ src/test/ui/traits/issue-102989.stderr | 72 +++++++++++++++++++ 3 files changed, 99 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/traits/issue-102989.rs create mode 100644 src/test/ui/traits/issue-102989.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index fda6a2236b195..4431cf9f4436b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2937,19 +2937,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::BinOp { rhs_span: Some(span), is_lit, .. } if *is_lit => span, _ => return, }; - match ( - trait_ref.skip_binder().self_ty().kind(), - trait_ref.skip_binder().substs.type_at(1).kind(), - ) { - (ty::Float(_), ty::Infer(InferTy::IntVar(_))) => { - err.span_suggestion_verbose( - rhs_span.shrink_to_hi(), - "consider using a floating-point literal by writing it with `.0`", - ".0", - Applicability::MaybeIncorrect, - ); - } - _ => {} + if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind() + && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().substs.type_at(1).kind() + { + err.span_suggestion_verbose( + rhs_span.shrink_to_hi(), + "consider using a floating-point literal by writing it with `.0`", + ".0", + Applicability::MaybeIncorrect, + ); } } diff --git a/src/test/ui/traits/issue-102989.rs b/src/test/ui/traits/issue-102989.rs new file mode 100644 index 0000000000000..cd517a1c4ac87 --- /dev/null +++ b/src/test/ui/traits/issue-102989.rs @@ -0,0 +1,18 @@ +// compile-flags: -Cinstrument-coverage +//~^ ERROR can't find crate for `profiler_builtins` + +#![no_core] +#![feature(no_core, lang_items)] +#[lang="sized"] +trait Sized { } //~ ERROR found duplicate lang item `sized` + +fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + //~^ ERROR `self` parameter is only allowed in associated functions + //~| ERROR cannot find type `Struct` in this scope + //~| ERROR mismatched types + let x = x << 1; + //~^ ERROR the size for values of type `{integer}` cannot be known at compilation time + //~| ERROR cannot find value `x` in this scope +} + +fn main() {} diff --git a/src/test/ui/traits/issue-102989.stderr b/src/test/ui/traits/issue-102989.stderr new file mode 100644 index 0000000000000..255fa6966efc9 --- /dev/null +++ b/src/test/ui/traits/issue-102989.stderr @@ -0,0 +1,72 @@ +error: `self` parameter is only allowed in associated functions + --> $DIR/issue-102989.rs:9:15 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ^^^^ not semantically valid as function parameter + | + = note: associated functions are those in `impl` or `trait` definitions + +error[E0412]: cannot find type `Struct` in this scope + --> $DIR/issue-102989.rs:9:22 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `x` in this scope + --> $DIR/issue-102989.rs:13:13 + | +LL | let x = x << 1; + | ^ help: a local variable with a similar name exists: `f` + +error: `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` + +error[E0463]: can't find crate for `profiler_builtins` + | + = note: the compiler may have been built without the profiler runtime + +error[E0152]: found duplicate lang item `sized` + --> $DIR/issue-102989.rs:7:1 + | +LL | trait Sized { } + | ^^^^^^^^^^^ + | + = note: the lang item is first defined in crate `core`. + = note: first definition in `core` loaded from $BUILD_DIR/aarch64-apple-darwin/stage1/lib/rustlib/aarch64-apple-darwin/lib/libcore-500f4c12402b1108.rlib + = note: second definition in the local crate (`issue_102989`) + +error: `#[panic_handler]` function required, but not found + +error: language item required, but not found: `eh_personality` + | + = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library + = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` + +error[E0277]: the size for values of type `{integer}` cannot be known at compilation time + --> $DIR/issue-102989.rs:13:15 + | +LL | let x = x << 1; + | ^^ doesn't have a size known at compile-time + | + = help: the trait `core::marker::Sized` is not implemented for `{integer}` + +error[E0308]: mismatched types + --> $DIR/issue-102989.rs:9:42 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ---------- ^^^^ expected `&u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | +note: consider returning one of these bindings + --> $DIR/issue-102989.rs:9:30 + | +LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { + | ^ +... +LL | let x = x << 1; + | ^ + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0152, E0277, E0308, E0412, E0425, E0463. +For more information about an error, try `rustc --explain E0152`. From 5378677c31e89ae2fe4de954631bde8efeac91d1 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 13 Oct 2022 15:07:39 +0900 Subject: [PATCH 14/21] normalize stderr --- src/test/ui/traits/issue-102989.rs | 3 ++- src/test/ui/traits/issue-102989.stderr | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/test/ui/traits/issue-102989.rs b/src/test/ui/traits/issue-102989.rs index cd517a1c4ac87..cb1e3271d26e8 100644 --- a/src/test/ui/traits/issue-102989.rs +++ b/src/test/ui/traits/issue-102989.rs @@ -1,5 +1,6 @@ +//~ ERROR can't find crate for `profiler_builtins` // compile-flags: -Cinstrument-coverage -//~^ ERROR can't find crate for `profiler_builtins` +// normalize-stderr-test "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" #![no_core] #![feature(no_core, lang_items)] diff --git a/src/test/ui/traits/issue-102989.stderr b/src/test/ui/traits/issue-102989.stderr index 255fa6966efc9..efea2251a13f8 100644 --- a/src/test/ui/traits/issue-102989.stderr +++ b/src/test/ui/traits/issue-102989.stderr @@ -1,5 +1,5 @@ error: `self` parameter is only allowed in associated functions - --> $DIR/issue-102989.rs:9:15 + --> $DIR/issue-102989.rs:10:15 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^ not semantically valid as function parameter @@ -7,13 +7,13 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { = note: associated functions are those in `impl` or `trait` definitions error[E0412]: cannot find type `Struct` in this scope - --> $DIR/issue-102989.rs:9:22 + --> $DIR/issue-102989.rs:10:22 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^^^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> $DIR/issue-102989.rs:13:13 + --> $DIR/issue-102989.rs:14:13 | LL | let x = x << 1; | ^ help: a local variable with a similar name exists: `f` @@ -25,13 +25,13 @@ error[E0463]: can't find crate for `profiler_builtins` = note: the compiler may have been built without the profiler runtime error[E0152]: found duplicate lang item `sized` - --> $DIR/issue-102989.rs:7:1 + --> $DIR/issue-102989.rs:8:1 | LL | trait Sized { } | ^^^^^^^^^^^ | = note: the lang item is first defined in crate `core`. - = note: first definition in `core` loaded from $BUILD_DIR/aarch64-apple-darwin/stage1/lib/rustlib/aarch64-apple-darwin/lib/libcore-500f4c12402b1108.rlib + = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib = note: second definition in the local crate (`issue_102989`) error: `#[panic_handler]` function required, but not found @@ -42,7 +42,7 @@ error: language item required, but not found: `eh_personality` = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` error[E0277]: the size for values of type `{integer}` cannot be known at compilation time - --> $DIR/issue-102989.rs:13:15 + --> $DIR/issue-102989.rs:14:15 | LL | let x = x << 1; | ^^ doesn't have a size known at compile-time @@ -50,7 +50,7 @@ LL | let x = x << 1; = help: the trait `core::marker::Sized` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/issue-102989.rs:9:42 + --> $DIR/issue-102989.rs:10:42 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ---------- ^^^^ expected `&u32`, found `()` @@ -58,7 +58,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | implicitly returns `()` as its body has no tail or `return` expression | note: consider returning one of these bindings - --> $DIR/issue-102989.rs:9:30 + --> $DIR/issue-102989.rs:10:30 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^ From feb4244f54c4ecf828ba8e0ae3d8c23d80b64646 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Sep 2022 23:28:14 +0000 Subject: [PATCH 15/21] Allow dyn* upcasting --- compiler/rustc_codegen_ssa/src/base.rs | 61 +++++++++++++++---- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 27 ++------ .../rustc_hir_analysis/src/check/coercion.rs | 12 +++- src/test/ui/dyn-star/upcast.rs | 33 ++++++++++ 4 files changed, 97 insertions(+), 36 deletions(-) create mode 100644 src/test/ui/dyn-star/upcast.rs diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index cb5436fd61a16..70e1fe62e4724 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -38,7 +38,7 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Symbol; use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType}; -use rustc_target::abi::{Align, VariantIdx}; +use rustc_target::abi::{Align, Size, VariantIdx}; use std::collections::BTreeSet; use std::convert::TryFrom; @@ -150,7 +150,12 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( (&ty::Array(_, len), &ty::Slice(_)) => { cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all())) } - (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + ( + &ty::Dynamic(ref data_a, _, src_dyn_kind), + &ty::Dynamic(ref data_b, _, target_dyn_kind), + ) => { + assert_eq!(src_dyn_kind, target_dyn_kind); + let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { @@ -166,11 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if let Some(entry_idx) = vptr_entry_idx { let ptr_ty = cx.type_i8p(); let ptr_align = cx.tcx().data_layout.pointer_align.abi; - let vtable_ptr_ty = cx.scalar_pair_element_backend_type( - cx.layout_of(cx.tcx().mk_mut_ptr(target)), - 1, - true, - ); + let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind); let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty)); let gep = bx.inbounds_gep( ptr_ty, @@ -186,18 +187,32 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( old_info } } - (_, &ty::Dynamic(ref data, ..)) => { - let vtable_ptr_ty = cx.scalar_pair_element_backend_type( - cx.layout_of(cx.tcx().mk_mut_ptr(target)), - 1, - true, - ); + (_, &ty::Dynamic(ref data, _, target_dyn_kind)) => { + let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind); cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty) } _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), } } +// Returns the vtable pointer type of a `dyn` or `dyn*` type +fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>( + cx: &Cx, + target: Ty<'tcx>, + kind: ty::DynKind, +) -> ::Type { + cx.scalar_pair_element_backend_type( + cx.layout_of(match kind { + // vtable is the second field of `*mut dyn Trait` + ty::Dyn => cx.tcx().mk_mut_ptr(target), + // vtable is the second field of `dyn* Trait` + ty::DynStar => target, + }), + 1, + true, + ) +} + /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer. pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, @@ -247,6 +262,26 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } +/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type. +pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + src: Bx::Value, + src_ty_and_layout: TyAndLayout<'tcx>, + dst_ty: Ty<'tcx>, + old_info: Option, +) -> (Bx::Value, Bx::Value) { + debug!("unsize_ptr: {:?} => {:?}", src_ty_and_layout.ty, dst_ty); + assert!(matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar))); + // FIXME(dyn-star): this is probably not the best way to check if this is + // a pointer, and really we should ensure that the value is a suitable + // pointer earlier in the compilation process. + let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) { + Some(_) => bx.ptrtoint(src, bx.cx().type_isize()), + None => bx.bitcast(src, bx.type_isize()), + }; + (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info)) +} + /// Coerces `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty`, and stores the result in `dst`. pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4ed99df1e8169..4aab31fbfe7da 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -4,7 +4,6 @@ use super::{FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; -use crate::meth::get_vtable; use crate::traits::*; use crate::MemFlags; @@ -14,7 +13,6 @@ use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; -use rustc_target::abi::Size; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "trace", skip(self, bx))] @@ -274,27 +272,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::CastKind::DynStar => { - let data = match operand.val { + let (lldata, llextra) = match operand.val { OperandValue::Ref(_, _, _) => todo!(), - OperandValue::Immediate(v) => v, - OperandValue::Pair(_, _) => todo!(), - }; - let trait_ref = - if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() { - data.principal() - } else { - bug!("Only valid to do a DynStar cast into a DynStar type") - }; - let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref); - let vtable = bx.pointercast(vtable, bx.cx().type_ptr_to(bx.cx().type_isize())); - // FIXME(dyn-star): this is probably not the best way to check if this is - // a pointer, and really we should ensure that the value is a suitable - // pointer earlier in the compilation process. - let data = match operand.layout.pointee_info_at(bx.cx(), Size::ZERO) { - Some(_) => bx.ptrtoint(data, bx.cx().type_isize()), - None => data, + OperandValue::Immediate(v) => (v, None), + OperandValue::Pair(v, l) => (v, Some(l)), }; - OperandValue::Pair(data, vtable) + let (lldata, llextra) = + base::cast_to_dyn_star(&mut bx, lldata, operand.layout, cast.ty, llextra); + OperandValue::Pair(lldata, llextra) } mir::CastKind::Pointer( PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs index 44e6438239774..a2bb249ba6e28 100644 --- a/compiler/rustc_hir_analysis/src/check/coercion.rs +++ b/compiler/rustc_hir_analysis/src/check/coercion.rs @@ -764,8 +764,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { { if a_data.principal_def_id() == b_data.principal_def_id() { return self.unify_and(a, b, |_| vec![]); - } else { - bug!("dyn* trait upcasting is not supported"); + } else if !self.tcx().features().trait_upcasting { + let mut err = feature_err( + &self.tcx.sess.parse_sess, + sym::trait_upcasting, + self.cause.span, + &format!( + "cannot cast `{a}` to `{b}`, trait upcasting coercion is experimental" + ), + ); + err.emit(); } } diff --git a/src/test/ui/dyn-star/upcast.rs b/src/test/ui/dyn-star/upcast.rs new file mode 100644 index 0000000000000..cee76ada7df3b --- /dev/null +++ b/src/test/ui/dyn-star/upcast.rs @@ -0,0 +1,33 @@ +// run-pass + +#![feature(dyn_star, trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo: Bar { + fn hello(&self); +} + +trait Bar { + fn world(&self); +} + +struct W(usize); + +impl Foo for W { + fn hello(&self) { + println!("hello!"); + } +} + +impl Bar for W { + fn world(&self) { + println!("world!"); + } +} + +fn main() { + let w: dyn* Foo = W(0); + w.hello(); + let w: dyn* Bar = w; + w.world(); +} From 0cb217d29b6cd9a67fc493a12a5754ed9d21671a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 14 Sep 2022 23:42:25 +0000 Subject: [PATCH 16/21] Remove CastCheckResult since it's unused --- compiler/rustc_hir_analysis/src/check/cast.rs | 22 +------------- compiler/rustc_hir_analysis/src/check/expr.rs | 9 +++--- .../clippy_lints/src/transmute/utils.rs | 29 +++++++++++-------- 3 files changed, 22 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs index 7587283014069..51abdd2e059d7 100644 --- a/compiler/rustc_hir_analysis/src/check/cast.rs +++ b/compiler/rustc_hir_analysis/src/check/cast.rs @@ -203,28 +203,8 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } -pub enum CastCheckResult<'tcx> { - Ok, - Deferred(CastCheck<'tcx>), - Err(ErrorGuaranteed), -} - -pub fn check_cast<'tcx>( - fcx: &FnCtxt<'_, 'tcx>, - expr: &'tcx hir::Expr<'tcx>, - expr_ty: Ty<'tcx>, - cast_ty: Ty<'tcx>, - cast_span: Span, - span: Span, -) -> CastCheckResult<'tcx> { - match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) { - Ok(check) => CastCheckResult::Deferred(check), - Err(e) => CastCheckResult::Err(e), - } -} - impl<'a, 'tcx> CastCheck<'tcx> { - fn new( + pub fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/check/expr.rs b/compiler/rustc_hir_analysis/src/check/expr.rs index 34c257845971e..71c6da862c94b 100644 --- a/compiler/rustc_hir_analysis/src/check/expr.rs +++ b/compiler/rustc_hir_analysis/src/check/expr.rs @@ -3,7 +3,7 @@ //! See `mod.rs` for more context on type checking in general. use crate::astconv::AstConv as _; -use crate::check::cast::{self, CastCheckResult}; +use crate::check::cast; use crate::check::coercion::CoerceMany; use crate::check::fatally_break_rust; use crate::check::method::SelfSource; @@ -1270,9 +1270,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) { - CastCheckResult::Ok => t_cast, - CastCheckResult::Deferred(cast_check) => { + match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { + Ok(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", t_cast, t_expr, cast_check, @@ -1280,7 +1279,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_cast_checks.push(cast_check); t_cast } - CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(), + Err(_) => self.tcx.ty_error(), } } } diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index b567d92230bb1..102f7541c8ce1 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,15 +1,16 @@ use rustc_hir::Expr; -use rustc_hir_analysis::check::{ - cast::{self, CastCheckResult}, - FnCtxt, Inherited, -}; +use rustc_hir_analysis::check::{cast, FnCtxt, Inherited}; use rustc_lint::LateContext; use rustc_middle::ty::{cast::CastKind, Ty}; use rustc_span::DUMMY_SP; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment -pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx>, to: Ty<'tcx>) -> bool { +pub(super) fn is_layout_incompatible<'tcx>( + cx: &LateContext<'tcx>, + from: Ty<'tcx>, + to: Ty<'tcx>, +) -> bool { if let Ok(from) = cx.tcx.try_normalize_erasing_regions(cx.param_env, from) && let Ok(to) = cx.tcx.try_normalize_erasing_regions(cx.param_env, to) && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from)) @@ -32,7 +33,9 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, ) -> bool { - use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; + use CastKind::{ + AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast, + }; matches!( check_cast(cx, e, from_ty, to_ty), Some(PtrPtrCast | PtrAddrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) @@ -43,7 +46,12 @@ pub(super) fn can_be_expressed_as_pointer_cast<'tcx>( /// the cast. In certain cases, including some invalid casts from array references /// to pointers, this may cause additional errors to be emitted and/or ICE error /// messages. This function will panic if that occurs. -fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> Option { +fn check_cast<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option { let hir_id = e.hir_id; let local_def_id = hir_id.owner.def_id; @@ -51,12 +59,9 @@ fn check_cast<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx> let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, hir_id); // If we already have errors, we can't be sure we can pointer cast. - assert!( - !fn_ctxt.errors_reported_since_creation(), - "Newly created FnCtxt contained errors" - ); + assert!(!fn_ctxt.errors_reported_since_creation(), "Newly created FnCtxt contained errors"); - if let CastCheckResult::Deferred(check) = cast::check_cast( + if let Ok(check) = cast::CastCheck::new( &fn_ctxt, e, from_ty, to_ty, // We won't show any error to the user, so we don't care what the span is here. DUMMY_SP, DUMMY_SP, From 8c7e836abb62331ebb8350c7724c95241ef95a51 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Oct 2022 04:55:07 +0000 Subject: [PATCH 17/21] Address nits, add test for implicit dyn-star coercion without feature gate --- compiler/rustc_codegen_ssa/src/base.rs | 7 +++++-- .../rustc_hir_analysis/src/check/coercion.rs | 4 +++- .../ui/dyn-star/auxiliary/dyn-star-foreign.rs | 10 ++++++++++ src/test/ui/dyn-star/make-dyn-star.rs | 5 +++++ src/test/ui/dyn-star/no-implicit-dyn-star.rs | 8 ++++++++ .../ui/dyn-star/no-implicit-dyn-star.stderr | 19 +++++++++++++++++++ 6 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/dyn-star/auxiliary/dyn-star-foreign.rs create mode 100644 src/test/ui/dyn-star/no-implicit-dyn-star.rs create mode 100644 src/test/ui/dyn-star/no-implicit-dyn-star.stderr diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 70e1fe62e4724..0ca6408aab910 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -270,8 +270,11 @@ pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( dst_ty: Ty<'tcx>, old_info: Option, ) -> (Bx::Value, Bx::Value) { - debug!("unsize_ptr: {:?} => {:?}", src_ty_and_layout.ty, dst_ty); - assert!(matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar))); + debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty); + assert!( + matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)), + "destination type must be a dyn*" + ); // FIXME(dyn-star): this is probably not the best way to check if this is // a pointer, and really we should ensure that the value is a suitable // pointer earlier in the compilation process. diff --git a/compiler/rustc_hir_analysis/src/check/coercion.rs b/compiler/rustc_hir_analysis/src/check/coercion.rs index a2bb249ba6e28..faa6c6d9356f4 100644 --- a/compiler/rustc_hir_analysis/src/check/coercion.rs +++ b/compiler/rustc_hir_analysis/src/check/coercion.rs @@ -777,6 +777,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } + // Check the obligations of the cast -- for example, when casting + // `usize` to `dyn* Clone + 'static`: let obligations = predicates .iter() .map(|predicate| { @@ -787,7 +789,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let predicate = predicate.with_self_ty(self.tcx, a); Obligation::new(self.cause.clone(), self.param_env, predicate) }) - // Enforce the region bound `'static` (e.g., `usize: 'static`, in our example). + // Enforce the region bound (e.g., `usize: 'static`, in our example). .chain([Obligation::new( self.cause.clone(), self.param_env, diff --git a/src/test/ui/dyn-star/auxiliary/dyn-star-foreign.rs b/src/test/ui/dyn-star/auxiliary/dyn-star-foreign.rs new file mode 100644 index 0000000000000..7673c79367833 --- /dev/null +++ b/src/test/ui/dyn-star/auxiliary/dyn-star-foreign.rs @@ -0,0 +1,10 @@ +#![feature(dyn_star)] +#![allow(incomplete_features)] + +use std::fmt::Display; + +pub fn require_dyn_star_display(_: dyn* Display) {} + +fn works_locally() { + require_dyn_star_display(1usize); +} diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs index 4f9393abb30e2..e5255a64ba119 100644 --- a/src/test/ui/dyn-star/make-dyn-star.rs +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -8,6 +8,11 @@ fn make_dyn_star(i: usize) { let _dyn_i: dyn* Debug = i; } +fn make_dyn_star_explicit(i: usize) { + let _dyn_i: dyn* Debug = i as dyn* Debug; +} + fn main() { make_dyn_star(42); + make_dyn_star_explicit(42); } diff --git a/src/test/ui/dyn-star/no-implicit-dyn-star.rs b/src/test/ui/dyn-star/no-implicit-dyn-star.rs new file mode 100644 index 0000000000000..d9470e2841770 --- /dev/null +++ b/src/test/ui/dyn-star/no-implicit-dyn-star.rs @@ -0,0 +1,8 @@ +// aux-build:dyn-star-foreign.rs + +extern crate dyn_star_foreign; + +fn main() { + dyn_star_foreign::require_dyn_star_display(1usize); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/dyn-star/no-implicit-dyn-star.stderr b/src/test/ui/dyn-star/no-implicit-dyn-star.stderr new file mode 100644 index 0000000000000..e7c5918629bdc --- /dev/null +++ b/src/test/ui/dyn-star/no-implicit-dyn-star.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/no-implicit-dyn-star.rs:6:48 + | +LL | dyn_star_foreign::require_dyn_star_display(1usize); + | ------------------------------------------ ^^^^^^ expected trait object `dyn std::fmt::Display`, found `usize` + | | + | arguments to this function are incorrect + | + = note: expected trait object `(dyn* std::fmt::Display + 'static)` + found type `usize` +note: function defined here + --> $DIR/auxiliary/dyn-star-foreign.rs:6:8 + | +LL | pub fn require_dyn_star_display(_: dyn* Display) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. From 40bb4b740b094e79ce93f0649fa4522ddaa2eafd Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 14 Oct 2022 09:58:48 +0100 Subject: [PATCH 18/21] Update cargo 12 commits in b8f30cb23c4e5f20854a4f683325782b7cff9837..b332991a57c9d055f1864de1eed93e2178d49440 2022-10-10 19:16:06 +0000 to 2022-10-13 22:05:28 +0000 - Differentiate the warning when an alias (built-in or user-defined) shadows an external subcommand (rust-lang/cargo#11170) - chore: Update tests for latest clap (rust-lang/cargo#11235) - feat(publish): Support 'publish.timeout' config behind '-Zpublish-timeout' (rust-lang/cargo#11230) - Add missing edition (rust-lang/cargo#11231) - doc(profiles): add module level doc (rust-lang/cargo#11219) - refactor(publish): Clarify which SourceId is being used (rust-lang/cargo#11216) - Add new SourceKind::SparseRegistry to differentiate sparse registries (rust-lang/cargo#11209) - Fix deadlock when build scripts are waiting for input on stdin (rust-lang/cargo#11205) - refactor: New variant `FeaturesFor::ArtifactDep` (rust-lang/cargo#11184) - Fix rustdoc warning about unclosed HTML tag (rust-lang/cargo#11221) - refactor(tests): Prepare for wait-for-publish test changes (rust-lang/cargo#11210) - Add configuration option for controlling crates.io protocol (rust-lang/cargo#11215) --- Cargo.lock | 8 ++++---- src/tools/cargo | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0cc7f8a1c7ce3..f393a91809417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -297,7 +297,7 @@ dependencies = [ "cargo-test-macro", "cargo-test-support", "cargo-util", - "clap 4.0.9", + "clap 4.0.15", "crates-io", "curl", "curl-sys", @@ -439,7 +439,7 @@ dependencies = [ [[package]] name = "cargo-util" -version = "0.2.1" +version = "0.2.2" dependencies = [ "anyhow", "core-foundation", @@ -602,9 +602,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.9" +version = "4.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30607dd93c420c6f1f80b544be522a0238a7db35e6a12968d28910983fee0df0" +checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f" dependencies = [ "atty", "bitflags", diff --git a/src/tools/cargo b/src/tools/cargo index b8f30cb23c4e5..b332991a57c9d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit b8f30cb23c4e5f20854a4f683325782b7cff9837 +Subproject commit b332991a57c9d055f1864de1eed93e2178d49440 From f528414e4092815e96690275c527717871ff411d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Oct 2022 11:32:00 +0200 Subject: [PATCH 19/21] Add missing checks for `doc(cfg_hide(...))` attribute --- .../locales/en-US/passes.ftl | 3 +++ compiler/rustc_passes/src/check_attr.rs | 23 +++++++++++++++++++ compiler/rustc_passes/src/errors.rs | 4 ++++ 3 files changed, 30 insertions(+) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 1f1c9c29d665a..4bc6bd9fb2207 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -145,6 +145,9 @@ passes_doc_test_takes_list = passes_doc_primitive = `doc(primitive)` should never have been stable +passes_doc_cfg_hide_takes_list = + `#[doc(cfg_hide(...)]` takes a list of attributes + passes_doc_test_unknown_any = unknown `doc` attribute `{$path}` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 73fb89bbc385e..c5ba4eb68fac0 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -934,6 +934,22 @@ impl CheckAttrVisitor<'_> { is_valid } + /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes. + /// Returns `true` if valid. + fn check_doc_cfg_hide(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool { + if meta.meta_item_list().is_some() { + true + } else { + self.tcx.emit_spanned_lint( + INVALID_DOC_ATTRIBUTES, + hir_id, + meta.span(), + errors::DocCfgHideTakesList, + ); + false + } + } + /// Runs various checks on `#[doc]` attributes. Returns `true` if valid. /// /// `specified_inline` should be initialized to `None` and kept for the scope @@ -987,6 +1003,13 @@ impl CheckAttrVisitor<'_> { is_valid = false; } + sym::cfg_hide + if !self.check_attr_crate_level(attr, meta, hir_id) + || !self.check_doc_cfg_hide(meta, hir_id) => + { + is_valid = false; + } + sym::inline | sym::no_inline if !self.check_doc_inline( attr, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 1cc81a9ab9884..ed54834134453 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -271,6 +271,10 @@ pub struct DocTestUnknown { #[diag(passes::doc_test_takes_list)] pub struct DocTestTakesList; +#[derive(LintDiagnostic)] +#[diag(passes::doc_cfg_hide_takes_list)] +pub struct DocCfgHideTakesList; + #[derive(LintDiagnostic)] #[diag(passes::doc_primitive)] pub struct DocPrimitive; From 6f0c2470dbc3eeff7aa243965ec8c3dc7b64e254 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Oct 2022 11:32:26 +0200 Subject: [PATCH 20/21] Add UI test for invalid `doc(cfg_hide(...))` attributes --- src/test/rustdoc-ui/doc_cfg_hide.rs | 11 +++++++ src/test/rustdoc-ui/doc_cfg_hide.stderr | 40 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/test/rustdoc-ui/doc_cfg_hide.rs create mode 100644 src/test/rustdoc-ui/doc_cfg_hide.stderr diff --git a/src/test/rustdoc-ui/doc_cfg_hide.rs b/src/test/rustdoc-ui/doc_cfg_hide.rs new file mode 100644 index 0000000000000..5d8791748a012 --- /dev/null +++ b/src/test/rustdoc-ui/doc_cfg_hide.rs @@ -0,0 +1,11 @@ +#![feature(doc_cfg_hide)] +#![deny(warnings)] + +#![doc(cfg_hide = "test")] //~ ERROR +//~^ WARN +#![doc(cfg_hide)] //~ ERROR +//~^ WARN + +#[doc(cfg_hide(doc))] //~ ERROR +//~^ WARN +pub fn foo() {} diff --git a/src/test/rustdoc-ui/doc_cfg_hide.stderr b/src/test/rustdoc-ui/doc_cfg_hide.stderr new file mode 100644 index 0000000000000..03623368cd047 --- /dev/null +++ b/src/test/rustdoc-ui/doc_cfg_hide.stderr @@ -0,0 +1,40 @@ +error: this attribute can only be applied at the crate level + --> $DIR/doc_cfg_hide.rs:9:7 + | +LL | #[doc(cfg_hide(doc))] + | ^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 + = note: read for more information +note: the lint level is defined here + --> $DIR/doc_cfg_hide.rs:2:9 + | +LL | #![deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(invalid_doc_attributes)]` implied by `#[deny(warnings)]` +help: to apply to the crate, use an inner attribute + | +LL | #![doc(cfg_hide(doc))] + | ~~~~~~~~~~~~~~~~~~~~~~ + +error: `#[doc(cfg_hide(...)]` takes a list of attributes + --> $DIR/doc_cfg_hide.rs:4:8 + | +LL | #![doc(cfg_hide = "test")] + | ^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 + +error: `#[doc(cfg_hide(...)]` takes a list of attributes + --> $DIR/doc_cfg_hide.rs:6:8 + | +LL | #![doc(cfg_hide)] + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #82730 + +error: aborting due to 3 previous errors + From 062ea9ce4ded4e5a864dfb4109d6533e03d67679 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sat, 15 Oct 2022 02:45:11 +0900 Subject: [PATCH 21/21] remove no_core feature --- src/test/ui/traits/issue-102989.rs | 5 +--- src/test/ui/traits/issue-102989.stderr | 35 ++++++++------------------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/test/ui/traits/issue-102989.rs b/src/test/ui/traits/issue-102989.rs index cb1e3271d26e8..62f95272fbfd2 100644 --- a/src/test/ui/traits/issue-102989.rs +++ b/src/test/ui/traits/issue-102989.rs @@ -1,9 +1,6 @@ -//~ ERROR can't find crate for `profiler_builtins` -// compile-flags: -Cinstrument-coverage // normalize-stderr-test "loaded from .*libcore-.*.rlib" -> "loaded from SYSROOT/libcore-*.rlib" -#![no_core] -#![feature(no_core, lang_items)] +#![feature(lang_items)] #[lang="sized"] trait Sized { } //~ ERROR found duplicate lang item `sized` diff --git a/src/test/ui/traits/issue-102989.stderr b/src/test/ui/traits/issue-102989.stderr index efea2251a13f8..efe1a24677457 100644 --- a/src/test/ui/traits/issue-102989.stderr +++ b/src/test/ui/traits/issue-102989.stderr @@ -1,5 +1,5 @@ error: `self` parameter is only allowed in associated functions - --> $DIR/issue-102989.rs:10:15 + --> $DIR/issue-102989.rs:7:15 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^ not semantically valid as function parameter @@ -7,50 +7,37 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { = note: associated functions are those in `impl` or `trait` definitions error[E0412]: cannot find type `Struct` in this scope - --> $DIR/issue-102989.rs:10:22 + --> $DIR/issue-102989.rs:7:22 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^^^^^^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> $DIR/issue-102989.rs:14:13 + --> $DIR/issue-102989.rs:11:13 | LL | let x = x << 1; | ^ help: a local variable with a similar name exists: `f` -error: `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` - -error[E0463]: can't find crate for `profiler_builtins` - | - = note: the compiler may have been built without the profiler runtime - error[E0152]: found duplicate lang item `sized` - --> $DIR/issue-102989.rs:8:1 + --> $DIR/issue-102989.rs:5:1 | LL | trait Sized { } | ^^^^^^^^^^^ | - = note: the lang item is first defined in crate `core`. + = note: the lang item is first defined in crate `core` (which `std` depends on) = note: first definition in `core` loaded from SYSROOT/libcore-*.rlib = note: second definition in the local crate (`issue_102989`) -error: `#[panic_handler]` function required, but not found - -error: language item required, but not found: `eh_personality` - | - = note: this can occur when a binary crate with `#![no_std]` is compiled for a target where `eh_personality` is defined in the standard library - = help: you may be able to compile for a target that doesn't need `eh_personality`, specify a target with `--target` or in `.cargo/config` - error[E0277]: the size for values of type `{integer}` cannot be known at compilation time - --> $DIR/issue-102989.rs:14:15 + --> $DIR/issue-102989.rs:11:15 | LL | let x = x << 1; | ^^ doesn't have a size known at compile-time | - = help: the trait `core::marker::Sized` is not implemented for `{integer}` + = help: the trait `std::marker::Sized` is not implemented for `{integer}` error[E0308]: mismatched types - --> $DIR/issue-102989.rs:10:42 + --> $DIR/issue-102989.rs:7:42 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ---------- ^^^^ expected `&u32`, found `()` @@ -58,7 +45,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | implicitly returns `()` as its body has no tail or `return` expression | note: consider returning one of these bindings - --> $DIR/issue-102989.rs:10:30 + --> $DIR/issue-102989.rs:7:30 | LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { | ^ @@ -66,7 +53,7 @@ LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 { LL | let x = x << 1; | ^ -error: aborting due to 10 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0152, E0277, E0308, E0412, E0425, E0463. +Some errors have detailed explanations: E0152, E0277, E0308, E0412, E0425. For more information about an error, try `rustc --explain E0152`.