]>
Commit | Line | Data |
---|---|---|
064997fb | 1 | use crate::check::intrinsicck::InlineAsmCtxt; |
923072b8 | 2 | |
29967ef6 | 3 | use super::compare_method::check_type_bounds; |
2b03887a | 4 | use super::compare_method::{compare_impl_method, compare_ty_impl}; |
1b1a35ee | 5 | use super::*; |
1b1a35ee | 6 | use rustc_attr as attr; |
04454e1e | 7 | use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; |
1b1a35ee | 8 | use rustc_hir as hir; |
923072b8 | 9 | use rustc_hir::def::{DefKind, Res}; |
cdc7bbd5 | 10 | use rustc_hir::def_id::{DefId, LocalDefId}; |
6a06907d | 11 | use rustc_hir::intravisit::Visitor; |
923072b8 | 12 | use rustc_hir::{ItemKind, Node, PathSegment}; |
064997fb | 13 | use rustc_infer::infer::outlives::env::OutlivesEnvironment; |
064997fb | 14 | use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt}; |
04454e1e | 15 | use rustc_infer::traits::Obligation; |
064997fb | 16 | use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; |
5099ac24 | 17 | use rustc_middle::hir::nested_filter; |
f2b60f7d | 18 | use rustc_middle::middle::stability::EvalResult; |
5e7ed085 | 19 | use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; |
1b1a35ee | 20 | use rustc_middle::ty::subst::GenericArgKind; |
cdc7bbd5 | 21 | use rustc_middle::ty::util::{Discr, IntTypeExt}; |
064997fb FG |
22 | use rustc_middle::ty::{ |
23 | self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, | |
24 | }; | |
136023e0 | 25 | use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; |
1b1a35ee | 26 | use rustc_span::symbol::sym; |
04454e1e | 27 | use rustc_span::{self, Span}; |
1b1a35ee | 28 | use rustc_target::spec::abi::Abi; |
2b03887a | 29 | use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; |
064997fb | 30 | use rustc_trait_selection::traits::{self, ObligationCtxt}; |
1b1a35ee | 31 | |
29967ef6 XL |
32 | use std::ops::ControlFlow; |
33 | ||
2b03887a | 34 | pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) { |
136023e0 XL |
35 | match tcx.sess.target.is_abi_supported(abi) { |
36 | Some(true) => (), | |
5e7ed085 FG |
37 | Some(false) => { |
38 | struct_span_err!( | |
39 | tcx.sess, | |
40 | span, | |
41 | E0570, | |
04454e1e | 42 | "`{abi}` is not a supported ABI for the current target", |
5e7ed085 FG |
43 | ) |
44 | .emit(); | |
45 | } | |
136023e0 | 46 | None => { |
2b03887a FG |
47 | tcx.struct_span_lint_hir( |
48 | UNSUPPORTED_CALLING_CONVENTIONS, | |
49 | hir_id, | |
50 | span, | |
51 | "use of calling convention not supported on this target", | |
52 | |lint| lint, | |
53 | ); | |
136023e0 | 54 | } |
1b1a35ee | 55 | } |
5869c6ff XL |
56 | |
57 | // This ABI is only allowed on function pointers | |
58 | if abi == Abi::CCmseNonSecureCall { | |
59 | struct_span_err!( | |
60 | tcx.sess, | |
61 | span, | |
62 | E0781, | |
c295e0f8 | 63 | "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers" |
5869c6ff | 64 | ) |
5e7ed085 | 65 | .emit(); |
5869c6ff | 66 | } |
1b1a35ee XL |
67 | } |
68 | ||
064997fb | 69 | fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { |
1b1a35ee | 70 | let def = tcx.adt_def(def_id); |
064997fb | 71 | let span = tcx.def_span(def_id); |
1b1a35ee | 72 | def.destructor(tcx); // force the destructor to be evaluated |
1b1a35ee | 73 | |
5e7ed085 | 74 | if def.repr().simd() { |
1b1a35ee XL |
75 | check_simd(tcx, span, def_id); |
76 | } | |
77 | ||
78 | check_transparent(tcx, span, def); | |
79 | check_packed(tcx, span, def); | |
80 | } | |
81 | ||
064997fb | 82 | fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { |
1b1a35ee | 83 | let def = tcx.adt_def(def_id); |
064997fb | 84 | let span = tcx.def_span(def_id); |
1b1a35ee | 85 | def.destructor(tcx); // force the destructor to be evaluated |
1b1a35ee XL |
86 | check_transparent(tcx, span, def); |
87 | check_union_fields(tcx, span, def_id); | |
88 | check_packed(tcx, span, def); | |
89 | } | |
90 | ||
29967ef6 XL |
91 | /// Check that the fields of the `union` do not need dropping. |
92 | fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { | |
1b1a35ee XL |
93 | let item_type = tcx.type_of(item_def_id); |
94 | if let ty::Adt(def, substs) = item_type.kind() { | |
95 | assert!(def.is_union()); | |
064997fb FG |
96 | |
97 | fn allowed_union_field<'tcx>( | |
98 | ty: Ty<'tcx>, | |
99 | tcx: TyCtxt<'tcx>, | |
100 | param_env: ty::ParamEnv<'tcx>, | |
101 | span: Span, | |
102 | ) -> bool { | |
103 | // We don't just accept all !needs_drop fields, due to semver concerns. | |
104 | match ty.kind() { | |
105 | ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check) | |
106 | ty::Tuple(tys) => { | |
107 | // allow tuples of allowed types | |
108 | tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span)) | |
109 | } | |
110 | ty::Array(elem, _len) => { | |
111 | // Like `Copy`, we do *not* special-case length 0. | |
112 | allowed_union_field(*elem, tcx, param_env, span) | |
113 | } | |
114 | _ => { | |
115 | // Fallback case: allow `ManuallyDrop` and things that are `Copy`. | |
116 | ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop()) | |
2b03887a | 117 | || ty.is_copy_modulo_regions(tcx, param_env) |
064997fb FG |
118 | } |
119 | } | |
120 | } | |
121 | ||
1b1a35ee | 122 | let param_env = tcx.param_env(item_def_id); |
064997fb | 123 | for field in &def.non_enum_variant().fields { |
1b1a35ee | 124 | let field_ty = field.ty(tcx, substs); |
064997fb FG |
125 | |
126 | if !allowed_union_field(field_ty, tcx, param_env, span) { | |
3c0e092e XL |
127 | let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) { |
128 | // We are currently checking the type this field came from, so it must be local. | |
129 | Some(Node::Field(field)) => (field.span, field.ty.span), | |
130 | _ => unreachable!("mir field has to correspond to hir field"), | |
131 | }; | |
1b1a35ee XL |
132 | struct_span_err!( |
133 | tcx.sess, | |
134 | field_span, | |
135 | E0740, | |
5099ac24 FG |
136 | "unions cannot contain fields that may need dropping" |
137 | ) | |
138 | .note( | |
139 | "a type is guaranteed not to need dropping \ | |
140 | when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type", | |
1b1a35ee | 141 | ) |
3c0e092e | 142 | .multipart_suggestion_verbose( |
5099ac24 FG |
143 | "when the type does not implement `Copy`, \ |
144 | wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped", | |
3c0e092e | 145 | vec![ |
5099ac24 | 146 | (ty_span.shrink_to_lo(), "std::mem::ManuallyDrop<".into()), |
3c0e092e XL |
147 | (ty_span.shrink_to_hi(), ">".into()), |
148 | ], | |
149 | Applicability::MaybeIncorrect, | |
150 | ) | |
1b1a35ee XL |
151 | .emit(); |
152 | return false; | |
064997fb FG |
153 | } else if field_ty.needs_drop(tcx, param_env) { |
154 | // This should never happen. But we can get here e.g. in case of name resolution errors. | |
155 | tcx.sess.delay_span_bug(span, "we should never accept maybe-dropping union fields"); | |
1b1a35ee XL |
156 | } |
157 | } | |
158 | } else { | |
159 | span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind()); | |
160 | } | |
161 | true | |
162 | } | |
163 | ||
29967ef6 | 164 | /// Check that a `static` is inhabited. |
064997fb | 165 | fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { |
29967ef6 XL |
166 | // Make sure statics are inhabited. |
167 | // Other parts of the compiler assume that there are no uninhabited places. In principle it | |
168 | // would be enough to check this for `extern` statics, as statics with an initializer will | |
169 | // have UB during initialization if they are uninhabited, but there also seems to be no good | |
170 | // reason to allow any statics to be uninhabited. | |
171 | let ty = tcx.type_of(def_id); | |
064997fb | 172 | let span = tcx.def_span(def_id); |
29967ef6 XL |
173 | let layout = match tcx.layout_of(ParamEnv::reveal_all().and(ty)) { |
174 | Ok(l) => l, | |
5e7ed085 FG |
175 | // Foreign statics that overflow their allowed size should emit an error |
176 | Err(LayoutError::SizeOverflow(_)) | |
177 | if { | |
178 | let node = tcx.hir().get_by_def_id(def_id); | |
179 | matches!( | |
180 | node, | |
181 | hir::Node::ForeignItem(hir::ForeignItem { | |
182 | kind: hir::ForeignItemKind::Static(..), | |
183 | .. | |
184 | }) | |
185 | ) | |
186 | } => | |
187 | { | |
188 | tcx.sess | |
189 | .struct_span_err(span, "extern static is too large for the current architecture") | |
190 | .emit(); | |
191 | return; | |
192 | } | |
193 | // Generic statics are rejected, but we still reach this case. | |
194 | Err(e) => { | |
195 | tcx.sess.delay_span_bug(span, &e.to_string()); | |
29967ef6 XL |
196 | return; |
197 | } | |
198 | }; | |
199 | if layout.abi.is_uninhabited() { | |
200 | tcx.struct_span_lint_hir( | |
201 | UNINHABITED_STATIC, | |
202 | tcx.hir().local_def_id_to_hir_id(def_id), | |
203 | span, | |
2b03887a | 204 | "static of uninhabited type", |
29967ef6 | 205 | |lint| { |
2b03887a | 206 | lint |
29967ef6 | 207 | .note("uninhabited statics cannot be initialized, and any access would be an immediate error") |
29967ef6 XL |
208 | }, |
209 | ); | |
210 | } | |
211 | } | |
212 | ||
1b1a35ee XL |
213 | /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` |
214 | /// projections that would result in "inheriting lifetimes". | |
2b03887a FG |
215 | fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { |
216 | let item = tcx.hir().item(id); | |
217 | let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else { | |
218 | tcx.sess.delay_span_bug(tcx.hir().span(id.hir_id()), "expected opaque item"); | |
219 | return; | |
220 | }; | |
221 | ||
222 | // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting | |
223 | // `async-std` (and `pub async fn` in general). | |
224 | // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! | |
225 | // See https://github.com/rust-lang/rust/issues/75100 | |
226 | if tcx.sess.opts.actually_rustdoc { | |
227 | return; | |
228 | } | |
229 | ||
230 | let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id()); | |
231 | let span = tcx.def_span(item.owner_id.def_id); | |
232 | ||
233 | check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span); | |
234 | if tcx.type_of(item.owner_id.def_id).references_error() { | |
29967ef6 XL |
235 | return; |
236 | } | |
2b03887a | 237 | if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() { |
29967ef6 XL |
238 | return; |
239 | } | |
2b03887a | 240 | check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin); |
1b1a35ee | 241 | } |
1b1a35ee XL |
242 | /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result |
243 | /// in "inheriting lifetimes". | |
6a06907d | 244 | #[instrument(level = "debug", skip(tcx, span))] |
a2a8927a | 245 | pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( |
1b1a35ee XL |
246 | tcx: TyCtxt<'tcx>, |
247 | def_id: LocalDefId, | |
248 | span: Span, | |
249 | ) { | |
a2a8927a | 250 | let item = tcx.hir().expect_item(def_id); |
fc512014 | 251 | debug!(?item, ?span); |
1b1a35ee | 252 | |
fc512014 | 253 | struct FoundParentLifetime; |
5099ac24 | 254 | struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); |
064997fb | 255 | impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { |
fc512014 | 256 | type BreakTy = FoundParentLifetime; |
1b1a35ee | 257 | |
fc512014 XL |
258 | fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { |
259 | debug!("FindParentLifetimeVisitor: r={:?}", r); | |
5099ac24 FG |
260 | if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r { |
261 | if index < self.0.parent_count as u32 { | |
fc512014 | 262 | return ControlFlow::Break(FoundParentLifetime); |
29967ef6 XL |
263 | } else { |
264 | return ControlFlow::CONTINUE; | |
265 | } | |
1b1a35ee XL |
266 | } |
267 | ||
268 | r.super_visit_with(self) | |
269 | } | |
270 | ||
5099ac24 | 271 | fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { |
923072b8 | 272 | if let ty::ConstKind::Unevaluated(..) = c.kind() { |
fc512014 | 273 | // FIXME(#72219) We currently don't detect lifetimes within substs |
1b1a35ee XL |
274 | // which would violate this check. Even though the particular substitution is not used |
275 | // within the const, this should still be fixed. | |
29967ef6 | 276 | return ControlFlow::CONTINUE; |
1b1a35ee XL |
277 | } |
278 | c.super_visit_with(self) | |
279 | } | |
280 | } | |
281 | ||
fc512014 | 282 | struct ProhibitOpaqueVisitor<'tcx> { |
94222f64 | 283 | tcx: TyCtxt<'tcx>, |
fc512014 XL |
284 | opaque_identity_ty: Ty<'tcx>, |
285 | generics: &'tcx ty::Generics, | |
6a06907d | 286 | selftys: Vec<(Span, Option<String>)>, |
fc512014 XL |
287 | } |
288 | ||
064997fb | 289 | impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { |
fc512014 XL |
290 | type BreakTy = Ty<'tcx>; |
291 | ||
292 | fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { | |
293 | debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); | |
294 | if t == self.opaque_identity_ty { | |
295 | ControlFlow::CONTINUE | |
296 | } else { | |
5099ac24 | 297 | t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics)) |
fc512014 XL |
298 | .map_break(|FoundParentLifetime| t) |
299 | } | |
300 | } | |
301 | } | |
302 | ||
a2a8927a | 303 | impl<'tcx> Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { |
5099ac24 | 304 | type NestedFilter = nested_filter::OnlyBodies; |
6a06907d | 305 | |
5099ac24 FG |
306 | fn nested_visit_map(&mut self) -> Self::Map { |
307 | self.tcx.hir() | |
6a06907d XL |
308 | } |
309 | ||
310 | fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { | |
311 | match arg.kind { | |
312 | hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { | |
2b03887a FG |
313 | [PathSegment { res: Res::SelfTyParam { .. }, .. }] => { |
314 | let impl_ty_name = None; | |
315 | self.selftys.push((path.span, impl_ty_name)); | |
316 | } | |
317 | [PathSegment { res: Res::SelfTyAlias { alias_to: def_id, .. }, .. }] => { | |
318 | let impl_ty_name = Some(self.tcx.def_path_str(*def_id)); | |
6a06907d XL |
319 | self.selftys.push((path.span, impl_ty_name)); |
320 | } | |
321 | _ => {} | |
322 | }, | |
323 | _ => {} | |
324 | } | |
325 | hir::intravisit::walk_ty(self, arg); | |
326 | } | |
327 | } | |
328 | ||
1b1a35ee | 329 | if let ItemKind::OpaqueTy(hir::OpaqueTy { |
a2a8927a | 330 | origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), |
1b1a35ee XL |
331 | .. |
332 | }) = item.kind | |
333 | { | |
334 | let mut visitor = ProhibitOpaqueVisitor { | |
335 | opaque_identity_ty: tcx.mk_opaque( | |
336 | def_id.to_def_id(), | |
337 | InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), | |
338 | ), | |
339 | generics: tcx.generics_of(def_id), | |
6a06907d XL |
340 | tcx, |
341 | selftys: vec![], | |
1b1a35ee XL |
342 | }; |
343 | let prohibit_opaque = tcx | |
29967ef6 | 344 | .explicit_item_bounds(def_id) |
1b1a35ee | 345 | .iter() |
fc512014 | 346 | .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor)); |
1b1a35ee | 347 | debug!( |
6a06907d XL |
348 | "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}", |
349 | prohibit_opaque, visitor.opaque_identity_ty, visitor.generics | |
1b1a35ee XL |
350 | ); |
351 | ||
fc512014 | 352 | if let Some(ty) = prohibit_opaque.break_value() { |
6a06907d | 353 | visitor.visit_item(&item); |
1b1a35ee | 354 | let is_async = match item.kind { |
5869c6ff | 355 | ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { |
a2a8927a | 356 | matches!(origin, hir::OpaqueTyOrigin::AsyncFn(..)) |
5869c6ff | 357 | } |
1b1a35ee XL |
358 | _ => unreachable!(), |
359 | }; | |
360 | ||
361 | let mut err = struct_span_err!( | |
362 | tcx.sess, | |
363 | span, | |
364 | E0760, | |
365 | "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ | |
29967ef6 | 366 | a parent scope", |
1b1a35ee XL |
367 | if is_async { "async fn" } else { "impl Trait" }, |
368 | ); | |
369 | ||
6a06907d XL |
370 | for (span, name) in visitor.selftys { |
371 | err.span_suggestion( | |
372 | span, | |
373 | "consider spelling out the type instead", | |
374 | name.unwrap_or_else(|| format!("{:?}", ty)), | |
375 | Applicability::MaybeIncorrect, | |
376 | ); | |
1b1a35ee XL |
377 | } |
378 | err.emit(); | |
379 | } | |
380 | } | |
381 | } | |
382 | ||
383 | /// Checks that an opaque type does not contain cycles. | |
384 | pub(super) fn check_opaque_for_cycles<'tcx>( | |
385 | tcx: TyCtxt<'tcx>, | |
386 | def_id: LocalDefId, | |
387 | substs: SubstsRef<'tcx>, | |
388 | span: Span, | |
389 | origin: &hir::OpaqueTyOrigin, | |
5e7ed085 | 390 | ) -> Result<(), ErrorGuaranteed> { |
136023e0 | 391 | if tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs).is_err() { |
5e7ed085 | 392 | let reported = match origin { |
a2a8927a | 393 | hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span), |
1b1a35ee | 394 | _ => opaque_type_cycle_error(tcx, def_id, span), |
5e7ed085 FG |
395 | }; |
396 | Err(reported) | |
29967ef6 XL |
397 | } else { |
398 | Ok(()) | |
1b1a35ee XL |
399 | } |
400 | } | |
401 | ||
29967ef6 XL |
402 | /// Check that the concrete type behind `impl Trait` actually implements `Trait`. |
403 | /// | |
404 | /// This is mostly checked at the places that specify the opaque type, but we | |
405 | /// check those cases in the `param_env` of that function, which may have | |
406 | /// bounds not on this opaque type: | |
407 | /// | |
2b03887a FG |
408 | /// ```ignore (illustrative) |
409 | /// type X<T> = impl Clone; | |
29967ef6 XL |
410 | /// fn f<T: Clone>(t: T) -> X<T> { |
411 | /// t | |
412 | /// } | |
2b03887a | 413 | /// ``` |
29967ef6 XL |
414 | /// |
415 | /// Without this check the above code is incorrectly accepted: we would ICE if | |
416 | /// some tried, for example, to clone an `Option<X<&mut ()>>`. | |
5099ac24 | 417 | #[instrument(level = "debug", skip(tcx))] |
29967ef6 XL |
418 | fn check_opaque_meets_bounds<'tcx>( |
419 | tcx: TyCtxt<'tcx>, | |
420 | def_id: LocalDefId, | |
421 | substs: SubstsRef<'tcx>, | |
422 | span: Span, | |
423 | origin: &hir::OpaqueTyOrigin, | |
424 | ) { | |
29967ef6 | 425 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); |
5099ac24 FG |
426 | let defining_use_anchor = match *origin { |
427 | hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, | |
428 | hir::OpaqueTyOrigin::TyAlias => def_id, | |
429 | }; | |
430 | let param_env = tcx.param_env(defining_use_anchor); | |
29967ef6 | 431 | |
2b03887a FG |
432 | let infcx = tcx |
433 | .infer_ctxt() | |
434 | .with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor)) | |
435 | .build(); | |
436 | let ocx = ObligationCtxt::new(&infcx); | |
437 | let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs); | |
438 | ||
439 | // `ReErased` regions appear in the "parent_substs" of closures/generators. | |
440 | // We're ignoring them here and replacing them with fresh region variables. | |
441 | // See tests in ui/type-alias-impl-trait/closure_{parent_substs,wf_outlives}.rs. | |
442 | // | |
443 | // FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it | |
444 | // here rather than using ReErased. | |
445 | let hidden_ty = tcx.bound_type_of(def_id.to_def_id()).subst(tcx, substs); | |
446 | let hidden_ty = tcx.fold_regions(hidden_ty, |re, _dbi| match re.kind() { | |
447 | ty::ReErased => infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)), | |
448 | _ => re, | |
449 | }); | |
29967ef6 | 450 | |
2b03887a | 451 | let misc_cause = traits::ObligationCause::misc(span, hir_id); |
29967ef6 | 452 | |
2b03887a FG |
453 | match infcx.at(&misc_cause, param_env).eq(opaque_ty, hidden_ty) { |
454 | Ok(infer_ok) => ocx.register_infer_ok_obligations(infer_ok), | |
455 | Err(ty_err) => { | |
456 | tcx.sess.delay_span_bug( | |
457 | span, | |
458 | &format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"), | |
459 | ); | |
460 | } | |
461 | } | |
29967ef6 | 462 | |
2b03887a FG |
463 | // Additionally require the hidden type to be well-formed with only the generics of the opaque type. |
464 | // Defining use functions may have more bounds than the opaque type, which is ok, as long as the | |
465 | // hidden type is well formed even without those bounds. | |
466 | let predicate = | |
467 | ty::Binder::dummy(ty::PredicateKind::WellFormed(hidden_ty.into())).to_predicate(tcx); | |
468 | ocx.register_obligation(Obligation::new(misc_cause, param_env, predicate)); | |
469 | ||
470 | // Check that all obligations are satisfied by the implementation's | |
471 | // version. | |
472 | let errors = ocx.select_all_or_error(); | |
473 | if !errors.is_empty() { | |
474 | infcx.err_ctxt().report_fulfillment_errors(&errors, None, false); | |
475 | } | |
476 | match origin { | |
477 | // Checked when type checking the function containing them. | |
478 | hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {} | |
479 | // Can have different predicates to their defining use | |
480 | hir::OpaqueTyOrigin::TyAlias => { | |
481 | let outlives_environment = OutlivesEnvironment::new(param_env); | |
482 | infcx.check_region_obligations_and_report_errors( | |
483 | defining_use_anchor, | |
484 | &outlives_environment, | |
485 | ); | |
486 | } | |
487 | } | |
488 | // Clean up after ourselves | |
489 | let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); | |
29967ef6 XL |
490 | } |
491 | ||
064997fb | 492 | fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { |
1b1a35ee | 493 | debug!( |
6a06907d | 494 | "check_item_type(it.def_id={:?}, it.name={})", |
2b03887a FG |
495 | id.owner_id, |
496 | tcx.def_path_str(id.owner_id.to_def_id()) | |
1b1a35ee XL |
497 | ); |
498 | let _indenter = indenter(); | |
2b03887a | 499 | match tcx.def_kind(id.owner_id) { |
04454e1e | 500 | DefKind::Static(..) => { |
2b03887a FG |
501 | tcx.ensure().typeck(id.owner_id.def_id); |
502 | maybe_check_static_with_link_section(tcx, id.owner_id.def_id); | |
503 | check_static_inhabited(tcx, id.owner_id.def_id); | |
1b1a35ee | 504 | } |
04454e1e | 505 | DefKind::Const => { |
2b03887a | 506 | tcx.ensure().typeck(id.owner_id.def_id); |
1b1a35ee | 507 | } |
04454e1e FG |
508 | DefKind::Enum => { |
509 | let item = tcx.hir().item(id); | |
510 | let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else { | |
511 | return; | |
512 | }; | |
2b03887a | 513 | check_enum(tcx, &enum_definition.variants, item.owner_id.def_id); |
1b1a35ee | 514 | } |
04454e1e FG |
515 | DefKind::Fn => {} // entirely within check_item_body |
516 | DefKind::Impl => { | |
517 | let it = tcx.hir().item(id); | |
518 | let hir::ItemKind::Impl(ref impl_) = it.kind else { | |
519 | return; | |
520 | }; | |
2b03887a FG |
521 | debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id); |
522 | if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) { | |
5869c6ff XL |
523 | check_impl_items_against_trait( |
524 | tcx, | |
525 | it.span, | |
2b03887a | 526 | it.owner_id.def_id, |
5869c6ff XL |
527 | impl_trait_ref, |
528 | &impl_.items, | |
529 | ); | |
5e7ed085 | 530 | check_on_unimplemented(tcx, it); |
1b1a35ee XL |
531 | } |
532 | } | |
04454e1e FG |
533 | DefKind::Trait => { |
534 | let it = tcx.hir().item(id); | |
535 | let hir::ItemKind::Trait(_, _, _, _, ref items) = it.kind else { | |
536 | return; | |
537 | }; | |
5e7ed085 | 538 | check_on_unimplemented(tcx, it); |
1b1a35ee XL |
539 | |
540 | for item in items.iter() { | |
541 | let item = tcx.hir().trait_item(item.id); | |
29967ef6 XL |
542 | match item.kind { |
543 | hir::TraitItemKind::Fn(ref sig, _) => { | |
544 | let abi = sig.header.abi; | |
545 | fn_maybe_err(tcx, item.ident.span, abi); | |
546 | } | |
a2a8927a | 547 | hir::TraitItemKind::Type(.., Some(default)) => { |
2b03887a | 548 | let assoc_item = tcx.associated_item(item.owner_id); |
29967ef6 | 549 | let trait_substs = |
2b03887a | 550 | InternalSubsts::identity_for_item(tcx, it.owner_id.to_def_id()); |
5e7ed085 | 551 | let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds( |
29967ef6 XL |
552 | tcx, |
553 | assoc_item, | |
554 | assoc_item, | |
a2a8927a | 555 | default.span, |
2b03887a | 556 | ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs }, |
29967ef6 XL |
557 | ); |
558 | } | |
559 | _ => {} | |
1b1a35ee XL |
560 | } |
561 | } | |
562 | } | |
04454e1e | 563 | DefKind::Struct => { |
2b03887a | 564 | check_struct(tcx, id.owner_id.def_id); |
1b1a35ee | 565 | } |
04454e1e | 566 | DefKind::Union => { |
2b03887a | 567 | check_union(tcx, id.owner_id.def_id); |
1b1a35ee | 568 | } |
04454e1e | 569 | DefKind::OpaqueTy => { |
2b03887a FG |
570 | check_opaque(tcx, id); |
571 | } | |
572 | DefKind::ImplTraitPlaceholder => { | |
573 | let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id()); | |
574 | // Only check the validity of this opaque type if the function has a default body | |
575 | if let hir::Node::TraitItem(hir::TraitItem { | |
576 | kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)), | |
577 | .. | |
578 | }) = tcx.hir().get_by_def_id(parent.expect_local()) | |
579 | { | |
580 | check_opaque(tcx, id); | |
1b1a35ee XL |
581 | } |
582 | } | |
04454e1e | 583 | DefKind::TyAlias => { |
2b03887a FG |
584 | let pty_ty = tcx.type_of(id.owner_id); |
585 | let generics = tcx.generics_of(id.owner_id); | |
1b1a35ee XL |
586 | check_type_params_are_used(tcx, &generics, pty_ty); |
587 | } | |
04454e1e FG |
588 | DefKind::ForeignMod => { |
589 | let it = tcx.hir().item(id); | |
590 | let hir::ItemKind::ForeignMod { abi, items } = it.kind else { | |
591 | return; | |
592 | }; | |
136023e0 | 593 | check_abi(tcx, it.hir_id(), it.span, abi); |
1b1a35ee | 594 | |
fc512014 XL |
595 | if abi == Abi::RustIntrinsic { |
596 | for item in items { | |
597 | let item = tcx.hir().foreign_item(item.id); | |
1b1a35ee XL |
598 | intrinsic::check_intrinsic_type(tcx, item); |
599 | } | |
fc512014 XL |
600 | } else if abi == Abi::PlatformIntrinsic { |
601 | for item in items { | |
602 | let item = tcx.hir().foreign_item(item.id); | |
1b1a35ee XL |
603 | intrinsic::check_platform_intrinsic_type(tcx, item); |
604 | } | |
605 | } else { | |
fc512014 | 606 | for item in items { |
2b03887a | 607 | let def_id = item.id.owner_id.def_id; |
29967ef6 | 608 | let generics = tcx.generics_of(def_id); |
1b1a35ee XL |
609 | let own_counts = generics.own_counts(); |
610 | if generics.params.len() - own_counts.lifetimes != 0 { | |
611 | let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { | |
612 | (_, 0) => ("type", "types", Some("u32")), | |
613 | // We don't specify an example value, because we can't generate | |
614 | // a valid value for any type. | |
615 | (0, _) => ("const", "consts", None), | |
616 | _ => ("type or const", "types or consts", None), | |
617 | }; | |
618 | struct_span_err!( | |
619 | tcx.sess, | |
620 | item.span, | |
621 | E0044, | |
04454e1e | 622 | "foreign items may not have {kinds} parameters", |
1b1a35ee | 623 | ) |
04454e1e | 624 | .span_label(item.span, &format!("can't have {kinds} parameters")) |
1b1a35ee XL |
625 | .help( |
626 | // FIXME: once we start storing spans for type arguments, turn this | |
627 | // into a suggestion. | |
628 | &format!( | |
629 | "replace the {} parameters with concrete {}{}", | |
630 | kinds, | |
631 | kinds_pl, | |
632 | egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), | |
633 | ), | |
634 | ) | |
635 | .emit(); | |
636 | } | |
637 | ||
fc512014 | 638 | let item = tcx.hir().foreign_item(item.id); |
29967ef6 XL |
639 | match item.kind { |
640 | hir::ForeignItemKind::Fn(ref fn_decl, _, _) => { | |
fc512014 | 641 | require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); |
29967ef6 XL |
642 | } |
643 | hir::ForeignItemKind::Static(..) => { | |
064997fb | 644 | check_static_inhabited(tcx, def_id); |
29967ef6 XL |
645 | } |
646 | _ => {} | |
1b1a35ee XL |
647 | } |
648 | } | |
649 | } | |
650 | } | |
923072b8 FG |
651 | DefKind::GlobalAsm => { |
652 | let it = tcx.hir().item(id); | |
653 | let hir::ItemKind::GlobalAsm(asm) = it.kind else { span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) }; | |
064997fb | 654 | InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, id.hir_id()); |
923072b8 | 655 | } |
04454e1e | 656 | _ => {} |
1b1a35ee XL |
657 | } |
658 | } | |
659 | ||
5e7ed085 | 660 | pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) { |
1b1a35ee | 661 | // an error would be reported if this fails. |
2b03887a | 662 | let _ = traits::OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id()); |
1b1a35ee XL |
663 | } |
664 | ||
665 | pub(super) fn check_specialization_validity<'tcx>( | |
666 | tcx: TyCtxt<'tcx>, | |
667 | trait_def: &ty::TraitDef, | |
668 | trait_item: &ty::AssocItem, | |
669 | impl_id: DefId, | |
5099ac24 | 670 | impl_item: &hir::ImplItemRef, |
1b1a35ee | 671 | ) { |
5e7ed085 | 672 | let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) else { return }; |
5869c6ff XL |
673 | let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| { |
674 | if parent.is_from_trait() { | |
675 | None | |
676 | } else { | |
5099ac24 | 677 | Some((parent, parent.item(tcx, trait_item.def_id))) |
5869c6ff XL |
678 | } |
679 | }); | |
1b1a35ee XL |
680 | |
681 | let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { | |
682 | match parent_item { | |
683 | // Parent impl exists, and contains the parent item we're trying to specialize, but | |
684 | // doesn't mark it `default`. | |
685 | Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { | |
686 | Some(Err(parent_impl.def_id())) | |
687 | } | |
688 | ||
689 | // Parent impl contains item and makes it specializable. | |
690 | Some(_) => Some(Ok(())), | |
691 | ||
692 | // Parent impl doesn't mention the item. This means it's inherited from the | |
693 | // grandparent. In that case, if parent is a `default impl`, inherited items use the | |
694 | // "defaultness" from the grandparent, else they are final. | |
695 | None => { | |
696 | if tcx.impl_defaultness(parent_impl.def_id()).is_default() { | |
697 | None | |
698 | } else { | |
699 | Some(Err(parent_impl.def_id())) | |
700 | } | |
701 | } | |
702 | } | |
703 | }); | |
704 | ||
705 | // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the | |
706 | // item. This is allowed, the item isn't actually getting specialized here. | |
707 | let result = opt_result.unwrap_or(Ok(())); | |
708 | ||
709 | if let Err(parent_impl) = result { | |
710 | report_forbidden_specialization(tcx, impl_item, parent_impl); | |
711 | } | |
712 | } | |
713 | ||
5099ac24 | 714 | fn check_impl_items_against_trait<'tcx>( |
1b1a35ee XL |
715 | tcx: TyCtxt<'tcx>, |
716 | full_impl_span: Span, | |
717 | impl_id: LocalDefId, | |
718 | impl_trait_ref: ty::TraitRef<'tcx>, | |
c295e0f8 | 719 | impl_item_refs: &[hir::ImplItemRef], |
1b1a35ee | 720 | ) { |
1b1a35ee XL |
721 | // If the trait reference itself is erroneous (so the compilation is going |
722 | // to fail), skip checking the items here -- the `impl_item` table in `tcx` | |
723 | // isn't populated for such impls. | |
724 | if impl_trait_ref.references_error() { | |
725 | return; | |
726 | } | |
727 | ||
728 | // Negative impls are not expected to have any items | |
729 | match tcx.impl_polarity(impl_id) { | |
730 | ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} | |
731 | ty::ImplPolarity::Negative => { | |
732 | if let [first_item_ref, ..] = impl_item_refs { | |
733 | let first_item_span = tcx.hir().impl_item(first_item_ref.id).span; | |
734 | struct_span_err!( | |
735 | tcx.sess, | |
736 | first_item_span, | |
737 | E0749, | |
738 | "negative impls cannot have any items" | |
739 | ) | |
740 | .emit(); | |
741 | } | |
742 | return; | |
743 | } | |
744 | } | |
745 | ||
1b1a35ee | 746 | let trait_def = tcx.trait_def(impl_trait_ref.def_id); |
5869c6ff | 747 | |
5099ac24 | 748 | for impl_item in impl_item_refs { |
2b03887a | 749 | let ty_impl_item = tcx.associated_item(impl_item.id.owner_id); |
5099ac24 FG |
750 | let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id { |
751 | tcx.associated_item(trait_item_id) | |
5869c6ff | 752 | } else { |
5099ac24 FG |
753 | // Checked in `associated_item`. |
754 | tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait"); | |
5869c6ff XL |
755 | continue; |
756 | }; | |
5099ac24 FG |
757 | let impl_item_full = tcx.hir().impl_item(impl_item.id); |
758 | match impl_item_full.kind { | |
759 | hir::ImplItemKind::Const(..) => { | |
2b03887a FG |
760 | let _ = tcx.compare_assoc_const_impl_item_with_trait_item(( |
761 | impl_item.id.owner_id.def_id, | |
762 | ty_impl_item.trait_item_def_id.unwrap(), | |
763 | )); | |
5099ac24 FG |
764 | } |
765 | hir::ImplItemKind::Fn(..) => { | |
766 | let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); | |
767 | compare_impl_method( | |
768 | tcx, | |
769 | &ty_impl_item, | |
5099ac24 FG |
770 | &ty_trait_item, |
771 | impl_trait_ref, | |
772 | opt_trait_span, | |
773 | ); | |
774 | } | |
2b03887a | 775 | hir::ImplItemKind::Type(impl_ty) => { |
5099ac24 FG |
776 | let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); |
777 | compare_ty_impl( | |
778 | tcx, | |
779 | &ty_impl_item, | |
780 | impl_ty.span, | |
781 | &ty_trait_item, | |
782 | impl_trait_ref, | |
783 | opt_trait_span, | |
784 | ); | |
1b1a35ee | 785 | } |
1b1a35ee | 786 | } |
5099ac24 FG |
787 | |
788 | check_specialization_validity( | |
789 | tcx, | |
790 | trait_def, | |
791 | &ty_trait_item, | |
792 | impl_id.to_def_id(), | |
793 | impl_item, | |
794 | ); | |
1b1a35ee XL |
795 | } |
796 | ||
1b1a35ee | 797 | if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { |
5869c6ff XL |
798 | // Check for missing items from trait |
799 | let mut missing_items = Vec::new(); | |
5099ac24 FG |
800 | |
801 | let mut must_implement_one_of: Option<&[Ident]> = | |
802 | trait_def.must_implement_one_of.as_deref(); | |
803 | ||
804 | for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) { | |
1b1a35ee | 805 | let is_implemented = ancestors |
5099ac24 | 806 | .leaf_def(tcx, trait_item_id) |
064997fb | 807 | .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value()); |
1b1a35ee XL |
808 | |
809 | if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { | |
5099ac24 FG |
810 | missing_items.push(tcx.associated_item(trait_item_id)); |
811 | } | |
812 | ||
f2b60f7d FG |
813 | // true if this item is specifically implemented in this impl |
814 | let is_implemented_here = ancestors | |
815 | .leaf_def(tcx, trait_item_id) | |
816 | .map_or(false, |node_item| !node_item.defining_node.is_from_trait()); | |
817 | ||
818 | if !is_implemented_here { | |
819 | match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { | |
820 | EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable( | |
821 | tcx, | |
822 | full_impl_span, | |
823 | trait_item_id, | |
824 | feature, | |
825 | reason, | |
826 | issue, | |
827 | ), | |
5099ac24 | 828 | |
f2b60f7d FG |
829 | // Unmarked default bodies are considered stable (at least for now). |
830 | EvalResult::Allow | EvalResult::Unmarked => {} | |
831 | } | |
832 | } | |
833 | ||
834 | if let Some(required_items) = &must_implement_one_of { | |
5099ac24 FG |
835 | if is_implemented_here { |
836 | let trait_item = tcx.associated_item(trait_item_id); | |
837 | if required_items.contains(&trait_item.ident(tcx)) { | |
838 | must_implement_one_of = None; | |
839 | } | |
1b1a35ee XL |
840 | } |
841 | } | |
842 | } | |
5869c6ff XL |
843 | |
844 | if !missing_items.is_empty() { | |
064997fb | 845 | missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span); |
5869c6ff | 846 | } |
5869c6ff | 847 | |
5099ac24 | 848 | if let Some(missing_items) = must_implement_one_of { |
5099ac24 | 849 | let attr_span = tcx |
04454e1e | 850 | .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of) |
5099ac24 | 851 | .map(|attr| attr.span); |
5869c6ff | 852 | |
064997fb FG |
853 | missing_items_must_implement_one_of_err( |
854 | tcx, | |
855 | tcx.def_span(impl_id), | |
856 | missing_items, | |
857 | attr_span, | |
858 | ); | |
5869c6ff | 859 | } |
1b1a35ee XL |
860 | } |
861 | } | |
862 | ||
1b1a35ee XL |
863 | pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { |
864 | let t = tcx.type_of(def_id); | |
04454e1e FG |
865 | if let ty::Adt(def, substs) = t.kind() |
866 | && def.is_struct() | |
867 | { | |
868 | let fields = &def.non_enum_variant().fields; | |
869 | if fields.is_empty() { | |
870 | struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); | |
871 | return; | |
872 | } | |
873 | let e = fields[0].ty(tcx, substs); | |
874 | if !fields.iter().all(|f| f.ty(tcx, substs) == e) { | |
875 | struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") | |
876 | .span_label(sp, "SIMD elements must have the same type") | |
877 | .emit(); | |
878 | return; | |
879 | } | |
880 | ||
881 | let len = if let ty::Array(_ty, c) = e.kind() { | |
882 | c.try_eval_usize(tcx, tcx.param_env(def.did())) | |
883 | } else { | |
884 | Some(fields.len() as u64) | |
885 | }; | |
886 | if let Some(len) = len { | |
887 | if len == 0 { | |
1b1a35ee XL |
888 | struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); |
889 | return; | |
04454e1e FG |
890 | } else if len > MAX_SIMD_LANES { |
891 | struct_span_err!( | |
892 | tcx.sess, | |
893 | sp, | |
894 | E0075, | |
895 | "SIMD vector cannot have more than {MAX_SIMD_LANES} elements", | |
896 | ) | |
897 | .emit(); | |
1b1a35ee XL |
898 | return; |
899 | } | |
04454e1e | 900 | } |
6a06907d | 901 | |
04454e1e FG |
902 | // Check that we use types valid for use in the lanes of a SIMD "vector register" |
903 | // These are scalar types which directly match a "machine" type | |
904 | // Yes: Integers, floats, "thin" pointers | |
905 | // No: char, "fat" pointers, compound types | |
906 | match e.kind() { | |
907 | ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors | |
908 | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok | |
909 | ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors | |
910 | ty::Array(t, _clen) | |
911 | if matches!( | |
912 | t.kind(), | |
913 | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) | |
914 | ) => | |
915 | { /* struct([f32; 4]) is ok */ } | |
916 | _ => { | |
917 | struct_span_err!( | |
918 | tcx.sess, | |
919 | sp, | |
920 | E0077, | |
921 | "SIMD vector element type should be a \ | |
922 | primitive scalar (integer/float/pointer) type" | |
923 | ) | |
924 | .emit(); | |
925 | return; | |
1b1a35ee XL |
926 | } |
927 | } | |
928 | } | |
929 | } | |
930 | ||
5e7ed085 FG |
931 | pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { |
932 | let repr = def.repr(); | |
1b1a35ee | 933 | if repr.packed() { |
04454e1e FG |
934 | for attr in tcx.get_attrs(def.did(), sym::repr) { |
935 | for r in attr::parse_repr_attr(&tcx.sess, attr) { | |
5e7ed085 | 936 | if let attr::ReprPacked(pack) = r |
04454e1e FG |
937 | && let Some(repr_pack) = repr.pack |
938 | && pack as u64 != repr_pack.bytes() | |
939 | { | |
940 | struct_span_err!( | |
941 | tcx.sess, | |
942 | sp, | |
943 | E0634, | |
944 | "type has conflicting packed representation hints" | |
945 | ) | |
946 | .emit(); | |
947 | } | |
1b1a35ee XL |
948 | } |
949 | } | |
950 | if repr.align.is_some() { | |
951 | struct_span_err!( | |
952 | tcx.sess, | |
953 | sp, | |
954 | E0587, | |
955 | "type has conflicting packed and align representation hints" | |
956 | ) | |
957 | .emit(); | |
958 | } else { | |
5e7ed085 | 959 | if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) { |
1b1a35ee XL |
960 | let mut err = struct_span_err!( |
961 | tcx.sess, | |
962 | sp, | |
963 | E0588, | |
964 | "packed type cannot transitively contain a `#[repr(align)]` type" | |
965 | ); | |
966 | ||
967 | err.span_note( | |
968 | tcx.def_span(def_spans[0].0), | |
969 | &format!( | |
970 | "`{}` has a `#[repr(align)]` attribute", | |
971 | tcx.item_name(def_spans[0].0) | |
972 | ), | |
973 | ); | |
974 | ||
975 | if def_spans.len() > 2 { | |
976 | let mut first = true; | |
977 | for (adt_def, span) in def_spans.iter().skip(1).rev() { | |
978 | let ident = tcx.item_name(*adt_def); | |
979 | err.span_note( | |
980 | *span, | |
981 | &if first { | |
982 | format!( | |
983 | "`{}` contains a field of type `{}`", | |
5e7ed085 | 984 | tcx.type_of(def.did()), |
1b1a35ee XL |
985 | ident |
986 | ) | |
987 | } else { | |
04454e1e | 988 | format!("...which contains a field of type `{ident}`") |
1b1a35ee XL |
989 | }, |
990 | ); | |
991 | first = false; | |
992 | } | |
993 | } | |
994 | ||
995 | err.emit(); | |
996 | } | |
997 | } | |
998 | } | |
999 | } | |
1000 | ||
1001 | pub(super) fn check_packed_inner( | |
1002 | tcx: TyCtxt<'_>, | |
1003 | def_id: DefId, | |
1004 | stack: &mut Vec<DefId>, | |
1005 | ) -> Option<Vec<(DefId, Span)>> { | |
1006 | if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() { | |
1007 | if def.is_struct() || def.is_union() { | |
5e7ed085 FG |
1008 | if def.repr().align.is_some() { |
1009 | return Some(vec![(def.did(), DUMMY_SP)]); | |
1b1a35ee XL |
1010 | } |
1011 | ||
1012 | stack.push(def_id); | |
1013 | for field in &def.non_enum_variant().fields { | |
04454e1e FG |
1014 | if let ty::Adt(def, _) = field.ty(tcx, substs).kind() |
1015 | && !stack.contains(&def.did()) | |
1016 | && let Some(mut defs) = check_packed_inner(tcx, def.did(), stack) | |
1017 | { | |
1018 | defs.push((def.did(), field.ident(tcx).span)); | |
1019 | return Some(defs); | |
1b1a35ee XL |
1020 | } |
1021 | } | |
1022 | stack.pop(); | |
1023 | } | |
1024 | } | |
1025 | ||
1026 | None | |
1027 | } | |
1028 | ||
5e7ed085 FG |
1029 | pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) { |
1030 | if !adt.repr().transparent() { | |
1b1a35ee XL |
1031 | return; |
1032 | } | |
1b1a35ee XL |
1033 | |
1034 | if adt.is_union() && !tcx.features().transparent_unions { | |
1035 | feature_err( | |
1036 | &tcx.sess.parse_sess, | |
1037 | sym::transparent_unions, | |
1038 | sp, | |
1039 | "transparent unions are unstable", | |
1040 | ) | |
1041 | .emit(); | |
1042 | } | |
1043 | ||
5e7ed085 FG |
1044 | if adt.variants().len() != 1 { |
1045 | bad_variant_count(tcx, adt, sp, adt.did()); | |
1046 | if adt.variants().is_empty() { | |
1b1a35ee XL |
1047 | // Don't bother checking the fields. No variants (and thus no fields) exist. |
1048 | return; | |
1049 | } | |
1050 | } | |
1051 | ||
064997fb FG |
1052 | // For each field, figure out if it's known to be a ZST and align(1), with "known" |
1053 | // respecting #[non_exhaustive] attributes. | |
1b1a35ee XL |
1054 | let field_infos = adt.all_fields().map(|field| { |
1055 | let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); | |
1056 | let param_env = tcx.param_env(field.did); | |
1057 | let layout = tcx.layout_of(param_env.and(ty)); | |
1058 | // We are currently checking the type this field came from, so it must be local | |
1059 | let span = tcx.hir().span_if_local(field.did).unwrap(); | |
5869c6ff XL |
1060 | let zst = layout.map_or(false, |layout| layout.is_zst()); |
1061 | let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1); | |
064997fb FG |
1062 | if !zst { |
1063 | return (span, zst, align1, None); | |
1064 | } | |
1065 | ||
1066 | fn check_non_exhaustive<'tcx>( | |
1067 | tcx: TyCtxt<'tcx>, | |
1068 | t: Ty<'tcx>, | |
1069 | ) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> { | |
1070 | match t.kind() { | |
1071 | ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), | |
1072 | ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), | |
1073 | ty::Adt(def, subst) => { | |
1074 | if !def.did().is_local() { | |
1075 | let non_exhaustive = def.is_variant_list_non_exhaustive() | |
1076 | || def | |
1077 | .variants() | |
1078 | .iter() | |
1079 | .any(ty::VariantDef::is_field_list_non_exhaustive); | |
1080 | let has_priv = def.all_fields().any(|f| !f.vis.is_public()); | |
1081 | if non_exhaustive || has_priv { | |
1082 | return ControlFlow::Break(( | |
1083 | def.descr(), | |
1084 | def.did(), | |
1085 | subst, | |
1086 | non_exhaustive, | |
1087 | )); | |
1088 | } | |
1089 | } | |
1090 | def.all_fields() | |
1091 | .map(|field| field.ty(tcx, subst)) | |
1092 | .try_for_each(|t| check_non_exhaustive(tcx, t)) | |
1093 | } | |
1094 | _ => ControlFlow::Continue(()), | |
1095 | } | |
1096 | } | |
1097 | ||
1098 | (span, zst, align1, check_non_exhaustive(tcx, ty).break_value()) | |
1b1a35ee XL |
1099 | }); |
1100 | ||
064997fb FG |
1101 | let non_zst_fields = field_infos |
1102 | .clone() | |
1103 | .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None }); | |
1b1a35ee | 1104 | let non_zst_count = non_zst_fields.clone().count(); |
136023e0 | 1105 | if non_zst_count >= 2 { |
1b1a35ee XL |
1106 | bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); |
1107 | } | |
064997fb FG |
1108 | let incompatible_zst_fields = |
1109 | field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count(); | |
1110 | let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2; | |
1111 | for (span, zst, align1, non_exhaustive) in field_infos { | |
1b1a35ee XL |
1112 | if zst && !align1 { |
1113 | struct_span_err!( | |
1114 | tcx.sess, | |
1115 | span, | |
1116 | E0691, | |
1117 | "zero-sized field in transparent {} has alignment larger than 1", | |
1118 | adt.descr(), | |
1119 | ) | |
1120 | .span_label(span, "has alignment larger than 1") | |
1121 | .emit(); | |
1122 | } | |
064997fb FG |
1123 | if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive { |
1124 | tcx.struct_span_lint_hir( | |
1125 | REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, | |
1126 | tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), | |
1127 | span, | |
2b03887a | 1128 | "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types", |
064997fb FG |
1129 | |lint| { |
1130 | let note = if non_exhaustive { | |
1131 | "is marked with `#[non_exhaustive]`" | |
1132 | } else { | |
1133 | "contains private fields" | |
1134 | }; | |
1135 | let field_ty = tcx.def_path_str_with_substs(def_id, substs); | |
2b03887a | 1136 | lint |
064997fb FG |
1137 | .note(format!("this {descr} contains `{field_ty}`, which {note}, \ |
1138 | and makes it not a breaking change to become non-zero-sized in the future.")) | |
064997fb FG |
1139 | }, |
1140 | ) | |
1141 | } | |
1b1a35ee XL |
1142 | } |
1143 | } | |
1144 | ||
1145 | #[allow(trivial_numeric_casts)] | |
064997fb | 1146 | fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) { |
1b1a35ee | 1147 | let def = tcx.adt_def(def_id); |
064997fb | 1148 | let sp = tcx.def_span(def_id); |
1b1a35ee XL |
1149 | def.destructor(tcx); // force the destructor to be evaluated |
1150 | ||
1151 | if vs.is_empty() { | |
f2b60f7d | 1152 | if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { |
1b1a35ee XL |
1153 | struct_span_err!( |
1154 | tcx.sess, | |
1155 | attr.span, | |
1156 | E0084, | |
1157 | "unsupported representation for zero-variant enum" | |
1158 | ) | |
1159 | .span_label(sp, "zero-variant enum") | |
1160 | .emit(); | |
1161 | } | |
1162 | } | |
1163 | ||
5e7ed085 | 1164 | let repr_type_ty = def.repr().discr_type().to_ty(tcx); |
1b1a35ee XL |
1165 | if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { |
1166 | if !tcx.features().repr128 { | |
1167 | feature_err( | |
1168 | &tcx.sess.parse_sess, | |
1169 | sym::repr128, | |
1170 | sp, | |
1171 | "repr with 128-bit type is unstable", | |
1172 | ) | |
1173 | .emit(); | |
1174 | } | |
1175 | } | |
1176 | ||
1177 | for v in vs { | |
1178 | if let Some(ref e) = v.disr_expr { | |
1179 | tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); | |
1180 | } | |
1181 | } | |
1182 | ||
2b03887a | 1183 | if tcx.adt_def(def_id).repr().int.is_none() { |
5869c6ff | 1184 | let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..)); |
1b1a35ee XL |
1185 | |
1186 | let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); | |
1187 | let has_non_units = vs.iter().any(|var| !is_unit(var)); | |
1188 | let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); | |
1189 | let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); | |
1190 | ||
1191 | if disr_non_unit || (disr_units && has_non_units) { | |
1192 | let mut err = | |
1193 | struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); | |
1194 | err.emit(); | |
1195 | } | |
1196 | } | |
1197 | ||
f2b60f7d | 1198 | detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp); |
1b1a35ee | 1199 | |
1b1a35ee XL |
1200 | check_transparent(tcx, sp, def); |
1201 | } | |
1202 | ||
f2b60f7d FG |
1203 | /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal |
1204 | fn detect_discriminant_duplicate<'tcx>( | |
94222f64 | 1205 | tcx: TyCtxt<'tcx>, |
f2b60f7d FG |
1206 | mut discrs: Vec<(VariantIdx, Discr<'tcx>)>, |
1207 | vs: &'tcx [hir::Variant<'tcx>], | |
1208 | self_span: Span, | |
1209 | ) { | |
1210 | // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate. | |
1211 | // Here `idx` refers to the order of which the discriminant appears, and its index in `vs` | |
1212 | let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| { | |
1213 | let var = &vs[idx]; // HIR for the duplicate discriminant | |
1214 | let (span, display_discr) = match var.disr_expr { | |
1215 | Some(ref expr) => { | |
1216 | // In the case the discriminant is both a duplicate and overflowed, let the user know | |
1217 | if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind | |
1218 | && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node | |
1219 | && *lit_value != dis.val | |
1220 | { | |
1221 | (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)")) | |
1222 | // Otherwise, format the value as-is | |
1223 | } else { | |
1224 | (tcx.hir().span(expr.hir_id), format!("`{dis}`")) | |
1225 | } | |
1226 | } | |
1227 | None => { | |
1228 | // At this point we know this discriminant is a duplicate, and was not explicitly | |
1229 | // assigned by the user. Here we iterate backwards to fetch the HIR for the last | |
1230 | // explicitly assigned discriminant, and letting the user know that this was the | |
1231 | // increment startpoint, and how many steps from there leading to the duplicate | |
1232 | if let Some((n, hir::Variant { span, ident, .. })) = | |
1233 | vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some()) | |
1234 | { | |
1235 | let ve_ident = var.ident; | |
1236 | let n = n + 1; | |
1237 | let sp = if n > 1 { "variants" } else { "variant" }; | |
1238 | ||
1239 | err.span_label( | |
1240 | *span, | |
1241 | format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"), | |
1242 | ); | |
1243 | } | |
1244 | ||
1245 | (vs[idx].span, format!("`{dis}`")) | |
1246 | } | |
1247 | }; | |
1248 | ||
1249 | err.span_label(span, format!("{display_discr} assigned here")); | |
1250 | }; | |
1251 | ||
1252 | // Here we loop through the discriminants, comparing each discriminant to another. | |
1253 | // When a duplicate is detected, we instantiate an error and point to both | |
1254 | // initial and duplicate value. The duplicate discriminant is then discarded by swapping | |
1255 | // it with the last element and decrementing the `vec.len` (which is why we have to evaluate | |
1256 | // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional | |
1257 | // style as we are mutating `discrs` on the fly). | |
1258 | let mut i = 0; | |
1259 | while i < discrs.len() { | |
1260 | let hir_var_i_idx = discrs[i].0.index(); | |
1261 | let mut error: Option<DiagnosticBuilder<'_, _>> = None; | |
1262 | ||
1263 | let mut o = i + 1; | |
1264 | while o < discrs.len() { | |
1265 | let hir_var_o_idx = discrs[o].0.index(); | |
1266 | ||
1267 | if discrs[i].1.val == discrs[o].1.val { | |
1268 | let err = error.get_or_insert_with(|| { | |
1269 | let mut ret = struct_span_err!( | |
1270 | tcx.sess, | |
1271 | self_span, | |
1272 | E0081, | |
1273 | "discriminant value `{}` assigned more than once", | |
1274 | discrs[i].1, | |
1275 | ); | |
1276 | ||
1277 | report(discrs[i].1, hir_var_i_idx, &mut ret); | |
1278 | ||
1279 | ret | |
1280 | }); | |
1281 | ||
1282 | report(discrs[o].1, hir_var_o_idx, err); | |
1283 | ||
1284 | // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty | |
1285 | discrs[o] = *discrs.last().unwrap(); | |
1286 | discrs.pop(); | |
1287 | } else { | |
1288 | o += 1; | |
1289 | } | |
94222f64 | 1290 | } |
923072b8 | 1291 | |
f2b60f7d FG |
1292 | if let Some(mut e) = error { |
1293 | e.emit(); | |
1294 | } | |
1295 | ||
1296 | i += 1; | |
1297 | } | |
94222f64 XL |
1298 | } |
1299 | ||
1b1a35ee XL |
1300 | pub(super) fn check_type_params_are_used<'tcx>( |
1301 | tcx: TyCtxt<'tcx>, | |
1302 | generics: &ty::Generics, | |
1303 | ty: Ty<'tcx>, | |
1304 | ) { | |
1305 | debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); | |
1306 | ||
1307 | assert_eq!(generics.parent, None); | |
1308 | ||
1309 | if generics.own_counts().types == 0 { | |
1310 | return; | |
1311 | } | |
1312 | ||
1313 | let mut params_used = BitSet::new_empty(generics.params.len()); | |
1314 | ||
1315 | if ty.references_error() { | |
1316 | // If there is already another error, do not emit | |
1317 | // an error for not using a type parameter. | |
5e7ed085 | 1318 | assert!(tcx.sess.has_errors().is_some()); |
1b1a35ee XL |
1319 | return; |
1320 | } | |
1321 | ||
5099ac24 | 1322 | for leaf in ty.walk() { |
04454e1e FG |
1323 | if let GenericArgKind::Type(leaf_ty) = leaf.unpack() |
1324 | && let ty::Param(param) = leaf_ty.kind() | |
1325 | { | |
1326 | debug!("found use of ty param {:?}", param); | |
1327 | params_used.insert(param.index); | |
1b1a35ee XL |
1328 | } |
1329 | } | |
1330 | ||
1331 | for param in &generics.params { | |
04454e1e FG |
1332 | if !params_used.contains(param.index) |
1333 | && let ty::GenericParamDefKind::Type { .. } = param.kind | |
1334 | { | |
1335 | let span = tcx.def_span(param.def_id); | |
1336 | struct_span_err!( | |
1337 | tcx.sess, | |
1338 | span, | |
1339 | E0091, | |
1340 | "type parameter `{}` is unused", | |
1341 | param.name, | |
1342 | ) | |
1343 | .span_label(span, "unused type parameter") | |
1344 | .emit(); | |
1b1a35ee XL |
1345 | } |
1346 | } | |
1347 | } | |
1348 | ||
1349 | pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { | |
04454e1e FG |
1350 | let module = tcx.hir_module_items(module_def_id); |
1351 | for id in module.items() { | |
1352 | check_item_type(tcx, id); | |
1353 | } | |
1b1a35ee XL |
1354 | } |
1355 | ||
5e7ed085 | 1356 | fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed { |
1b1a35ee XL |
1357 | struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") |
1358 | .span_label(span, "recursive `async fn`") | |
1359 | .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") | |
6a06907d XL |
1360 | .note( |
1361 | "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion", | |
1362 | ) | |
5e7ed085 | 1363 | .emit() |
1b1a35ee XL |
1364 | } |
1365 | ||
1366 | /// Emit an error for recursive opaque types. | |
1367 | /// | |
1368 | /// If this is a return `impl Trait`, find the item's return expressions and point at them. For | |
1369 | /// direct recursion this is enough, but for indirect recursion also point at the last intermediary | |
1370 | /// `impl Trait`. | |
1371 | /// | |
1372 | /// If all the return expressions evaluate to `!`, then we explain that the error will go away | |
1373 | /// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. | |
5e7ed085 | 1374 | fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed { |
1b1a35ee XL |
1375 | let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); |
1376 | ||
1377 | let mut label = false; | |
5099ac24 FG |
1378 | if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) { |
1379 | let typeck_results = tcx.typeck(def_id); | |
1b1a35ee XL |
1380 | if visitor |
1381 | .returns | |
1382 | .iter() | |
1383 | .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) | |
1384 | .all(|ty| matches!(ty.kind(), ty::Never)) | |
1385 | { | |
1386 | let spans = visitor | |
1387 | .returns | |
1388 | .iter() | |
1389 | .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some()) | |
1390 | .map(|expr| expr.span) | |
1391 | .collect::<Vec<Span>>(); | |
1392 | let span_len = spans.len(); | |
1393 | if span_len == 1 { | |
1394 | err.span_label(spans[0], "this returned value is of `!` type"); | |
1395 | } else { | |
1396 | let mut multispan: MultiSpan = spans.clone().into(); | |
1397 | for span in spans { | |
064997fb | 1398 | multispan.push_span_label(span, "this returned value is of `!` type"); |
1b1a35ee XL |
1399 | } |
1400 | err.span_note(multispan, "these returned values have a concrete \"never\" type"); | |
1401 | } | |
1402 | err.help("this error will resolve once the item's body returns a concrete type"); | |
1403 | } else { | |
1404 | let mut seen = FxHashSet::default(); | |
1405 | seen.insert(span); | |
1406 | err.span_label(span, "recursive opaque type"); | |
1407 | label = true; | |
1408 | for (sp, ty) in visitor | |
1409 | .returns | |
1410 | .iter() | |
1411 | .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) | |
1412 | .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) | |
1413 | { | |
94222f64 | 1414 | struct OpaqueTypeCollector(Vec<DefId>); |
064997fb | 1415 | impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector { |
fc512014 | 1416 | fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { |
1b1a35ee XL |
1417 | match *t.kind() { |
1418 | ty::Opaque(def, _) => { | |
1419 | self.0.push(def); | |
29967ef6 | 1420 | ControlFlow::CONTINUE |
1b1a35ee XL |
1421 | } |
1422 | _ => t.super_visit_with(self), | |
1423 | } | |
1424 | } | |
1425 | } | |
94222f64 | 1426 | let mut visitor = OpaqueTypeCollector(vec![]); |
1b1a35ee XL |
1427 | ty.visit_with(&mut visitor); |
1428 | for def_id in visitor.0 { | |
1429 | let ty_span = tcx.def_span(def_id); | |
1430 | if !seen.contains(&ty_span) { | |
04454e1e | 1431 | err.span_label(ty_span, &format!("returning this opaque type `{ty}`")); |
1b1a35ee XL |
1432 | seen.insert(ty_span); |
1433 | } | |
04454e1e | 1434 | err.span_label(sp, &format!("returning here with type `{ty}`")); |
1b1a35ee XL |
1435 | } |
1436 | } | |
1437 | } | |
1438 | } | |
1439 | if !label { | |
1440 | err.span_label(span, "cannot resolve opaque type"); | |
1441 | } | |
5e7ed085 | 1442 | err.emit() |
1b1a35ee | 1443 | } |