rustc_hir_analysis/check/
mod.rs1pub mod always_applicable;
66mod check;
67mod compare_impl_item;
68mod entry;
69pub mod intrinsic;
70mod region;
71pub mod wfcheck;
72
73use std::num::NonZero;
74
75pub use check::{check_abi, check_custom_abi};
76use rustc_abi::VariantIdx;
77use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
78use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
79use rustc_hir::LangItem;
80use rustc_hir::def_id::{DefId, LocalDefId};
81use rustc_hir::intravisit::Visitor;
82use rustc_index::bit_set::DenseBitSet;
83use rustc_infer::infer::{self, TyCtxtInferExt as _};
84use rustc_infer::traits::ObligationCause;
85use rustc_middle::query::Providers;
86use rustc_middle::ty::error::{ExpectedFound, TypeError};
87use rustc_middle::ty::print::with_types_for_signature;
88use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode};
89use rustc_middle::{bug, span_bug};
90use rustc_session::parse::feature_err;
91use rustc_span::def_id::CRATE_DEF_ID;
92use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
93use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
94use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
95use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor;
96use rustc_trait_selection::traits::ObligationCtxt;
97use tracing::debug;
98
99use self::compare_impl_item::collect_return_position_impl_trait_in_trait_tys;
100use self::region::region_scope_tree;
101use crate::{errors, require_c_abi_if_c_variadic};
102
103pub(super) fn provide(providers: &mut Providers) {
105 *providers = Providers {
106 adt_destructor,
107 adt_async_destructor,
108 region_scope_tree,
109 collect_return_position_impl_trait_in_trait_tys,
110 compare_impl_item: compare_impl_item::compare_impl_item,
111 check_coroutine_obligations: check::check_coroutine_obligations,
112 check_potentially_region_dependent_goals: check::check_potentially_region_dependent_goals,
113 check_type_wf: wfcheck::check_type_wf,
114 check_well_formed: wfcheck::check_well_formed,
115 ..*providers
116 };
117}
118
119fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Destructor> {
120 let dtor = tcx.calculate_dtor(def_id, always_applicable::check_drop_impl);
121 if dtor.is_none() && tcx.features().async_drop() {
122 if let Some(async_dtor) = adt_async_destructor(tcx, def_id) {
123 let span = tcx.def_span(async_dtor.impl_did);
125 tcx.dcx().emit_err(errors::AsyncDropWithoutSyncDrop { span });
126 }
127 }
128 dtor
129}
130
131fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::AsyncDestructor> {
132 tcx.calculate_async_dtor(def_id, always_applicable::check_drop_impl)
133}
134
135fn get_owner_return_paths(
138 tcx: TyCtxt<'_>,
139 def_id: LocalDefId,
140) -> Option<(LocalDefId, ReturnsVisitor<'_>)> {
141 let hir_id = tcx.local_def_id_to_hir_id(def_id);
142 let parent_id = tcx.hir_get_parent_item(hir_id).def_id;
143 tcx.hir_node_by_def_id(parent_id).body_id().map(|body_id| {
144 let body = tcx.hir_body(body_id);
145 let mut visitor = ReturnsVisitor::default();
146 visitor.visit_body(body);
147 (parent_id, visitor)
148 })
149}
150
151pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
152 if !tcx.sess.target.is_like_wasm {
154 return;
155 }
156
157 let Some(link_section) = tcx.codegen_fn_attrs(id).link_section else {
159 return;
160 };
161
162 if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
186 && !alloc.inner().provenance().ptrs().is_empty()
187 && !link_section.as_str().starts_with(".init_array")
188 {
189 let msg = "statics with a custom `#[link_section]` must be a \
190 simple list of bytes on the wasm target with no \
191 extra levels of indirection such as references";
192 tcx.dcx().span_err(tcx.def_span(id), msg);
193 }
194}
195
196fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
197 let span = tcx.def_span(impl_item);
198 let ident = tcx.item_ident(impl_item);
199
200 let err = match tcx.span_of_impl(parent_impl) {
201 Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
202 Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
203 };
204
205 tcx.dcx().emit_err(err);
206}
207
208fn missing_items_err(
209 tcx: TyCtxt<'_>,
210 impl_def_id: LocalDefId,
211 missing_items: &[ty::AssocItem],
212 full_impl_span: Span,
213) {
214 let missing_items =
215 missing_items.iter().filter(|trait_item| !trait_item.is_impl_trait_in_trait());
216
217 let missing_items_msg = missing_items
218 .clone()
219 .map(|trait_item| trait_item.name().to_string())
220 .collect::<Vec<_>>()
221 .join("`, `");
222
223 let sugg_sp = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(full_impl_span)
224 && snippet.ends_with("}")
225 {
226 let hi = full_impl_span.hi() - BytePos(1);
228 full_impl_span.with_lo(hi).with_hi(hi)
231 } else {
232 full_impl_span.shrink_to_hi()
233 };
234
235 let padding =
237 tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
238 let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
239 (Vec::new(), Vec::new(), Vec::new());
240
241 for &trait_item in missing_items {
242 let snippet = with_types_for_signature!(suggestion_signature(
243 tcx,
244 trait_item,
245 tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(),
246 ));
247 let code = format!("{padding}{snippet}\n{padding}");
248 if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
249 missing_trait_item_label
250 .push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
251 missing_trait_item.push(errors::MissingTraitItemSuggestion {
252 span: sugg_sp,
253 code,
254 snippet,
255 });
256 } else {
257 missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone {
258 span: sugg_sp,
259 code,
260 snippet,
261 })
262 }
263 }
264
265 tcx.dcx().emit_err(errors::MissingTraitItem {
266 span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
267 missing_items_msg,
268 missing_trait_item_label,
269 missing_trait_item,
270 missing_trait_item_none,
271 });
272}
273
274fn missing_items_must_implement_one_of_err(
275 tcx: TyCtxt<'_>,
276 impl_span: Span,
277 missing_items: &[Ident],
278 annotation_span: Option<Span>,
279) {
280 let missing_items_msg =
281 missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
282
283 tcx.dcx().emit_err(errors::MissingOneOfTraitItem {
284 span: impl_span,
285 note: annotation_span,
286 missing_items_msg,
287 });
288}
289
290fn default_body_is_unstable(
291 tcx: TyCtxt<'_>,
292 impl_span: Span,
293 item_did: DefId,
294 feature: Symbol,
295 reason: Option<Symbol>,
296 issue: Option<NonZero<u32>>,
297) {
298 let missing_item_name = tcx.item_ident(item_did);
299 let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
300 match reason {
301 Some(r) => {
302 some_note = true;
303 reason_str = r.to_string();
304 }
305 None => none_note = true,
306 };
307
308 let mut err = tcx.dcx().create_err(errors::MissingTraitItemUnstable {
309 span: impl_span,
310 some_note,
311 none_note,
312 missing_item_name,
313 feature,
314 reason: reason_str,
315 });
316
317 let inject_span = item_did.is_local().then(|| tcx.crate_level_attribute_injection_span());
318 rustc_session::parse::add_feature_diagnostics_for_issue(
319 &mut err,
320 &tcx.sess,
321 feature,
322 rustc_feature::GateIssue::Library(issue),
323 false,
324 inject_span,
325 );
326
327 err.emit();
328}
329
330fn bounds_from_generic_predicates<'tcx>(
332 tcx: TyCtxt<'tcx>,
333 predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
334) -> (String, String) {
335 let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
336 let mut projections = vec![];
337 for (predicate, _) in predicates {
338 debug!("predicate {:?}", predicate);
339 let bound_predicate = predicate.kind();
340 match bound_predicate.skip_binder() {
341 ty::ClauseKind::Trait(trait_predicate) => {
342 let entry = types.entry(trait_predicate.self_ty()).or_default();
343 let def_id = trait_predicate.def_id();
344 if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
345 entry.push(trait_predicate.def_id());
347 }
348 }
349 ty::ClauseKind::Projection(projection_pred) => {
350 projections.push(bound_predicate.rebind(projection_pred));
351 }
352 _ => {}
353 }
354 }
355
356 let mut where_clauses = vec![];
357 let mut types_str = vec![];
358 for (ty, bounds) in types {
359 if let ty::Param(_) = ty.kind() {
360 let mut bounds_str = vec![];
361 for bound in bounds {
362 let mut projections_str = vec![];
363 for projection in &projections {
364 let p = projection.skip_binder();
365 if bound == tcx.parent(p.projection_term.def_id)
366 && p.projection_term.self_ty() == ty
367 {
368 let name = tcx.item_name(p.projection_term.def_id);
369 projections_str.push(format!("{} = {}", name, p.term));
370 }
371 }
372 let bound_def_path = tcx.def_path_str(bound);
373 if projections_str.is_empty() {
374 where_clauses.push(format!("{}: {}", ty, bound_def_path));
375 } else {
376 bounds_str.push(format!("{}<{}>", bound_def_path, projections_str.join(", ")));
377 }
378 }
379 if bounds_str.is_empty() {
380 types_str.push(ty.to_string());
381 } else {
382 types_str.push(format!("{}: {}", ty, bounds_str.join(" + ")));
383 }
384 } else {
385 where_clauses.extend(
388 bounds.into_iter().map(|bound| format!("{}: {}", ty, tcx.def_path_str(bound))),
389 );
390 }
391 }
392
393 let generics =
394 if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
395
396 let where_clauses = if where_clauses.is_empty() {
397 "".to_string()
398 } else {
399 format!(" where {}", where_clauses.join(", "))
400 };
401
402 (generics, where_clauses)
403}
404
405fn fn_sig_suggestion<'tcx>(
407 tcx: TyCtxt<'tcx>,
408 sig: ty::FnSig<'tcx>,
409 ident: Ident,
410 predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>,
411 assoc: ty::AssocItem,
412) -> String {
413 let args = sig
414 .inputs()
415 .iter()
416 .enumerate()
417 .map(|(i, ty)| {
418 Some(match ty.kind() {
419 ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
420 ty::Ref(reg, ref_ty, mutability) if i == 0 => {
421 let reg = format!("{reg} ");
422 let reg = match ®[..] {
423 "'_ " | " " => "",
424 reg => reg,
425 };
426 if assoc.is_method() {
427 match ref_ty.kind() {
428 ty::Param(param) if param.name == kw::SelfUpper => {
429 format!("&{}{}self", reg, mutability.prefix_str())
430 }
431
432 _ => format!("self: {ty}"),
433 }
434 } else {
435 format!("_: {ty}")
436 }
437 }
438 _ => {
439 if assoc.is_method() && i == 0 {
440 format!("self: {ty}")
441 } else {
442 format!("_: {ty}")
443 }
444 }
445 })
446 })
447 .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
448 .flatten()
449 .collect::<Vec<String>>()
450 .join(", ");
451 let mut output = sig.output();
452
453 let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
454 output = if let ty::Alias(_, alias_ty) = *output.kind()
455 && let Some(output) = tcx
456 .explicit_item_self_bounds(alias_ty.def_id)
457 .iter_instantiated_copied(tcx, alias_ty.args)
458 .find_map(|(bound, _)| {
459 bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
460 }) {
461 output
462 } else {
463 span_bug!(
464 ident.span,
465 "expected async fn to have `impl Future` output, but it returns {output}"
466 )
467 };
468 "async "
469 } else {
470 ""
471 };
472
473 let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
474
475 let safety = sig.safety.prefix_str();
476 let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
477
478 format!("{safety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
484}
485
486fn suggestion_signature<'tcx>(
490 tcx: TyCtxt<'tcx>,
491 assoc: ty::AssocItem,
492 impl_trait_ref: ty::TraitRef<'tcx>,
493) -> String {
494 let args = ty::GenericArgs::identity_for_item(tcx, assoc.def_id).rebase_onto(
495 tcx,
496 assoc.container_id(tcx),
497 impl_trait_ref.with_replaced_self_ty(tcx, tcx.types.self_param).args,
498 );
499
500 match assoc.kind {
501 ty::AssocKind::Fn { .. } => fn_sig_suggestion(
502 tcx,
503 tcx.liberate_late_bound_regions(
504 assoc.def_id,
505 tcx.fn_sig(assoc.def_id).instantiate(tcx, args),
506 ),
507 assoc.ident(tcx),
508 tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
509 assoc,
510 ),
511 ty::AssocKind::Type { .. } => {
512 let (generics, where_clauses) = bounds_from_generic_predicates(
513 tcx,
514 tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
515 );
516 format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
517 }
518 ty::AssocKind::Const { name } => {
519 let ty = tcx.type_of(assoc.def_id).instantiate_identity();
520 let val = tcx
521 .infer_ctxt()
522 .build(TypingMode::non_body_analysis())
523 .err_ctxt()
524 .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
525 .unwrap_or_else(|| "value".to_string());
526 format!("const {}: {} = {};", name, ty, val)
527 }
528 }
529}
530
531fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, did: DefId) {
533 let variant_spans: Vec<_> = adt
534 .variants()
535 .iter()
536 .map(|variant| tcx.hir_span_if_local(variant.def_id).unwrap())
537 .collect();
538 let (mut spans, mut many) = (Vec::new(), None);
539 if let [start @ .., end] = &*variant_spans {
540 spans = start.to_vec();
541 many = Some(*end);
542 }
543 tcx.dcx().emit_err(errors::TransparentEnumVariant {
544 span: sp,
545 spans,
546 many,
547 number: adt.variants().len(),
548 path: tcx.def_path_str(did),
549 });
550}
551
552fn bad_non_zero_sized_fields<'tcx>(
555 tcx: TyCtxt<'tcx>,
556 adt: ty::AdtDef<'tcx>,
557 field_count: usize,
558 field_spans: impl Iterator<Item = Span>,
559 sp: Span,
560) {
561 if adt.is_enum() {
562 tcx.dcx().emit_err(errors::TransparentNonZeroSizedEnum {
563 span: sp,
564 spans: field_spans.collect(),
565 field_count,
566 desc: adt.descr(),
567 });
568 } else {
569 tcx.dcx().emit_err(errors::TransparentNonZeroSized {
570 span: sp,
571 spans: field_spans.collect(),
572 field_count,
573 desc: adt.descr(),
574 });
575 }
576}
577
578pub fn potentially_plural_count(count: usize, word: &str) -> String {
580 format!("{} {}{}", count, word, pluralize!(count))
581}
582
583pub fn check_function_signature<'tcx>(
584 tcx: TyCtxt<'tcx>,
585 mut cause: ObligationCause<'tcx>,
586 fn_id: DefId,
587 expected_sig: ty::PolyFnSig<'tcx>,
588) -> Result<(), ErrorGuaranteed> {
589 fn extract_span_for_error_reporting<'tcx>(
590 tcx: TyCtxt<'tcx>,
591 err: TypeError<'_>,
592 cause: &ObligationCause<'tcx>,
593 fn_id: LocalDefId,
594 ) -> rustc_span::Span {
595 let mut args = {
596 let node = tcx.expect_hir_owner_node(fn_id);
597 let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
598 decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
599 };
600
601 match err {
602 TypeError::ArgumentMutability(i)
603 | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
604 _ => cause.span,
605 }
606 }
607
608 let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
609
610 let param_env = ty::ParamEnv::empty();
611
612 let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
613 let ocx = ObligationCtxt::new_with_diagnostics(infcx);
614
615 let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
616
617 let norm_cause = ObligationCause::misc(cause.span, local_id);
618 let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
619
620 match ocx.eq(&cause, param_env, expected_sig, actual_sig) {
621 Ok(()) => {
622 let errors = ocx.select_all_or_error();
623 if !errors.is_empty() {
624 return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
625 }
626 }
627 Err(err) => {
628 let err_ctxt = infcx.err_ctxt();
629 if fn_id.is_local() {
630 cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
631 }
632 let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
633 let mut diag = tcx.dcx().create_err(failure_code);
634 err_ctxt.note_type_err(
635 &mut diag,
636 &cause,
637 None,
638 Some(param_env.and(infer::ValuePairs::PolySigs(ExpectedFound {
639 expected: expected_sig,
640 found: actual_sig,
641 }))),
642 err,
643 false,
644 None,
645 );
646 return Err(diag.emit());
647 }
648 }
649
650 if let Err(e) = ocx.resolve_regions_and_report_errors(local_id, param_env, []) {
651 return Err(e);
652 }
653
654 Ok(())
655}