Skip to content

Commit 0fcd88d

Browse files
committed
Fix infinite obligation loop for Send/Sync
1 parent ca7408b commit 0fcd88d

File tree

3 files changed

+31
-10
lines changed

3 files changed

+31
-10
lines changed

clippy_lints/src/any_coerce.rs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::rustc::infer::InferCtxt;
1212
use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
1313
use crate::rustc::traits;
1414
use crate::rustc::ty::adjustment::Adjust;
15-
use crate::rustc::ty::{self, ToPolyTraitRef, Ty};
15+
use crate::rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt};
1616
use crate::rustc::{declare_tool_lint, lint_array};
1717
use crate::syntax_pos::symbol::Ident;
1818
use crate::utils::{match_def_path, paths, span_lint_and_then};
@@ -96,21 +96,27 @@ fn check_unsize_coercion<'tcx>(
9696
// redo the typechecking for this coercion to see if it required unsizing something to `dyn Any`
9797
// see https://github.com/rust-lang/rust/blob/cae6efc37d70ab7d353e6ab9ce229d59a65ed643/src/librustc_typeck/check/coercion.rs#L454-L611
9898
let tcx = infcx.tcx;
99+
let coerce_unsized_trait_did = tcx.lang_items().coerce_unsized_trait().unwrap();
100+
let unsize_trait_did = tcx.lang_items().unsize_trait().unwrap();
101+
99102
// don't report overflow errors
100103
let mut selcx = traits::SelectionContext::with_query_mode(&infcx, traits::TraitQueryMode::Canonical);
101104
let mut queue = VecDeque::new();
102105
queue.push_back(
103106
ty::TraitRef::new(
104-
tcx.lang_items().coerce_unsized_trait().unwrap(),
107+
coerce_unsized_trait_did,
105108
tcx.mk_substs_trait(src_ty, &[tgt_ty.into()]),
106109
)
107110
.to_poly_trait_ref(),
108111
);
109112
while let Some(trait_ref) = queue.pop_front() {
110-
if match_def_path(tcx, trait_ref.def_id(), &paths::ANY_TRAIT) {
113+
if_chain! {
114+
if trait_ref.def_id() == unsize_trait_did;
115+
if is_type_dyn_any(tcx, trait_ref.skip_binder().input_types().nth(1).unwrap());
111116
// found something unsizing to `dyn Any`
112117
let coerced_to_any = trait_ref.self_ty();
113-
if type_contains_any(&mut selcx, param_env, coerced_to_any) {
118+
if type_contains_any(&mut selcx, param_env, coerced_to_any);
119+
then {
114120
return Some(LintData { coerced_to_any });
115121
}
116122
}
@@ -120,12 +126,14 @@ fn check_unsize_coercion<'tcx>(
120126
trait_ref.to_poly_trait_predicate(),
121127
));
122128
if let Ok(Some(vtable)) = select_result {
123-
// we only care about trait predicates
129+
// we only care about trait predicates for these traits
130+
let traits = [coerce_unsized_trait_did, unsize_trait_did];
124131
queue.extend(
125132
vtable
126133
.nested_obligations()
127134
.into_iter()
128-
.filter_map(|oblig| oblig.predicate.to_opt_poly_trait_ref()),
135+
.filter_map(|oblig| oblig.predicate.to_opt_poly_trait_ref())
136+
.filter(|tr| traits.contains(&tr.def_id())),
129137
);
130138
}
131139
}
@@ -140,8 +148,7 @@ fn type_contains_any<'tcx>(
140148
// check if it derefs to `dyn Any`
141149
if_chain! {
142150
if let Some((any_src_deref_ty, _deref_count)) = fully_deref_type(selcx, param_env, ty);
143-
if let ty::TyKind::Dynamic(trait_list, _) = any_src_deref_ty.sty;
144-
if match_def_path(selcx.tcx(), trait_list.skip_binder().principal().def_id, &paths::ANY_TRAIT);
151+
if is_type_dyn_any(selcx.tcx(), any_src_deref_ty);
145152
then {
146153
// TODO: use deref_count to make a suggestion
147154
return true;
@@ -151,6 +158,20 @@ fn type_contains_any<'tcx>(
151158
false
152159
}
153160

161+
fn is_type_dyn_any<'tcx>(
162+
tcx: TyCtxt<'_, '_, 'tcx>,
163+
ty: Ty<'tcx>,
164+
) -> bool {
165+
if_chain! {
166+
if let ty::TyKind::Dynamic(trait_list, _) = ty.sty;
167+
if match_def_path(tcx, trait_list.skip_binder().principal().def_id, &paths::ANY_TRAIT);
168+
then {
169+
return true;
170+
}
171+
}
172+
false
173+
}
174+
154175
/// Calls [deref_type] repeatedly
155176
fn fully_deref_type<'tcx>(
156177
selcx: &mut traits::SelectionContext<'_, '_, 'tcx>,

tests/ui/any_coerce.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ struct Unsizeable<T: ?Sized, U: ?Sized, V: ?Sized> {
2929
}
3030

3131
fn main() {
32-
let mut box_any: Box<dyn Any> = Box::new(Foo);
32+
let mut box_any: Box<dyn Any + Send> = Box::new(Foo);
3333
let _: *mut dyn Any = &mut box_any; // LINT
3434
let _: *mut dyn Any = &mut *box_any; // ok
3535

tests/ui/any_coerce.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: coercing `std::boxed::Box<(dyn std::any::Any + 'static)>` to `dyn Any`
1+
error: coercing `std::boxed::Box<(dyn std::any::Any + std::marker::Send + 'static)>` to `dyn Any`
22
--> $DIR/any_coerce.rs:33:27
33
|
44
33 | let _: *mut dyn Any = &mut box_any; // LINT

0 commit comments

Comments
 (0)