Skip to content

Macro expansion often produces invalid Span values #23480

Closed
@michaelwoerister

Description

The span of many AST node types is pieced together from the spans of the node's children. Here is an example from Parser::parse_more_binops:

let lhs_span = lhs.span;
let rhs_span = rhs.span;
let binary = self.mk_binary(codemap::respan(cur_op_span, cur_op), lhs, rhs);
let bin = self.mk_expr(lhs_span.lo, rhs_span.hi, binary);

Unfortunately, in the macro expansion phase, this can lead to undesirable results. Consider the following example:

add1!(3);
macro_rules! add1 { ($val:expr) => ( { 1 + $val } ) }

Here lhs and rhs come from completely different contexts. lhs_span comes from the macro-definition-site (lo: 50, hi: 51) while rhs_span comes from the expansion-site (lo: 6, hi:7). Taking lo from lhs and hi from rhs, as the above code does, we end up with a span of lo: 50, hi: 7. This value can't be interpreted in any meaningful way.

A similar error can occur for any kind of AST node where a sub-node is located directly at the border of a parent:

// binary operators
$expr + $expr

// unary operators
! $expr

// closures
|x| $expr

// parameters
fn foo($expr: $ty) {}

// type parameters
fn bar<$ident: $ty>

// type ascription
$expr : $type

// C-style enums
enum Foo {
    $ident = $expr,
}

// derived types
& &mut $ty

// where clauses
fn baz<T>() where T: $ty {}

// call expressions (?)
$e()

// path expressions (?)
$x::foo()

// ... probably others

This invalid Span values may lead to strange error messages and caused at least one ICE (#23115).

Metadata

Assignees

No one assigned

    Labels

    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)A-parserArea: The parsing of Rust source code to an ASTC-bugCategory: This is a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions