about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
authorDan Aloni <alonid@gmail.com>2018-04-10 02:08:47 +0300
committerDan Aloni <alonid@gmail.com>2018-05-13 19:17:02 +0300
commit37ed2ab91038567bafe3fd2e545c7d1631ff2ab0 (patch)
tree27b8125e37ecd34720f6cee3286e821c6a6df96d /src/test
parent3e955a058108fcadf0a8222de5868b0c905534d5 (diff)
downloadrust-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.rs143
-rw-r--r--src/test/ui/feature-gate-macro-literal-matcher.rs19
-rw-r--r--src/test/ui/feature-gate-macro-literal-matcher.stderr11
-rw-r--r--src/test/ui/macro-invalid-fragment-spec.stderr2
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