Skip to content

Commit bb89df6

Browse files
committed
Auto merge of #121018 - oli-obk:impl_unsafety, r=TaKO8Ki
Fully stop using the HIR in trait impl checks At least I hope I found all happy path usages. I'll need to check if I can figure out a way to make queries declare that they don't access the HIR except in error paths
2 parents cc1c099 + 7320623 commit bb89df6

File tree

5 files changed

+80
-69
lines changed

5 files changed

+80
-69
lines changed

Diff for: compiler/rustc_hir_analysis/src/coherence/builtin.rs

+41-37
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
1515
use rustc_infer::traits::Obligation;
1616
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
1717
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
18-
use rustc_span::Span;
18+
use rustc_span::{Span, DUMMY_SP};
1919
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
2020
use rustc_trait_selection::traits::misc::{
2121
type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
@@ -25,13 +25,14 @@ use rustc_trait_selection::traits::ObligationCtxt;
2525
use rustc_trait_selection::traits::{self, ObligationCause};
2626
use std::collections::BTreeMap;
2727

28-
pub fn check_trait(
29-
tcx: TyCtxt<'_>,
28+
pub fn check_trait<'tcx>(
29+
tcx: TyCtxt<'tcx>,
3030
trait_def_id: DefId,
3131
impl_def_id: LocalDefId,
32+
impl_header: ty::ImplTraitHeader<'tcx>,
3233
) -> Result<(), ErrorGuaranteed> {
3334
let lang_items = tcx.lang_items();
34-
let checker = Checker { tcx, trait_def_id, impl_def_id };
35+
let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
3536
let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
3637
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
3738
res = res.and(
@@ -50,24 +51,25 @@ struct Checker<'tcx> {
5051
tcx: TyCtxt<'tcx>,
5152
trait_def_id: DefId,
5253
impl_def_id: LocalDefId,
54+
impl_header: ty::ImplTraitHeader<'tcx>,
5355
}
5456

5557
impl<'tcx> Checker<'tcx> {
5658
fn check(
5759
&self,
5860
trait_def_id: Option<DefId>,
59-
f: impl FnOnce(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
61+
f: impl FnOnce(&Self) -> Result<(), ErrorGuaranteed>,
6062
) -> Result<(), ErrorGuaranteed> {
61-
if Some(self.trait_def_id) == trait_def_id { f(self.tcx, self.impl_def_id) } else { Ok(()) }
63+
if Some(self.trait_def_id) == trait_def_id { f(self) } else { Ok(()) }
6264
}
6365
}
6466

65-
fn visit_implementation_of_drop(
66-
tcx: TyCtxt<'_>,
67-
impl_did: LocalDefId,
68-
) -> Result<(), ErrorGuaranteed> {
67+
fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
68+
let tcx = checker.tcx;
69+
let header = checker.impl_header;
70+
let impl_did = checker.impl_def_id;
6971
// Destructors only work on local ADT types.
70-
match tcx.type_of(impl_did).instantiate_identity().kind() {
72+
match header.trait_ref.self_ty().kind() {
7173
ty::Adt(def, _) if def.did().is_local() => return Ok(()),
7274
ty::Error(_) => return Ok(()),
7375
_ => {}
@@ -78,70 +80,72 @@ fn visit_implementation_of_drop(
7880
Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span }))
7981
}
8082

81-
fn visit_implementation_of_copy(
82-
tcx: TyCtxt<'_>,
83-
impl_did: LocalDefId,
84-
) -> Result<(), ErrorGuaranteed> {
83+
fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
84+
let tcx = checker.tcx;
85+
let impl_header = checker.impl_header;
86+
let impl_did = checker.impl_def_id;
8587
debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
8688

87-
let self_type = tcx.type_of(impl_did).instantiate_identity();
89+
let self_type = impl_header.trait_ref.self_ty();
8890
debug!("visit_implementation_of_copy: self_type={:?} (bound)", self_type);
8991

9092
let param_env = tcx.param_env(impl_did);
9193
assert!(!self_type.has_escaping_bound_vars());
9294

9395
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
9496

95-
if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
97+
if let ty::ImplPolarity::Negative = impl_header.polarity {
9698
return Ok(());
9799
}
98-
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
99100

100-
let cause = traits::ObligationCause::misc(span, impl_did);
101+
let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
101102
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
102103
Ok(()) => Ok(()),
103104
Err(CopyImplementationError::InfringingFields(fields)) => {
105+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
104106
Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span))
105107
}
106108
Err(CopyImplementationError::NotAnAdt) => {
109+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
107110
Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span }))
108111
}
109112
Err(CopyImplementationError::HasDestructor) => {
113+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
110114
Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span }))
111115
}
112116
}
113117
}
114118

