diff options
| author | bors <bors@rust-lang.org> | 2024-07-19 02:05:32 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-07-19 02:05:32 +0000 |
| commit | 3d68afc9e821b00d59058abc9bda670b07639955 (patch) | |
| tree | 8a3e5766b52fa3d7d75223a44425d11b4556f305 /compiler/rustc_hir_analysis/src | |
| parent | 5affbb17153bc69a9d5d8d2faa4e399a014a211e (diff) | |
| parent | d1250bc1d53360184cc9dbebd385c3492a01e683 (diff) | |
| download | rust-3d68afc9e821b00d59058abc9bda670b07639955.tar.gz rust-3d68afc9e821b00d59058abc9bda670b07639955.zip | |
Auto merge of #127936 - matthiaskrgr:rollup-ci0eg7k, r=tgross35
Rollup of 8 pull requests Successful merges: - #127418 (Wrap too long type name) - #127594 (Fuchsia status code match arm) - #127835 (Fix ICE in suggestion caused by `⩵` being recovered as `==`) - #127858 (match lowering: Rename `MatchPair` to `MatchPairTree`) - #127871 (Mention that type parameters are used recursively on bivariance error) - #127913 (remove `debug-logging` default from tools profile) - #127925 (Remove tag field from `Relation`s) - #127929 (Use more accurate span for `addr_of!` suggestion) r? `@ghost` `@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/check.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/errs.rs | 35 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/check/wfcheck.rs | 133 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/errors.rs | 69 |
4 files changed, 177 insertions, 61 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index bf8ef18c04f..dbc265ad3ff 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1572,6 +1572,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD param_name, param_def_kind: tcx.def_descr(param.def_id), help: errors::UnusedGenericParameterHelp::TyAlias { param_name }, + usage_spans: vec![], const_param_help, }); diag.code(E0091); diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index 17cb20df754..19a0476e630 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -1,5 +1,4 @@ use rustc_hir as hir; -use rustc_hir_pretty::qpath_to_string; use rustc_lint_defs::builtin::STATIC_MUT_REFS; use rustc_middle::ty::{Mutability, TyCtxt}; use rustc_span::Span; @@ -12,9 +11,17 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) { let hir_id = expr.hir_id; if let hir::ExprKind::AddrOf(borrow_kind, m, expr) = expr.kind && matches!(borrow_kind, hir::BorrowKind::Ref) - && let Some(var) = path_if_static_mut(tcx, expr) + && path_if_static_mut(expr) { - handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id); + handle_static_mut_ref( + tcx, + span, + span.with_hi(expr.span.lo()), + span.shrink_to_hi(), + span.edition().at_least_rust_2024(), + m, + hir_id, + ); } } @@ -24,12 +31,13 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind && let hir::ByRef::Yes(rmutbl) = ba.0 && let Some(init) = loc.init - && let Some(var) = path_if_static_mut(tcx, init) + && path_if_static_mut(init) { handle_static_mut_ref( tcx, init.span, - var, + init.span.shrink_to_lo(), + init.span.shrink_to_hi(), loc.span.edition().at_least_rust_2024(), rmutbl, stmt.hir_id, @@ -37,38 +45,39 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) { } } -fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> { +fn path_if_static_mut(expr: &hir::Expr<'_>) -> bool { if let hir::ExprKind::Path(qpath) = expr.kind && let hir::QPath::Resolved(_, path) = qpath && let hir::def::Res::Def(def_kind, _) = path.res && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = def_kind { - return Some(qpath_to_string(&tcx, &qpath)); + return true; } - None + false } fn handle_static_mut_ref( tcx: TyCtxt<'_>, span: Span, - var: String, + lo: Span, + hi: Span, e2024: bool, mutable: Mutability, hir_id: hir::HirId, ) { if e2024 { let (sugg, shared) = if mutable == Mutability::Mut { - (errors::StaticMutRefSugg::Mut { span, var }, "mutable") + (errors::MutRefSugg::Mut { lo, hi }, "mutable") } else { - (errors::StaticMutRefSugg::Shared { span, var }, "shared") + (errors::MutRefSugg::Shared { lo, hi }, "shared") }; tcx.dcx().emit_err(errors::StaticMutRef { span, sugg, shared }); } else { let (sugg, shared) = if mutable == Mutability::Mut { - (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable") + (errors::MutRefSugg::Mut { lo, hi }, "mutable") } else { - (errors::RefOfMutStaticSugg::Shared { span, var }, "shared") + (errors::MutRefSugg::Shared { lo, hi }, "shared") }; tcx.emit_node_span_lint( STATIC_MUT_REFS, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index b2ef07d65c5..809427f86ee 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -4,12 +4,12 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par use crate::errors; use crate::fluent_generated as fluent; -use hir::intravisit::Visitor; +use hir::intravisit::{self, Visitor}; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::def::DefKind; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; @@ -1799,7 +1799,7 @@ fn receiver_is_implemented<'tcx>( fn check_variances_for_type_defn<'tcx>( tcx: TyCtxt<'tcx>, - item: &hir::Item<'tcx>, + item: &'tcx hir::Item<'tcx>, hir_generics: &hir::Generics<'tcx>, ) { let identity_args = ty::GenericArgs::identity_for_item(tcx, item.owner_id); @@ -1886,21 +1886,21 @@ fn check_variances_for_type_defn<'tcx>( hir::ParamName::Error => {} _ => { let has_explicit_bounds = explicitly_bounded_params.contains(¶meter); - report_bivariance(tcx, hir_param, has_explicit_bounds, item.kind); + report_bivariance(tcx, hir_param, has_explicit_bounds, item); } } } } -fn report_bivariance( - tcx: TyCtxt<'_>, - param: &rustc_hir::GenericParam<'_>, +fn report_bivariance<'tcx>( + tcx: TyCtxt<'tcx>, + param: &'tcx hir::GenericParam<'tcx>, has_explicit_bounds: bool, - item_kind: ItemKind<'_>, + item: &'tcx hir::Item<'tcx>, ) -> ErrorGuaranteed { let param_name = param.name.ident(); - let help = match item_kind { + let help = match item.kind { ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => { if let Some(def_id) = tcx.lang_items().phantom_data() { errors::UnusedGenericParameterHelp::Adt { @@ -1915,6 +1915,49 @@ fn report_bivariance( item_kind => bug!("report_bivariance: unexpected item kind: {item_kind:?}"), }; + let mut usage_spans = vec![]; + intravisit::walk_item( + &mut CollectUsageSpans { spans: &mut usage_spans, param_def_id: param.def_id.to_def_id() }, + item, + ); + + if !usage_spans.is_empty() { + // First, check if the ADT is (probably) cyclical. We say probably here, since + // we're not actually looking into substitutions, just walking through fields. + // And we only recurse into the fields of ADTs, and not the hidden types of + // opaques or anything else fancy. + let item_def_id = item.owner_id.to_def_id(); + let is_probably_cyclical = if matches!( + tcx.def_kind(item_def_id), + DefKind::Struct | DefKind::Union | DefKind::Enum + ) { + IsProbablyCyclical { tcx, adt_def_id: item_def_id, seen: Default::default() } + .visit_all_fields(tcx.adt_def(item_def_id)) + .is_break() + } else { + false + }; + // If the ADT is cyclical, then if at least one usage of the type parameter or + // the `Self` alias is present in the, then it's probably a cyclical struct, and + // we should call those parameter usages recursive rather than just saying they're + // unused... + // + // We currently report *all* of the parameter usages, since computing the exact + // subset is very involved, and the fact we're mentioning recursion at all is + // likely to guide the user in the right direction. + if is_probably_cyclical { + let diag = tcx.dcx().create_err(errors::RecursiveGenericParameter { + spans: usage_spans, + param_span: param.span, + param_name, + param_def_kind: tcx.def_descr(param.def_id.to_def_id()), + help, + note: (), + }); + return diag.emit(); + } + } + let const_param_help = matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds) .then_some(()); @@ -1923,6 +1966,7 @@ fn report_bivariance( span: param.span, param_name, param_def_kind: tcx.def_descr(param.def_id.to_def_id()), + usage_spans, help, const_param_help, }); @@ -1930,6 +1974,77 @@ fn report_bivariance( diag.emit() } +/// Detects cases where an ADT is trivially cyclical -- we want to detect this so +/// /we only mention that its parameters are used cyclically if the ADT is truly +/// cyclical. +/// +/// Notably, we don't consider substitutions here, so this may have false positives. +struct IsProbablyCyclical<'tcx> { + tcx: TyCtxt<'tcx>, + adt_def_id: DefId, + seen: FxHashSet<DefId>, +} + +impl<'tcx> IsProbablyCyclical<'tcx> { + fn visit_all_fields(&mut self, adt_def: ty::AdtDef<'tcx>) -> ControlFlow<(), ()> { + for field in adt_def.all_fields() { + self.tcx.type_of(field.did).instantiate_identity().visit_with(self)?; + } + + ControlFlow::Continue(()) + } +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IsProbablyCyclical<'tcx> { + type Result = ControlFlow<(), ()>; + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> { + if let Some(adt_def) = t.ty_adt_def() { + if adt_def.did() == self.adt_def_id { + return ControlFlow::Break(()); + } + + if self.seen.insert(adt_def.did()) { + self.visit_all_fields(adt_def)?; + } + } + + t.super_visit_with(self) + } +} + +/// Collect usages of the `param_def_id` and `Res::SelfTyAlias` in the HIR. +/// +/// This is used to report places where the user has used parameters in a +/// non-variance-constraining way for better bivariance errors. +struct CollectUsageSpans<'a> { + spans: &'a mut Vec<Span>, + param_def_id: DefId, +} + +impl<'tcx> Visitor<'tcx> for CollectUsageSpans<'_> { + type Result = (); + + fn visit_generics(&mut self, _g: &'tcx rustc_hir::Generics<'tcx>) -> Self::Result { + // Skip the generics. We only care about fields, not where clause/param bounds. + } + + fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result { + if let hir::TyKind::Path(hir::QPath::Resolved(None, qpath)) = t.kind { + if let Res::Def(DefKind::TyParam, def_id) = qpath.res + && def_id == self.param_def_id + { + self.spans.push(t.span); + return; + } else if let Res::SelfTyAlias { .. } = qpath.res { + self.spans.push(t.span); + return; + } + } + intravisit::walk_ty(self, t); + } +} + impl<'tcx> WfCheckingCtxt<'_, 'tcx> { /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 0ee87a13e9e..03311fed396 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1500,33 +1500,33 @@ pub struct StaticMutRef<'a> { #[label] pub span: Span, #[subdiagnostic] - pub sugg: StaticMutRefSugg, + pub sugg: MutRefSugg, pub shared: &'a str, } #[derive(Subdiagnostic)] -pub enum StaticMutRefSugg { - #[suggestion( +pub enum MutRefSugg { + #[multipart_suggestion( hir_analysis_suggestion, style = "verbose", - code = "addr_of!({var})", applicability = "maybe-incorrect" )] Shared { - #[primary_span] - span: Span, - var: String, + #[suggestion_part(code = "addr_of!(")] + lo: Span, + #[suggestion_part(code = ")")] + hi: Span, }, - #[suggestion( + #[multipart_suggestion( hir_analysis_suggestion_mut, style = "verbose", - code = "addr_of_mut!({var})", applicability = "maybe-incorrect" )] Mut { - #[primary_span] - span: Span, - var: String, + #[suggestion_part(code = "addr_of_mut!(")] + lo: Span, + #[suggestion_part(code = ")")] + hi: Span, }, } @@ -1539,36 +1539,10 @@ pub struct RefOfMutStatic<'a> { #[label] pub span: Span, #[subdiagnostic] - pub sugg: RefOfMutStaticSugg, + pub sugg: MutRefSugg, pub shared: &'a str, } -#[derive(Subdiagnostic)] -pub enum RefOfMutStaticSugg { - #[suggestion( - hir_analysis_suggestion, - style = "verbose", - code = "addr_of!({var})", - applicability = "maybe-incorrect" - )] - Shared { - #[primary_span] - span: Span, - var: String, - }, - #[suggestion( - hir_analysis_suggestion_mut, - style = "verbose", - code = "addr_of_mut!({var})", - applicability = "maybe-incorrect" - )] - Mut { - #[primary_span] - span: Span, - var: String, - }, -} - #[derive(Diagnostic)] #[diag(hir_analysis_not_supported_delegation)] pub struct NotSupportedDelegation<'a> { @@ -1597,12 +1571,29 @@ pub(crate) struct UnusedGenericParameter { pub span: Span, pub param_name: Ident, pub param_def_kind: &'static str, + #[label(hir_analysis_usage_spans)] + pub usage_spans: Vec<Span>, #[subdiagnostic] pub help: UnusedGenericParameterHelp, #[help(hir_analysis_const_param_help)] pub const_param_help: Option<()>, } +#[derive(Diagnostic)] +#[diag(hir_analysis_recursive_generic_parameter)] +pub(crate) struct RecursiveGenericParameter { + #[primary_span] + pub spans: Vec<Span>, + #[label] + pub param_span: Span, + pub param_name: Ident, + pub param_def_kind: &'static str, + #[subdiagnostic] + pub help: UnusedGenericParameterHelp, + #[note] + pub note: (), +} + #[derive(Subdiagnostic)] pub(crate) enum UnusedGenericParameterHelp { #[help(hir_analysis_unused_generic_parameter_adt_help)] |
