Skip to content

Commit

Permalink
Auto merge of rust-lang#137717 - matthiaskrgr:rollup-ejtd189, r=<try>
Browse files Browse the repository at this point in the history
Rollup of 4 pull requests

Successful merges:

 - rust-lang#136579 (Fix UB in ThinVec::flat_map_in_place)
 - rust-lang#137455 (Reuse machinery from `tail_expr_drop_order` for `if_let_rescope`)
 - rust-lang#137480 (Return unexpected termination error instead of panicing in `Thread::join`)
 - rust-lang#137694 (Spruce up `AttributeKind` docs)

r? `@ghost`
`@rustbot` modify labels: rollup

try-job: i686-msvc-1
  • Loading branch information
bors committed Feb 27, 2025
2 parents 96cfc75 + c90d8df commit be046d7
Show file tree
Hide file tree
Showing 14 changed files with 468 additions and 209 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3916,6 +3916,7 @@ dependencies = [
"rustc_target",
"rustc_trait_selection",
"rustc_type_ir",
"smallvec",
"tracing",
"unicode-security",
]
Expand Down
13 changes: 8 additions & 5 deletions compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,14 @@ impl Deprecation {
}
}

/// Attributes represent parsed, *built in*, inert attributes. That means,
/// attributes that are not actually ever expanded.
/// For more information on this, see the module docs on the rustc_attr_parsing crate.
/// Represent parsed, *built in*, inert attributes.
///
/// That means attributes that are not actually ever expanded.
/// For more information on this, see the module docs on the [`rustc_attr_parsing`] crate.
/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler.
/// These are kept around after the AST, into the HIR and further on.
///
/// The word parsed could be a little misleading here, because the parser already parses
/// The word "parsed" could be a little misleading here, because the parser already parses
/// attributes early on. However, the result, an [`ast::Attribute`]
/// is only parsed at a high level, still containing a token stream in many cases. That is
/// because the structure of the contents varies from attribute to attribute.
Expand All @@ -153,7 +154,9 @@ impl Deprecation {
/// the place where `must_use` is checked) little to no extra parsing or validating needs to
/// happen.
///
/// For more docs, look in [`rustc_attr`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_attr/index.html)
/// For more docs, look in [`rustc_attr_parsing`].
///
/// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
pub enum AttributeKind {
// tidy-alphabetical-start
Expand Down
42 changes: 25 additions & 17 deletions compiler/rustc_data_structures/src/flat_map_in_place.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ptr;
use std::{mem, ptr};

use smallvec::{Array, SmallVec};
use thin_vec::ThinVec;
Expand All @@ -13,39 +13,44 @@ pub trait FlatMapInPlace<T>: Sized {
// The implementation of this method is syntactically identical for all the
// different vector types.
macro_rules! flat_map_in_place {
() => {
($vec:ident $( where T: $bound:path)?) => {
fn flat_map_in_place<F, I>(&mut self, mut f: F)
where
F: FnMut(T) -> I,
I: IntoIterator<Item = T>,
{
struct LeakGuard<'a, T $(: $bound)?>(&'a mut $vec<T>);

impl<'a, T $(: $bound)?> Drop for LeakGuard<'a, T> {
fn drop(&mut self) {
unsafe {
self.0.set_len(0); // make sure we just leak elements in case of panic
}
}
}

let this = LeakGuard(self);

let mut read_i = 0;
let mut write_i = 0;
unsafe {
let mut old_len = self.len();
self.set_len(0); // make sure we just leak elements in case of panic

while read_i < old_len {
while read_i < this.0.len() {
// move the read_i'th item out of the vector and map it
// to an iterator
let e = ptr::read(self.as_ptr().add(read_i));
let e = ptr::read(this.0.as_ptr().add(read_i));
let iter = f(e).into_iter();
read_i += 1;

for e in iter {
if write_i < read_i {
ptr::write(self.as_mut_ptr().add(write_i), e);
ptr::write(this.0.as_mut_ptr().add(write_i), e);
write_i += 1;
} else {
// If this is reached we ran out of space
// in the middle of the vector.
// However, the vector is in a valid state here,
// so we just do a somewhat inefficient insert.
self.set_len(old_len);
self.insert(write_i, e);

old_len = self.len();
self.set_len(0);
this.0.insert(write_i, e);

read_i += 1;
write_i += 1;
Expand All @@ -54,20 +59,23 @@ macro_rules! flat_map_in_place {
}

// write_i tracks the number of actually written new items.
self.set_len(write_i);
this.0.set_len(write_i);

// The ThinVec is in a sane state again. Prevent the LeakGuard from leaking the data.
mem::forget(this);
}
}
};
}

impl<T> FlatMapInPlace<T> for Vec<T> {
flat_map_in_place!();
flat_map_in_place!(Vec);
}

impl<T, A: Array<Item = T>> FlatMapInPlace<T> for SmallVec<A> {
flat_map_in_place!();
flat_map_in_place!(SmallVec where T: Array);
}

impl<T> FlatMapInPlace<T> for ThinVec<T> {
flat_map_in_place!();
flat_map_in_place!(ThinVec);
}
1 change: 1 addition & 0 deletions compiler/rustc_lint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tracing = "0.1"
unicode-security = "0.1.0"
# tidy-alphabetical-end
5 changes: 5 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
*[other] {" "}{$identifier_type}
} Unicode general security profile
lint_if_let_dtor = {$dtor_kind ->
[dyn] value may invoke a custom destructor because it contains a trait object
*[concrete] value invokes this custom destructor
}
lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024
.label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
.help = the value is now dropped here in Edition 2024
Expand Down
77 changes: 59 additions & 18 deletions compiler/rustc_lint/src/if_let_rescope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ use rustc_errors::{
Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
};
use rustc_hir::{self as hir, HirIdSet};
use rustc_macros::LintDiagnostic;
use rustc_middle::ty::TyCtxt;
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::significant_drop_order::{
extract_component_with_significant_dtor, ty_dtor_span,
};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::{FutureIncompatibilityReason, LintId};
use rustc_session::{declare_lint, impl_lint_pass};
use rustc_span::Span;
use rustc_span::edition::Edition;
use rustc_span::{DUMMY_SP, Span};
use smallvec::SmallVec;

use crate::{LateContext, LateLintPass};

Expand Down Expand Up @@ -130,13 +134,15 @@ impl IfLetRescope {
hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(),
_ => return,
};
let mut seen_dyn = false;
let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr);
let mut significant_droppers = vec![];
let mut lifetime_ends = vec![];
let mut closing_brackets = 0;
let mut alt_heads = vec![];
let mut match_heads = vec![];
let mut consequent_heads = vec![];
let mut destructors = vec![];
let mut first_if_to_lint = None;
let mut first_if_to_rewrite = false;
let mut empty_alt = false;
Expand All @@ -160,11 +166,25 @@ impl IfLetRescope {
let before_conseq = conseq.span.shrink_to_lo();
let lifetime_end = source_map.end_point(conseq.span);

if let ControlFlow::Break(significant_dropper) =
if let ControlFlow::Break((drop_span, drop_tys)) =
(FindSignificantDropper { cx }).check_if_let_scrutinee(init)
{
destructors.extend(drop_tys.into_iter().filter_map(|ty| {
if let Some(span) = ty_dtor_span(tcx, ty) {
Some(DestructorLabel { span, dtor_kind: "concrete" })
} else if matches!(ty.kind(), ty::Dynamic(..)) {
if seen_dyn {
None
} else {
seen_dyn = true;
Some(DestructorLabel { span: DUMMY_SP, dtor_kind: "dyn" })
}
} else {
None
}
}));
first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id)));
significant_droppers.push(significant_dropper);
significant_droppers.push(drop_span);
lifetime_ends.push(lifetime_end);
if ty_ascription.is_some()
|| !expr.span.can_be_used_for_suggestions()
Expand Down Expand Up @@ -227,6 +247,7 @@ impl IfLetRescope {
hir_id,
span,
IfLetRescopeLint {
destructors,
significant_droppers,
lifetime_ends,
rewrite: first_if_to_rewrite.then_some(IfLetRescopeRewrite {
Expand Down Expand Up @@ -288,6 +309,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
#[derive(LintDiagnostic)]
#[diag(lint_if_let_rescope)]
struct IfLetRescopeLint {
#[subdiagnostic]
destructors: Vec<DestructorLabel>,
#[label]
significant_droppers: Vec<Span>,
#[help]
Expand Down Expand Up @@ -347,6 +370,14 @@ impl Subdiagnostic for IfLetRescopeRewrite {
}
}

#[derive(Subdiagnostic)]
#[note(lint_if_let_dtor)]
struct DestructorLabel {
#[primary_span]
span: Span,
dtor_kind: &'static str,
}

struct AltHead(Span);

struct ConsequentRewrite {
Expand Down Expand Up @@ -374,7 +405,10 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
/// of the scrutinee itself, and also recurses into the expression to find any ref
/// exprs (or autoref) which would promote temporaries that would be scoped to the
/// end of this `if`.
fn check_if_let_scrutinee(&mut self, init: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
fn check_if_let_scrutinee(
&mut self,
init: &'tcx hir::Expr<'tcx>,
) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
self.check_promoted_temp_with_drop(init)?;
self.visit_expr(init)
}
Expand All @@ -385,28 +419,35 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
/// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref)
/// or is the scrutinee of the `if let`, *and* the expression is not a place
/// expr, and it has a significant drop.
fn check_promoted_temp_with_drop(&self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
if !expr.is_place_expr(|base| {
fn check_promoted_temp_with_drop(
&self,
expr: &'tcx hir::Expr<'tcx>,
) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
if expr.is_place_expr(|base| {
self.cx
.typeck_results()
.adjustments()
.get(base.hir_id)
.is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
}) && self
.cx
.typeck_results()
.expr_ty(expr)
.has_significant_drop(self.cx.tcx, self.cx.typing_env())
{
ControlFlow::Break(expr.span)
} else {
ControlFlow::Continue(())
}) {
return ControlFlow::Continue(());
}

let drop_tys = extract_component_with_significant_dtor(
self.cx.tcx,
self.cx.typing_env(),
self.cx.typeck_results().expr_ty(expr),
);
if drop_tys.is_empty() {
return ControlFlow::Continue(());
}

ControlFlow::Break((expr.span, drop_tys))
}
}

impl<'tcx> Visitor<'tcx> for FindSignificantDropper<'_, 'tcx> {
type Result = ControlFlow<Span>;
type Result = ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)>;

fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> Self::Result {
// Blocks introduce temporary terminating scope for all of its
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ pub mod normalize_erasing_regions;
pub mod pattern;
pub mod print;
pub mod relate;
pub mod significant_drop_order;
pub mod trait_def;
pub mod util;
pub mod visit;
Expand Down
Loading

0 comments on commit be046d7

Please sign in to comment.