115-
fn visit_implementation_of_const_param_ty(
116-
tcx: TyCtxt<'_>,
117-
impl_did: LocalDefId,
118-
) -> Result<(), ErrorGuaranteed> {
119-
let self_type = tcx.type_of(impl_did).instantiate_identity();
119+
fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
120+
let tcx = checker.tcx;
121+
let header = checker.impl_header;
122+
let impl_did = checker.impl_def_id;
123+
let self_type = header.trait_ref.self_ty();
120124
assert!(!self_type.has_escaping_bound_vars());
121125

122126
let param_env = tcx.param_env(impl_did);
123127

124-
if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
128+
if let ty::ImplPolarity::Negative = header.polarity {
125129
return Ok(());
126130
}
127-
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
128131

129-
let cause = traits::ObligationCause::misc(span, impl_did);
132+
let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did);
130133
match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
131134
Ok(()) => Ok(()),
132135
Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
136+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
133137
Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span))
134138
}
135139
Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
140+
let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
136141
Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span }))
137142
}
138143
}
139144
}
140145

141-
fn visit_implementation_of_coerce_unsized(
142-
tcx: TyCtxt<'_>,
143-
impl_did: LocalDefId,
144-
) -> Result<(), ErrorGuaranteed> {
146+
fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
147+
let tcx = checker.tcx;
148+
let impl_did = checker.impl_def_id;
145149
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
146150

147151
// Just compute this for the side-effects, in particular reporting
@@ -151,20 +155,20 @@ fn visit_implementation_of_coerce_unsized(
151155
tcx.at(span).ensure().coerce_unsized_info(impl_did)
152156
}
153157

154-
fn visit_implementation_of_dispatch_from_dyn(
155-
tcx: TyCtxt<'_>,
156-
impl_did: LocalDefId,
157-
) -> Result<(), ErrorGuaranteed> {
158+
fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
159+
let tcx = checker.tcx;
160+
let header = checker.impl_header;
161+
let impl_did = checker.impl_def_id;
162+
let trait_ref = header.trait_ref;
158163
debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
159164

160165
let span = tcx.def_span(impl_did);
161166

162167
let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
163168

164-
let source = tcx.type_of(impl_did).instantiate_identity();
169+
let source = trait_ref.self_ty();
165170
assert!(!source.has_escaping_bound_vars());
166171
let target = {
167-
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
168172
assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
169173

170174
trait_ref.args.type_at(1)

Diff for: compiler/rustc_hir_analysis/src/coherence/mod.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fn check_impl(
2323
tcx: TyCtxt<'_>,
2424
impl_def_id: LocalDefId,
2525
trait_ref: ty::TraitRef<'_>,
26+
trait_def: &ty::TraitDef,
2627
) -> Result<(), ErrorGuaranteed> {
2728
debug!(
2829
"(checking implementation) adding impl for trait '{:?}', item '{}'",
@@ -36,19 +37,20 @@ fn check_impl(
3637
return Ok(());
3738
}
3839

39-
enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id)
40-
.and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id))
40+
enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id, trait_def)
41+
.and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id, trait_def))
4142
}
4243

