1 // Copyright 2015 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.
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.
11 // ignore-cross-compile
13 #![feature(rustc_private)]
20 use syntax::source_map::{FilePathMapping, FileName};
22 use syntax::parse::{ParseSess, PResult};
23 use syntax::parse::new_parser_from_source_str;
24 use syntax::parse::parser::Parser;
25 use syntax::parse::token;
27 use syntax::str::char_at;
28 use syntax::parse::attr::*;
29 use syntax::print::pprust;
32 // Copied out of syntax::util::parser_testing
34 pub fn string_to_parser<'a>(ps: &'a ParseSess, source_str: String) -> Parser<'a> {
35 new_parser_from_source_str(ps, FileName::Custom("bogofile".to_owned()), source_str)
38 fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> PResult<'a, T> where
39 F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
41 let mut p = string_to_parser(&ps, s);
44 if ps.span_diagnostic.has_errors() || p.token != token::Eof {
45 if let Err(mut e) = x {
48 return Err(p.fatal("parse error"));
54 fn expr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, P<ast::Expr>> {
55 with_error_checking_parse(s.to_string(), ps, |p| {
60 fn stmt<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, ast::Stmt> {
61 with_error_checking_parse(s.to_string(), ps, |p| {
62 p.parse_stmt().map(|s| s.unwrap())
66 fn attr<'a>(s: &str, ps: &'a ParseSess) -> PResult<'a, ast::Attribute> {
67 with_error_checking_parse(s.to_string(), ps, |p| {
68 p.parse_attribute(true)
72 fn str_compare<T, F: Fn(&T) -> String>(e: &str, expected: &[T], actual: &[T], f: F) {
73 let expected: Vec<_> = expected.iter().map(|e| f(e)).collect();
74 let actual: Vec<_> = actual.iter().map(|e| f(e)).collect();
76 if expected != actual {
77 panic!("parsed `{}` as {:?}, expected {:?}", e, actual, expected);
81 fn check_expr_attrs(es: &str, expected: &[&str]) {
82 let ps = ParseSess::new(FilePathMapping::empty());
83 let e = expr(es, &ps).expect("parse error");
84 let actual = &e.attrs;
86 &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(),
88 pprust::attribute_to_string);
91 fn check_stmt_attrs(es: &str, expected: &[&str]) {
92 let ps = ParseSess::new(FilePathMapping::empty());
93 let e = stmt(es, &ps).expect("parse error");
94 let actual = e.node.attrs();
96 &expected.iter().map(|r| attr(r, &ps).unwrap()).collect::<Vec<_>>(),
98 pprust::attribute_to_string);
101 fn reject_expr_parse(es: &str) {
102 let ps = ParseSess::new(FilePathMapping::empty());
103 match expr(es, &ps) {
104 Ok(_) => panic!("parser did not reject `{}`", es),
105 Err(mut e) => e.cancel(),
109 fn reject_stmt_parse(es: &str) {
110 let ps = ParseSess::new(FilePathMapping::empty());
111 match stmt(es, &ps) {
112 Ok(_) => panic!("parser did not reject `{}`", es),
113 Err(mut e) => e.cancel(),
118 syntax::with_globals(|| run());
122 let both = &["#[attr]", "#![attr]"];
123 let outer = &["#[attr]"];
126 check_expr_attrs("#[attr] box 0", outer);
127 reject_expr_parse("box #![attr] 0");
129 check_expr_attrs("#[attr] [#![attr]]", both);
130 check_expr_attrs("#[attr] [#![attr] 0]", both);
131 check_expr_attrs("#[attr] [#![attr] 0; 0]", both);
132 check_expr_attrs("#[attr] [#![attr] 0, 0, 0]", both);
133 reject_expr_parse("[#[attr]]");
135 check_expr_attrs("#[attr] foo()", outer);
136 check_expr_attrs("#[attr] x.foo()", outer);
137 reject_expr_parse("foo#[attr]()");
138 reject_expr_parse("foo(#![attr])");
139 reject_expr_parse("x.foo(#![attr])");
140 reject_expr_parse("x.#[attr]foo()");
141 reject_expr_parse("x.#![attr]foo()");
143 check_expr_attrs("#[attr] (#![attr])", both);
144 check_expr_attrs("#[attr] (#![attr] #[attr] 0,)", both);
145 check_expr_attrs("#[attr] (#![attr] #[attr] 0, 0)", both);
147 check_expr_attrs("#[attr] 0 + #[attr] 0", none);
148 check_expr_attrs("#[attr] 0 / #[attr] 0", none);
149 check_expr_attrs("#[attr] 0 & #[attr] 0", none);
150 check_expr_attrs("#[attr] 0 % #[attr] 0", none);
151 check_expr_attrs("#[attr] (0 + 0)", outer);
152 reject_expr_parse("0 + #![attr] 0");
154 check_expr_attrs("#[attr] !0", outer);
155 check_expr_attrs("#[attr] -0", outer);
156 reject_expr_parse("!#![attr] 0");
157 reject_expr_parse("-#![attr] 0");
159 check_expr_attrs("#[attr] false", outer);
160 check_expr_attrs("#[attr] 0", outer);
161 check_expr_attrs("#[attr] 'c'", outer);
163 check_expr_attrs("#[attr] x as Y", none);
164 check_expr_attrs("#[attr] (x as Y)", outer);
165 reject_expr_parse("x #![attr] as Y");
167 reject_expr_parse("#[attr] if false {}");
168 reject_expr_parse("if false #[attr] {}");
169 reject_expr_parse("if false {#![attr]}");
170 reject_expr_parse("if false {} #[attr] else {}");
171 reject_expr_parse("if false {} else #[attr] {}");
172 reject_expr_parse("if false {} else {#![attr]}");
173 reject_expr_parse("if false {} else #[attr] if true {}");
174 reject_expr_parse("if false {} else if true #[attr] {}");
175 reject_expr_parse("if false {} else if true {#![attr]}");
177 reject_expr_parse("#[attr] if let Some(false) = false {}");
178 reject_expr_parse("if let Some(false) = false #[attr] {}");
179 reject_expr_parse("if let Some(false) = false {#![attr]}");
180 reject_expr_parse("if let Some(false) = false {} #[attr] else {}");
181 reject_expr_parse("if let Some(false) = false {} else #[attr] {}");
182 reject_expr_parse("if let Some(false) = false {} else {#![attr]}");
183 reject_expr_parse("if let Some(false) = false {} else #[attr] if let Some(false) = true {}");
184 reject_expr_parse("if let Some(false) = false {} else if let Some(false) = true #[attr] {}");
185 reject_expr_parse("if let Some(false) = false {} else if let Some(false) = true {#![attr]}");
187 check_expr_attrs("#[attr] while true {#![attr]}", both);
189 check_expr_attrs("#[attr] while let Some(false) = true {#![attr]}", both);
191 check_expr_attrs("#[attr] for x in y {#![attr]}", both);
193 check_expr_attrs("#[attr] loop {#![attr]}", both);
195 check_expr_attrs("#[attr] match true {#![attr] #[attr] _ => false}", both);
197 check_expr_attrs("#[attr] || #[attr] foo", outer);
198 check_expr_attrs("#[attr] move || #[attr] foo", outer);
199 check_expr_attrs("#[attr] || #[attr] { #![attr] foo }", outer);
200 check_expr_attrs("#[attr] move || #[attr] { #![attr] foo }", outer);
201 check_expr_attrs("#[attr] || { #![attr] foo }", outer);
202 check_expr_attrs("#[attr] move || { #![attr] foo }", outer);
203 reject_expr_parse("|| #![attr] foo");
204 reject_expr_parse("move || #![attr] foo");
205 reject_expr_parse("|| #![attr] {foo}");
206 reject_expr_parse("move || #![attr] {foo}");
208 check_expr_attrs("#[attr] { #![attr] }", both);
209 check_expr_attrs("#[attr] { #![attr] let _ = (); }", both);
210 check_expr_attrs("#[attr] { #![attr] let _ = (); foo }", both);
212 check_expr_attrs("#[attr] x = y", none);
213 check_expr_attrs("#[attr] (x = y)", outer);
215 check_expr_attrs("#[attr] x += y", none);
216 check_expr_attrs("#[attr] (x += y)", outer);
218 check_expr_attrs("#[attr] foo.bar", outer);
219 check_expr_attrs("(#[attr] foo).bar", none);
221 check_expr_attrs("#[attr] foo.0", outer);
222 check_expr_attrs("(#[attr] foo).0", none);
224 check_expr_attrs("#[attr] foo[bar]", outer);
225 check_expr_attrs("(#[attr] foo)[bar]", none);
227 check_expr_attrs("#[attr] 0..#[attr] 0", none);
228 check_expr_attrs("#[attr] 0..", none);
229 reject_expr_parse("#[attr] ..#[attr] 0");
230 reject_expr_parse("#[attr] ..");
232 check_expr_attrs("#[attr] (0..0)", outer);
233 check_expr_attrs("#[attr] (0..)", outer);
234 check_expr_attrs("#[attr] (..0)", outer);
235 check_expr_attrs("#[attr] (..)", outer);
237 check_expr_attrs("#[attr] foo::bar::baz", outer);
239 check_expr_attrs("#[attr] &0", outer);
240 check_expr_attrs("#[attr] &mut 0", outer);
241 check_expr_attrs("#[attr] & #[attr] 0", outer);
242 check_expr_attrs("#[attr] &mut #[attr] 0", outer);
243 reject_expr_parse("#[attr] &#![attr] 0");
244 reject_expr_parse("#[attr] &mut #![attr] 0");
246 check_expr_attrs("#[attr] break", outer);
247 check_expr_attrs("#[attr] continue", outer);
248 check_expr_attrs("#[attr] return", outer);
250 check_expr_attrs("#[attr] foo!()", outer);
251 check_expr_attrs("#[attr] foo!(#![attr])", outer);
252 check_expr_attrs("#[attr] foo![]", outer);
253 check_expr_attrs("#[attr] foo![#![attr]]", outer);
254 check_expr_attrs("#[attr] foo!{}", outer);
255 check_expr_attrs("#[attr] foo!{#![attr]}", outer);
257 check_expr_attrs("#[attr] Foo { #![attr] bar: baz }", both);
258 check_expr_attrs("#[attr] Foo { #![attr] ..foo }", both);
259 check_expr_attrs("#[attr] Foo { #![attr] bar: baz, ..foo }", both);
261 check_expr_attrs("#[attr] (#![attr] 0)", both);
263 // Look at statements in their natural habitat...
272 check_stmt_attrs("#[attr] let _ = 0", outer);
273 check_stmt_attrs("#[attr] 0", outer);
274 check_stmt_attrs("#[attr] {#![attr]}", both);
275 check_stmt_attrs("#[attr] foo!()", outer);
276 check_stmt_attrs("#[attr] foo![]", outer);
277 check_stmt_attrs("#[attr] foo!{}", outer);
279 reject_stmt_parse("#[attr] #![attr] let _ = 0");
280 reject_stmt_parse("#[attr] #![attr] 0");
281 reject_stmt_parse("#[attr] #![attr] foo!()");
282 reject_stmt_parse("#[attr] #![attr] foo![]");
283 reject_stmt_parse("#[attr] #![attr] foo!{}");
285 // FIXME: Allow attributes in pattern constexprs?
286 // would require parens in patterns to allow disambiguation...
287 // —which is now available under the `pattern_parentheses` feature gate
288 // (tracking issue #51087)
290 reject_expr_parse("match 0 {
293 reject_expr_parse("match 0 {
294 0..=#[attr] -10 => ()
296 reject_expr_parse("match 0 {
297 0..=-#[attr] 10 => ()
299 reject_expr_parse("match 0 {
300 0..=#[attr] FOO => ()
303 // make sure we don't catch this bug again...