diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6845b92dac0b9..22032476c9daf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2666,13 +2666,18 @@ impl<'a> Parser<'a> { } else { try!(self.parse_prefix_expr()) }; - if self.expr_is_complete(&*lhs) && min_prec == 0 { + if self.expr_is_complete(&*lhs) { // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 return Ok(lhs); } let cur_op_span = self.span; self.expected_tokens.push(TokenType::Operator); while let Some(op) = AssocOp::from_token(&self.token) { + let restrictions = if op.is_assign_like() { + self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL + } else { + self.restrictions + }; if op.precedence() < min_prec { break; } @@ -2706,12 +2711,19 @@ impl<'a> Parser<'a> { break } + let rhs = try!(match op.fixity() { - Fixity::Right => self.parse_assoc_expr_with(op.precedence(), None), - Fixity::Left => self.parse_assoc_expr_with(op.precedence() + 1, None), + Fixity::Right => self.with_res(restrictions, |this|{ + this.parse_assoc_expr_with(op.precedence(), None) + }), + Fixity::Left => self.with_res(restrictions, |this|{ + this.parse_assoc_expr_with(op.precedence() + 1, None) + }), // We currently have no non-associative operators that are not handled above by // the special cases. The code is here only for future convenience. - Fixity::None => self.parse_assoc_expr_with(op.precedence() + 1, None), + Fixity::None => self.with_res(restrictions, |this|{ + this.parse_assoc_expr_with(op.precedence() + 1, None) + }), }); lhs = match op { @@ -2974,13 +2986,22 @@ impl<'a> Parser<'a> { self.parse_expr_res(Restrictions::empty()) } - /// Parse an expression, subject to the given restrictions - pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult> { + /// Evaluate the closure with restrictions in place. + /// + /// After the closure is evaluated, restrictions are reset. + pub fn with_res(&mut self, r: Restrictions, f: F) -> PResult> + where F: FnOnce(&mut Self) -> PResult> { let old = self.restrictions; self.restrictions = r; - let e = try!(self.parse_assoc_expr()); + let r = f(self); self.restrictions = old; - return Ok(e); + return r; + + } + + /// Parse an expression, subject to the given restrictions + pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult> { + self.with_res(r, |this| this.parse_assoc_expr()) } /// Parse the RHS of a local variable declaration (e.g. '= 14;') diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index d09a23c12f184..bf3a8def39011 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -172,6 +172,16 @@ impl AssocOp { } } + pub fn is_assign_like(&self) -> bool { + use self::AssocOp::*; + match *self { + Assign | AssignOp(_) | Inplace => true, + Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply | Divide | + Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | + LOr | DotDot => false + } + } + pub fn to_ast_binop(&self) -> Option { use self::AssocOp::*; match *self { diff --git a/src/test/run-pass/issue-29071-2.rs b/src/test/run-pass/issue-29071-2.rs new file mode 100644 index 0000000000000..8e69c063f99a0 --- /dev/null +++ b/src/test/run-pass/issue-29071-2.rs @@ -0,0 +1,40 @@ +// Copyright 2015 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. + +fn t1() -> u32 { + let x; + x = if true { [1, 2, 3] } else { [2, 3, 4] }[0]; + x +} + +fn t2() -> [u32; 1] { + if true { [1, 2, 3]; } else { [2, 3, 4]; } + [0] +} + +fn t3() -> u32 { + let x; + x = if true { i1 as F } else { i2 as F }(); + x +} + +fn t4() -> () { + if true { i1 as F; } else { i2 as F; } + () +} + +type F = fn() -> u32; +fn i1() -> u32 { 1 } +fn i2() -> u32 { 2 } + +fn main() { + assert_eq!(t1(), 1); + assert_eq!(t3(), 1); +}