Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a new mismatched-lifetime-syntaxes lint #138677

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1206,7 +1206,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.next_node_id()
};
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
Lifetime { ident: Ident::new(kw::Empty, span), id }
});
let lifetime = self.lower_lifetime(&region);
hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx))
@@ -1222,7 +1222,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.next_node_id()
};
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
Lifetime { ident: Ident::new(kw::Empty, span), id }
});
let lifetime = self.lower_lifetime(&region);
let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx));
14 changes: 3 additions & 11 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

use rustc_ast::ParamKindOrd;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};

@@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec<Span>);

// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
impl Subdiagnostic for EmptyLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.0, "");
}
}
@@ -749,11 +745,7 @@ pub(crate) struct StableFeature {
}

impl Subdiagnostic for StableFeature {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("name", self.name);
diag.arg("since", self.since);
diag.help(fluent::ast_passes_stable_since);
10 changes: 3 additions & 7 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
SubdiagMessageOp, Subdiagnostic,
Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@@ -683,13 +683,9 @@ pub(crate) struct FormatUnusedArg {
// Allow the singular form to be a subdiagnostic of the multiple-unused
// form of diagnostic.
impl Subdiagnostic for FormatUnusedArg {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("named", self.named);
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg);
diag.span_label(self.span, msg);
}
}
10 changes: 3 additions & 7 deletions compiler/rustc_const_eval/src/errors.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ use rustc_abi::WrappingRange;
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
MultiSpan, SubdiagMessageOp, Subdiagnostic,
MultiSpan, Subdiagnostic,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -290,19 +290,15 @@ pub struct FrameNote {
}

impl Subdiagnostic for FrameNote {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("times", self.times);
diag.arg("where_", self.where_);
diag.arg("instance", self.instance);
let mut span: MultiSpan = self.span.into();
if self.has_label && !self.span.is_dummy() {
span.push_span_label(self.span, fluent::const_eval_frame_note_last);
}
let msg = f(diag, fluent::const_eval_frame_note.into());
let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
diag.span_note(span, msg);
}
}
28 changes: 8 additions & 20 deletions compiler/rustc_errors/src/diagnostic.rs
Original file line number Diff line number Diff line change
@@ -181,22 +181,9 @@ where
Self: Sized,
{
/// Add a subdiagnostic to an existing diagnostic.
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
self.add_to_diag_with(diag, &|_, m| m);
}

/// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
/// (to optionally perform eager translation).
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
f: &F,
);
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
}

pub trait SubdiagMessageOp<G: EmissionGuarantee> =
Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;

/// Trait implemented by lint types. This should not be implemented manually. Instead, use
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
#[rustc_diagnostic_item = "LintDiagnostic"]
@@ -1225,15 +1212,16 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// interpolated variables).
#[rustc_lint_diagnostics]
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
let dcx = self.dcx;
subdiagnostic.add_to_diag_with(self, &|diag, msg| {
let args = diag.args.iter();
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
dcx.eagerly_translate(msg, args)
});
subdiagnostic.add_to_diag(self);
self
}

pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
let args = self.args.iter();
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
self.dcx.eagerly_translate(msg, args)
}

