diff options
| author | Dan Aloni <alonid@gmail.com> | 2018-04-10 02:08:47 +0300 |
|---|---|---|
| committer | Dan Aloni <alonid@gmail.com> | 2018-05-13 19:17:02 +0300 |
| commit | 37ed2ab91038567bafe3fd2e545c7d1631ff2ab0 (patch) | |
| tree | 27b8125e37ecd34720f6cee3286e821c6a6df96d /src/test | |
| parent | 3e955a058108fcadf0a8222de5868b0c905534d5 (diff) | |
| download | rust-37ed2ab91038567bafe3fd2e545c7d1631ff2ab0.tar.gz rust-37ed2ab91038567bafe3fd2e545c7d1631ff2ab0.zip | |
Macros: Add a 'literal' fragment specifier
Implements RFC 1576.
See: https://github.com/rust-lang/rfcs/blob/master/text/1576-macros-literal-matcher.md
Changes are mostly in libsyntax, docs, and tests. Feature gate is
enabled for 1.27.0.
Many thanks to Vadim Petrochenkov for following through code reviews
and suggestions.
Example:
````rust
macro_rules! test_literal {
($l:literal) => {
println!("literal: {}", $l);
};
($e:expr) => {
println!("expr: {}", $e);
};
}
fn main() {
let a = 1;
test_literal!(a);
test_literal!(2);
test_literal!(-3);
}
```
Output:
```
expr: 1
literal: 2
literal: -3
```
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/run-pass/macro-literal.rs | 143 | ||||
| -rw-r--r-- | src/test/ui/feature-gate-macro-literal-matcher.rs | 19 | ||||
| -rw-r--r-- | src/test/ui/feature-gate-macro-literal-matcher.stderr | 11 | ||||
| -rw-r--r-- | src/test/ui/macro-invalid-fragment-spec.stderr | 2 |
4 files changed, 174 insertions, 1 deletions
diff --git a/src/test/run-pass/macro-literal.rs b/src/test/run-pass/macro-literal.rs new file mode 100644 index 00000000000..0bcda7bc144 --- /dev/null +++ b/src/test/run-pass/macro-literal.rs @@ -0,0 +1,143 @@ +// Copyright 2018 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. + +#![feature(macro_literal_matcher)] + +macro_rules! mtester { + ($l:literal) => { + &format!("macro caught literal: {}", $l) + }; + ($e:expr) => { + &format!("macro caught expr: {}", $e) + }; +} + +macro_rules! two_negative_literals { + ($l1:literal $l2:literal) => { + &format!("macro caught literals: {}, {}", $l1, $l2) + }; +} + +macro_rules! only_expr { + ($e:expr) => { + &format!("macro caught expr: {}", $e) + }; +} + +macro_rules! mtester_dbg { + ($l:literal) => { + &format!("macro caught literal: {:?}", $l) + }; + ($e:expr) => { + &format!("macro caught expr: {:?}", $e) + }; +} + +macro_rules! catch_range { + ($s:literal ... $e:literal) => { + &format!("macro caught literal: {} ... {}", $s, $e) + }; + (($s:expr) ... ($e:expr)) => { // Must use ')' before '...' + &format!("macro caught expr: {} ... {}", $s, $e) + }; +} + +macro_rules! pat_match { + ($s:literal ... $e:literal) => { + match 3 { + $s ... $e => "literal, in range", + _ => "literal, other", + } + }; + ($s:pat) => { + match 3 { + $s => "pat, single", + _ => "pat, other", + } + }; +} + +macro_rules! match_attr { + (#[$attr:meta] $e:literal) => { + "attr matched literal" + }; + (#[$attr:meta] $e:expr) => { + "attr matched expr" + }; +} + +macro_rules! match_produced_attr { + ($lit: literal) => { + // Struct with doc comment passed via $literal + #[doc = $lit] + struct LiteralProduced; + }; + ($expr: expr) => { + struct ExprProduced; + }; +} + +macro_rules! test_user { + ($s:literal, $e:literal) => { + { + let mut v = Vec::new(); + for i in $s .. $e { + v.push(i); + } + "literal" + } + }; + ($s:expr, $e: expr) => { + { + let mut v = Vec::new(); + for i in $s .. $e { + v.push(i); + } + "expr" + } + }; +} + +pub fn main() { + // Cases where 'literal' catches + assert_eq!(mtester!("str"), "macro caught literal: str"); + assert_eq!(mtester!(2), "macro caught literal: 2"); + assert_eq!(mtester!(2.2), "macro caught literal: 2.2"); + assert_eq!(mtester!(1u32), "macro caught literal: 1"); + assert_eq!(mtester!(0x32), "macro caught literal: 50"); + assert_eq!(mtester!('c'), "macro caught literal: c"); + assert_eq!(mtester!(-1.2), "macro caught literal: -1.2"); + assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3"); + assert_eq!(catch_range!(2 ... 3), "macro caught literal: 2 ... 3"); + assert_eq!(match_attr!(#[attr] 1), "attr matched literal"); + assert_eq!(test_user!(10, 20), "literal"); + assert_eq!(mtester!(false), "macro caught literal: false"); + assert_eq!(mtester!(true), "macro caught literal: true"); + match_produced_attr!("a"); + let _a = LiteralProduced; + assert_eq!(pat_match!(1 ... 3), "literal, in range"); + assert_eq!(pat_match!(4 ... 6), "literal, other"); + + // Cases where 'expr' catches + assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2"); + assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2"); + assert_eq!(mtester!((1 + 3)), "macro caught expr: 4"); + assert_eq!(mtester_dbg!(()), "macro caught expr: ()"); + assert_eq!(catch_range!((1 + 1) ... (2 + 2)), "macro caught expr: 2 ... 4"); + assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr"); + assert_eq!(test_user!(10, (20 + 2)), "expr"); + + match_produced_attr!((3 + 2)); + let _b = ExprProduced; + + // Cases where 'pat' matched + assert_eq!(pat_match!(3), "pat, single"); + assert_eq!(pat_match!(6), "pat, other"); +} diff --git a/src/test/ui/feature-gate-macro-literal-matcher.rs b/src/test/ui/feature-gate-macro-literal-matcher.rs new file mode 100644 index 00000000000..db5cca193ab --- /dev/null +++ b/src/test/ui/feature-gate-macro-literal-matcher.rs @@ -0,0 +1,19 @@ +// Copyright 2018 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. + +// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher +// feature gate is not used. + +macro_rules! m { ($lt:literal) => {} } +//~^ ERROR :literal fragment specifier is experimental and subject to change + +fn main() { + m!("some string literal"); +} diff --git a/src/test/ui/feature-gate-macro-literal-matcher.stderr b/src/test/ui/feature-gate-macro-literal-matcher.stderr new file mode 100644 index 00000000000..f714b916966 --- /dev/null +++ b/src/test/ui/feature-gate-macro-literal-matcher.stderr @@ -0,0 +1,11 @@ +error[E0658]: :literal fragment specifier is experimental and subject to change (see issue #35625) + --> $DIR/feature-gate-macro-literal-matcher.rs:14:19 + | +LL | macro_rules! m { ($lt:literal) => {} } + | ^^^^^^^^^^^ + | + = help: add #![feature(macro_literal_matcher)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macro-invalid-fragment-spec.stderr b/src/test/ui/macro-invalid-fragment-spec.stderr index bdb0e4a5c40..765621f51d4 100644 --- a/src/test/ui/macro-invalid-fragment-spec.stderr +++ b/src/test/ui/macro-invalid-fragment-spec.stderr @@ -4,7 +4,7 @@ error: invalid fragment specifier `foo` LL | ($x:foo) => () | ^^^^^^ | - = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis` + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis` error: aborting due to previous error |