4344
fn enforce_trait_manually_implementable(
4445
tcx: TyCtxt<'_>,
4546
impl_def_id: LocalDefId,
4647
trait_def_id: DefId,
48+
trait_def: &ty::TraitDef,
4749
) -> Result<(), ErrorGuaranteed> {
4850
let impl_header_span = tcx.def_span(impl_def_id);
4951

5052
// Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
51-
if tcx.trait_def(trait_def_id).deny_explicit_impl {
53+
if trait_def.deny_explicit_impl {
5254
let trait_name = tcx.item_name(trait_def_id);
5355
let mut err = struct_span_code_err!(
5456
tcx.dcx(),
@@ -67,8 +69,7 @@ fn enforce_trait_manually_implementable(
6769
return Err(err.emit());
6870
}
6971

70-
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable =
71-
tcx.trait_def(trait_def_id).specialization_kind
72+
if let ty::trait_def::TraitSpecializationKind::AlwaysApplicable = trait_def.specialization_kind
7273
{
7374
if !tcx.features().specialization
7475
&& !tcx.features().min_specialization
@@ -87,8 +88,9 @@ fn enforce_empty_impls_for_marker_traits(
8788
tcx: TyCtxt<'_>,
8889
impl_def_id: LocalDefId,
8990
trait_def_id: DefId,
91+
trait_def: &ty::TraitDef,
9092
) -> Result<(), ErrorGuaranteed> {
91-
if !tcx.trait_def(trait_def_id).is_marker {
93+
if !trait_def.is_marker {
9294
return Ok(());
9395
}
9496

@@ -132,14 +134,15 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
132134
let mut res = tcx.ensure().specialization_graph_of(def_id);
133135

134136
for &impl_def_id in impls {
135-
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
137+
let trait_header = tcx.impl_trait_header(impl_def_id).unwrap().instantiate_identity();
138+
let trait_def = tcx.trait_def(trait_header.trait_ref.def_id);
136139

137-
res = res.and(check_impl(tcx, impl_def_id, trait_ref));
138-
res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
140+
res = res.and(check_impl(tcx, impl_def_id, trait_header.trait_ref, trait_def));
141+
res = res.and(check_object_overlap(tcx, impl_def_id, trait_header.trait_ref));
139142

140-
res = res.and(unsafety::check_item(tcx, impl_def_id, trait_ref));
143+
res = res.and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def));
141144
res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
142-
res = res.and(builtin::check_trait(tcx, def_id, impl_def_id));
145+
res = res.and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header));
143146
}
144147

145148
res

Diff for: compiler/rustc_hir_analysis/src/coherence/unsafety.rs

+23-21
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
//! crate or pertains to a type defined in this crate.
33
44
use rustc_errors::{codes::*, struct_span_code_err};
5-
use rustc_hir as hir;
65
use rustc_hir::Unsafety;
7-
use rustc_middle::ty::{TraitRef, TyCtxt};
6+
use rustc_middle::ty::{ImplPolarity::*, ImplTraitHeader, TraitDef, TyCtxt};
87
use rustc_span::def_id::LocalDefId;
98
use rustc_span::ErrorGuaranteed;
109

1110
pub(super) fn check_item(
1211
tcx: TyCtxt<'_>,
1312
def_id: LocalDefId,
14-
trait_ref: TraitRef<'_>,
13+
trait_header: ImplTraitHeader<'_>,
14+
trait_def: &TraitDef,
1515
) -> Result<(), ErrorGuaranteed> {
16-
let item = tcx.hir().expect_item(def_id);
17-
let impl_ = item.expect_impl();
18-
let trait_def = tcx.trait_def(trait_ref.def_id);
19-
let unsafe_attr = impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
20-
match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
21-
(Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
16+
let trait_ref = trait_header.trait_ref;
17+
let unsafe_attr =
18+
tcx.generics_of(def_id).params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
19+
match (trait_def.unsafety, unsafe_attr, trait_header.unsafety, trait_header.polarity) {
20+
(Unsafety::Normal, None, Unsafety::Unsafe, Positive | Reservation) => {
21+
let span = tcx.def_span(def_id);
2222
return Err(struct_span_code_err!(
2323
tcx.dcx(),
2424
tcx.def_span(def_id),
@@ -27,18 +27,19 @@ pub(super) fn check_item(
2727
trait_ref.print_trait_sugared()
2828
)
2929
.with_span_suggestion_verbose(
30-
item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
30+
span.with_hi(span.lo() + rustc_span::BytePos(7)),
3131
"remove `unsafe` from this trait implementation",
3232
"",
3333
rustc_errors::Applicability::MachineApplicable,
3434
)
3535
.emit());
3636
}
3737

38-
(Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
38+
(Unsafety::Unsafe, _, Unsafety::Normal, Positive | Reservation) => {
39+
let span = tcx.def_span(def_id);
3940
return Err(struct_span_code_err!(
4041
tcx.dcx(),
41-
tcx.def_span(def_id),
42+
span,
4243
E0200,
4344
"the trait `{}` requires an `unsafe impl` declaration",
4445
trait_ref.print_trait_sugared()
@@ -50,18 +51,19 @@ pub(super) fn check_item(
5051
trait_ref.print_trait_sugared()
5152
))
5253
.with_span_suggestion_verbose(
53-
item.span.shrink_to_lo(),
54+
span.shrink_to_lo(),
5455
"add `unsafe` to this trait implementation",
5556
"unsafe ",
5657
rustc_errors::Applicability::MaybeIncorrect,
5758
)
5859
.emit());
5960
}
6061

61-
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
62+
(Unsafety::Normal, Some(attr_name), Unsafety::Normal, Positive | Reservation) => {
63+
let span = tcx.def_span(def_id);
6264
return Err(struct_span_code_err!(
6365
tcx.dcx(),
64-
tcx.def_span(def_id),
66+
span,
6567
E0569,
6668
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
6769
attr_name
@@ -73,22 +75,22 @@ pub(super) fn check_item(
7375
trait_ref.print_trait_sugared()
7476
))
7577
.with_span_suggestion_verbose(
76-
item.span.shrink_to_lo(),
78+
span.shrink_to_lo(),
7779
"add `unsafe` to this trait implementation",
7880
"unsafe ",
7981
rustc_errors::Applicability::MaybeIncorrect,
8082
)
8183
.emit());
8284
}
8385

84-
(_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
86+
(_, _, Unsafety::Unsafe, Negative) => {
8587
// Reported in AST validation
86-
tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
88+
tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "unsafe negative impl");
8789
Ok(())
8890
}
89-
(_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
90-
| (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
91-
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
91+
(_, _, Unsafety::Normal, Negative)
92+
| (Unsafety::Unsafe, _, Unsafety::Unsafe, Positive | Reservation)
93+
| (Unsafety::Normal, Some(_), Unsafety::Unsafe, Positive | Reservation)
9294
| (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()),
9395
}
9496
}

Diff for: compiler/rustc_hir_analysis/src/collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,7 @@ fn impl_trait_header(
15391539
};
15401540
ty::EarlyBinder::bind(ty::ImplTraitHeader {
15411541
trait_ref,
1542+
unsafety: impl_.unsafety,
15421543
polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
15431544
})
15441545
})

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

+1
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ pub struct ImplHeader<'tcx> {
252252
pub struct ImplTraitHeader<'tcx> {
253253
pub trait_ref: ty::TraitRef<'tcx>,
254254
pub polarity: ImplPolarity,
255+
pub unsafety: hir::Unsafety,
255256
}
256257

257258
#[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]

0 commit comments

Comments
 (0)