Rollup merge of #144711 - compiler-errors:op-span, r=petrochenkov

Consider operator's span when computing binop expr span

When computing the span of a binop consisting of `lhs` and `rhs`, we previously just took the spans of `lhs.span.to(rhs.span)`. In the case that both `lhs` and `rhs` are both arguments to a macro, this can produce a wildly incorrect span.

To fix this, first compute the span between `lhs` and the binary operator, which will cause `lhs` to possibly be adjusted to a relevant macro metavar, and then compute that span extended to `rhs`, which will cause it to also be adjusted to a relevant macro metavar.

This coincidentally fixes a FIXME in `tests/ui/lint/wide_pointer_comparisons.rs` and suppresses a nonsense suggestion.
This commit is contained in:
Jana Dönszelmann 2025-07-31 17:19:39 +02:00 committed by GitHub
commit edd2574848
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 20 additions and 17 deletions

View file

@ -263,10 +263,11 @@ impl<'a> Parser<'a> {
continue;
}
let op_span = op.span;
let op = op.node;
// Special cases:
if op == AssocOp::Cast {
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
lhs = self.parse_assoc_op_cast(lhs, lhs_span, op_span, ExprKind::Cast)?;
continue;
} else if let AssocOp::Range(limits) = op {
// If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
@ -284,7 +285,7 @@ impl<'a> Parser<'a> {
this.parse_expr_assoc_with(min_prec, attrs)
})?;
let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
let span = self.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span);
lhs = match op {
AssocOp::Binary(ast_op) => {
let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs);
@ -429,7 +430,7 @@ impl<'a> Parser<'a> {
None
};
let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
let span = self.mk_expr_sp(&lhs, lhs.span, cur_op_span, rhs_span);
let range = self.mk_range(Some(lhs), rhs, limits);
Ok(self.mk_expr(span, range))
}
@ -654,10 +655,11 @@ impl<'a> Parser<'a> {
&mut self,
lhs: P<Expr>,
lhs_span: Span,
op_span: Span,
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
) -> PResult<'a, P<Expr>> {
let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs))
this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, op_span, rhs.span), expr_kind(lhs, rhs))
};
// Save the state of the parser before parsing type normally, in case there is a
@ -4005,11 +4007,12 @@ impl<'a> Parser<'a> {
/// Create expression span ensuring the span of the parent node
/// is larger than the span of lhs and rhs, including the attributes.
fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span {
fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, op_span: Span, rhs_span: Span) -> Span {
lhs.attrs
.iter()
.find(|a| a.style == AttrStyle::Outer)
.map_or(lhs_span, |a| a.span)
.to(op_span)
.to(rhs_span)
}

View file

@ -106,7 +106,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
res
} else {
// Example cases:
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
// - `#[foo = 1+1]`: results in `ast::ExprKind::Binary`.
// - `#[foo = include_str!("nonexistent-file.rs")]`:
// results in `ast::ExprKind::Err`. In that case we delay
// the error because an earlier error will have already

View file

@ -146,12 +146,10 @@ fn main() {
{
macro_rules! cmp {
($a:tt, $b:tt) => { $a == $b }
//~^ WARN ambiguous wide pointer comparison
}
// FIXME: This lint uses some custom span combination logic.
// Rewrite it to adapt to the new metavariable span rules.
cmp!(a, b);
//~^ WARN ambiguous wide pointer comparison
}
{

View file

@ -720,18 +720,20 @@ LL + std::ptr::eq(*a, *b)
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:153:14
--> $DIR/wide_pointer_comparisons.rs:148:33
|
LL | ($a:tt, $b:tt) => { $a == $b }
| ^^^^^^^^
...
LL | cmp!(a, b);
| ^^^^
| ---------- in this macro invocation
|
help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
|
LL | cmp!(std::ptr::addr_eq(a, b));
| ++++++++++++++++++ +
= help: use explicit `std::ptr::eq` method to compare metadata and addresses
= help: use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
= note: this warning originates in the macro `cmp` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:159:39
--> $DIR/wide_pointer_comparisons.rs:157:39
|
LL | ($a:ident, $b:ident) => { $a == $b }
| ^^^^^^^^
@ -747,7 +749,7 @@ LL + ($a:ident, $b:ident) => { std::ptr::addr_eq($a, $b) }
|
warning: ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
--> $DIR/wide_pointer_comparisons.rs:169:37
--> $DIR/wide_pointer_comparisons.rs:167:37
|
LL | ($a:expr, $b:expr) => { $a == $b }
| ^^^^^^^^