Change:
Tracking issue for rust-lang/rfcs.
Is anyone working on implementation already? If not I can take a crack at it.
I'll probably do it.
Huh oh, we have an issue already: do we mean to include potentially minus-prefixed literals? If yes, we have a problem because 1. it means we have to return an Expr instead of a Lit, which means I'm not sure one will be able to use the bound fragment in a non-expr context (for example in a static array type?) and 2. it's no longer always a single-TT, so the benefits in terms of future-proofing are a bit less good. If we don't... well, we loose expressivity. I have no idea what is more intuitive though... Would you, as a Rust user, expect to parse ? I certainly can think of use cases for this...
good point. I think I would have expected it, I also agree with the complications.
Can't we upgrade Lit to support negative literals?
I'd expect "literal" (or a future integer-literal specifier) to include (negative 5), but not (the negation of positive 5). Perhaps that expectation doesn't match reality, though. For instance, based on parsing rules for non-literals, I'd expect to act like . So, if handling both and as literals makes this easier, that works. But "literal" definitely needs to include negative numbers, or we'd have a weird user trap to explain.
I'd expect "literal" (or a future integer-literal specifier) to include -5 (negative 5), but not - 5 (the negation of positive 5). Unary operators, including minus, are processed purely by the parser at the moment, no lexer involved. So their treatment is whitespace agnostic. (I personally think this is a good thing.)
I agree with is not syntactically different from and has no reason to be. But I also agree with the fact that the user will probably expect negative numbers to work as literals (even it – syntactically – they're not).
is also supported in literal patterns while arbitrary expressions are not. It'd be reasonable to support it in fragments as well.
Another thing that won't match is a macro call, like , or any of the other macros that I think of as expanding to a literal (, ...). I dunno, maybe this is not such a good idea after all. Re-reading the RFC in a more skeptical light, I felt like the "Motivation" section could use some more concrete use cases. Maybe this is just failure of imagination on my part, though! I think the likelihood of this feature attracting people who really want constant expressions should be acknowledged as a drawback, too.
That's fine IMO. Personally I'd like it to match only explicit literals in code to distinguish, for example, between literal and identifier and produce different code for them. Right now this is not possible because all of , , are too broad and conflict with each other.
Hi All, I have implemented this feature in my fork of Rust over 1.25.0, under this branch: Following a quick review by a rustc mentor I may have the free time to provide a full pull request for this.
BTW label has the tooltip "implemented in nightly and unstable" but I did not see it there, i.e. commits & pull requests referencing this. Did I miss it?
The implementation that I worked on was merged, yay!
Is there anything stopping an FCP for this?
It's currently merged in unstable; do you mean an FCP to declare it stable?
Yes, an FCP to stabilise. Should have clarified.
Currently, it is not possible to pass a literal from a macro to another macro. . I think this is a bug.
Interesting! That is a bug. I opened to track it.
Agreed, this should be allowed just like passing any other node types.
Is there anything else preventing this from being stabilized? The issue above has been fixed.
This has baked for some time now and I believe it should be ready for stabilization. So let's start the review. merge The feature gate test is here: Unstable book: Tests defined here:
Team member has proposed to merge this. The next step is review by the rest of the tagged teams: [x] [x] [x] [x] [x] [ ] [x] [x] [x] [ ] No concerns currently listed. Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
Reading through the tests, I see that is a literal. While that makes sense to me, I remember hearing that it wasn't, but was instead a negation operator and a literal. Am I misremembering?
cc on
I agree that it makes sense. I would say that even if is interpreted as negation + a literal, I would probably still want the macro matcher to accept since that behavior seems more intuitive. In other words, I would see being more as an implementation detail than what a literal is in the mental model.
I think that the nuance with causes a bit of a problem, because I don't think it should be treated as a literal, but I also don't think that the current implementation of would allow detecting it either. You could naïvely allow but that would allow which is clearly wrong.
there are tests currently implemented that verify that is detected as a literal.
I worded that wrong; I meant that only having a matcher and not being able to distinguish strings and numbers means that you can't easily make not a literal.
for procedural macros the input as lexed by the compiler is (two tokens) but procedural macros can create tokens that are negatives (like ). In that sense matching for makes sense to me.
Are literals generated by the compiler counted as true literals? A quick example would be something like: This fails to match, as the expansion, I guess, happens after the selection. I just naively assumed that would have worked.
is not a literal generated by the compiler, it is an identifier followed by an exclamation mark followed by a set of parentheses containing some tokens. See for example: If you were to use it in expression position, it would be interpreted as an invocation of which expands to a string literal. In this case and in your macro though, it is never in a syntactic position where it would be treated as an expression.
I can understand semantically why it doesn't make sense, I just thought it would have, but that being said, I already changed it to , so there's no issue. It just made more sense to me as a literal, because according to the compiler, it could generate a literal from it. I guess it was more a question than an actual issue.
This is true, but there's more to it! A few built-in macros can expand their arguments eagerly through ~m a g i c~, so they accept and likes even if they expect string literals: Fortunately (or not), this currently cannot be done in user-defined macros.
I actually just realised that I can't change it to , as it's used in . So, I've just had to manually unroll the macro. ! It doesn't look pretty. :( Ninja edit: I just tested what actually happens if you try to pass in a non-literal with . It rejects it the exact same way. Does the already make use of this feature? If not, the seems to propagate the required token. Oh, unless the compiler steps in... That's actually probably the case... I've reverted it back to the type.
:bell: This is now entering its final comment period, as per the . :bell:
The final comment period, with a disposition to merge, as per the , is now complete.
Since you implemented this, would you be willing to write up the stabilization PR?
sure
This appears to be missing from the Rust reference

Discussion:
<del> # `macro_literal_matcher` The tracking issue for this feature is: [#35625] The RFC is: [rfc#1576]. With this feature gate enabled, the [list of designators] gains one more entry: * `literal`: a literal. Examples: 2, "string", 'c' A `literal` may be followed by anything, similarly to the `ident` specifier. [rfc#1576]: http://rust-lang.github.io/rfcs/1576-macros-literal-matcher.html [#35625]: https://github.com/rust-lang/rust/issues/35625 [list of designators]: ../reference/macros-by-example.html ------------------------ </del>

use ext::tt::macro_parser::{parse, parse_failure_msg}; use ext::tt::quoted; use ext::tt::transcribe::transcribe; <del> use feature_gate::{self, emit_feature_err, Features, GateIssue}; </del> <ins> use feature_gate::Features; </ins> use parse::{Directory, ParseSess}; use parse::parser::Parser; use parse::token::{self, NtTT};

Ok(()) } <del> fn is_legal_fragment_specifier(sess: &ParseSess, features: &Features, attrs: &[ast::Attribute], </del> <ins> fn is_legal_fragment_specifier(_sess: &ParseSess, _features: &Features, _attrs: &[ast::Attribute], </ins> frag_name: &str, <del> frag_span: Span) -> bool { </del> <ins> _frag_span: Span) -> bool { /* * If new fragment specifiers are invented in nightly, `_sess`, * `_features`, `_attrs`, and `_frag_span` will be useful here * for checking against feature gates. See past versions of * this function. */ </ins> match frag_name { "item" | "block" | "stmt" | "expr" | "pat" | "lifetime" | <del> "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "" => true, "literal" => { if !features.macro_literal_matcher && !attr::contains_name(attrs, "allow_internal_unstable") { let explain = feature_gate::EXPLAIN_LITERAL_MATCHER; emit_feature_err(sess, "macro_literal_matcher", frag_span, GateIssue::Language, explain); } true }, </del> <ins> "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "literal" | "" => true, </ins> _ => false, } }

// Allows irrefutable patterns in if-let and while-let statements (RFC 2086) (active, irrefutable_let_patterns, "1.27.0", Some(44495), None), <del> // Allows use of the :literal macro fragment specifier (RFC 1576) (active, macro_literal_matcher, "1.27.0", Some(35625), None), </del> // inconsistent bounds in where clauses (active, trivial_bounds, "1.28.0", Some(48214), None),

(accepted, impl_header_lifetime_elision, "1.31.0", Some(15872), None), // `extern crate foo as bar;` puts `bar` into extern prelude. (accepted, extern_crate_item_prelude, "1.31.0", Some(55599), None), <ins> // Allows use of the :literal macro fragment specifier (RFC 1576) (accepted, macro_literal_matcher, "1.31.0", Some(35625), None), </ins> ); // If you change this, please modify src/doc/unstable-book as well. You must

pub const EXPLAIN_DERIVE_UNDERSCORE: &'static str = "attributes of the form `#[derive_*]` are reserved for the compiler"; <del> pub const EXPLAIN_LITERAL_MATCHER: &'static str = ":literal fragment specifier is experimental and subject to change"; </del> pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = "unsized tuple coercion is not stable enough for use and is subject to change";

// except according to those terms. // run-pass <del> #![feature(macro_literal_matcher)] </del> macro_rules! a { ($i:literal) => { "right" };

// except according to those terms. // run-pass <del> #![feature(macro_literal_matcher)] </del> macro_rules! mtester { ($l:literal) => {

<del> // 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"); } </del>

<del> 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`. </del>