Skip to content

Commit

Permalink
Auto merge of #130569 - cuviper:beta-next, r=cuviper
Browse files Browse the repository at this point in the history
[beta] backports

- Don't warn empty branches unreachable for now #129103
- Win: Add dbghelp to the list of import libraries #130047
- `RepeatN`: use MaybeUninit #130145
- Update LLVM to 19 327ca6c #130212
- Revert #129749 to fix segfault in LLVM #130477
- Check params for unsafety in THIR #130531

r? cuviper
  • Loading branch information
bors committed Sep 20, 2024
2 parents 4976ae4 + 49891df commit 86853ee
Show file tree
Hide file tree
Showing 25 changed files with 212 additions and 470 deletions.
10 changes: 3 additions & 7 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1212,11 +1212,7 @@ struct LLVMRustThinLTOData {
// Not 100% sure what these are, but they impact what's internalized and
// what's inlined across modules, I believe.
#if LLVM_VERSION_GE(18, 0)
#if LLVM_VERSION_GE(20, 0)
FunctionImporter::ImportListsTy ImportLists;
#else
DenseMap<StringRef, FunctionImporter::ImportMapTy> ImportLists;
#endif
DenseMap<StringRef, FunctionImporter::ExportSetTy> ExportLists;
DenseMap<StringRef, GVSummaryMapTy> ModuleToDefinedGVSummaries;
#else
Expand Down Expand Up @@ -1425,13 +1421,13 @@ LLVMRustPrepareThinLTOInternalize(const LLVMRustThinLTOData *Data,
return true;
}

extern "C" bool LLVMRustPrepareThinLTOImport(LLVMRustThinLTOData *Data,
extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data,
LLVMModuleRef M,
LLVMTargetMachineRef TM) {
Module &Mod = *unwrap(M);
TargetMachine &Target = *unwrap(TM);

const auto &ImportList = Data->ImportLists[Mod.getModuleIdentifier()];
const auto &ImportList = Data->ImportLists.lookup(Mod.getModuleIdentifier());
auto Loader = [&](StringRef Identifier) {
const auto &Memory = Data->ModuleMap.lookup(Identifier);
auto &Context = Mod.getContext();
Expand Down Expand Up @@ -1614,7 +1610,7 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut,
LLVMRustThinLTOData *Data) {
SmallString<40> Key;
llvm::lto::Config conf;
const auto &ImportList = Data->ImportLists[ModId];
const auto &ImportList = Data->ImportLists.lookup(ModId);
const auto &ExportList = Data->ExportLists.lookup(ModId);
const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
warnings: self.warnings,
suggest_unsafe_block: self.suggest_unsafe_block,
};
// params in THIR may be unsafe, e.g. a union pattern.
for param in &inner_thir.params {
if let Some(param_pat) = param.pat.as_deref() {
inner_visitor.visit_pat(param_pat);
}
}
// Visit the body.
inner_visitor.visit_expr(&inner_thir[expr]);
// Unsafe blocks can be used in the inner body, make sure to take it into account
self.safety_context = inner_visitor.safety_context;
Expand Down Expand Up @@ -1066,6 +1073,13 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
warnings: &mut warnings,
suggest_unsafe_block: true,
};
// params in THIR may be unsafe, e.g. a union pattern.
for param in &thir.params {
if let Some(param_pat) = param.pat.as_deref() {
visitor.visit_pat(param_pat);
}
}
// Visit the body.
visitor.visit_expr(&thir[expr]);

warnings.sort_by_key(|w| w.block_span);
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_pattern_analysis/src/usefulness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,11 @@ impl<Cx: PatCx> PlaceInfo<Cx> {
self.is_scrutinee && matches!(ctors_for_ty, ConstructorSet::NoConstructors);
// Whether empty patterns are counted as useful or not. We only warn an empty arm unreachable if
// it is guaranteed unreachable by the opsem (i.e. if the place is `known_valid`).
let empty_arms_are_unreachable = self.validity.is_known_valid();
// We don't want to warn empty patterns as unreachable by default just yet. We will in a
// later version of rust or under a different lint name, see
// https://github.com/rust-lang/rust/pull/129103.
let empty_arms_are_unreachable = self.validity.is_known_valid()
&& (is_toplevel_exception || cx.is_exhaustive_patterns_feature_on());
// Whether empty patterns can be omitted for exhaustiveness. We ignore place validity in the
// toplevel exception and `exhaustive_patterns` cases for backwards compatibility.
let can_omit_empty_arms = self.validity.is_known_valid()
Expand Down
60 changes: 45 additions & 15 deletions library/core/src/iter/sources/repeat_n.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::fmt;
use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator};
use crate::mem::ManuallyDrop;
use crate::mem::{self, MaybeUninit};
use crate::num::NonZero;

/// Creates a new iterator that repeats a single element a given number of times.
Expand Down Expand Up @@ -58,14 +59,12 @@ use crate::num::NonZero;
#[inline]
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
let mut element = ManuallyDrop::new(element);

if count == 0 {
// SAFETY: we definitely haven't dropped it yet, since we only just got
// passed it in, and because the count is zero the instance we're about
// to create won't drop it, so to avoid leaking we need to now.
unsafe { ManuallyDrop::drop(&mut element) };
}
let element = if count == 0 {
// `element` gets dropped eagerly.
MaybeUninit::uninit()
} else {
MaybeUninit::new(element)
};

RepeatN { element, count }
}
Expand All @@ -74,31 +73,60 @@ pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
///
/// This `struct` is created by the [`repeat_n()`] function.
/// See its documentation for more.
#[derive(Clone, Debug)]
#[stable(feature = "iter_repeat_n", since = "1.82.0")]
pub struct RepeatN<A> {
count: usize,
// Invariant: has been dropped iff count == 0.
element: ManuallyDrop<A>,
// Invariant: uninit iff count == 0.
element: MaybeUninit<A>,
}

