From c18da3ccd4cca6295bba599324962a469aae9aa9 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 6 Sep 2023 02:21:56 +0000 Subject: [PATCH 01/11] Add regression test for LLVM 17-rc3 miscompile See #115385 for more details. --- tests/codegen/issues/issue-115385.rs | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/codegen/issues/issue-115385.rs diff --git a/tests/codegen/issues/issue-115385.rs b/tests/codegen/issues/issue-115385.rs new file mode 100644 index 0000000000000..773b3507f2390 --- /dev/null +++ b/tests/codegen/issues/issue-115385.rs @@ -0,0 +1,50 @@ +// compile-flags: -O -Ccodegen-units=1 +// only-x86_64-unknown-linux-gnu + +#![crate_type = "lib"] + +#[repr(i64)] +pub enum Boolean { + False = 0, + True = 1, +} + +impl Clone for Boolean { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Boolean {} + +extern "C" { + fn set_value(foo: *mut i64); +} + +pub fn foo(x: bool) { + let mut foo = core::mem::MaybeUninit::::uninit(); + unsafe { + set_value(foo.as_mut_ptr()); + } + + if x { + let l1 = unsafe { *foo.as_mut_ptr().cast::() }; + if matches!(l1, Boolean::False) { + unsafe { + *foo.as_mut_ptr() = 0; + } + } + } + + let l2 = unsafe { *foo.as_mut_ptr() }; + if l2 == 2 { + // CHECK: call void @bar + bar(); + } +} + +#[no_mangle] +#[inline(never)] +pub fn bar() { + println!("Working correctly!"); +} From fe614712dded0a861fbcbf654663128318eb6dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 4 Sep 2023 23:12:30 +0200 Subject: [PATCH 02/11] Extract parallel operations in `rustc_data_structures::sync` into a new `parallel` submodule --- compiler/rustc_data_structures/src/sync.rs | 176 +--------------- .../src/sync/parallel.rs | 188 ++++++++++++++++++ 2 files changed, 193 insertions(+), 171 deletions(-) create mode 100644 compiler/rustc_data_structures/src/sync/parallel.rs diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index e82b0f6d49673..a12889c5e2b16 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -41,12 +41,9 @@ //! [^2] `MTLockRef` is a typedef. pub use crate::marker::*; -use parking_lot::Mutex; -use std::any::Any; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; -use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; mod lock; pub use lock::{Lock, LockGuard}; @@ -54,6 +51,11 @@ pub use lock::{Lock, LockGuard}; mod worker_local; pub use worker_local::{Registry, WorkerLocal}; +mod parallel; +#[cfg(parallel_compiler)] +pub use parallel::scope; +pub use parallel::{join, par_for_each_in, par_map, parallel_guard}; + pub use std::sync::atomic::Ordering; pub use std::sync::atomic::Ordering::SeqCst; @@ -105,37 +107,6 @@ mod mode { pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; -/// A guard used to hold panics that occur during a parallel section to later by unwound. -/// This is used for the parallel compiler to prevent fatal errors from non-deterministically -/// hiding errors by ensuring that everything in the section has completed executing before -/// continuing with unwinding. It's also used for the non-parallel code to ensure error message -/// output match the parallel compiler for testing purposes. -pub struct ParallelGuard { - panic: Mutex>>, -} - -impl ParallelGuard { - pub fn run(&self, f: impl FnOnce() -> R) -> Option { - catch_unwind(AssertUnwindSafe(f)) - .map_err(|err| { - *self.panic.lock() = Some(err); - }) - .ok() - } -} - -/// This gives access to a fresh parallel guard in the closure and will unwind any panics -/// caught in it after the closure returns. -#[inline] -pub fn parallel_guard(f: impl FnOnce(&ParallelGuard) -> R) -> R { - let guard = ParallelGuard { panic: Mutex::new(None) }; - let ret = f(&guard); - if let Some(panic) = guard.panic.into_inner() { - resume_unwind(panic); - } - ret -} - cfg_if! { if #[cfg(not(parallel_compiler))] { use std::ops::Add; @@ -227,44 +198,6 @@ cfg_if! { pub type AtomicU32 = Atomic; pub type AtomicU64 = Atomic; - pub fn join(oper_a: A, oper_b: B) -> (RA, RB) - where A: FnOnce() -> RA, - B: FnOnce() -> RB - { - let (a, b) = parallel_guard(|guard| { - let a = guard.run(oper_a); - let b = guard.run(oper_b); - (a, b) - }); - (a.unwrap(), b.unwrap()) - } - - #[macro_export] - macro_rules! parallel { - ($($blocks:block),*) => {{ - $crate::sync::parallel_guard(|guard| { - $(guard.run(|| $blocks);)* - }); - }} - } - - pub fn par_for_each_in(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) { - parallel_guard(|guard| { - t.into_iter().for_each(|i| { - guard.run(|| for_each(i)); - }); - }) - } - - pub fn par_map>( - t: T, - mut map: impl FnMut(<::IntoIter as Iterator>::Item) -> R, - ) -> C { - parallel_guard(|guard| { - t.into_iter().filter_map(|i| guard.run(|| map(i))).collect() - }) - } - pub use std::rc::Rc as Lrc; pub use std::rc::Weak as Weak; pub use std::cell::Ref as ReadGuard; @@ -370,105 +303,6 @@ cfg_if! { use std::thread; - #[inline] - pub fn join(oper_a: A, oper_b: B) -> (RA, RB) - where - A: FnOnce() -> RA + DynSend, - B: FnOnce() -> RB + DynSend, - { - if mode::is_dyn_thread_safe() { - let oper_a = FromDyn::from(oper_a); - let oper_b = FromDyn::from(oper_b); - let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()())); - (a.into_inner(), b.into_inner()) - } else { - let (a, b) = parallel_guard(|guard| { - let a = guard.run(oper_a); - let b = guard.run(oper_b); - (a, b) - }); - (a.unwrap(), b.unwrap()) - } - } - - // This function only works when `mode::is_dyn_thread_safe()`. - pub fn scope<'scope, OP, R>(op: OP) -> R - where - OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, - R: DynSend, - { - let op = FromDyn::from(op); - rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() - } - - /// Runs a list of blocks in parallel. The first block is executed immediately on - /// the current thread. Use that for the longest running block. - #[macro_export] - macro_rules! parallel { - (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { - parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) - }; - (impl $fblock:block [$($blocks:expr,)*] []) => { - ::rustc_data_structures::sync::scope(|s| { - $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); - s.spawn(move |_| block.into_inner()());)* - (|| $fblock)(); - }); - }; - ($fblock:block, $($blocks:block),*) => { - if rustc_data_structures::sync::is_dyn_thread_safe() { - // Reverse the order of the later blocks since Rayon executes them in reverse order - // when using a single thread. This ensures the execution order matches that - // of a single threaded rustc. - parallel!(impl $fblock [] [$($blocks),*]); - } else { - $crate::sync::parallel_guard(|guard| { - guard.run(|| $fblock); - $(guard.run(|| $blocks);)* - }); - } - }; - } - - use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; - - pub fn par_for_each_in + IntoParallelIterator>( - t: T, - for_each: impl Fn(I) + DynSync + DynSend - ) { - parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { - let for_each = FromDyn::from(for_each); - t.into_par_iter().for_each(|i| { - guard.run(|| for_each(i)); - }); - } else { - t.into_iter().for_each(|i| { - guard.run(|| for_each(i)); - }); - } - }); - } - - pub fn par_map< - I, - T: IntoIterator + IntoParallelIterator, - R: std::marker::Send, - C: FromIterator + FromParallelIterator - >( - t: T, - map: impl Fn(I) -> R + DynSync + DynSend - ) -> C { - parallel_guard(|guard| { - if mode::is_dyn_thread_safe() { - let map = FromDyn::from(map); - t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect() - } else { - t.into_iter().filter_map(|i| guard.run(|| map(i))).collect() - } - }) - } - /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread const ERROR_CHECKING: bool = false; diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs new file mode 100644 index 0000000000000..1944ddfb710d8 --- /dev/null +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -0,0 +1,188 @@ +//! This module defines parallel operations that are implemented in +//! one way for the serial compiler, and another way the parallel compiler. + +#![allow(dead_code)] + +use parking_lot::Mutex; +use std::any::Any; +use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe}; + +#[cfg(not(parallel_compiler))] +pub use disabled::*; +#[cfg(parallel_compiler)] +pub use enabled::*; + +/// A guard used to hold panics that occur during a parallel section to later by unwound. +/// This is used for the parallel compiler to prevent fatal errors from non-deterministically +/// hiding errors by ensuring that everything in the section has completed executing before +/// continuing with unwinding. It's also used for the non-parallel code to ensure error message +/// output match the parallel compiler for testing purposes. +pub struct ParallelGuard { + panic: Mutex>>, +} + +impl ParallelGuard { + pub fn run(&self, f: impl FnOnce() -> R) -> Option { + catch_unwind(AssertUnwindSafe(f)) + .map_err(|err| { + *self.panic.lock() = Some(err); + }) + .ok() + } +} + +/// This gives access to a fresh parallel guard in the closure and will unwind any panics +/// caught in it after the closure returns. +#[inline] +pub fn parallel_guard(f: impl FnOnce(&ParallelGuard) -> R) -> R { + let guard = ParallelGuard { panic: Mutex::new(None) }; + let ret = f(&guard); + if let Some(panic) = guard.panic.into_inner() { + resume_unwind(panic); + } + ret +} + +mod disabled { + use crate::sync::parallel_guard; + + #[macro_export] + #[cfg(not(parallel_compiler))] + macro_rules! parallel { + ($($blocks:block),*) => {{ + $crate::sync::parallel_guard(|guard| { + $(guard.run(|| $blocks);)* + }); + }} + } + + pub fn join(oper_a: A, oper_b: B) -> (RA, RB) + where + A: FnOnce() -> RA, + B: FnOnce() -> RB, + { + let (a, b) = parallel_guard(|guard| { + let a = guard.run(oper_a); + let b = guard.run(oper_b); + (a, b) + }); + (a.unwrap(), b.unwrap()) + } + + pub fn par_for_each_in(t: T, mut for_each: impl FnMut(T::Item)) { + parallel_guard(|guard| { + t.into_iter().for_each(|i| { + guard.run(|| for_each(i)); + }); + }) + } + + pub fn par_map>( + t: T, + mut map: impl FnMut(<::IntoIter as Iterator>::Item) -> R, + ) -> C { + parallel_guard(|guard| t.into_iter().filter_map(|i| guard.run(|| map(i))).collect()) + } +} + +#[cfg(parallel_compiler)] +mod enabled { + use crate::sync::{mode, parallel_guard, DynSend, DynSync, FromDyn}; + + /// Runs a list of blocks in parallel. The first block is executed immediately on + /// the current thread. Use that for the longest running block. + #[macro_export] + macro_rules! parallel { + (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { + parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) + }; + (impl $fblock:block [$($blocks:expr,)*] []) => { + ::rustc_data_structures::sync::scope(|s| { + $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); + s.spawn(move |_| block.into_inner()());)* + (|| $fblock)(); + }); + }; + ($fblock:block, $($blocks:block),*) => { + if rustc_data_structures::sync::is_dyn_thread_safe() { + // Reverse the order of the later blocks since Rayon executes them in reverse order + // when using a single thread. This ensures the execution order matches that + // of a single threaded rustc. + parallel!(impl $fblock [] [$($blocks),*]); + } else { + $crate::sync::parallel_guard(|guard| { + guard.run(|| $fblock); + $(guard.run(|| $blocks);)* + }); + } + }; + } + + // This function only works when `mode::is_dyn_thread_safe()`. + pub fn scope<'scope, OP, R>(op: OP) -> R + where + OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, + R: DynSend, + { + let op = FromDyn::from(op); + rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() + } + + #[inline] + pub fn join(oper_a: A, oper_b: B) -> (RA, RB) + where + A: FnOnce() -> RA + DynSend, + B: FnOnce() -> RB + DynSend, + { + if mode::is_dyn_thread_safe() { + let oper_a = FromDyn::from(oper_a); + let oper_b = FromDyn::from(oper_b); + let (a, b) = rayon::join( + move || FromDyn::from(oper_a.into_inner()()), + move || FromDyn::from(oper_b.into_inner()()), + ); + (a.into_inner(), b.into_inner()) + } else { + super::disabled::join(oper_a, oper_b) + } + } + + use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; + + pub fn par_for_each_in + IntoParallelIterator>( + t: T, + for_each: impl Fn(I) + DynSync + DynSend, + ) { + parallel_guard(|guard| { + if mode::is_dyn_thread_safe() { + let for_each = FromDyn::from(for_each); + t.into_par_iter().for_each(|i| { + guard.run(|| for_each(i)); + }); + } else { + t.into_iter().for_each(|i| { + guard.run(|| for_each(i)); + }); + } + }); + } + + pub fn par_map< + I, + T: IntoIterator + IntoParallelIterator, + R: std::marker::Send, + C: FromIterator + FromParallelIterator, + >( + t: T, + map: impl Fn(I) -> R + DynSync + DynSend, + ) -> C { + parallel_guard(|guard| { + if mode::is_dyn_thread_safe() { + let map = FromDyn::from(map); + t.into_par_iter().filter_map(|i| guard.run(|| map(i))).collect() + } else { + t.into_iter().filter_map(|i| guard.run(|| map(i))).collect() + } + }) + } +} From ddd8878d697ac0006b25000137d457093917ae12 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 6 Sep 2023 22:13:56 +0000 Subject: [PATCH 03/11] Address feedback --- ...115385.rs => issue-115385-llvm-jump-threading.rs} | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) rename tests/codegen/issues/{issue-115385.rs => issue-115385-llvm-jump-threading.rs} (84%) diff --git a/tests/codegen/issues/issue-115385.rs b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs similarity index 84% rename from tests/codegen/issues/issue-115385.rs rename to tests/codegen/issues/issue-115385-llvm-jump-threading.rs index 773b3507f2390..142e3596d9617 100644 --- a/tests/codegen/issues/issue-115385.rs +++ b/tests/codegen/issues/issue-115385-llvm-jump-threading.rs @@ -1,5 +1,4 @@ // compile-flags: -O -Ccodegen-units=1 -// only-x86_64-unknown-linux-gnu #![crate_type = "lib"] @@ -19,6 +18,7 @@ impl Copy for Boolean {} extern "C" { fn set_value(foo: *mut i64); + fn bar(); } pub fn foo(x: bool) { @@ -39,12 +39,8 @@ pub fn foo(x: bool) { let l2 = unsafe { *foo.as_mut_ptr() }; if l2 == 2 { // CHECK: call void @bar - bar(); + unsafe { + bar(); + } } } - -#[no_mangle] -#[inline(never)] -pub fn bar() { - println!("Working correctly!"); -} From 086cf346342263f3f53a7b1794fd7623f94d82fe Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 7 Sep 2023 06:04:37 +0000 Subject: [PATCH 04/11] Don't ICE when computing ctype's repr_nullable_ptr for possibly-unsized ty --- compiler/rustc_lint/src/types.rs | 7 ++++++- .../lint/lint-ctypes-option-nonnull-unsized.rs | 8 ++++++++ .../lint-ctypes-option-nonnull-unsized.stderr | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs create mode 100644 tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fc4c29eb36d61..b30ab1b47338d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -923,7 +923,12 @@ pub(crate) fn repr_nullable_ptr<'tcx>( } // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_abi = &tcx.layout_of(param_env.and(field_ty)).unwrap().abi; + let field_ty_layout = tcx.layout_of(param_env.and(field_ty)); + if field_ty_layout.is_err() && !field_ty.has_non_region_param() { + bug!("should be able to compute the layout of non-polymorphic type"); + } + + let field_ty_abi = &field_ty_layout.ok()?.abi; if let Abi::Scalar(field_ty_scalar) = field_ty_abi { match field_ty_scalar.valid_range(&tcx) { WrappingRange { start: 0, end } diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs new file mode 100644 index 0000000000000..ca08eb23a57eb --- /dev/null +++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.rs @@ -0,0 +1,8 @@ +#![deny(improper_ctypes_definitions)] + +extern "C" fn foo() -> Option<&'static T> { + //~^ ERROR `extern` fn uses type `Option<&T>`, which is not FFI-safe + None +} + +fn main() {} diff --git a/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr new file mode 100644 index 0000000000000..f59fb3cc750dd --- /dev/null +++ b/tests/ui/lint/lint-ctypes-option-nonnull-unsized.stderr @@ -0,0 +1,16 @@ +error: `extern` fn uses type `Option<&T>`, which is not FFI-safe + --> $DIR/lint-ctypes-option-nonnull-unsized.rs:3:45 + | +LL | extern "C" fn foo() -> Option<&'static T> { + | ^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint +note: the lint level is defined here + --> $DIR/lint-ctypes-option-nonnull-unsized.rs:1:9 + | +LL | #![deny(improper_ctypes_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 254e13d9f9dd38817a28880b99acd29a2fcc5613 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Sep 2023 07:38:03 +0200 Subject: [PATCH 05/11] fix homogeneous_aggregate not ignoring some 1-ZST --- compiler/rustc_target/src/abi/call/mod.rs | 13 ++++-- tests/ui/abi/compatibility.rs | 10 +---- .../ui/layout/homogeneous-aggr-transparent.rs | 44 +++++++++++++++++++ .../homogeneous-aggr-transparent.stderr | 32 ++++++++++++++ 4 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 tests/ui/layout/homogeneous-aggr-transparent.rs create mode 100644 tests/ui/layout/homogeneous-aggr-transparent.stderr diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 5d75974279ed0..1a4a46ceb4025 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -382,8 +382,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// only a single type (e.g., `(u32, u32)`). Such aggregates are often /// special-cased in ABIs. /// - /// Note: We generally ignore fields of zero-sized type when computing - /// this value (see #56877). + /// Note: We generally ignore 1-ZST fields when computing this value (see #56877). /// /// This is public so that it can be used in unit tests, but /// should generally only be relevant to the ABI details of @@ -441,12 +440,18 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { let mut total = start; for i in 0..layout.fields.count() { + let field = layout.field(cx, i); + if field.is_1zst() { + // No data here and no impact on layout, can be ignored. + // (We might be able to also ignore all aligned ZST but that's less clear.) + continue; + } + if !is_union && total != layout.fields.offset(i) { + // This field isn't just after the previous one we considered, abort. return Err(Heterogeneous); } - let field = layout.field(cx, i); - result = result.merge(field.homogeneous_aggregate(cx)?)?; // Keep track of the offset (without padding). diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index 0bbcba200c7e3..56ff1ebc52429 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -105,6 +105,8 @@ test_transparent!(zst, Zst); test_transparent!(unit, ()); test_transparent!(pair, (i32, f32)); // mixing in some floats since they often get special treatment test_transparent!(triple, (i8, i16, f32)); // chosen to fit into 64bit +test_transparent!(triple_f32, (f32, f32, f32)); // homogeneous case +test_transparent!(triple_f64, (f64, f64, f64)); test_transparent!(tuple, (i32, f32, i64, f64)); test_transparent!(empty_array, [u32; 0]); test_transparent!(empty_1zst_array, [u8; 0]); @@ -112,14 +114,6 @@ test_transparent!(small_array, [i32; 2]); // chosen to fit into 64bit test_transparent!(large_array, [i32; 16]); test_transparent!(enum_, Option); test_transparent!(enum_niched, Option<&'static i32>); -// Pure-float types that are not ScalarPair seem to be tricky. -// FIXME: -#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))] -mod tricky { - use super::*; - test_transparent!(triple_f32, (f32, f32, f32)); - test_transparent!(triple_f64, (f64, f64, f64)); -} // RFC 3391 . macro_rules! test_nonnull { diff --git a/tests/ui/layout/homogeneous-aggr-transparent.rs b/tests/ui/layout/homogeneous-aggr-transparent.rs new file mode 100644 index 0000000000000..9703d2bf294f6 --- /dev/null +++ b/tests/ui/layout/homogeneous-aggr-transparent.rs @@ -0,0 +1,44 @@ +#![feature(rustc_attrs)] +#![feature(transparent_unions)] +use std::marker::PhantomData; + +// Regression test for #115664. We want to ensure that `repr(transparent)` wrappers do not affect +// the result of `homogeneous_aggregate`. + +type Tuple = (f32, f32, f32); + +struct Zst; + +#[repr(transparent)] +struct Wrapper1(T); +#[repr(transparent)] +struct Wrapper2((), Zst, T); +#[repr(transparent)] +struct Wrapper3(T, [u8; 0], PhantomData); +#[repr(transparent)] +union WrapperUnion { + nothing: (), + something: T, +} + +#[rustc_layout(homogeneous_aggregate)] +pub type Test0 = Tuple; +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + +#[rustc_layout(homogeneous_aggregate)] +pub type Test1 = Wrapper1; +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + +#[rustc_layout(homogeneous_aggregate)] +pub type Test2 = Wrapper2; +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + +#[rustc_layout(homogeneous_aggregate)] +pub type Test3 = Wrapper3; +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + +#[rustc_layout(homogeneous_aggregate)] +pub type Test4 = WrapperUnion; +//~^ ERROR homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + +fn main() {} diff --git a/tests/ui/layout/homogeneous-aggr-transparent.stderr b/tests/ui/layout/homogeneous-aggr-transparent.stderr new file mode 100644 index 0000000000000..99eb703ac82b8 --- /dev/null +++ b/tests/ui/layout/homogeneous-aggr-transparent.stderr @@ -0,0 +1,32 @@ +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + --> $DIR/homogeneous-aggr-transparent.rs:25:1 + | +LL | pub type Test0 = Tuple; + | ^^^^^^^^^^^^^^ + +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + --> $DIR/homogeneous-aggr-transparent.rs:29:1 + | +LL | pub type Test1 = Wrapper1; + | ^^^^^^^^^^^^^^ + +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + --> $DIR/homogeneous-aggr-transparent.rs:33:1 + | +LL | pub type Test2 = Wrapper2; + | ^^^^^^^^^^^^^^ + +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + --> $DIR/homogeneous-aggr-transparent.rs:37:1 + | +LL | pub type Test3 = Wrapper3; + | ^^^^^^^^^^^^^^ + +error: homogeneous_aggregate: Ok(Homogeneous(Reg { kind: Float, size: Size(4 bytes) })) + --> $DIR/homogeneous-aggr-transparent.rs:41:1 + | +LL | pub type Test4 = WrapperUnion; + | ^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + From 0ed291453da7b7233f1b6f6535a2d7e80610d568 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 10 Sep 2023 09:31:10 +0000 Subject: [PATCH 06/11] Rename after_parsing callback to after_crate_root_parsing To avoid confusion if it is called after all parsing is done or not. --- compiler/rustc_driver_impl/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index e56347ab38e9b..0fe5a96619990 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -162,9 +162,10 @@ pub fn abort_on_err(result: Result, sess: &Session) -> T pub trait Callbacks { /// Called before creating the compiler instance fn config(&mut self, _config: &mut interface::Config) {} - /// Called after parsing. Return value instructs the compiler whether to + /// Called after parsing the crate root. Submodules are not yet parsed when + /// this callback is called. Return value instructs the compiler whether to /// continue the compilation afterwards (defaults to `Compilation::Continue`) - fn after_parsing<'tcx>( + fn after_crate_root_parsing<'tcx>( &mut self, _compiler: &interface::Compiler, _queries: &'tcx Queries<'tcx>, @@ -407,7 +408,7 @@ fn run_compiler( return early_exit(); } - if callbacks.after_parsing(compiler, queries) == Compilation::Stop { + if callbacks.after_crate_root_parsing(compiler, queries) == Compilation::Stop { return early_exit(); } From 90e9053189da16be1f1ee00836e692edb9bf8154 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 10 Sep 2023 09:32:38 +0000 Subject: [PATCH 07/11] Deprecate the pre_configure query Only deprecating it rather than making it private to just in case someone has a use case for it. --- compiler/rustc_interface/src/queries.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index e0d9998d919b1..f3a026f71a2bb 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -116,6 +116,7 @@ impl<'tcx> Queries<'tcx> { .compute(|| passes::parse(self.session()).map_err(|mut parse_error| parse_error.emit())) } + #[deprecated = "pre_configure may be made private in the future. If you need it please open an issue with your use case."] pub fn pre_configure(&self) -> Result> { self.pre_configure.compute(|| { let mut krate = self.parse()?.steal(); @@ -173,6 +174,7 @@ impl<'tcx> Queries<'tcx> { pub fn global_ctxt(&'tcx self) -> Result>> { self.gcx.compute(|| { let sess = self.session(); + #[allow(deprecated)] let (krate, pre_configured_attrs) = self.pre_configure()?.steal(); // parse `#[crate_name]` even if `--crate-name` was passed, to make sure it matches. From 2eca717a240a37e4e996d727b6506d2f2e990b74 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 10 Sep 2023 09:44:03 +0000 Subject: [PATCH 08/11] Remove EarlyErrorHandler argument from after_analysis callback It is only used by miri which can create a new one using the Session. --- compiler/rustc_driver_impl/src/lib.rs | 3 +-- compiler/rustc_smir/src/rustc_internal/mod.rs | 2 -- src/tools/miri/src/bin/miri.rs | 4 ++-- tests/run-make-fulldeps/obtain-borrowck/driver.rs | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 0fe5a96619990..f38adefa7c0b8 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -185,7 +185,6 @@ pub trait Callbacks { /// continue the compilation afterwards (defaults to `Compilation::Continue`) fn after_analysis<'tcx>( &mut self, - _handler: &EarlyErrorHandler, _compiler: &interface::Compiler, _queries: &'tcx Queries<'tcx>, ) -> Compilation { @@ -446,7 +445,7 @@ fn run_compiler( queries.global_ctxt()?.enter(|tcx| tcx.analysis(()))?; - if callbacks.after_analysis(&handler, compiler, queries) == Compilation::Stop { + if callbacks.after_analysis(compiler, queries) == Compilation::Stop { return early_exit(); } diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 73b8e060dd830..4203990ab0560 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -16,7 +16,6 @@ use rustc_driver::{Callbacks, Compilation, RunCompiler}; use rustc_interface::{interface, Queries}; use rustc_middle::mir::interpret::AllocId; use rustc_middle::ty::TyCtxt; -use rustc_session::EarlyErrorHandler; pub use rustc_span::def_id::{CrateNum, DefId}; fn with_tables(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R { @@ -233,7 +232,6 @@ where /// continue the compilation afterwards (defaults to `Compilation::Continue`) fn after_analysis<'tcx>( &mut self, - _handler: &EarlyErrorHandler, _compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>, ) -> Compilation { diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 97718f1f4a9f7..1e9219d4bb23a 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -59,7 +59,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_analysis<'tcx>( &mut self, - handler: &EarlyErrorHandler, _: &rustc_interface::interface::Compiler, queries: &'tcx rustc_interface::Queries<'tcx>, ) -> Compilation { @@ -68,7 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { tcx.sess.fatal("miri cannot be run on programs that fail compilation"); } - init_late_loggers(handler, tcx); + let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format); + init_late_loggers(&handler, tcx); if !tcx.crate_types().contains(&CrateType::Executable) { tcx.sess.fatal("miri only makes sense on bin crates"); } diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs index 04c551cf4bb6c..b59a65a713f95 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs @@ -27,7 +27,7 @@ use rustc_interface::{Config, Queries}; use rustc_middle::query::queries::mir_borrowck::ProvidedValue; use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::TyCtxt; -use rustc_session::{Session, EarlyErrorHandler}; +use rustc_session::Session; use std::cell::RefCell; use std::collections::HashMap; use std::thread_local; @@ -58,7 +58,6 @@ impl rustc_driver::Callbacks for CompilerCalls { // the result. fn after_analysis<'tcx>( &mut self, - _handler: &EarlyErrorHandler, compiler: &Compiler, queries: &'tcx Queries<'tcx>, ) -> Compilation { From c2e790044cee9095a9df0d7116005561c67924fe Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Sep 2023 08:14:39 +0000 Subject: [PATCH 09/11] Allow loading the SMIR for constants and statics --- compiler/rustc_smir/src/rustc_smir/mod.rs | 2 +- tests/ui-fulldeps/stable-mir/crate-info.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 7e533f990fd19..f4ef5fd13a41e 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -84,7 +84,7 @@ impl<'tcx> Context for Tables<'tcx> { fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body { let def_id = self[item]; - let mir = self.tcx.optimized_mir(def_id); + let mir = self.tcx.instance_mir(ty::InstanceDef::Item(def_id)); stable_mir::mir::Body { blocks: mir .basic_blocks diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs index d55eae86f074d..a11720c4b5542 100644 --- a/tests/ui-fulldeps/stable-mir/crate-info.rs +++ b/tests/ui-fulldeps/stable-mir/crate-info.rs @@ -154,6 +154,10 @@ fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> { } } + let foo_const = get_item(tcx, &items, (DefKind::Const, "FOO")).unwrap(); + // Ensure we don't panic trying to get the body of a constant. + foo_const.body(); + ControlFlow::Continue(()) } @@ -191,6 +195,8 @@ fn generate_input(path: &str) -> std::io::Result<()> { write!( file, r#" + pub const FOO: u32 = 1 + 2; + fn generic(t: T) -> [(); U] {{ _ = t; [(); U] From b99ace4179d6318b71d66a7919654cab70bf0104 Mon Sep 17 00:00:00 2001 From: DianQK Date: Mon, 11 Sep 2023 19:36:06 +0800 Subject: [PATCH 10/11] Add a test for #108030 Closes #108030. This issue has been resolved in LLVM 17. --- tests/run-make/lto-linkage-used-attr/Makefile | 9 ++++ tests/run-make/lto-linkage-used-attr/lib.rs | 50 +++++++++++++++++++ tests/run-make/lto-linkage-used-attr/main.rs | 10 ++++ 3 files changed, 69 insertions(+) create mode 100644 tests/run-make/lto-linkage-used-attr/Makefile create mode 100644 tests/run-make/lto-linkage-used-attr/lib.rs create mode 100644 tests/run-make/lto-linkage-used-attr/main.rs diff --git a/tests/run-make/lto-linkage-used-attr/Makefile b/tests/run-make/lto-linkage-used-attr/Makefile new file mode 100644 index 0000000000000..e78b83890ed3b --- /dev/null +++ b/tests/run-make/lto-linkage-used-attr/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +# Verify that the impl_* symbols are preserved. #108030 +# only-x86_64-unknown-linux-gnu +# min-llvm-version: 17 + +all: + $(RUSTC) -Cdebuginfo=0 -Copt-level=3 lib.rs + $(RUSTC) -Clto=fat -Cdebuginfo=0 -Copt-level=3 main.rs diff --git a/tests/run-make/lto-linkage-used-attr/lib.rs b/tests/run-make/lto-linkage-used-attr/lib.rs new file mode 100644 index 0000000000000..0a92ea9cd226b --- /dev/null +++ b/tests/run-make/lto-linkage-used-attr/lib.rs @@ -0,0 +1,50 @@ +#![crate_type = "rlib"] +#![crate_type = "cdylib"] + +#[macro_export] +macro_rules! asm_func { + ($name:expr, $body:expr $(, $($args:tt)*)?) => { + core::arch::global_asm!( + concat!( + ".p2align 4\n", + ".hidden ", $name, "\n", + ".global ", $name, "\n", + ".type ", $name, ",@function\n", + $name, ":\n", + $body, + ".size ", $name, ",.-", $name, + ) + $(, $($args)*)? + ); + }; +} + +macro_rules! libcall_trampoline { + ($libcall:ident ; $libcall_impl:ident) => { + asm_func!( + stringify!($libcall), + concat!( + " + .cfi_startproc simple + .cfi_def_cfa_offset 0 + jmp {} + .cfi_endproc + ", + ), + sym $libcall_impl + ); + }; +} + +pub mod trampolines { + extern "C" { + pub fn table_fill_funcref(); + pub fn table_fill_externref(); + } + + unsafe extern "C" fn impl_table_fill_funcref() {} + unsafe extern "C" fn impl_table_fill_externref() {} + + libcall_trampoline!(table_fill_funcref ; impl_table_fill_funcref); + libcall_trampoline!(table_fill_externref ; impl_table_fill_externref); +} diff --git a/tests/run-make/lto-linkage-used-attr/main.rs b/tests/run-make/lto-linkage-used-attr/main.rs new file mode 100644 index 0000000000000..256b02e5b0be0 --- /dev/null +++ b/tests/run-make/lto-linkage-used-attr/main.rs @@ -0,0 +1,10 @@ +extern crate lib; + +use lib::trampolines::*; + +fn main() { + unsafe { + table_fill_externref(); + table_fill_funcref(); + } +} From 5dd01ccf1c1bd451b1a59eb7c8c276b771229c9d Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 11 Sep 2023 13:01:15 -0400 Subject: [PATCH 11/11] Update books --- src/doc/edition-guide | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 2751bdcef1254..34fca48ed2845 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 2751bdcef125468ea2ee006c11992cd1405aebe5 +Subproject commit 34fca48ed284525b2f124bf93c51af36d6685492 diff --git a/src/doc/nomicon b/src/doc/nomicon index 388750b081c08..e3f3af69dce71 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 388750b081c0893c275044d37203f97709e058ba +Subproject commit e3f3af69dce71cd37a785bccb7e58449197d940c diff --git a/src/doc/reference b/src/doc/reference index d43038932adeb..ee7c676fd6e28 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit d43038932adeb16ada80e206d4c073d851298101 +Subproject commit ee7c676fd6e287459cb407337652412c990686c0 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 07e0df2f006e5..c954202c1e172 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 07e0df2f006e59d171c6bf3cafa9d61dbeb520d8 +Subproject commit c954202c1e1720cba5628f99543cc01188c7d6fc diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index b123ab4754127..08bb147d51e81 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit b123ab4754127d822ffb38349ce0fbf561f1b2fd +Subproject commit 08bb147d51e815b96e8db7ba4cf870f201c11ff8