Skip to content

Commit a06e9c8

Browse files
committed
Auto merge of #127486 - matthiaskrgr:rollup-lvv018b, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - #120248 (Make casts of pointers to trait objects stricter) - #127355 (Mark format! with must_use hint) - #127399 (Verify that allocations output by GVN are sufficiently aligned.) - #127460 (clarify `sys::unix::fd::FileDesc::drop` comment) - #127467 (bootstrap: once_cell::sync::Lazy -> std::sync::LazyLock) Failed merges: - #127357 (Remove `StructuredDiag`) r? `@ghost` `@rustbot` modify labels: rollup
2 parents cfd7cf5 + a659f7a commit a06e9c8

File tree

59 files changed

+900
-259
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+900
-259
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+66-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use rustc_span::def_id::CRATE_DEF_ID;
3838
use rustc_span::source_map::Spanned;
3939
use rustc_span::symbol::sym;
4040
use rustc_span::Span;
41+
use rustc_span::DUMMY_SP;
4142
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
4243
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
4344
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
@@ -49,6 +50,7 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
4950
use rustc_mir_dataflow::move_paths::MoveData;
5051
use rustc_mir_dataflow::ResultsCursor;
5152

53+
use crate::renumber::RegionCtxt;
5254
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
5355
use crate::{
5456
borrow_set::BorrowSet,
@@ -2333,7 +2335,57 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
23332335
let cast_ty_from = CastTy::from_ty(ty_from);
23342336
let cast_ty_to = CastTy::from_ty(*ty);
23352337
match (cast_ty_from, cast_ty_to) {
2336-
(Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => (),
2338+
(Some(CastTy::Ptr(src)), Some(CastTy::Ptr(dst))) => {
2339+
let mut normalize = |t| self.normalize(t, location);
2340+
let src_tail =
2341+
tcx.struct_tail_with_normalize(src.ty, &mut normalize, || ());
2342+
let dst_tail =
2343+
tcx.struct_tail_with_normalize(dst.ty, &mut normalize, || ());
2344+
2345+
// This checks (lifetime part of) vtable validity for pointer casts,
2346+
// which is irrelevant when there are aren't principal traits on both sides (aka only auto traits).
2347+
//
2348+
// Note that other checks (such as denying `dyn Send` -> `dyn Debug`) are in `rustc_hir_typeck`.
2349+
if let ty::Dynamic(src_tty, ..) = src_tail.kind()
2350+
&& let ty::Dynamic(dst_tty, ..) = dst_tail.kind()
2351+
&& src_tty.principal().is_some()
2352+
&& dst_tty.principal().is_some()
2353+
{
2354+
// Remove auto traits.
2355+
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
2356+
let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
2357+
tcx.mk_poly_existential_predicates(
2358+
&src_tty.without_auto_traits().collect::<Vec<_>>(),
2359+
),
2360+
tcx.lifetimes.re_static,
2361+
ty::Dyn,
2362+
));
2363+
let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
2364+
tcx.mk_poly_existential_predicates(
2365+
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
2366+
),
2367+
tcx.lifetimes.re_static,
2368+
ty::Dyn,
2369+
));
2370+
2371+
// Replace trait object lifetimes with fresh vars, to allow casts like
2372+
// `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static`,
2373+
let src_obj =
2374+
freshen_single_trait_object_lifetime(self.infcx, src_obj);
2375+
let dst_obj =
2376+
freshen_single_trait_object_lifetime(self.infcx, dst_obj);
2377+
2378+
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
2379+
2380+
self.eq_types(
2381+
src_obj,
2382+
dst_obj,
2383+
location.to_locations(),
2384+
ConstraintCategory::Cast { unsize_to: None },
2385+
)
2386+
.unwrap();
2387+
}
2388+
}
23372389
_ => {
23382390
span_mirbug!(
23392391
self,
@@ -2856,3 +2908,16 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
28562908
Ok(output)
28572909
}
28582910
}
2911+
2912+
fn freshen_single_trait_object_lifetime<'tcx>(
2913+
infcx: &BorrowckInferCtxt<'tcx>,
2914+
ty: Ty<'tcx>,
2915+
) -> Ty<'tcx> {
2916+
let &ty::Dynamic(tty, _, dyn_kind @ ty::Dyn) = ty.kind() else { bug!("expected trait object") };
2917+
2918+
let fresh = infcx
2919+
.next_region_var(rustc_infer::infer::RegionVariableOrigin::MiscVariable(DUMMY_SP), || {
2920+
RegionCtxt::Unknown
2921+
});
2922+
infcx.tcx.mk_ty_from_kind(ty::Dynamic(tty, fresh, dyn_kind))
2923+
}

