Skip to content

Commit 636d7ff

Browse files
committed
Auto merge of rust-lang#129275 - matthiaskrgr:rollup-qv64hg6, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#129194 (Fix bootstrap test `detect_src_and_out` on Windows) - rust-lang#129217 (safe transmute: check lifetimes) - rust-lang#129223 ( Fix wrong argument for `get_fn_decl`) - rust-lang#129235 (Check that `#[may_dangle]` is properly applied) - rust-lang#129245 (Fix a typo in `rustc_hir` doc comment) - rust-lang#129271 (Prevent double panic in query system, improve diagnostics) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 5601d14 + 7730356 commit 636d7ff

File tree

25 files changed

+746
-150
lines changed

25 files changed

+746
-150
lines changed

compiler/rustc_hir/src/hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,7 @@ pub struct LetExpr<'hir> {
13951395
pub pat: &'hir Pat<'hir>,
13961396
pub ty: Option<&'hir Ty<'hir>>,
13971397
pub init: &'hir Expr<'hir>,
1398-
/// `Recovered::Yes` when this let expressions is not in a syntanctically valid location.
1398+
/// `Recovered::Yes` when this let expressions is not in a syntactically valid location.
13991399
/// Used to prevent building MIR in such situations.
14001400
pub recovered: ast::Recovered,
14011401
}

compiler/rustc_hir_typeck/src/coercion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1859,7 +1859,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
18591859
};
18601860

18611861
// If this is due to an explicit `return`, suggest adding a return type.
1862-
if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(parent_id)
1862+
if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(block_or_return_id)
18631863
&& !due_to_block
18641864
{
18651865
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);

compiler/rustc_passes/messages.ftl

+5-2
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,9 @@ passes_macro_export_on_decl_macro =
444444
passes_macro_use =
445445
`#[{$name}]` only has an effect on `extern crate` and modules
446446
447+
passes_may_dangle =
448+
`#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl
449+
447450
passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
448451
passes_missing_const_err =
449452
attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
@@ -475,8 +478,8 @@ passes_multiple_start_functions =
475478
.previous = previous `#[start]` function here
476479
477480
passes_must_not_suspend =
478-
`must_not_suspend` attribute should be applied to a struct, enum, or trait
479-
.label = is not a struct, enum, or trait
481+
`must_not_suspend` attribute should be applied to a struct, enum, union, or trait
482+
.label = is not a struct, enum, union, or trait
480483
481484
passes_must_use_async =
482485
`must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within

compiler/rustc_passes/src/check_attr.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
189189
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
190190
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
191191
[sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
192+
[sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr),
192193
[sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
193194
[sym::rustc_allow_incoherent_impl, ..] => {
194195
self.check_allow_incoherent_impl(attr, span, target)
@@ -255,7 +256,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
255256
| sym::cfg_attr
256257
// need to be fixed
257258
| sym::cfi_encoding // FIXME(cfi_encoding)
258-
| sym::may_dangle // FIXME(dropck_eyepatch)
259259
| sym::pointee // FIXME(derive_smart_pointer)
260260
| sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
261261
| sym::used // handled elsewhere to restrict to static items
@@ -1363,7 +1363,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13631363
}
13641364
}
13651365

1366-
/// Checks if `#[must_not_suspend]` is applied to a function.
1366+
/// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait.
13671367
fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) {
13681368
match target {
13691369
Target::Struct | Target::Enum | Target::Union | Target::Trait => {}
@@ -1373,6 +1373,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
13731373
}
13741374
}
13751375