impl<A> RepeatN<A> {
/// Returns the element if it hasn't been dropped already.
fn element_ref(&self) -> Option<&A> {
if self.count > 0 {
// SAFETY: The count is non-zero, so it must be initialized.
Some(unsafe { self.element.assume_init_ref() })
} else {
None
}
}
/// If we haven't already dropped the element, return it in an option.
///
/// Clears the count so it won't be dropped again later.
#[inline]
fn take_element(&mut self) -> Option<A> {
if self.count > 0 {
self.count = 0;
let element = mem::replace(&mut self.element, MaybeUninit::uninit());
// SAFETY: We just set count to zero so it won't be dropped again,
// and it used to be non-zero so it hasn't already been dropped.
unsafe { Some(ManuallyDrop::take(&mut self.element)) }
unsafe { Some(element.assume_init()) }
} else {
None
}
}
}

#[stable(feature = "iter_repeat_n", since = "1.82.0")]
impl<A: Clone> Clone for RepeatN<A> {
fn clone(&self) -> RepeatN<A> {
RepeatN {
count: self.count,
element: self.element_ref().cloned().map_or_else(MaybeUninit::uninit, MaybeUninit::new),
}
}
}

#[stable(feature = "iter_repeat_n", since = "1.82.0")]
impl<A: fmt::Debug> fmt::Debug for RepeatN<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RepeatN")
.field("count", &self.count)
.field("element", &self.element_ref())
.finish()
}
}

#[stable(feature = "iter_repeat_n", since = "1.82.0")]
impl<A> Drop for RepeatN<A> {
fn drop(&mut self) {
Expand Down Expand Up @@ -194,9 +222,11 @@ impl<A: Clone> UncheckedIterator for RepeatN<A> {
// SAFETY: the check above ensured that the count used to be non-zero,
// so element hasn't been dropped yet, and we just lowered the count to
// zero so it won't be dropped later, and thus it's okay to take it here.
unsafe { ManuallyDrop::take(&mut self.element) }
unsafe { mem::replace(&mut self.element, MaybeUninit::uninit()).assume_init() }
} else {
A::clone(&self.element)
// SAFETY: the count is non-zero, so it must have not been dropped yet.
let element = unsafe { self.element.assume_init_ref() };
A::clone(element)
}
}
}
24 changes: 24 additions & 0 deletions library/core/tests/iter/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,27 @@ fn test_repeat_n_drop() {
drop((x0, x1, x2));
assert_eq!(count.get(), 3);
}

#[test]
fn test_repeat_n_soundness() {
let x = std::iter::repeat_n(String::from("use after free"), 0);
println!("{x:?}");

pub struct PanicOnClone;

impl Clone for PanicOnClone {
fn clone(&self) -> Self {
unreachable!()
}
}

// `repeat_n` should drop the element immediately if `count` is zero.
// `Clone` should then not try to clone the element.
let x = std::iter::repeat_n(PanicOnClone, 0);
let _ = x.clone();

let mut y = std::iter::repeat_n(Box::new(0), 1);
let x = y.next().unwrap();
let _z = y;
assert_eq!(0, *x);
}
1 change: 1 addition & 0 deletions library/windows_targets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ pub macro link {
#[link(name = "ntdll")]
#[link(name = "userenv")]
#[link(name = "ws2_32")]
#[link(name = "dbghelp")] // required for backtrace-rs symbolization
extern "C" {}
2 changes: 1 addition & 1 deletion src/llvm-project
Submodule llvm-project updated 188 files
Loading

0 comments on commit 86853ee

Please sign in to comment.