Skip to content

Commit d5a99f3

Browse files
committed
check type error recursively in typeck
1 parent 176e545 commit d5a99f3

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

compiler/rustc_hir_typeck/src/lib.rs

+44-1
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,11 @@ mod typeck_root_ctxt;
4242
mod upvar;
4343
mod writeback;
4444

45+
use core::ops::ControlFlow;
46+
4547
pub use coercion::can_coerce;
4648
use fn_ctxt::FnCtxt;
49+
use rustc_data_structures::fx::FxHashSet;
4750
use rustc_data_structures::unord::UnordSet;
4851
use rustc_errors::codes::*;
4952
use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed};
@@ -55,7 +58,7 @@ use rustc_hir_analysis::check::check_abi;
5558
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
5659
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
5760
use rustc_middle::query::Providers;
58-
use rustc_middle::ty::{self, Ty, TyCtxt};
61+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
5962
use rustc_middle::{bug, span_bug};
6063
use rustc_session::config;
6164
use rustc_span::def_id::LocalDefId;
@@ -116,6 +119,41 @@ pub fn inspect_typeck<'tcx>(
116119
typeck_with_fallback(tcx, def_id, fallback, Some(inspect))
117120
}
118121

122+
struct RecursiveHasErrorVisitor<'tcx> {
123+
tcx: TyCtxt<'tcx>,
124+
// To avoid cycle when visiting recursive types.
125+
visited_tys: FxHashSet<Ty<'tcx>>,
126+
}
127+
128+
impl<'tcx> RecursiveHasErrorVisitor<'tcx> {
129+
fn new(tcx: TyCtxt<'tcx>) -> Self {
130+
RecursiveHasErrorVisitor { tcx, visited_tys: Default::default() }
131+
}
132+
}
133+
134+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for RecursiveHasErrorVisitor<'tcx> {
135+
type Result = ControlFlow<ErrorGuaranteed>;
136+
137+
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
138+
self.visited_tys.insert(t.clone());
139+
if let ty::Adt(def, args) = t.kind() {
140+
let field_tys: Vec<_> = def.all_fields().map(|f| f.ty(self.tcx, args)).collect();
141+
for field_ty in field_tys {
142+
if !self.visited_tys.contains(&field_ty) {
143+
// Force early return with `Break`.
144+
// Visitors don't bail by default.
145+
field_ty.visit_with(self)?;
146+
}
147+
}
148+
}
149+
t.super_visit_with(self)
150+
}
151+
152+
fn visit_error(&mut self, guar: ErrorGuaranteed) -> Self::Result {
153+
ControlFlow::Break(guar)
154+
}
155+
}
156+
119157
#[instrument(level = "debug", skip(tcx, fallback, inspector), ret)]
120158
fn typeck_with_fallback<'tcx>(
121159
tcx: TyCtxt<'tcx>,
@@ -168,6 +206,11 @@ fn typeck_with_fallback<'tcx>(
168206

169207
let expected_type = fcx.normalize(body.value.span, expected_type);
170208

209+
let mut error_visitor = RecursiveHasErrorVisitor::new(tcx);
210+
if let ControlFlow::Break(guar) = expected_type.visit_with(&mut error_visitor) {
211+
fcx.set_tainted_by_errors(guar);
212+
}
213+
171214
let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
172215
fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code);
173216

tests/ui/typeck/wide_ptr_transmute.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// issue #127742
2+
struct Vtable(dyn Cap);
3+
//~^ ERROR missing lifetime specifier
4+
5+
trait Cap<'a> {}
6+
7+
union Transmute {
8+
t: u64,
9+
u: &'static Vtable,
10+
}
11+
12+
const G: &'static Vtable = unsafe { Transmute { t: 1 }.u };
13+
fn main() {}
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0106]: missing lifetime specifier
2+
--> $DIR/wide_ptr_transmute.rs:2:19
3+
|
4+
LL | struct Vtable(dyn Cap);
5+
| ^^^ expected named lifetime parameter
6+
|
7+
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
8+
help: consider making the bound lifetime-generic with a new `'a` lifetime
9+
|
10+
LL | struct Vtable(dyn for<'a> Cap<'a>);
11+
| +++++++ ++++
12+
help: consider introducing a named lifetime parameter
13+
|
14+
LL | struct Vtable<'a>(dyn Cap<'a>);
15+
| ++++ ++++
16+
17+
error: aborting due to 1 previous error
18+
19+
For more information about this error, try `rustc --explain E0106`.

0 commit comments

Comments
 (0)