Skip to content

Commit 4a8aa40

Browse files
authored
Rollup merge of rust-lang#116787 - a-lafrance:span-internal-lint, r=oli-obk
Implement an internal lint encouraging use of `Span::eq_ctxt` Adds a new Rustc internal lint that forbids use of `.ctxt() == .ctxt()` for spans, encouraging use of `.eq_ctxt()` instead (see rust-lang#49509). Also fixed a few violations of the lint in the Rustc codebase (a fun additional way I could test my code). Edit: MIR opt folks I believe that's why you're CC'ed, just a heads up. Two things I'm not sure about: 1. The way I chose to detect calls to `Span::ctxt`. I know adding diagnostic items to methods is generally discouraged, but after some searching and experimenting I couldn't find anything else that worked, so I went with it. That said, I'm happy to implement something different if there's a better way out there. (For what it's worth, if there is a better way, it might be worth documenting in the rustc-dev-guide, which I'm happy to take care of) 2. The error message for the lint. Ideally it would probably be good to give some context as to why the suggestion is made (e.g. `rustc::default_hash_types` tells the user that it's because of performance), but I don't have that context so I couldn't put it in the error message. Happy to iterate on the error message based on feedback during review. r? `@oli-obk`
2 parents 560e498 + e89d4d4 commit 4a8aa40

File tree

25 files changed

+89
-21
lines changed

25 files changed

+89
-21
lines changed

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
650650
.sess
651651
.source_map()
652652
.is_multiline(call_expr.span.with_lo(callee_expr.span.hi()))
653-
&& call_expr.span.ctxt() == callee_expr.span.ctxt();
653+
&& call_expr.span.eq_ctxt(callee_expr.span);
654654
if call_is_multiline {
655655
err.span_suggestion(
656656
callee_expr.span.shrink_to_hi(),

compiler/rustc_lint/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
494494
495495
lint_requested_level = requested on the command line with `{$level} {$lint_name}`
496496
497+
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
498+
497499
lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
498500
.label = target type is set here
499501

compiler/rustc_lint/src/internal.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
44
use crate::lints::{
55
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
6-
QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
6+
QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
77
UntranslatableDiagnosticTrivial,
88
};
99
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
1010
use rustc_ast as ast;
1111
use rustc_hir::def::Res;
1212
use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
13-
use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
13+
use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
1414
use rustc_middle::ty;
1515
use rustc_session::{declare_lint_pass, declare_tool_lint};
1616
use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -537,3 +537,33 @@ impl LateLintPass<'_> for BadOptAccess {
537537
}
538538
}
539539
}
540+
541+
declare_tool_lint! {
542+
pub rustc::SPAN_USE_EQ_CTXT,
543+
Allow,
544+
"forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead",
545+
report_in_external_macro: true
546+
}
547+
548+
declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
549+
550+
impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
551+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
552+
if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind {
553+
if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
554+
cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
555+
}
556+
}
557+
}
558+
}
559+
560+
fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
561+
match &expr.kind {
562+
ExprKind::MethodCall(..) => cx
563+
.typeck_results()
564+
.type_dependent_def_id(expr.hir_id)
565+
.is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)),
566+
567+
_ => false,
568+
}
569+
}

compiler/rustc_lint/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ fn register_internals(store: &mut LintStore) {
531531
store.register_late_mod_pass(|_| Box::new(BadOptAccess));
532532
store.register_lints(&PassByValue::get_lints());
533533
store.register_late_mod_pass(|_| Box::new(PassByValue));
534+
store.register_lints(&SpanUseEqCtxt::get_lints());
535+
store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
534536
// FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
535537
// `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
536538
// these lints will trigger all of the time - change this once migration to diagnostic structs
@@ -548,6 +550,7 @@ fn register_internals(store: &mut LintStore) {
548550
LintId::of(USAGE_OF_QUALIFIED_TY),
549551
LintId::of(EXISTING_DOC_KEYWORD),
550552
LintId::of(BAD_OPT_ACCESS),
553+
LintId::of(SPAN_USE_EQ_CTXT),
551554
],
552555
);
553556
}

compiler/rustc_lint/src/lints.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,10 @@ pub struct QueryInstability {
900900
pub query: Symbol,
901901
}
902902

903+
#[derive(LintDiagnostic)]
904+
#[diag(lint_span_use_eq_ctxt)]
905+
pub struct SpanUseEqCtxtDiag;
906+
903907
#[derive(LintDiagnostic)]
904908
#[diag(lint_tykind_kind)]
905909
pub struct TykindKind {

compiler/rustc_mir_transform/src/coverage/spans.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ impl<'a> CoverageSpansGenerator<'a> {
404404

405405
let Some(visible_macro) = curr.visible_macro(self.body_span) else { return };
406406
if let Some(prev) = &self.some_prev
407-
&& prev.expn_span.ctxt() == curr.expn_span.ctxt()
407+
&& prev.expn_span.eq_ctxt(curr.expn_span)
408408
{
409409
return;
410410
}

compiler/rustc_passes/src/loops.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
231231
AsyncClosure(closure_span) => {
232232
self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
233233
}
234-
UnlabeledBlock(block_span) if is_break && block_span.ctxt() == break_span.ctxt() => {
234+
UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
235235
let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
236236
self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion });
237237
}

compiler/rustc_span/src/span_encoding.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ impl Span {
212212

213213
/// This function is used as a fast path when decoding the full `SpanData` is not necessary.
214214
/// It's a cut-down version of `data_untracked`.
215+
#[cfg_attr(not(test), rustc_diagnostic_item = "SpanCtxt")]
215216
#[inline]
216217
pub fn ctxt(self) -> SyntaxContext {
217218
if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ symbols! {
303303
SliceIndex,
304304
SliceIter,
305305
Some,
306+
SpanCtxt,
306307
String,
307308
StructuralEq,
308309
StructuralPartialEq,

src/tools/clippy/clippy_lints/src/dereference.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
701701

702702
fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
703703
if let Some(parent) = get_parent_expr(cx, e)
704-
&& parent.span.ctxt() == e.span.ctxt()
704+
&& parent.span.eq_ctxt(e.span)
705705
{
706706
match parent.kind {
707707
ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _)

0 commit comments

Comments
 (0)