Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only the first expression in an include!d file is included. #35560

Open
emilio opened this issue Aug 10, 2016 · 9 comments
Open

Only the first expression in an include!d file is included. #35560

emilio opened this issue Aug 10, 2016 · 9 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@emilio
Copy link
Contributor

emilio commented Aug 10, 2016

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)
@TimNN
Copy link
Contributor

TimNN commented Aug 10, 2016

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.rs in 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.

@jonas-schievink
Copy link
Contributor

But the contents of helper.rs aren'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)?

@emilio
Copy link
Contributor Author

emilio commented Aug 10, 2016

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!

@ExpHP
Copy link
Contributor

ExpHP commented Jan 17, 2017

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?

@Mark-Simulacrum Mark-Simulacrum added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) A-syntaxext Area: Syntax extensions labels May 19, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 25, 2017
@est31
Copy link
Member

est31 commented Jan 3, 2018

Still happens, just ran into this today. Braces can be used as a workaround.

{
print("foo");
print("bar");
print("foobar");
}

cc @jseyfried @nrc

@jseyfried jseyfried self-assigned this Jan 3, 2018
@jonas-schievink jonas-schievink added the A-diagnostics Area: Messages for errors, warnings, and lints label May 16, 2019
@pnkfelix pnkfelix changed the title Only the first macro expansion of an include!d file is expanded. Only the first expression in an include!d file is included. Sep 19, 2019
Centril added a commit to Centril/rust that referenced this issue Oct 8, 2019
…rochenkov

Warn if include macro fails to include entire file

This currently introduces an error, mainly because that was just simpler, and I'm not entirely certain if we can introduce a lint without an RFC and such.

This is primarily to get feedback on the approach and overall aim -- in particular, do we think this is helpful? If so, we probably will need lang-team sign off and decide if it should be an error (as currently introduced by this PR), a lint, or a warning.

r? @petrochenkov

cc rust-lang#35560
@crlf0710 crlf0710 added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jun 11, 2020
@jyn514
Copy link
Member

jyn514 commented Jul 14, 2021

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.)

@jyn514 jyn514 closed this as completed Jul 14, 2021
@est31
Copy link
Member

est31 commented Jul 14, 2021

@jyn514 seems that there is still a decision to be made whether to turn this into a hard error or so: #64284

@jyn514
Copy link
Member

jyn514 commented Jul 14, 2021

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.

@jyn514 jyn514 reopened this Jul 14, 2021
@est31
Copy link
Member

est31 commented Jul 14, 2021

@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 include macro 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);
}

@jyn514 jyn514 removed the A-syntaxext Area: Syntax extensions label Jul 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

9 participants