compiler/rustc_errors/src/diagnostic_impls.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -298,15 +298,21 @@ impl IntoDiagArg for hir::def::Namespace {
298298
}
299299

300300
#[derive(Clone)]
301-
pub struct DiagSymbolList(Vec<Symbol>);
301+
pub struct DiagSymbolList<S = Symbol>(Vec<S>);
302302

303-
impl From<Vec<Symbol>> for DiagSymbolList {
304-
fn from(v: Vec<Symbol>) -> Self {
303+
impl<S> From<Vec<S>> for DiagSymbolList<S> {
304+
fn from(v: Vec<S>) -> Self {
305305
DiagSymbolList(v)
306306
}
307307
}
308308

309-
impl IntoDiagArg for DiagSymbolList {
309+
impl<S> FromIterator<S> for DiagSymbolList<S> {
310+
fn from_iter<T: IntoIterator<Item = S>>(iter: T) -> Self {
311+
iter.into_iter().collect::<Vec<_>>().into()
312+
}
313+
}
314+
315+
impl<S: std::fmt::Display> IntoDiagArg for DiagSymbolList<S> {
310316
fn into_diag_arg(self) -> DiagArgValue {
311317
DiagArgValue::StrListSepByAnd(
312318
self.0.into_iter().map(|sym| Cow::Owned(format!("`{sym}`"))).collect(),

compiler/rustc_hir_typeck/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
138138
hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
139139
hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
140140
141+
hir_typeck_ptr_cast_add_auto_to_object = adding {$traits_len ->
142+
[1] an auto trait {$traits}
143+
*[other] auto traits {$traits}
144+
} to a trait object in a pointer cast may cause UB later on
145+
141146
hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression
142147
hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression
143148
hir_typeck_remove_semi_for_coerce_ret = the `match` arms can conform to this return type

compiler/rustc_hir_typeck/src/cast.rs

+117-31
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ use super::FnCtxt;
3232

3333
use crate::errors;
3434
use crate::type_error_struct;
35-
use hir::ExprKind;
35+
use rustc_data_structures::fx::FxHashSet;
3636
use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
37-
use rustc_hir as hir;
37+
use rustc_hir::{self as hir, ExprKind};
3838
use rustc_macros::{TypeFoldable, TypeVisitable};
3939
use rustc_middle::bug;
4040
use rustc_middle::mir::Mutability;
@@ -44,7 +44,7 @@ use rustc_middle::ty::error::TypeError;
4444
use rustc_middle::ty::TyCtxt;
4545
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
4646
use rustc_session::lint;
47-
use rustc_span::def_id::{DefId, LOCAL_CRATE};
47+
use rustc_span::def_id::LOCAL_CRATE;
4848
use rustc_span::symbol::sym;
4949
use rustc_span::Span;
5050
use rustc_span::DUMMY_SP;
@@ -73,7 +73,7 @@ enum PointerKind<'tcx> {
7373
/// No metadata attached, ie pointer to sized type or foreign type
7474
Thin,
7575
/// A trait object
76-
VTable(Option<DefId>),
76+
VTable(&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>),
7777
/// Slice
7878
Length,
7979
/// The unsize info of this projection or opaque type
@@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
101101

102102
Ok(match *t.kind() {
103103
ty::Slice(_) | ty::Str => Some(PointerKind::Length),
104-
ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty.principal_def_id())),
104+
ty::Dynamic(tty, _, ty::Dyn) => Some(PointerKind::VTable(tty)),
105105
ty::Adt(def, args) if def.is_struct() => match def.non_enum_variant().tail_opt() {
106106
None => Some(PointerKind::Thin),
107107
Some(f) => {
@@ -755,7 +755,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
755755
Err(CastError::IllegalCast)
756756
}
757757

758-
// ptr -> *
758+
// ptr -> ptr
759759
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
760760

761761
// ptr-addr-cast
@@ -799,40 +799,126 @@ impl<'a, 'tcx> CastCheck<'tcx> {
799799
fn check_ptr_ptr_cast(
800800
&self,
801801
fcx: &FnCtxt<'a, 'tcx>,
802-
m_expr: ty::TypeAndMut<'tcx>,
803-
m_cast: ty::TypeAndMut<'tcx>,
802+
m_src: ty::TypeAndMut<'tcx>,
803+
m_dst: ty::TypeAndMut<'tcx>,
804804
) -> Result<CastKind, CastError> {
805-
debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}", m_expr, m_cast);
805+
debug!("check_ptr_ptr_cast m_src={m_src:?} m_dst={m_dst:?}");
806806
// ptr-ptr cast. vtables must match.
807807

808-
let expr_kind = fcx.pointer_kind(m_expr.ty, self.span)?;
809-
let cast_kind = fcx.pointer_kind(m_cast.ty, self.span)?;
808+
let src_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_src.ty, self.span)?);
809+
let dst_kind = fcx.tcx.erase_regions(fcx.pointer_kind(m_dst.ty, self.span)?);
810810

811-
let Some(cast_kind) = cast_kind else {
811+
match (src_kind, dst_kind) {
812812
// We can't cast if target pointer kind is unknown
813-
return Err(CastError::UnknownCastPtrKind);
814-
};
813+
(_, None) => Err(CastError::UnknownCastPtrKind),
814+
// Cast to thin pointer is OK
815+
(_, Some(PointerKind::Thin)) => Ok(CastKind::PtrPtrCast),
815816

816-
// Cast to thin pointer is OK
817-
if cast_kind == PointerKind::Thin {
818-
return Ok(CastKind::PtrPtrCast);
819-
}
820-
821-
let Some(expr_kind) = expr_kind else {
822817
// We can't cast to fat pointer if source pointer kind is unknown
823-
return Err(CastError::UnknownExprPtrKind);
824-
};
818+
(None, _) => Err(CastError::UnknownExprPtrKind),
819+
820+
// thin -> fat? report invalid cast (don't complain about vtable kinds)
821+
(Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast),
822+
823+
// trait object -> trait object? need to do additional checks
824+
(Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
825+
match (src_tty.principal(), dst_tty.principal()) {
826+
// A<dyn Src<...> + SrcAuto> -> B<dyn Dst<...> + DstAuto>. need to make sure
827+
// - `Src` and `Dst` traits are the same
828+
// - traits have the same generic arguments
829+
// - `SrcAuto` is a superset of `DstAuto`
830+
(Some(src_principal), Some(dst_principal)) => {
831+
let tcx = fcx.tcx;
832+
833+
// Check that the traits are actually the same.
834+
// The `dyn Src = dyn Dst` check below would suffice,
835+
// but this may produce a better diagnostic.
836+
//
837+
// Note that trait upcasting goes through a different mechanism (`coerce_unsized`)
838+
// and is unaffected by this check.
839+
if src_principal.def_id() != dst_principal.def_id() {
840+
return Err(CastError::DifferingKinds);
841+
}
825842

826-
// thin -> fat? report invalid cast (don't complain about vtable kinds)
827-
if expr_kind == PointerKind::Thin {
828-
return Err(CastError::SizedUnsizedCast);
829-
}
843+
// We need to reconstruct trait object types.
844+
// `m_src` and `m_dst` won't work for us here because they will potentially
845+
// contain wrappers, which we do not care about.
846+
//
847+
// e.g. we want to allow `dyn T -> (dyn T,)`, etc.
848+
//
849+
// We also need to skip auto traits to emit an FCW and not an error.
850+
let src_obj = tcx.mk_ty_from_kind(ty::Dynamic(
851+
tcx.mk_poly_existential_predicates(
852+
&src_tty.without_auto_traits().collect::<Vec<_>>(),
853+
),
854+
tcx.lifetimes.re_erased,
855+
ty::Dyn,
856+
));
857+
let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic(
858+
tcx.mk_poly_existential_predicates(
859+
&dst_tty.without_auto_traits().collect::<Vec<_>>(),
860+
),
861+
tcx.lifetimes.re_erased,
862+
ty::Dyn,
863+
));
830864

831-
// vtable kinds must match
832-
if fcx.tcx.erase_regions(cast_kind) == fcx.tcx.erase_regions(expr_kind) {
833-
Ok(CastKind::PtrPtrCast)
834-
} else {
835-
Err(CastError::DifferingKinds)
865+
// `dyn Src = dyn Dst`, this checks for matching traits/generics
866+
fcx.demand_eqtype(self.span, src_obj, dst_obj);
867+
868+
// Check that `SrcAuto` (+auto traits implied by `Src`) is a superset of `DstAuto`.
869+
// Emit an FCW otherwise.
870+
let src_auto: FxHashSet<_> = src_tty
871+
.auto_traits()
872+
.chain(
873+
tcx.supertrait_def_ids(src_principal.def_id())
874+
.filter(|def_id| tcx.trait_is_auto(*def_id)),
875+
)
876+
.collect();
877+
878+
let added = dst_tty
879+
.auto_traits()
880+
.filter(|trait_did| !src_auto.contains(trait_did))
881+
.collect::<Vec<_>>();
882+
883+
if !added.is_empty() {
884+
tcx.emit_node_span_lint(
885+
lint::builtin::PTR_CAST_ADD_AUTO_TO_OBJECT,
886+
self.expr.hir_id,
887+
self.span,
888+
errors::PtrCastAddAutoToObject {
889+
traits_len: added.len(),
890+
traits: {
891+
let mut traits: Vec<_> = added
892+
.into_iter()
893+
.map(|trait_did| tcx.def_path_str(trait_did))
894+
.collect();
895+
896+
traits.sort();
897+
traits.into()
898+
},
899+
},
900+
)
901+
}
902+
903+
Ok(CastKind::PtrPtrCast)
904+
}
905+
906+
// dyn Auto -> dyn Auto'? ok.
907+
(None, None) => Ok(CastKind::PtrPtrCast),
908+
909+
// dyn Trait -> dyn Auto? should be ok, but we used to not allow it.
910+
// FIXME: allow this
911+
(Some(_), None) => Err(CastError::DifferingKinds),
912+
913+
// dyn Auto -> dyn Trait? not ok.
914+
(None, Some(_)) => Err(CastError::DifferingKinds),
915+
}
916+
}
917+
918+
// fat -> fat? metadata kinds must match
919+
(Some(src_kind), Some(dst_kind)) if src_kind == dst_kind => Ok(CastKind::PtrPtrCast),
920+
921+
(_, _) => Err(CastError::DifferingKinds),
836922
}
837923
}
838924

compiler/rustc_hir_typeck/src/errors.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ use std::borrow::Cow;
44

55
use crate::fluent_generated as fluent;
66
use rustc_errors::{
7-
codes::*, Applicability, Diag, DiagArgValue, EmissionGuarantee, IntoDiagArg, MultiSpan,
8-
SubdiagMessageOp, Subdiagnostic,
7+
codes::*, Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg,
8+
MultiSpan, SubdiagMessageOp, Subdiagnostic,
99
};
1010
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
1111
use rustc_middle::ty::{self, Ty};
@@ -253,6 +253,13 @@ pub struct LossyProvenanceInt2Ptr<'tcx> {
253253
pub sugg: LossyProvenanceInt2PtrSuggestion,
254254
}
255255

256+
#[derive(LintDiagnostic)]
257+
#[diag(hir_typeck_ptr_cast_add_auto_to_object)]
258+
pub struct PtrCastAddAutoToObject {
259+
pub traits_len: usize,
260+
pub traits: DiagSymbolList<String>,
261+
}
262+
256263
#[derive(Subdiagnostic)]
257264
#[multipart_suggestion(hir_typeck_suggestion, applicability = "has-placeholders")]
258265
pub struct LossyProvenanceInt2PtrSuggestion {

0 commit comments

Comments
 (0)