diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2017-07-04 17:04:34 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2017-07-07 11:21:57 +0300 |
| commit | 5fa1c1b5f3e03a8f2049c6a36f58fae1fe05852d (patch) | |
| tree | ce6a673749a2eba6d0605dc1ed7410ee85fdd6ac | |
| parent | 24fc541e7cee966ad8752eb8360f0d4e9ba0bef0 (diff) | |
| download | rust-5fa1c1b5f3e03a8f2049c6a36f58fae1fe05852d.tar.gz rust-5fa1c1b5f3e03a8f2049c6a36f58fae1fe05852d.zip | |
Fix spans for binary operator expression with interpolated identifiers
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 17 | ||||
| -rw-r--r-- | src/test/ui/issue-42954.rs | 20 | ||||
| -rw-r--r-- | src/test/ui/issue-42954.stderr | 13 |
3 files changed, 45 insertions, 5 deletions
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<Attribute>, rhs: Option<Vec<Attribute>>) 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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 + |
