How to pass a whole crate to a procedural macro? - rust

I'm trying to pass my whole crate to a procedural macro.
I've tried putting this code on top of my lib.rs:
#![my_macro]
#![feature(proc_macro)]
extern crate my_macro;
use my_macro::{my_macro};
and failed: error: cannot find attribute macro 'my_macro' in this scope
I've tried also putting the macro invocation below the use clause:
#![feature(proc_macro)]
extern crate my_macro;
use mock_macro::{my_macro};
#![my_macro]
but failed as well: error: an inner attribute is not permitted in this context
Is it possible to do it? (I know syn has a function for parsing a whole crate)

This is possible as of Rust 1.25.0-nightly as long as you enable feature(extern_absolute_paths) and use an absolute path for your attribute macro.
#![::my_crate::my_macro]
#![feature(extern_absolute_paths, proc_macro)]
The issue of attribute macros invoked at the crate root is being tracked in rust-lang/rust#41430. We expect to remove the limitation that the attribute must be specified with an absolute path as the implementation of RFC 2126 proceeds further. You may run into other limitations too, in particular attempting to inject functions into the crate from a crate-level procedural macro currently crashes the compiler.

Related

Refer to an extern crate in macro expansion

I'm trying to write some macros that work in nostd environment as well as in std environment. In order to do so I have this kind of code in proc macro crate:
#[cfg(not(feature = "alloc"))]
{
quote!(err.message = Some(::std::borrow::Cow::from(#m));)
}
#[cfg(feature = "alloc")]
{
quote!(err.message = Some(::alloc::borrow::Cow::from(#m));)
}
This correctly produces the code that uses alloc when alloc feature is enabled, but the compiler complains
error[E0433]: failed to resolve: could not find `alloc` in the list of imported crates
Of course the reason is that the macro expansion is missing
extern crate alloc;
But adding that is a problem. Since it's a procedural derive macro, the extern crate will be added on each derive call. How can I refer to an extern crate in macro expansion? Using $crate does not seem to work inside quote!.
You can wrap the expansion in a block, then you can define alloc multiple times.
Another common practice for proc macros that need auxiliary types is to create a crate that provides them, and reexport the macro from it. E.g. create mycrate and mycrate-macros. Then you can get rid of the whole alloc feature if you only need alloc-accessible types, like:
#![no_std]
extern crate alloc;
#[doc(inline)]
pub use mycrate_macros::my_macro;
#[doc(hidden)]
pub use alloc:borrow::Cow;
Then in the macro refer to ::my_crate::Cow.

How to make an item visible in my binary crate targets but not any other crates?

I would like to generate multiple binaries using a lot of the same common code. If I write everything in src/main.rs I can simply mark items at pub(crate) and access the code without exporting it. However if I put the binary in src/bin/foo.rs then I can not find a way to access this without marking everything pub. I would not like to mark everything pub not only because I don't want others to depend on it but also because it renders visibility checking ineffective.
The only workaround I have found is to put the file inside of the src directory then put a simple shim in bin/foo-bar.rs that just calls my_crate::bin_foo_bar::main(). This isn't very tidy and requires a bunch of overhead.
Inside your package you may define a single lib crate and multiple binary crates. If you declare a type inside your library crate as pub(crate) it will obviously unvisible from your binary crates. So revise the definitions. A package is not a crate, it is a package of crates. And pub(crate) types are only visible inside the crate they belong to.

Is it possible to control which macros are imported from a module?

The documentation says that if a macro_use attribute is on an extern crate statement, then it can specify which macros are imported like this: #[macro_use(macro1, macro2)]. Is there any way to do this for mod statements?

"cargo check" gives dead code warning for function used only by test [duplicate]

I'm writing a program in Rust and I have some tests for it. I wrote a helper function for these tests, but whenever I build using cargo build it warns me that the function is never used:
warning: function is never used: ... #[warn(dead_code)] on by default
How I can mark this function as used so as not to get the warnings?
Specific question
How I can mark this function as used so as not to get the warnings?
The Rust compiler runs many lints to warn you about possible issues in your code and the dead_code lint is one of them. It can be very useful in pointing out mistakes when code is complete, but may also be a nuisance at earlier stages. Often, this can be solved by either deleting unused code, or by marking a public method. However, all lints can be turned off by allowing them, and your error message (#[warn(dead_code)] on by default) contains the name of the lint you could disable.
#[allow(dead_code)]
fn my_unused_function() {}
Alternative for testing
I wrote a helper function for these tests, but whenever I build using cargo build it warns me that the function is never used.
This happens to be a special case, which is that code that is only used for testing isn't needed in the real executable and should probably not be included.
In order to optionally disable compilation of test code, you can mark it accordingly using the cfg attribute with the test profile.
#[cfg(test)]
fn my_test_specific_function() {}
When marked in this way, the compiler knows to ignore the method during compilation. This is similar to commonly used ifdef usage in other languages like C or C++, where you are telling a preprocessor to ignore the enclosed code unless TESTING is defined.
#ifdef TESTING
...
#endif
For people getting this warning while making a rust library, you may get this if you don't have your modules set to pub in your lib.rs.
pub mod foo;
If something is only used in tests, it should be omitted altogether. This can be done with the #[cfg(test)] attribute.
dead_code is a lint, which means you can allow it on the thing that's causing it to trigger.
#[allow(dead_code)]
fn dummy() {}
fn main() {}
There is another situation where this can occur. If you have several helper functions in a module, e.g. in tests/utils/mod.rs and then several integration tests (tests/a.rs, tests/b.rs) each of which does
mod utils;
use utils::...;
then you will get dead code warnings if you do not use all of the code from all of the tests. For example if test a.rs only uses utils::foo and b.rs only uses utils::bar then you will get dead code warnings for both.
That is because each test is compiled as an independent crate. Here is the bug report for it. It looks difficult to solve so I wouldn't hold my breath.
You can disable specific lints for a whole project in Rust by going into your main.rs file and adding the following at the very top of the file:
#![allow(
dead_code,
unused_imports
)]
You max prefix the unused function name with an underscore:
fn _dummy() {}
fn main() {}
See: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#dead-code
For some reason I found that setting the main function to public:
pub fn main()
and then copying my main.rs file to lib.rs
cp src/main.rs src/lib.rs
then recompiling fixed this.
No need to use a macro for it, although the macro should work for non main functions.

Figure out code from what module is "use"d in a large rust project (servo)

I'm trying to read the code of servo. As an example, I'm looking at this code in layout_task.rs:
use url::Url;
..and I want to know which code this refers to (the answer is rust-url).
Per the Rust reference §6.1.2.2 Use declarations,
the paths contained in use items are relative to the crate root [...]
It is also possible to use self and super at the beginning of a use item to refer to the current and direct parent modules respectively.
All rules regarding accessing declared modules in use declarations apply to both module declarations and extern crate declarations.
The reference (§5 Crates and source files) does not explicitly say what a "crate root" is, but it does share that:
A crate contains a tree of nested module scopes. The top level of this tree is a module that is anonymous [...] The Rust compiler is always invoked with a single source file as input, and always produces a single output crate. The processing of that source file may result in other source files being loaded as modules.
So it seems that to find the crate root that the current file (layout_task.rs) belongs to, we need to figure out what source file rustc is invoked with when building the crate. With Cargo this is specified in Cargo.toml and defaults to src/lib.rs:
[lib]
path = "src/lib.rs"
In my case, here's Cargo.toml and the lib.rs has:
extern crate url;
pub mod layout_task;
So far so good. To find out what the extern crate refers to, we need to look at Cargo.toml again:
[dependencies.url]
version = "0.2"
The cargo docs claim that "Dependencies from crates.io are not declared with separate sections", but apparently they can be... So we look the package up on crates.io: https://crates.io/crates/url

Resources