1376+
/// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl.
1377+
fn check_may_dangle(&self, hir_id: HirId, attr: &Attribute) {
1378+
if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id)
1379+
&& matches!(
1380+
param.kind,
1381+
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. }
1382+
)
1383+
&& matches!(param.source, hir::GenericParamSource::Generics)
1384+
&& let parent_hir_id = self.tcx.parent_hir_id(hir_id)
1385+
&& let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
1386+
&& let hir::ItemKind::Impl(impl_) = item.kind
1387+
&& let Some(trait_) = impl_.of_trait
1388+
&& let Some(def_id) = trait_.trait_def_id()
1389+
&& self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
1390+
{
1391+
return;
1392+
}
1393+
1394+
self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span });
1395+
}
1396+
13761397
/// Checks if `#[cold]` is applied to a non-function.
13771398
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
13781399
match target {

compiler/rustc_passes/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,13 @@ pub struct NonExportedMacroInvalidAttrs {
737737
pub attr_span: Span,
738738
}
739739

740+
#[derive(Diagnostic)]
741+
#[diag(passes_may_dangle)]
742+
pub struct InvalidMayDangle {
743+
#[primary_span]
744+
pub attr_span: Span,
745+
}
746+
740747
#[derive(LintDiagnostic)]
741748
#[diag(passes_unused_duplicate)]
742749
pub struct UnusedDuplicate {

compiler/rustc_query_impl/src/plumbing.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -702,11 +702,17 @@ macro_rules! define_queries {
702702
let name = stringify!($name);
703703
$crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
704704
};
705-
tcx.query_system.states.$name.try_collect_active_jobs(
705+
let res = tcx.query_system.states.$name.try_collect_active_jobs(
706706
tcx,
707707
make_query,
708708
qmap,
709-
).unwrap();
709+
);
710+
// this can be called during unwinding, and the function has a `try_`-prefix, so
711+
// don't `unwrap()` here, just manually check for `None` and do best-effort error
712+
// reporting.
713+
if res.is_none() {
714+
tracing::warn!("Failed to collect active jobs for query with name `{}`!", stringify!($name));
715+
}
710716
}
711717

712718
pub fn alloc_self_profile_query_strings<'tcx>(tcx: TyCtxt<'tcx>, string_cache: &mut QueryKeyStringCache) {

compiler/rustc_query_system/src/query/plumbing.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,15 @@ where
181181
cache.complete(key, result, dep_node_index);
182182

183183
let job = {
184-
let mut lock = state.active.lock_shard_by_value(&key);
185-
lock.remove(&key).unwrap().expect_job()
184+
let val = {
185+
// don't keep the lock during the `unwrap()` of the retrieved value, or we taint the
186+
// underlying shard.
187+
// since unwinding also wants to look at this map, this can also prevent a double
188+
// panic.
189+
let mut lock = state.active.lock_shard_by_value(&key);
190+
lock.remove(&key)
191+
};
192+
val.unwrap().expect_job()
186193
};
187194

188195
job.signal_complete();

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+103-73
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
1717
use rustc_infer::traits::ObligationCauseCode;
1818
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
1919
use rustc_middle::ty::{
20-
self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TraitPredicate, Ty,
21-
TyCtxt, Upcast,
20+
self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, Ty, TyCtxt, Upcast,
2221
};
2322
use rustc_middle::{bug, span_bug};
2423
use rustc_span::def_id::DefId;
@@ -292,90 +291,120 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
292291
&mut self,
293292
obligation: &PolyTraitObligation<'tcx>,
294293
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
295-
use rustc_transmute::{Answer, Condition};
296-
#[instrument(level = "debug", skip(tcx, obligation, predicate))]
294+
use rustc_transmute::{Answer, Assume, Condition};
295+
296+
/// Generate sub-obligations for reference-to-reference transmutations.
297+
fn reference_obligations<'tcx>(
298+
tcx: TyCtxt<'tcx>,
299+
obligation: &PolyTraitObligation<'tcx>,
300+
(src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
301+
(dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
302+
assume: Assume,
303+
) -> Vec<PredicateObligation<'tcx>> {
304+
let make_transmute_obl = |src, dst| {
305+
let transmute_trait = obligation.predicate.def_id();
306+
let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2);
307+
let trait_ref = ty::TraitRef::new(
308+
tcx,
309+
transmute_trait,
310+
[
311+
ty::GenericArg::from(dst),
312+
ty::GenericArg::from(src),
313+
ty::GenericArg::from(assume),
314+
],
315+
);
316+
Obligation::with_depth(
317+
tcx,
318+
obligation.cause.clone(),
319+
obligation.recursion_depth + 1,
320+
obligation.param_env,
321+
obligation.predicate.rebind(trait_ref),
322+
)
323+
};
324+
325+
let make_freeze_obl = |ty| {
326+
let trait_ref = ty::TraitRef::new(
327+
tcx,
328+
tcx.require_lang_item(LangItem::Freeze, None),
329+
[ty::GenericArg::from(ty)],
330+
);
331+
Obligation::with_depth(
332+
tcx,
333+
obligation.cause.clone(),
334+
obligation.recursion_depth + 1,
335+
obligation.param_env,
336+
trait_ref,
337+
)
338+
};
339+
340+
let make_outlives_obl = |target, region| {
341+
let outlives = ty::OutlivesPredicate(target, region);
342+
Obligation::with_depth(
343+
tcx,
344+
obligation.cause.clone(),
345+
obligation.recursion_depth + 1,
346+
obligation.param_env,
347+
obligation.predicate.rebind(outlives),
348+
)
349+
};
350+
351+
// Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`,
352+
// it is always the case that `Src` must be transmutable into `Dst`,
353+
// and that that `'src` must outlive `'dst`.
354+
let mut obls = vec![make_transmute_obl(src_ty, dst_ty)];
355+
if !assume.lifetimes {
356+
obls.push(make_outlives_obl(src_lifetime, dst_lifetime));
357+
}
358+
359+
// Given a transmutation from `&Src`, both `Src` and `Dst` must be
360+
// `Freeze`, otherwise, using the transmuted value could lead to
361+
// data races.
362+
if src_mut == Mutability::Not {
363+
obls.extend([make_freeze_obl(src_ty), make_freeze_obl(dst_ty)])
364+
}
365+
366+
// Given a transmutation into `&'dst mut Dst`, it also must be the
367+
// case that `Dst` is transmutable into `Src`. For example,
368+
// transmuting bool -> u8 is OK as long as you can't update that u8
369+
// to be > 1, because you could later transmute the u8 back to a
370+
// bool and get undefined behavior. It also must be the case that
371+
// `'dst` lives exactly as long as `'src`.
372+
if dst_mut == Mutability::Mut {
373+
obls.push(make_transmute_obl(dst_ty, src_ty));
374+
if !assume.lifetimes {
375+
obls.push(make_outlives_obl(dst_lifetime, src_lifetime));
376+
}
377+
}
378+
379+
obls
380+
}
381+
382+
/// Flatten the `Condition` tree into a conjunction of obligations.
383+
#[instrument(level = "debug", skip(tcx, obligation))]
297384
fn flatten_answer_tree<'tcx>(
298385
tcx: TyCtxt<'tcx>,
299386
obligation: &PolyTraitObligation<'tcx>,
300-
predicate: TraitPredicate<'tcx>,
301387
cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>,
388+
assume: Assume,
302389
) -> Vec<PredicateObligation<'tcx>> {
303390
match cond {
304391
// FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll`
305392
// Not possible until the trait solver supports disjunctions of obligations
306393
Condition::IfAll(conds) | Condition::IfAny(conds) => conds
307394
.into_iter()
308-
.flat_map(|cond| flatten_answer_tree(tcx, obligation, predicate, cond))
395+
.flat_map(|cond| flatten_answer_tree(tcx, obligation, cond, assume))
309396
.collect(),
310-
Condition::IfTransmutable { src, dst } => {
311-
let transmute_trait = obligation.predicate.def_id();
312-
let assume_const = predicate.trait_ref.args.const_at(2);
313-
let make_transmute_obl = |from_ty, to_ty| {
314-
let trait_ref = ty::TraitRef::new(
315-
tcx,
316-
transmute_trait,
317-
[
318-
ty::GenericArg::from(to_ty),
319-
ty::GenericArg::from(from_ty),
320-
ty::GenericArg::from(assume_const),
321-
],
322-
);
323-
Obligation::with_depth(
324-
tcx,
325-
obligation.cause.clone(),
326-
obligation.recursion_depth + 1,
327-
obligation.param_env,
328-
trait_ref,
329-
)
330-
};
331-
332-
let make_freeze_obl = |ty| {
333-
let trait_ref = ty::TraitRef::new(
334-
tcx,
335-
tcx.require_lang_item(LangItem::Freeze, None),
336-
[ty::GenericArg::from(ty)],
337-
);
338-
Obligation::with_depth(
339-
tcx,
340-
obligation.cause.clone(),
341-
obligation.recursion_depth + 1,
342-
obligation.param_env,
343-
trait_ref,
344-
)
345-
};
346-
347-
let mut obls = vec![];
348-
349-
// If the source is a shared reference, it must be `Freeze`;
350-
// otherwise, transmuting could lead to data races.
351-
if src.mutability == Mutability::Not {
352-
obls.extend([make_freeze_obl(src.ty), make_freeze_obl(dst.ty)])
353-
}
354-
355-
// If Dst is mutable, check bidirectionally.
356-
// For example, transmuting bool -> u8 is OK as long as you can't update that u8
357-
// to be > 1, because you could later transmute the u8 back to a bool and get UB.
358-
match dst.mutability {
359-
Mutability::Not => obls.push(make_transmute_obl(src.ty, dst.ty)),
360-
Mutability::Mut => obls.extend([
361-
make_transmute_obl(src.ty, dst.ty),
362-
make_transmute_obl(dst.ty, src.ty),
363-
]),
364-
}
365-
366-
obls
367-
}
397+
Condition::IfTransmutable { src, dst } => reference_obligations(
398+
tcx,
399+
obligation,
400+
(src.lifetime, src.ty, src.mutability),
401+
(dst.lifetime, dst.ty, dst.mutability),
402+
assume,
403+
),
368404
}
369405
}
370406

