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

Macro expansion often produces invalid Span values #23480

Closed
michaelwoerister opened this issue Mar 18, 2015 · 6 comments
Closed

Macro expansion often produces invalid Span values #23480

michaelwoerister opened this issue Mar 18, 2015 · 6 comments
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The parsing of Rust source code to an AST. C-bug Category: This is a bug.

Comments

@michaelwoerister
Copy link
Member

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).

@michaelwoerister michaelwoerister added A-parser Area: The parsing of Rust source code to an AST. A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) labels Mar 18, 2015
@kmcallister
Copy link
Contributor

We should have a library of common span operations that ensures the syntax contexts match. These operations are necessarily partial; there's no sensible way to union spans from two different contexts. But we could introduce a "span set" or "compound span" to handle that.

@michaelwoerister
Copy link
Member Author

My proposal would be to use the context that the defining operator/token for the given AST node is in. For example, for a binary operation AST node, use the context the operator token originally occurs. For the above example, that would mean:

macro_rules! add1 { ($val:expr) => ( { 1 + $val } ) }
                                       ^^^^^^^^
// the span of the (+) AST node lies within the macro-definition,
// regardless where $val comes from

bors added a commit that referenced this issue Mar 19, 2015
… r=alexcrichton

This should solve issues #23115, #23469, and #23407.

As the title says, this is just a workaround. The underlying problem is that macro expansion can produce invalid spans. I've opened issue #23480 so we don't forget about that.
Manishearth added a commit to Manishearth/rust that referenced this issue Mar 20, 2015
…erflow-bug, r=alexcrichton

 This should solve issues rust-lang#23115, rust-lang#23469, and rust-lang#23407.

As the title says, this is just a workaround. The underlying problem is that macro expansion can produce invalid spans. I've opened issue rust-lang#23480 so we don't forget about that.
@steveklabnik
Copy link
Member

Triage: there's been a lot of work on spans with the new error format, but I'm not close enough to it to know if it fixes this issue.

@jseyfried
Copy link
Contributor

jseyfried commented Feb 8, 2017

cc #39450, which is on the declarative macros 2.0 roadmap.

@kmcallister @michaelwoerister
The current plan here is to add more span information to "interpolated tokens" (NoDelim token trees in the macros 2.0 framework) and make the parser smart enough to know when to use e.g. the span of the meta-variable $val versus the span where $val came from.

@jseyfried jseyfried reopened this Mar 17, 2017
bors added a commit that referenced this issue Mar 30, 2017
macros: improve `Span`'s expansion information

This PR improves `Span`'s expansion information. More specifically:
 - It refactors AST node span construction to preserve expansion information.
   - Today, we only use the underlying tokens' `BytePos`s, throwing away the `ExpnId`s.
   - This improves the accuracy of AST nodes' expansion information, fixing #30506.
 - It refactors `span.expn_id: ExpnId` to `span.ctxt: SyntaxContext` and removes `ExpnId`.
   - This gives all tokens as much hygiene information as `Ident`s.
   - This is groundwork for procedural macros 2.0 `TokenStream` API.
   - This is also groundwork for declarative macros 2.0, which will need this hygiene information for some non-`Ident` tokens.
 - It simplifies processing of spans' expansion information throughout the compiler.
 - It fixes #40649.
 - It fixes #39450 and fixes part of #23480.

r? @nrc
@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 22, 2017
kennytm added a commit to kennytm/rust that referenced this issue Feb 2, 2018
…s Minimize weird spans involving macro context Sometimes the parser attempts to synthesize spans from within a macro context with the span for the captured argument, leading to non-sensical spans with very bad output. Given that an incorrect span is worse than a partially incomplete span, when detecting this situation return only one of the spans without merging them. Fix rust-lang#32072, rust-lang#47778. CC rust-lang#23480.
@estebank
Copy link
Contributor

I believe this is minimized (if not out right eliminated) after #47942.

@Mark-Simulacrum
Copy link
Member

I'm going to close this in favor of opening more targeted bugs/PRs as we come across them, in particular in light of @estebank's previous comment about this being most likely fixed today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-parser Area: The parsing of Rust source code to an AST. C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

6 participants