Skip to content
/ rust Public
forked from rust-lang/rust

Commit 7035da7

Browse files
authored
Rollup merge of rust-lang#159061 - chenyukang:yukang-fix-148219-trivial-casts-dyn-any, r=folkertdev
Skip trivial cast lint for trait object upcasts Fixes rust-lang#148219 In the case like `(other as &dyn Any).downcast_ref::<T>()`, removing the cast can change method lookup, so the cast is not always trivial, so skip lint on it.
2 parents 28e67e0 + d7418a0 commit 7035da7

3 files changed

Lines changed: 75 additions & 0 deletions

File tree

compiler/rustc_hir_typeck/src/cast.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
731731
}
732732

733733
fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
734+
if self.is_non_trivial_ref_trait_object_upcast(fcx) {
735+
return;
736+
}
737+
734738
let (numeric, lint) = if self.cast_ty.is_numeric() && self.expr_ty.is_numeric() {
735739
(true, lint::builtin::TRIVIAL_NUMERIC_CASTS)
736740
} else {
@@ -746,6 +750,35 @@ impl<'a, 'tcx> CastCheck<'tcx> {
746750
);
747751
}
748752

753+
// A trait-object upcast from a method receiver, such as
754+
// `(other as &dyn Any).downcast_ref::<u32>()`,
755+
// is not trivial, because it may change the method resolution, we want to skip the lint in this case.
756+
// see issue #148219
757+
fn is_non_trivial_ref_trait_object_upcast(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
758+
if !matches!(
759+
(self.expr_ty.kind(), self.cast_ty.kind()),
760+
(ty::Ref(_, from_ty, _), ty::Ref(_, to_ty, _))
761+
if matches!(
762+
(from_ty.kind(), to_ty.kind()),
763+
(ty::Dynamic(from_data, _), ty::Dynamic(to_data, _)) if from_data != to_data
764+
)
765+
) {
766+
return false;
767+
}
768+
769+
let hir::Node::Expr(cast_expr) = fcx.tcx.parent_hir_node(self.expr.hir_id) else {
770+
return false;
771+
};
772+
let hir::Node::Expr(parent) = fcx.tcx.parent_hir_node(cast_expr.hir_id) else {
773+
return false;
774+
};
775+
776+
matches!(
777+
parent.kind,
778+
hir::ExprKind::MethodCall(_, receiver, ..) if receiver.hir_id == cast_expr.hir_id
779+
)
780+
}
781+
749782
fn expr_span_for_type_resolution(&self, fcx: &FnCtxt<'a, 'tcx>) -> Span {
750783
if let hir::ExprKind::Index(_, idx, _) = self.expr.kind
751784
&& fcx.resolve_vars_if_possible(self.expr_ty).is_ty_var()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! Trait-object upcasts used as method receivers can affect method lookup.
2+
3+
//@ check-pass
4+
5+
#![warn(trivial_casts)]
6+
7+
use std::any::Any;
8+
9+
trait DynKey: Any {}
10+
11+
impl<T: Any> DynKey for T {}
12+
13+
fn method_receiver(other: &dyn DynKey) {
14+
let _ = (other as &dyn Any).downcast_ref::<u32>();
15+
}
16+
17+
fn plain_binding(other: &dyn DynKey) {
18+
// This cast is trivial, but it is not used as a method receiver,
19+
// so it should be linted.
20+
let _ = other as &dyn Any;
21+
//~^ WARN trivial cast
22+
}
23+
24+
fn main() {
25+
method_receiver(&0u32);
26+
plain_binding(&0u32);
27+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
warning: trivial cast: `&(dyn DynKey + 'static)` as `&(dyn Any + 'static)`
2+
--> $DIR/trivial-casts-dyn-any-issue-148219.rs:20:13
3+
|
4+
LL | let _ = other as &dyn Any;
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= help: cast can be replaced by coercion; this might require a temporary variable
8+
note: the lint level is defined here
9+
--> $DIR/trivial-casts-dyn-any-issue-148219.rs:5:9
10+
|
11+
LL | #![warn(trivial_casts)]
12+
| ^^^^^^^^^^^^^
13+
14+
warning: 1 warning emitted
15+

0 commit comments

Comments
 (0)