Change:
Hello I have this code: (unfortunately, I don't have a minimal code example yet). It fails with (for some reason this is the version I get if I run , it seems to be one day off) and newer, but passes with older versions of nighly as well as stable and beta. The error I get is: This is actually , so the „originates in a macro outside of the current crate“ part is wrong. Also, renaming the macro makes it compile again. This leads me to think something (the compiler) brought in a colliding macro with the same name. Is my theory about the colliding macro true? Can this killing of my poor innocent macro be prevented somehow? Should local macros have precedence? Or, at least, should I get a better error message, like complaining when I define the macro, not when I use it? This makes me think that if I had the bad luck of having a same-name macro with the same invocation syntax, it would silently expand the wrong one.
Not sure if it is relevant, but there is already a in the standard library.
Minimized, side effect of :
Or alternatively with a singularly unhelpful error message ( isn't even used here, just defined):
Same thing happens with a or macro. just to the list. Should macros with those names be illegal, or should we work around them?
should use . IIRC rust already has the qualified macro feature.
So I guess there are three "issues" here: a macro expands to another macro, that macro is resolved where the expansion happens, not the definition (although that is expected as far as I know) have macros in which depend on other macros from being available as defined in . This is bad in my opinion and should maybe be fixed (one idea would be to to make macros like available as as well, for use in . This would at least reduce the likelihood of them being redefined Real Edit: that doesn't work for compiler-provided macros like ). a call to inside of which causes the regression here. Edit: Tagging as since the definition of the macro is their responsibility although I guess / may be applicable as well.
Sadly, that doesn't work: , and are compiler-builtin macros that don't exist in any crate.
An empty implementation, however, does exist at the std/core root (presumably for documentation reasons). I don't know much about the compiler internals, but would it be possible to "fill in" that implementation, instead of creating a "new" builtin macro?
I see, so there was the macro in the library to start with and I should rename it. Still, I think the error message could be a bit more helpful.
Your macro definition shouldn't interfere with the standard library, but yes, that's what's currently happening. I realized that my proposed "filling in" solution also wouldn't work with . I'm not sure how to approach this.
Since is unstable I think telling the developers to use instead of is permitted. There should be a lint which warns about shadowing any of the built-in macros. (Alternatively, would it be possible to rewrite , , as procedural macros (instead of libsyntax built-in plugins) that respects (macro modularization)? developers would still need to to use them.)
Needs to be prioritized. There's probably something we can do better here.
cc -- this is due to an issue with macros 1.0 hygiene, maybe macros 2.0 can be made to prevent situations like this?
Yeah, macros 2.0 already prevents situations like this. Example:
One way to fix this issue would be to migrate the macros to macros 2.0. However, this would be a breaking change (e.g. people might be intentionally "overriding" dependencies of the macros). Also, IIRC I tried something like this a while ago and found some breakage due to overriding in practice. That being said, it might be worth assessing migrating with a warning cycle or some other partial mitigation. cc
Caveat: while macros 2.0 prevents this situation, it doesn't help when using macros 1.0 from . More specifically, a macros 2.0 can still "override" a dependency of an unhygienic macros 1.0. It might be possible to special-case certain situation so that macros 2.0 do not "override" unhygienic macros 1.0 dependencies. For example, we could say: Suppose a name is expanded from exclusively 1.0 macros. Consider the resolution of this name (which is unhygienic) without any of the macros 2.0 in scope. If the 2.0-less resolution matches how the name would resolve it it were fully hygienic (i.e. if it instead came from exclusively 2.0 macros), then use this resolution instead. However, this would add complexity and probably has other downsides (e.g. breaking invariants preserved by macro expansion).
Out of curiosity, could we define unstable macros in the compiler like and use those in the macro here? That'd fix the regression at least, right? Othrewise, is there perhaps another sort of small patch we could apply to avoid the regression here? Beta's going out in just over a month!
I see the nominated label, would be great to have a team talk about this. There needs to be a decision on whether this change is expected breakage or a bug? Or, to formulate the question more generally: is it forbidden for any macro of the standard library to change which macros it calls, or is such change allowed? Also similar question: is it allowed for a macro in the standard library to become a wrapper of another macro? If it becomes, it adds 1 to the depth and could cause to code (which uses the recursion depth up to the limit, but doesn't attempt to surpass the limit) to be rejected that was previously accepted. has no section on macros...
I think it should be OK to move away from unhygienic "dependency overrides" (e.g. with ) if it doesn't cause breakage in practice. I doubt this would be an issue in practice, but if it is we could always add a small offset to the global recursion limit when computing the recursion limit for macros (macro expansion is , so this is OK).
just to confirm, but the "workaround" here would be to add a macro to the compiler versus to the standard library, because if the standard library had a macro that expanded to that wouldn't work, right?
Right. We could instead define a declarative macros 2.0 in the standard library that expanded to , and that would work due to hygiene; however, I think it would be cleaner to just add to the compiler.
Why is adding to the compiler better?
is already in the compiler, so adding would be a single-line change. Also, declarative macros 2.0 is unstable enough that I'm not sure we want to use for stable APIs yet.
out of curiosity, would you be willing to help implement the workaround here?
depends on whether such a workaround would actually be helping people. would it help you? are there any results of a crater run on the beta available?
I already worked around the problem by renaming the macro (it is a private one to generate some code, so I don't care about its name). It was just the surprise the code broke. But if you ask if it would have helped me if it was there to begin with, then I think yes ‒ I didn't have a clue what was wrong and only reporting the issue helped shed some light.
Ah unfortunately we don't have a crater run yet to see the impact of this.
Discussed in compiler meeting. Awaiting some sort of crater run before assessing priority.
Libss concluded the same!
I've looked at the root regressions from a crater run between stable and beta (), and couldn't find any regression introduced by this issue. They would have shown up there because this PR made it into beta but is not in stable yet.
There's , which is an old version of Diesel.
oh, right. Missed it :) So dunno then... PR to ? Or should this be fixed in the compiler because it affected diesel?
I think this should be fixed in the standard library by making a macro 2.0.
above [mentioned]: In that sense, would you be opposed to a compiler-defined macro (that's unstable) that libstd calls? It does indeed seem like we should implement this!
I don't care what fix happens, only that it does.
out of curiosity, would you be willing to help implement this?
sure! IMO its not really needed, but you seem to insist...

Discussion:
// option. This file may not be copied, modified, or distributed // except according to those terms. <ins> #[macro_export] // This stability attribute is totally useless. #[stable(feature = "rust1", since = "1.0.0")] #[cfg(stage0)] macro_rules! __rust_unstable_column { () => { column!() } } </ins> /// Entry point of thread panic, for details, see std::macros #[macro_export] #[allow_internal_unstable]

); ($msg:expr) => ({ static _MSG_FILE_LINE_COL: (&'static str, &'static str, u32, u32) = <del> ($msg, file!(), line!(), column!()); </del> <ins> ($msg, file!(), line!(), __rust_unstable_column!()); </ins> $crate::panicking::panic(&_MSG_FILE_LINE_COL) }); ($fmt:expr, $($arg:tt)*) => ({

// insufficient, since the user may have // `#[forbid(dead_code)]` and which cannot be overridden. static _MSG_FILE_LINE_COL: (&'static str, u32, u32) = <del> (file!(), line!(), column!()); </del> <ins> (file!(), line!(), __rust_unstable_column!()); </ins> $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_MSG_FILE_LINE_COL) }); }

//! library. Each macro is available for use when linking against the standard //! library. <ins> #[macro_export] // This stability attribute is totally useless. #[stable(feature = "rust1", since = "1.0.0")] #[cfg(stage0)] macro_rules! __rust_unstable_column { () => { column!() } } </ins> /// The entry point for panic of Rust threads. /// /// This macro is used to inject panic into a Rust thread, causing the thread to

($msg:expr) => ({ $crate::rt::begin_panic($msg, { // static requires less code at runtime, more constant data <del> static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!()); </del> <ins> static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), __rust_unstable_column!()); </ins> &_FILE_LINE_COL }) });

// used inside a dead function. Just `#[allow(dead_code)]` is // insufficient, since the user may have // `#[forbid(dead_code)]` and which cannot be overridden. <del> static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!()); </del> <ins> static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), __rust_unstable_column!()); </ins> &_FILE_LINE_COL }) });

base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32)) } <ins> /* __rust_unstable_column!(): expands to the current column number */ pub fn expand_column_gated(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box<base::MacResult+'static> { if sp.allows_unstable() { expand_column(cx, sp, tts) } else { cx.span_fatal(sp, "the __rust_unstable_column macro is unstable"); } } </ins> /// file!(): expands to the current filename */ /// The filemap (`loc.file`) contains a bunch more information we could spit /// out if we wanted.

use syntax::ext::source_util::*; register! { line: expand_line, <ins> __rust_unstable_column: expand_column_gated, </ins> column: expand_column, file: expand_file, stringify: expand_stringify,

<ins> // Copyright 2017 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 main() { println!("{}", __rust_unstable_column!()); //~^ERROR the __rust_unstable_column macro is unstable } </ins>

<ins> // Copyright 2017 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. #![allow(unused)] macro_rules! column { ($i:ident) => { $i }; } fn foo() -> ! { panic!(); } fn main() {} </ins>