371-
// We erase regions here because transmutability calls layout queries,
372-
// which does not handle inference regions and doesn't particularly
373-
// care about other regions. Erasing late-bound regions is equivalent
374-
// to instantiating the binder with placeholders then erasing those
375-
// placeholder regions.
376-
let predicate = self
377-
.tcx()
378-
.erase_regions(self.tcx().instantiate_bound_regions_with_erased(obligation.predicate));
407+
let predicate = obligation.predicate.skip_binder();
379408

380409
let Some(assume) = rustc_transmute::Assume::from_const(
381410
self.infcx.tcx,
@@ -387,6 +416,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
387416

388417
let dst = predicate.trait_ref.args.type_at(0);
389418
let src = predicate.trait_ref.args.type_at(1);
419+
390420
debug!(?src, ?dst);
391421
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
392422
let maybe_transmutable = transmute_env.is_transmutable(
@@ -397,7 +427,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
397427

398428
let fully_flattened = match maybe_transmutable {
399429
Answer::No(_) => Err(Unimplemented)?,
400-
Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, predicate, cond),
430+
Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume),
401431
Answer::Yes => vec![],
402432
};
403433

compiler/rustc_transmute/src/layout/mod.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ pub mod rustc {
6363
use std::fmt::{self, Write};
6464

6565
use rustc_middle::mir::Mutability;
66-
use rustc_middle::ty::{self, Ty};
66+
use rustc_middle::ty::layout::{LayoutCx, LayoutError};
67+
use rustc_middle::ty::{self, Ty, TyCtxt};
68+
use rustc_target::abi::Layout;
6769

6870
/// A reference in the layout.
6971
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
@@ -120,4 +122,13 @@ pub mod rustc {
120122
self != &Self::Primitive
121123
}
122124
}
125+
126+
pub(crate) fn layout_of<'tcx>(
127+
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
128+
ty: Ty<'tcx>,
129+
) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
130+
use rustc_middle::ty::layout::LayoutOf;
131+
let ty = cx.tcx.erase_regions(ty);
132+
cx.layout_of(ty).map(|tl| tl.layout)
133+
}
123134
}

0 commit comments

Comments
 (0)