Skip to content

Commit be046d7

Browse files
committed
Auto merge of rust-lang#137717 - matthiaskrgr:rollup-ejtd189, r=<try>
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
2 parents 96cfc75 + c90d8df commit be046d7

File tree

14 files changed

+468
-209
lines changed

14 files changed

+468
-209
lines changed

Diff for: Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3916,6 +3916,7 @@ dependencies = [
39163916
"rustc_target",
39173917
"rustc_trait_selection",
39183918
"rustc_type_ir",
3919+
"smallvec",
39193920
"tracing",
39203921
"unicode-security",
39213922
]

Diff for: compiler/rustc_attr_data_structures/src/attributes.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,14 @@ impl Deprecation {
138138
}
139139
}
140140

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

33
use smallvec::{Array, SmallVec};
44
use thin_vec::ThinVec;
@@ -13,39 +13,44 @@ pub trait FlatMapInPlace<T>: Sized {
1313
// The implementation of this method is syntactically identical for all the
1414
// different vector types.
1515
macro_rules! flat_map_in_place {
16-
() => {
16+
($vec:ident $( where T: $bound:path)?) => {
1717
fn flat_map_in_place<F, I>(&mut self, mut f: F)
1818
where
1919
F: FnMut(T) -> I,
2020
I: IntoIterator<Item = T>,
2121
{
22+
struct LeakGuard<'a, T $(: $bound)?>(&'a mut $vec<T>);
23+
24+
impl<'a, T $(: $bound)?> Drop for LeakGuard<'a, T> {
25+
fn drop(&mut self) {
26+
unsafe {
27+
self.0.set_len(0); // make sure we just leak elements in case of panic
28+
}
29+
}
30+
}
31+
32+
let this = LeakGuard(self);
33+
2234
let mut read_i = 0;
2335
let mut write_i = 0;
2436
unsafe {
25-
let mut old_len = self.len();
26-
self.set_len(0); // make sure we just leak elements in case of panic
27-
28-
while read_i < old_len {
37+
while read_i < this.0.len() {
2938
// move the read_i'th item out of the vector and map it
3039
// to an iterator
31-
let e = ptr::read(self.as_ptr().add(read_i));
40+
let e = ptr::read(this.0.as_ptr().add(read_i));
3241
let iter = f(e).into_iter();
3342
read_i += 1;
3443

3544
for e in iter {
3645
if write_i < read_i {
37-
ptr::write(self.as_mut_ptr().add(write_i), e);
46+
ptr::write(this.0.as_mut_ptr().add(write_i), e);
3847
write_i += 1;
3948
} else {
4049
// If this is reached we ran out of space
4150
// in the middle of the vector.
4251
// However, the vector is in a valid state here,
4352
// so we just do a somewhat inefficient insert.
44-
self.set_len(old_len);
45-
self.insert(write_i, e);
46-
47-
old_len = self.len();
48-
self.set_len(0);
53+
this.0.insert(write_i, e);
4954

5055
read_i += 1;
5156
write_i += 1;
@@ -54,20 +59,23 @@ macro_rules! flat_map_in_place {
5459
}
5560

5661
// write_i tracks the number of actually written new items.
57-
self.set_len(write_i);
62+
this.0.set_len(write_i);
63+
64+
// The ThinVec is in a sane state again. Prevent the LeakGuard from leaking the data.
65+
mem::forget(this);
5866
}
5967
}
6068
};
6169
}
6270

6371
impl<T> FlatMapInPlace<T> for Vec<T> {
64-
flat_map_in_place!();
72+
flat_map_in_place!(Vec);
6573
}
6674

6775
impl<T, A: Array<Item = T>> FlatMapInPlace<T> for SmallVec<A> {
68-
flat_map_in_place!();
76+
flat_map_in_place!(SmallVec where T: Array);
6977
}
7078

7179
impl<T> FlatMapInPlace<T> for ThinVec<T> {
72-
flat_map_in_place!();
80+
flat_map_in_place!(ThinVec);
7381
}

Diff for: compiler/rustc_lint/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ rustc_span = { path = "../rustc_span" }
2424
rustc_target = { path = "../rustc_target" }
2525
rustc_trait_selection = { path = "../rustc_trait_selection" }
2626
rustc_type_ir = { path = "../rustc_type_ir" }
27+
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
2728
tracing = "0.1"
2829
unicode-security = "0.1.0"
2930
# tidy-alphabetical-end

Diff for: compiler/rustc_lint/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
333333
*[other] {" "}{$identifier_type}
334334
} Unicode general security profile
335335
336+
lint_if_let_dtor = {$dtor_kind ->
337+
[dyn] value may invoke a custom destructor because it contains a trait object
338+
*[concrete] value invokes this custom destructor
339+
}
340+
336341
lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024
337342
.label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
338343
.help = the value is now dropped here in Edition 2024

Diff for: compiler/rustc_lint/src/if_let_rescope.rs

+59-18
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ use rustc_errors::{
77
Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
88
};
99
use rustc_hir::{self as hir, HirIdSet};
10-
use rustc_macros::LintDiagnostic;
11-
use rustc_middle::ty::TyCtxt;
10+
use rustc_macros::{LintDiagnostic, Subdiagnostic};
1211
use rustc_middle::ty::adjustment::Adjust;
12+
use rustc_middle::ty::significant_drop_order::{
13+
extract_component_with_significant_dtor, ty_dtor_span,
14+
};
15+
use rustc_middle::ty::{self, Ty, TyCtxt};
1316
use rustc_session::lint::{FutureIncompatibilityReason, LintId};
1417
use rustc_session::{declare_lint, impl_lint_pass};
15-
use rustc_span::Span;
1618
use rustc_span::edition::Edition;
19+
use rustc_span::{DUMMY_SP, Span};
20+
use smallvec::SmallVec;
1721

1822
use crate::{LateContext, LateLintPass};
1923

@@ -130,13 +134,15 @@ impl IfLetRescope {
130134
hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(),
131135
_ => return,
132136
};
137+
let mut seen_dyn = false;
133138
let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr);
134139
let mut significant_droppers = vec![];
135140
let mut lifetime_ends = vec![];
136141
let mut closing_brackets = 0;
137142
let mut alt_heads = vec![];
138143
let mut match_heads = vec![];
139144
let mut consequent_heads = vec![];
145+
let mut destructors = vec![];
140146
let mut first_if_to_lint = None;
141147
let mut first_if_to_rewrite = false;
142148
let mut empty_alt = false;
@@ -160,11 +166,25 @@ impl IfLetRescope {
160166
let before_conseq = conseq.span.shrink_to_lo();
161167
let lifetime_end = source_map.end_point(conseq.span);
162168

163-
if let ControlFlow::Break(significant_dropper) =
169+
if let ControlFlow::Break((drop_span, drop_tys)) =
164170
(FindSignificantDropper { cx }).check_if_let_scrutinee(init)
165171
{
172+
destructors.extend(drop_tys.into_iter().filter_map(|ty| {
173+
if let Some(span) = ty_dtor_span(tcx, ty) {
174+
Some(DestructorLabel { span, dtor_kind: "concrete" })
175+
} else if matches!(ty.kind(), ty::Dynamic(..)) {
176+
if seen_dyn {
177+
None
178+
} else {
179+
seen_dyn = true;
180+
Some(DestructorLabel { span: DUMMY_SP, dtor_kind: "dyn" })
181+
}
182+
} else {
183+
None
184+
}
185+
}));
166186
first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id)));
167-
significant_droppers.push(significant_dropper);
187+
significant_droppers.push(drop_span);
168188
lifetime_ends.push(lifetime_end);
169189
if ty_ascription.is_some()
170190
|| !expr.span.can_be_used_for_suggestions()
@@ -227,6 +247,7 @@ impl IfLetRescope {
227247
hir_id,
228248
span,
229249
IfLetRescopeLint {
250+
destructors,
230251
significant_droppers,
231252
lifetime_ends,
232253
rewrite: first_if_to_rewrite.then_some(IfLetRescopeRewrite {
@@ -288,6 +309,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
288309
#[derive(LintDiagnostic)]
289310
#[diag(lint_if_let_rescope)]
290311
struct IfLetRescopeLint {
312+
#[subdiagnostic]
313+
destructors: Vec<DestructorLabel>,
291314
#[label]
292315
significant_droppers: Vec<Span>,
293316
#[help]
@@ -347,6 +370,14 @@ impl Subdiagnostic for IfLetRescopeRewrite {
347370
}
348371
}
349372

373+
#[derive(Subdiagnostic)]
374+
#[note(lint_if_let_dtor)]
375+
struct DestructorLabel {
376+
#[primary_span]
377+
span: Span,
378+
dtor_kind: &'static str,
379+
}
380+
350381
struct AltHead(Span);
351382

352383
struct ConsequentRewrite {
@@ -374,7 +405,10 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
374405
/// of the scrutinee itself, and also recurses into the expression to find any ref
375406
/// exprs (or autoref) which would promote temporaries that would be scoped to the
376407
/// end of this `if`.
377-
fn check_if_let_scrutinee(&mut self, init: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
408+
fn check_if_let_scrutinee(
409+
&mut self,
410+
init: &'tcx hir::Expr<'tcx>,
411+
) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
378412
self.check_promoted_temp_with_drop(init)?;
379413
self.visit_expr(init)
380414
}
@@ -385,28 +419,35 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
385419
/// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref)
386420
/// or is the scrutinee of the `if let`, *and* the expression is not a place
387421
/// expr, and it has a significant drop.
388-
fn check_promoted_temp_with_drop(&self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
389-
if !expr.is_place_expr(|base| {
422+
fn check_promoted_temp_with_drop(
423+
&self,
424+
expr: &'tcx hir::Expr<'tcx>,
425+
) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
426+
if expr.is_place_expr(|base| {
390427
self.cx
391428
.typeck_results()
392429
.adjustments()
393430
.get(base.hir_id)
394431
.is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
395-
}) && self
396-
.cx
397-
.typeck_results()
398-
.expr_ty(expr)
399-
.has_significant_drop(self.cx.tcx, self.cx.typing_env())
400-
{
401-
ControlFlow::Break(expr.span)
402-
} else {
403-
ControlFlow::Continue(())
432+
}) {
433+
return ControlFlow::Continue(());
404434
}
435+
436+
let drop_tys = extract_component_with_significant_dtor(
437+
self.cx.tcx,
438+
self.cx.typing_env(),
439+
self.cx.typeck_results().expr_ty(expr),
440+
);
441+
if drop_tys.is_empty() {
442+
return ControlFlow::Continue(());
443+
}
444+
445+
ControlFlow::Break((expr.span, drop_tys))
405446
}
406447
}
407448

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

411452
fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> Self::Result {
412453
// Blocks introduce temporary terminating scope for all of its

Diff for: compiler/rustc_middle/src/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ pub mod normalize_erasing_regions;
122122
pub mod pattern;
123123
pub mod print;
124124
pub mod relate;
125+
pub mod significant_drop_order;
125126
pub mod trait_def;
126127
pub mod util;
127128
pub mod visit;

0 commit comments

Comments
 (0)