]> git.lizzy.rs Git - rust.git/commitdiff
Fix restrictions when parsing rhs of equalities
authorSimonas Kazlauskas <git@kazlauskas.me>
Fri, 16 Oct 2015 19:42:06 +0000 (22:42 +0300)
committerSimonas Kazlauskas <git@kazlauskas.me>
Tue, 27 Oct 2015 19:55:10 +0000 (21:55 +0200)
src/libsyntax/parse/parser.rs
src/libsyntax/util/parser.rs
src/test/run-pass/issue-29071-2.rs [new file with mode: 0644]

index 6845b92dac0b93bc8b9c6db4e720d5b35db63abd..22032476c9daf94ba5952cceffdcac50a7e6a1d8 100644 (file)
@@ -2666,13 +2666,18 @@ pub fn parse_assoc_expr_with(&mut self, min_prec: usize, lhs: Option<P<Expr>>) -
         } 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 @@ pub fn parse_assoc_expr_with(&mut self, min_prec: usize, lhs: Option<P<Expr>>) -
                     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 @@ pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> {
         self.parse_expr_res(Restrictions::empty())
     }
 
-    /// Parse an expression, subject to the given restrictions
-    pub fn parse_expr_res(&mut self, r: Restrictions) -> PResult<P<Expr>> {
+    /// Evaluate the closure with restrictions in place.
+    ///
+    /// After the closure is evaluated, restrictions are reset.
+    pub fn with_res<F>(&mut self, r: Restrictions, f: F) -> PResult<P<Expr>>
+    where F: FnOnce(&mut Self) -> PResult<P<Expr>> {
         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<P<Expr>> {
+        self.with_res(r, |this| this.parse_assoc_expr())
     }
 
     /// Parse the RHS of a local variable declaration (e.g. '= 14;')
index d09a23c12f184d24542c4b869d2b41341dff74ac..bf3a8def39011bc243c8e7f239e55b72ec80b33a 100644 (file)
@@ -172,6 +172,16 @@ pub fn is_comparison(&self) -> bool {
         }
     }
 
+    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<ast::BinOp_> {
         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 (file)
index 0000000..8e69c06
--- /dev/null
@@ -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 <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.
+
+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);
+}