Only the first expression in an include!d file is included.
If you have a file that invokes a macro and you include! it, the following happens:
main.rs
fn main() {
macro_rules! my_macro {
($name:expr) => {{
printn!("{}", $name);
}}
}
include!("helper.rs");
}
helper.rs
my_macro!("foo");
my_macro!("bar");
STR
$ rustc main.rs
$ ./main
foo
Expected output
Should print foo and bar, just as if the code would have been inlined.
Tested with latest nightly and stable:
rustc 1.12.0-nightly (080e0e072 2016-08-08)
rustc 1.10.0 (cfcb716cf 2016-07-03)
This is unrelated to the macros used in the included file, the following exhibits the same problem:
main.rs:fn print(s: &str) { println!("{}", s); } fn main() { include!("helper.rs"); }helper.rs:print("foo"); print("bar"); print("foobar");It looks like the issue is rather that
include!inside of a function expands to the first statement only.Wrapping the contents of
helper.rsin braces prints all three lines.Also note that the documentation of
include!says:Parse the current given file as an expression.
Thus the current behaviour is probably as documented.
Tim Neumann at 2016-08-10 15:31:34
But the contents of
helper.rsaren't a valid expression, it's only valid as a list of statements. Maybe it's parsed as an expression and the remainder is thrown away (like macros used to do)?Jonas Schievink at 2016-08-10 15:44:15
Oh I see. If file contents are thrown away though, I think at least a warning would come handy, but yeah, I see now, thanks!
Emilio Cobos Álvarez at 2016-08-10 16:09:39
Someone reported a similar experience on users, trying to use
[include!("path")]to populate an array.While it doesn't surprise me that the result is limited to a single expression or statement, it seems like there ought to be an error message?
Michael Lamparski at 2017-01-17 23:16:56
Still happens, just ran into this today. Braces can be used as a workaround.
{ print("foo"); print("bar"); print("foobar"); }cc @jseyfried @nrc
est31 at 2018-01-03 13:43:11
While it doesn't surprise me that the result is limited to a single expression or statement, it seems like there ought to be an error message?
The compiler now gives an error if there are multiple expressions in the included file:
error: include macro expected single expression in source --> helper.rs:1:16 | 1 | println!("foo"); | ^ | = note: `#[deny(incomplete_include)]` on by default(presumably it's a deny-by-default lint and not a hard error for backwards-compatibility reasons.)
jyn at 2021-07-14 03:52:16
@jyn514 seems that there is still a decision to be made whether to turn this into a hard error or so: #64284
est31 at 2021-07-14 03:57:32
I mean, I personally don't think we should be making things hard errors unless there's a specific reason to, the only benefit is that it slightly simplifies the compiler. I guess it doesn't hurt to have an issue open; but I would rather bring this up in a T-lang meeting and have a decision one way or another than leave this open indefinitely.
jyn at 2021-07-14 04:07:54
@jyn514 yeah if the decision by the lang team is to keep it a deny by default lint indefinitely, it's okay too. As you've rightly pointed out, errors should be introduced cautiously to previously compiling code. There should be a decision on it, though, because there are possible other resolutions.
For example, this works right now and prints
hello 1, hello 2:fn main() { macro_rules! my_macro { () => { println!("hello 1"); println!("hello 2"); } } my_macro!(); }So why can't the
includemacro follow this behaviour? Doing so would be a breaking change at this point, but maybe the new behaviour could be introduced at an edition boundary. Note that this doesn't work though:fn main() { macro_rules! my_macro { () => { 1,2,3 //~ERROR macro expansion ignores token `,` and any following } } let v = [my_macro!()]; println!("{:?}", v); }est31 at 2021-07-14 04:28:02