Skip to content

Commit f4da040

Browse files
committed
rollup merge of #17290 : bkoropoff/issue-17283
2 parents 04c537f + 0e230c0 commit f4da040

File tree

2 files changed

+68
-34
lines changed

2 files changed

+68
-34
lines changed

src/libsyntax/parse/parser.rs

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,13 @@ use std::mem;
8888
use std::rc::Rc;
8989
use std::iter;
9090

91-
#[allow(non_camel_case_types)]
92-
#[deriving(PartialEq)]
93-
pub enum restriction {
94-
UNRESTRICTED,
95-
RESTRICT_STMT_EXPR,
96-
RESTRICT_NO_BAR_OP,
97-
RESTRICT_NO_BAR_OR_DOUBLEBAR_OP,
98-
RESTRICT_NO_STRUCT_LITERAL,
91+
bitflags! {
92+
flags Restrictions: u8 {
93+
static Unrestricted = 0b0000,
94+
static RestrictionStmtExpr = 0b0001,
95+
static RestrictionNoBarOp = 0b0010,
96+
static RestrictionNoStructLiteral = 0b0100
97+
}
9998
}
10099

101100
type ItemInfo = (Ident, Item_, Option<Vec<Attribute> >);
@@ -314,7 +313,7 @@ pub struct Parser<'a> {
314313
pub buffer_start: int,
315314
pub buffer_end: int,
316315
pub tokens_consumed: uint,
317-
pub restriction: restriction,
316+
pub restrictions: Restrictions,
318317
pub quote_depth: uint, // not (yet) related to the quasiquoter
319318
pub reader: Box<Reader+'a>,
320319
pub interner: Rc<token::IdentInterner>,
@@ -383,7 +382,7 @@ impl<'a> Parser<'a> {
383382
buffer_start: 0,
384383
buffer_end: 0,
385384
tokens_consumed: 0,
386-
restriction: UNRESTRICTED,
385+
restrictions: Unrestricted,
387386
quote_depth: 0,
388387
obsolete_set: HashSet::new(),
389388
mod_path_stack: Vec::new(),
@@ -2189,7 +2188,7 @@ impl<'a> Parser<'a> {
21892188
if self.token == token::LBRACE {
21902189
// This is a struct literal, unless we're prohibited
21912190
// from parsing struct literals here.
2192-
if self.restriction != RESTRICT_NO_STRUCT_LITERAL {
2191+
if !self.restrictions.contains(RestrictionNoStructLiteral) {
21932192
// It's a struct literal.
21942193
self.bump();
21952194
let mut fields = Vec::new();
@@ -2651,12 +2650,9 @@ impl<'a> Parser<'a> {
26512650

26522651
// Prevent dynamic borrow errors later on by limiting the
26532652
// scope of the borrows.
2654-
match (&self.token, &self.restriction) {
2655-
(&token::BINOP(token::OR), &RESTRICT_NO_BAR_OP) => return lhs,
2656-
(&token::BINOP(token::OR),
2657-
&RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) => return lhs,
2658-
(&token::OROR, &RESTRICT_NO_BAR_OR_DOUBLEBAR_OP) => return lhs,
2659-
_ => { }
2653+
if self.token == token::BINOP(token::OR) &&
2654+
self.restrictions.contains(RestrictionNoBarOp) {
2655+
return lhs;
26602656
}
26612657

26622658
let cur_opt = token_to_binop(&self.token);
@@ -2696,15 +2692,16 @@ impl<'a> Parser<'a> {
26962692
pub fn parse_assign_expr(&mut self) -> P<Expr> {
26972693
let lo = self.span.lo;
26982694
let lhs = self.parse_binops();
2695+
let restrictions = self.restrictions & RestrictionNoStructLiteral;
26992696
match self.token {
27002697
token::EQ => {
27012698
self.bump();
2702-
let rhs = self.parse_expr();
2699+
let rhs = self.parse_expr_res(restrictions);
27032700
self.mk_expr(lo, rhs.span.hi, ExprAssign(lhs, rhs))
27042701
}
27052702
token::BINOPEQ(op) => {
27062703
self.bump();
2707-
let rhs = self.parse_expr();
2704+
let rhs = self.parse_expr_res(restrictions);
27082705
let aop = match op {
27092706
token::PLUS => BiAdd,
27102707
token::MINUS => BiSub,
@@ -2730,7 +2727,7 @@ impl<'a> Parser<'a> {
27302727
/// Parse an 'if' expression ('if' token already eaten)
27312728
pub fn parse_if_expr(&mut self) -> P<Expr> {
27322729
let lo = self.last_span.lo;
2733-
let cond = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
2730+
let cond = self.parse_expr_res(RestrictionNoStructLiteral);
27342731
let thn = self.parse_block();
27352732
let mut els: Option<P<Expr>> = None;
27362733
let mut hi = thn.span.hi;
@@ -2791,7 +2788,7 @@ impl<'a> Parser<'a> {
27912788
let lo = self.last_span.lo;
27922789
let pat = self.parse_pat();
27932790
self.expect_keyword(keywords::In);
2794-
let expr = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
2791+
let expr = self.parse_expr_res(RestrictionNoStructLiteral);
27952792
let loop_block = self.parse_block();
27962793
let hi = self.span.hi;
27972794

@@ -2800,7 +2797,7 @@ impl<'a> Parser<'a> {
28002797

28012798
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::Ident>) -> P<Expr> {
28022799
let lo = self.last_span.lo;
2803-
let cond = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
2800+
let cond = self.parse_expr_res(RestrictionNoStructLiteral);
28042801
let body = self.parse_block();
28052802
let hi = body.span.hi;
28062803
return self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident));
@@ -2815,7 +2812,7 @@ impl<'a> Parser<'a> {
28152812

28162813
fn parse_match_expr(&mut self) -> P<Expr> {
28172814
let lo = self.last_span.lo;
2818-
let discriminant = self.parse_expr_res(RESTRICT_NO_STRUCT_LITERAL);
2815+
let discriminant = self.parse_expr_res(RestrictionNoStructLiteral);
28192816
self.commit_expr_expecting(&*discriminant, token::LBRACE);
28202817
let mut arms: Vec<Arm> = Vec::new();
28212818
while self.token != token::RBRACE {
@@ -2834,7 +2831,7 @@ impl<'a> Parser<'a> {
28342831
guard = Some(self.parse_expr());
28352832
}
28362833
self.expect(&token::FAT_ARROW);
2837-
let expr = self.parse_expr_res(RESTRICT_STMT_EXPR);
2834+
let expr = self.parse_expr_res(RestrictionStmtExpr);
28382835

28392836
let require_comma =
28402837
!classify::expr_is_simple_block(&*expr)
@@ -2856,15 +2853,15 @@ impl<'a> Parser<'a> {
28562853

28572854
/// Parse an expression
28582855
pub fn parse_expr(&mut self) -> P<Expr> {
2859-
return self.parse_expr_res(UNRESTRICTED);
2856+
return self.parse_expr_res(Unrestricted);
28602857
}
28612858

2862-
/// Parse an expression, subject to the given restriction
2863-
pub fn parse_expr_res(&mut self, r: restriction) -> P<Expr> {
2864-
let old = self.restriction;
2865-
self.restriction = r;
2859+
/// Parse an expression, subject to the given restrictions
2860+
pub fn parse_expr_res(&mut self, r: Restrictions) -> P<Expr> {
2861+
let old = self.restrictions;
2862+
self.restrictions = r;
28662863
let e = self.parse_assign_expr();
2867-
self.restriction = old;
2864+
self.restrictions = old;
28682865
return e;
28692866
}
28702867

@@ -3153,9 +3150,9 @@ impl<'a> Parser<'a> {
31533150
self.look_ahead(2, |t| {
31543151
*t != token::COMMA && *t != token::RBRACKET
31553152
}) {
3156-
let start = self.parse_expr_res(RESTRICT_NO_BAR_OP);
3153+
let start = self.parse_expr_res(RestrictionNoBarOp);
31573154
self.eat(&token::DOTDOT);
3158-
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
3155+
let end = self.parse_expr_res(RestrictionNoBarOp);
31593156
pat = PatRange(start, end);
31603157
} else if is_plain_ident(&self.token) && !can_be_enum_or_struct {
31613158
let id = self.parse_ident();
@@ -3441,7 +3438,7 @@ impl<'a> Parser<'a> {
34413438
check_expected_item(self, found_attrs);
34423439

34433440
// Remainder are line-expr stmts.
3444-
let e = self.parse_expr_res(RESTRICT_STMT_EXPR);
3441+
let e = self.parse_expr_res(RestrictionStmtExpr);
34453442
P(spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID)))
34463443
}
34473444
}
@@ -3450,7 +3447,7 @@ impl<'a> Parser<'a> {
34503447

34513448
/// Is this expression a successfully-parsed statement?
34523449
fn expr_is_complete(&mut self, e: &Expr) -> bool {
3453-
self.restriction == RESTRICT_STMT_EXPR &&
3450+
self.restrictions.contains(RestrictionStmtExpr) &&
34543451
!classify::expr_requires_semi_to_be_stmt(e)
34553452
}
34563453

src/test/compile-fail/issue-17283.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that the parser does not attempt to parse struct literals
12+
// within assignments in if expressions.
13+
14+
struct Foo {
15+
foo: uint
16+
}
17+
18+
fn main() {
19+
let x = 1u;
20+
let y: Foo;
21+
22+
// `x { ... }` should not be interpreted as a struct literal here
23+
if x = x {
24+
//~^ ERROR mismatched types: expected `bool`, found `()` (expected bool, found ())
25+
println!("{}", x);
26+
}
27+
// Explicit parentheses on the left should match behavior of above
28+
if (x = x) {
29+
//~^ ERROR mismatched types: expected `bool`, found `()` (expected bool, found ())
30+
println!("{}", x);
31+
}
32+
// The struct literal interpretation is fine with explicit parentheses on the right
33+
if y = (Foo { foo: x }) {
34+
//~^ ERROR mismatched types: expected `bool`, found `()` (expected bool, found ())
35+
println!("{}", x);
36+
}
37+
}

0 commit comments

Comments
 (0)