with_fn! { with_span,
/// Add a span.
#[rustc_lint_diagnostics]
8 changes: 2 additions & 6 deletions compiler/rustc_errors/src/diagnostic_impls.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ use {rustc_ast as ast, rustc_hir as hir};
use crate::diagnostic::DiagLocation;
use crate::{
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent,
Subdiagnostic, fluent_generated as fluent,
};

pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
@@ -384,11 +384,7 @@ pub struct SingleLabelManySpans {
pub label: &'static str,
}
impl Subdiagnostic for SingleLabelManySpans {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: &F,
) {
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.spans, self.label);
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ pub use codes::*;
pub use diagnostic::{
BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
SubdiagMessageOp, Subdiagnostic,
Subdiagnostic,
};
pub use diagnostic_impls::{
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
7 changes: 1 addition & 6 deletions compiler/rustc_hir/src/def.rs
Original file line number Diff line number Diff line change
@@ -845,12 +845,7 @@ pub enum LifetimeRes {
/// late resolution. Those lifetimes will be inferred by typechecking.
Infer,
/// `'static` lifetime.
Static {
/// We do not want to emit `elided_named_lifetimes`
/// when we are inside of a const item or a static,
/// because it would get too annoying.
suppress_elision_warning: bool,
},
Static,
/// Resolution failure.
Error,
/// HACK: This is used to recover the NodeId of an elided lifetime.
28 changes: 21 additions & 7 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
@@ -89,7 +89,7 @@ impl ParamName {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
pub enum LifetimeName {
/// User-given names or fresh (synthetic) names.
Param(LocalDefId),
@@ -158,12 +158,26 @@ impl Lifetime {
}

pub fn is_anonymous(&self) -> bool {
self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime
self.is_syntactically_hidden() || self.is_syntactically_anonymous()
}

pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) {
if self.ident.name == kw::Empty {
if self.ident.span.is_empty() {
pub fn is_syntactically_hidden(&self) -> bool {
self.ident.name == kw::Empty
}

pub fn is_syntactically_anonymous(&self) -> bool {
self.ident.name == kw::UnderscoreLifetime
}

pub fn is_static(&self) -> bool {
self.res == LifetimeName::Static
}

pub fn suggestion_position(&self, is_ref: bool) -> (LifetimeSuggestionPosition, Span) {
if self.is_syntactically_hidden() {
if is_ref {
(LifetimeSuggestionPosition::Ampersand, self.ident.span)
} else if self.ident.span.is_empty() {
(LifetimeSuggestionPosition::ElidedPathArgument, self.ident.span)
} else {
(LifetimeSuggestionPosition::ElidedPath, self.ident.span.shrink_to_hi())
@@ -177,9 +191,9 @@ impl Lifetime {
}
}

pub fn suggestion(&self, new_lifetime: &str) -> (Span, String) {
pub fn suggestion(&self, new_lifetime: &str, is_ref: bool) -> (Span, String) {
debug_assert!(new_lifetime.starts_with('\''));
let (pos, span) = self.suggestion_position();
let (pos, span) = self.suggestion_position(is_ref);
let code = match pos {
LifetimeSuggestionPosition::Normal => format!("{new_lifetime}"),
LifetimeSuggestionPosition::Ampersand => format!("{new_lifetime} "),
28 changes: 22 additions & 6 deletions compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
Original file line number Diff line number Diff line change
@@ -64,6 +64,7 @@ struct BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
rbv: &'a mut ResolveBoundVars,
scope: ScopeRef<'a>,
is_ref: bool,
}

#[derive(Debug)]
@@ -245,8 +246,12 @@ pub(crate) fn provide(providers: &mut Providers) {
#[instrument(level = "debug", skip(tcx))]
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
let mut rbv = ResolveBoundVars::default();
let mut visitor =
BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } };
let mut visitor = BoundVarContext {
tcx,
rbv: &mut rbv,
scope: &Scope::Root { opt_parent_item: None },
is_ref: false,
};
match tcx.hir_owner_node(local_def_id) {
hir::OwnerNode::Item(item) => visitor.visit_item(item),
hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
@@ -648,7 +653,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
match *arg {
hir::PreciseCapturingArg::Lifetime(lt) => match lt.res {
LifetimeName::Param(def_id) => {
self.resolve_lifetime_ref(def_id, lt);
self.resolve_lifetime_ref(def_id, lt, false);
}
LifetimeName::Error => {}
LifetimeName::ImplicitObjectLifetimeDefault
@@ -701,6 +706,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {

#[instrument(level = "debug", skip(self))]
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
let old_is_ref = self.is_ref;

match ty.kind {
hir::TyKind::BareFn(c) => {
let (mut bound_vars, binders): (FxIndexMap<LocalDefId, ResolvedArg>, Vec<_>) = c
@@ -797,6 +804,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
}
hir::TyKind::Ref(lifetime_ref, ref mt) => {
self.is_ref = true;
self.visit_lifetime(lifetime_ref);
let scope = Scope::ObjectLifetimeDefault {
lifetime: self.rbv.defs.get(&lifetime_ref.hir_id.local_id).cloned(),
@@ -821,6 +829,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}
_ => intravisit::walk_ty(self, ty),
}

self.is_ref = old_is_ref;
}

#[instrument(level = "debug", skip(self))]
@@ -878,7 +888,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime)
}
hir::LifetimeName::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
self.resolve_lifetime_ref(param_def_id, lifetime_ref, self.is_ref)
}
// If we've already reported an error, just ignore `lifetime_ref`.
hir::LifetimeName::Error => {}
@@ -888,6 +898,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
}

fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: HirId) {
let old_is_ref = self.is_ref;
self.is_ref = false;

for (i, segment) in path.segments.iter().enumerate() {
let depth = path.segments.len() - i - 1;
if let Some(args) = segment.args {
@@ -897,6 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
if let Res::Def(DefKind::TyParam | DefKind::ConstParam, param_def_id) = path.res {
self.resolve_type_ref(param_def_id.expect_local(), hir_id);
}

self.is_ref = old_is_ref;
}

fn visit_fn(
@@ -1092,7 +1107,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
{
let BoundVarContext { tcx, rbv, .. } = self;
let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope };
let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope, is_ref: false };
let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
{
let _enter = span.enter();
@@ -1201,6 +1216,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
&mut self,
region_def_id: LocalDefId,
lifetime_ref: &'tcx hir::Lifetime,
is_ref: bool,
) {
// Walk up the scope chain, tracking the number of fn scopes
// that we pass through, until we find a lifetime with the
@@ -1266,7 +1282,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
(generics.span, "<'a>".to_owned())
};

let lifetime_sugg = lifetime_ref.suggestion("'a");
let lifetime_sugg = lifetime_ref.suggestion("'a", is_ref);
let suggestions = vec![lifetime_sugg, new_param_sugg];

diag.span_label(
Loading
Loading