Skip to content

Commit

Permalink
Auto merge of #130979 - matthiaskrgr:rollup-u7ylca5, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 5 pull requests

Successful merges:

 - #128778 (atomics: allow atomic and non-atomic reads to race)
 - #130918 (simplify LLVM submodule handling)
 - #130960 (Only add an automatic SONAME for Rust dylibs)
 - #130973 (compiletest: rename "runtest/crash.rs" to "runtest/crashes.rs" to be in line with the test directory)
 - #130976 (remove couple redundant clones)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Sep 28, 2024
2 parents 612796c + 2fca8e5 commit e6eb451
Show file tree
Hide file tree
Showing 31 changed files with 420 additions and 345 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ pub(crate) fn expand_deriving_smart_ptr(
// Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`.
let gen_args = vec![GenericArg::Type(alt_self_type.clone())];
add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone());
add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args.clone());
add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args);
}

fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2490,7 +2490,7 @@ fn add_order_independent_options(
}
}

cmd.set_output_kind(link_output_kind, out_filename);
cmd.set_output_kind(link_output_kind, crate_type, out_filename);

add_relro_args(cmd, sess);

Expand Down
83 changes: 69 additions & 14 deletions compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,12 @@ pub(crate) trait Linker {
fn is_cc(&self) -> bool {
false
}
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
fn set_output_kind(
&mut self,
output_kind: LinkOutputKind,
crate_type: CrateType,
out_filename: &Path,
);
fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
bug!("dylib linked with unsupported linker")
}
Expand Down Expand Up @@ -396,7 +401,7 @@ impl<'a> GccLinker<'a> {
]);
}

