From 5fa1c1b5f3e03a8f2049c6a36f58fae1fe05852d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 4 Jul 2017 17:04:34 +0300 Subject: [PATCH] Fix spans for binary operator expression with interpolated identifiers --- src/libsyntax/parse/parser.rs | 17 ++++++++++++----- src/test/ui/issue-42954.rs | 20 ++++++++++++++++++++ src/test/ui/issue-42954.stderr | 13 +++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/issue-42954.rs create mode 100644 src/test/ui/issue-42954.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 23d85232369..f35ecbe20e0 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -150,13 +150,14 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) lhs } -#[derive(Clone, PartialEq)] +#[derive(Clone, Copy, PartialEq)] enum PrevTokenKind { DocComment, Comma, Plus, Interpolated, Eof, + Ident, Other, } @@ -1040,6 +1041,7 @@ impl<'a> Parser<'a> { token::BinOp(token::Plus) => PrevTokenKind::Plus, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, + token::Ident(..) => PrevTokenKind::Ident, _ => PrevTokenKind::Other, }; @@ -2777,10 +2779,15 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Operator); while let Some(op) = AssocOp::from_token(&self.token) { - let lhs_span = if self.prev_token_kind == PrevTokenKind::Interpolated { - self.prev_span - } else { - lhs.span + // Adjust the span for interpolated LHS to point to the `$lhs` token and not to what + // it refers to. Interpolated identifiers are unwrapped early and never show up here + // as `PrevTokenKind::Interpolated` so if LHS is a single identifier we always process + // it as "interpolated", it doesn't change the answer for non-interpolated idents. + let lhs_span = match (self.prev_token_kind, &lhs.node) { + (PrevTokenKind::Interpolated, _) => self.prev_span, + (PrevTokenKind::Ident, &ExprKind::Path(None, ref path)) + if path.segments.len() == 1 => self.prev_span, + _ => lhs.span, }; let cur_op_span = self.span; diff --git a/src/test/ui/issue-42954.rs b/src/test/ui/issue-42954.rs new file mode 100644 index 00000000000..ee0367b8a68 --- /dev/null +++ b/src/test/ui/issue-42954.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! is_plainly_printable { + ($i: ident) => { + $i as u32 < 0 + }; +} + +fn main() { + let c = 'a'; + is_plainly_printable!(c); +} diff --git a/src/test/ui/issue-42954.stderr b/src/test/ui/issue-42954.stderr new file mode 100644 index 00000000000..0ac3d82c719 --- /dev/null +++ b/src/test/ui/issue-42954.stderr @@ -0,0 +1,13 @@ +error: `<` is interpreted as a start of generic arguments for `u32`, not a comparison + --> $DIR/issue-42954.rs:13:19 + | +13 | $i as u32 < 0 + | - ^ interpreted as generic argument + | | + | not interpreted as comparison + | +help: if you want to compare the casted value then write: + | ($i as u32) < 0 + +error: aborting due to previous error +