fn build_dylib(&mut self, out_filename: &Path) {
fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) {
// On mac we need to tell the linker to let this library be rpathed
if self.sess.target.is_like_osx {
if !self.is_ld {
Expand Down Expand Up @@ -427,7 +432,7 @@ impl<'a> GccLinker<'a> {
let mut out_implib = OsString::from("--out-implib=");
out_implib.push(out_filename.with_file_name(implib_name));
self.link_arg(out_implib);
} else {
} else if crate_type == CrateType::Dylib {
// When dylibs are linked by a full path this value will get into `DT_NEEDED`
// instead of the full path, so the library can be later found in some other
// location than that specific path.
Expand Down Expand Up @@ -474,7 +479,12 @@ impl<'a> Linker for GccLinker<'a> {
!self.is_ld
}

fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
fn set_output_kind(
&mut self,
output_kind: LinkOutputKind,
crate_type: CrateType,
out_filename: &Path,
) {
match output_kind {
LinkOutputKind::DynamicNoPicExe => {
if !self.is_ld && self.is_gnu {
Expand Down Expand Up @@ -509,10 +519,10 @@ impl<'a> Linker for GccLinker<'a> {
self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
}
}
LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename),
LinkOutputKind::StaticDylib => {
self.link_or_cc_arg("-static");
self.build_dylib(out_filename);
self.build_dylib(crate_type, out_filename);
}
LinkOutputKind::WasiReactorExe => {
self.link_args(&["--entry", "_initialize"]);
Expand Down Expand Up @@ -866,7 +876,12 @@ impl<'a> Linker for MsvcLinker<'a> {
&mut self.cmd
}

fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
fn set_output_kind(
&mut self,
output_kind: LinkOutputKind,
_crate_type: CrateType,
out_filename: &Path,
) {
match output_kind {
LinkOutputKind::DynamicNoPicExe
| LinkOutputKind::DynamicPicExe
Expand Down Expand Up @@ -1124,7 +1139,13 @@ impl<'a> Linker for EmLinker<'a> {
true
}

fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn set_output_kind(
&mut self,
_output_kind: LinkOutputKind,
_crate_type: CrateType,
_out_filename: &Path,
) {
}

fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
// Emscripten always links statically
Expand Down Expand Up @@ -1273,7 +1294,12 @@ impl<'a> Linker for WasmLd<'a> {
&mut self.cmd
}

fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
fn set_output_kind(
&mut self,
output_kind: LinkOutputKind,
_crate_type: CrateType,
_out_filename: &Path,
) {
match output_kind {
LinkOutputKind::DynamicNoPicExe
| LinkOutputKind::DynamicPicExe
Expand Down Expand Up @@ -1422,7 +1448,13 @@ impl<'a> Linker for L4Bender<'a> {
&mut self.cmd
}

fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn set_output_kind(
&mut self,
_output_kind: LinkOutputKind,
_crate_type: CrateType,
_out_filename: &Path,
) {
}

fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) {
self.hint_static();
Expand Down Expand Up @@ -1568,7 +1600,12 @@ impl<'a> Linker for AixLinker<'a> {
&mut self.cmd
}

fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
fn set_output_kind(
&mut self,
output_kind: LinkOutputKind,
_crate_type: CrateType,
out_filename: &Path,
) {
match output_kind {
LinkOutputKind::DynamicDylib => {
self.hint_dynamic();
Expand Down Expand Up @@ -1775,7 +1812,13 @@ impl<'a> Linker for PtxLinker<'a> {
&mut self.cmd
}

fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn set_output_kind(
&mut self,
_output_kind: LinkOutputKind,
_crate_type: CrateType,
_out_filename: &Path,
) {
}

fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
panic!("staticlibs not supported")
Expand Down Expand Up @@ -1841,7 +1884,13 @@ impl<'a> Linker for LlbcLinker<'a> {
&mut self.cmd
}

fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn set_output_kind(
&mut self,
_output_kind: LinkOutputKind,
_crate_type: CrateType,
_out_filename: &Path,
) {
}

fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
panic!("staticlibs not supported")
Expand Down Expand Up @@ -1912,7 +1961,13 @@ impl<'a> Linker for BpfLinker<'a> {
&mut self.cmd
}

fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn set_output_kind(
&mut self,
_output_kind: LinkOutputKind,
_crate_type: CrateType,
_out_filename: &Path,
) {
}

fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) {
panic!("staticlibs not supported")
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1027,7 +1027,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
// Point at this range.
first_range: thir_pat.span,
// That's the gap that isn't covered.
max: gap_as_pat.to_string(),
max: gap_as_pat,
// Suggest `lo..=max` instead.
suggestion: suggested_range,
},
Expand Down
10 changes: 6 additions & 4 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1895,11 +1895,17 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
/// uniqueness guarantee for mutable references is unaffected. There is *no* legal way to obtain
/// aliasing `&mut`, not even with `UnsafeCell<T>`.
///
/// `UnsafeCell` does nothing to avoid data races; they are still undefined behavior. If multiple
/// threads have access to the same `UnsafeCell`, they must follow the usual rules of the
/// [concurrent memory model]: conflicting non-synchronized accesses must be done via the APIs in
/// [`core::sync::atomic`].
///
/// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer
/// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer
/// correctly.
///
/// [`.get()`]: `UnsafeCell::get`
/// [concurrent memory model]: ../sync/atomic/index.html#memory-model-for-atomic-accesses
///
/// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious:
///
Expand All @@ -1922,10 +1928,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
/// live memory and the compiler is allowed to insert spurious reads if it can prove that this
/// memory has not yet been deallocated.
///
/// - At all times, you must avoid data races. If multiple threads have access to
/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other
/// accesses (or use atomics).
///
/// To assist with proper design, the following scenarios are explicitly declared legal
/// for single-threaded code:
///
Expand Down
81 changes: 50 additions & 31 deletions library/core/src/sync/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,42 @@
//!
//! ## Memory model for atomic accesses
//!
//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`.
//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating
//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference
//! ends. A Rust atomic type that is exclusively owned or behind a mutable reference does *not*
//! correspond to an “atomic object” in C++, since the underlying primitive can be mutably accessed,
//! for example with `get_mut`, to perform non-atomic operations.
//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically the rules
//! from the [`intro.races`][cpp-intro.races] section, without the "consume" memory ordering. Since
//! C++ uses an object-based memory model whereas Rust is access-based, a bit of translation work
//! has to be done to apply the C++ rules to Rust: whenever C++ talks about "the value of an
//! object", we understand that to mean the resulting bytes obtained when doing a read. When the C++
//! standard talks about "the value of an atomic object", this refers to the result of doing an
//! atomic load (via the operations provided in this module). A "modification of an atomic object"
//! refers to an atomic store.
//!
//! [cpp]: https://en.cppreference.com/w/cpp/atomic
//! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the
//! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being
//! destroyed when the lifetime of the shared reference ends. The main difference is that Rust
//! permits concurrent atomic and non-atomic reads to the same memory as those cause no issue in the
//! C++ memory model, they are just forbidden in C++ because memory is partitioned into "atomic
//! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object
//! into an atomic object).
//!
//! The most important aspect of this model is that *data races* are undefined behavior. A data race
//! is defined as conflicting non-synchronized accesses where at least one of the accesses is
//! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at
//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before*
//! the other, according to the happens-before order of the memory model.
//!
//! Each method takes an [`Ordering`] which represents the strength of
//! the memory barrier for that operation. These orderings are the
//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2].
//! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust
//! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially
//! overlap. In other words, every pair of non-synchronized atomic accesses must be either disjoint,
//! access the exact same memory (including using the same access size), or both be reads.
//!
//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order
//! [2]: ../../../nomicon/atomics.html
//! Each atomic access takes an [`Ordering`] which defines how the operation interacts with the
//! happens-before order. These orderings behave the same as the corresponding [C++20 atomic
//! orderings][cpp_memory_order]. For more information, see the [nomicon].
//!
//! Since C++ does not support mixing atomic and non-atomic accesses, or non-synchronized
//! different-sized accesses to the same data, Rust does not support those operations either.
//! Note that both of those restrictions only apply if the accesses are non-synchronized.
//! [cpp]: https://en.cppreference.com/w/cpp/atomic
//! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races
//! [cpp_memory_order]: https://en.cppreference.com/w/cpp/atomic/memory_order
//! [nomicon]: ../../../nomicon/atomics.html
//!
//! ```rust,no_run undefined_behavior
//! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering};
Expand All @@ -52,27 +69,29 @@
//! let atomic = AtomicU16::new(0);
//!
//! thread::scope(|s| {
//! // This is UB: mixing atomic and non-atomic accesses
//! s.spawn(|| atomic.store(1, Ordering::Relaxed));
//! s.spawn(|| unsafe { atomic.as_ptr().write(2) });
//! // This is UB: conflicting non-synchronized accesses, at least one of which is non-atomic.
//! s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store
//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write
//! });
//!
//! thread::scope(|s| {
//! // This is UB: even reads are not allowed to be mixed
//! s.spawn(|| atomic.load(Ordering::Relaxed));
//! s.spawn(|| unsafe { atomic.as_ptr().read() });
//! // This is fine: the accesses do not conflict (as none of them performs any modification).
//! // In C++ this would be disallowed since creating an `atomic_ref` precludes
//! // further non-atomic accesses, but Rust does not have that limitation.
//! s.spawn(|| atomic.load(Ordering::Relaxed)); // atomic load
//! s.spawn(|| unsafe { atomic.as_ptr().read() }); // non-atomic read
//! });
//!
//! thread::scope(|s| {
//! // This is fine, `join` synchronizes the code in a way such that atomic
//! // and non-atomic accesses can't happen "at the same time"
//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
//! handle.join().unwrap();
//! s.spawn(|| unsafe { atomic.as_ptr().write(2) });
//! // This is fine: `join` synchronizes the code in a way such that the atomic
//! // store happens-before the non-atomic write.
//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store
//! handle.join().unwrap(); // synchronize
//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write
//! });
//!
//! thread::scope(|s| {
//! // This is UB: using different-sized atomic accesses to the same data
//! // This is UB: non-synchronized conflicting differently-sized atomic accesses.
//! s.spawn(|| atomic.store(1, Ordering::Relaxed));
//! s.spawn(|| unsafe {
//! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic);
Expand All @@ -81,8 +100,8 @@
//! });
//!
//! thread::scope(|s| {
//! // This is fine, `join` synchronizes the code in a way such that
//! // differently-sized accesses can't happen "at the same time"
//! // This is fine: `join` synchronizes the code in a way such that
//! // the 1-byte store happens-before the 2-byte store.
//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
//! handle.join().unwrap();
//! s.spawn(|| unsafe {
Expand Down Expand Up @@ -137,7 +156,7 @@
//!
//! # Atomic accesses to read-only memory
//!
//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting
//! In general, *all* atomic accesses on read-only memory are undefined behavior. For instance, attempting
//! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only
//! operation) can still cause a segmentation fault if the underlying memory page is mapped read-only. Since
//! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault
Expand All @@ -153,7 +172,7 @@
//!
//! As an exception from the general rule stated above, "sufficiently small" atomic loads with
//! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not
//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies
//! undefined behavior. The exact size limit for what makes a load "sufficiently small" varies
//! depending on the target:
//!
//! | `target_arch` | Size limit |
Expand Down
3 changes: 2 additions & 1 deletion src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1205,7 +1205,8 @@ pub fn rustc_cargo_env(
// busting caches (e.g. like #71152).
if builder.config.llvm_enabled(target) {
let building_is_expensive =
crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).should_build();
crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false)
.should_build();
// `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler
let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage;
let should_skip_build = building_is_expensive && can_skip_build;
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2036,7 +2036,7 @@ fn maybe_install_llvm(
}
!builder.config.dry_run()
} else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) =
llvm::prebuilt_llvm_config(builder, target)
llvm::prebuilt_llvm_config(builder, target, true)
{
let mut cmd = command(llvm_config);
cmd.arg("--libfiles");
Expand Down
Loading

0 comments on commit e6eb451

Please sign in to comment.