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

possible regression around paths and macro-generated modules #38190

Closed
durka opened this issue Dec 6, 2016 · 15 comments
Closed

possible regression around paths and macro-generated modules #38190

durka opened this issue Dec 6, 2016 · 15 comments
Assignees
Labels
regression-from-stable-to-beta Performance or correctness regression from stable to beta.

Comments

@durka
Copy link
Contributor

durka commented Dec 6, 2016

I have some code that builds on stable and does not build on beta. I am not sure whether it is exploiting a compiler bug or not, but the changes seem related to #37602 (cc @jseyfried).

Here is the code: https://github.com/durka/mod-dir-regr

Note that if you pretty=expanded the code on stable, then use the beta compiler to compile it, it does work. So there is something going on with the macro.

@durka
Copy link
Contributor Author

durka commented Dec 6, 2016

Oh yeah, and the error:

seas:mod-dir-regr alex$ cargo +beta build
   Compiling mod-dir-regr v0.1.0 (file:///Users/alex/mod-dir-regr)
error: file not found for module `wrapper`
 --> src/lib.rs:8:9
  |
8 |     mod wrapper;
  |         ^^^^^^^
  |
  = help: name the file either wrapper.rs or wrapper/mod.rs inside the directory ""

error: Could not compile `mod-dir-regr`.

To learn more, run the command again with --verbose.

@jseyfried jseyfried self-assigned this Dec 6, 2016
@jseyfried
Copy link
Contributor

This was unintentionally introduced in #37569.

Investigating further, it appears that non-inline modules parsed into item fragments were already buggy before #37569. For example, wrapping mod-dir-regr's group_attr! { ... } invocation in an inline module mod foo { group_attr! { ... } } didn't change wrapper's path, but wrapping the invocation in a non-inline module mod foo; at foo/mod.rs did.

I think the best way forward is to fix this regression and the pre-existing bug at once and backport to beta (I'll submit a PR by tomorrow). Fixing the pre-existing bug technically a breaking change, but I believe it won't break anything not already broken by #37569, and I haven't seen any breakage from #37602 in the weekly regression reports.

@durka
Copy link
Contributor Author

durka commented Dec 6, 2016

Well this did break my code, I was using a non-stripped-down version of group_attr! in production. But if you tell me I was relying on a bug before, I'd believe you.

@durka
Copy link
Contributor Author

durka commented Dec 6, 2016

Another weird part of the regression has to do with #[path]. The path given to the attribute is supposed to be relative to the current file. But once you are inside this strange path-less module created by group_attr!, it becomes relative to the directory where rustc is invoked. Try replacing mod wrapper; with #[path="wrapper/mod.rs"] mod wrapper;, and cargo build from the crate root doesn't work. But go into the src directory, then it does work. Crazy.

@jseyfried
Copy link
Contributor

jseyfried commented Dec 6, 2016

@durka
Does your code have a relevant group_attr! invocation in an inline module? That's the only way the pre-existing bug could apply.

But once you are inside this strange path-less module created by group_attr!, it becomes relative to the directory where rustc is invoked

Right, that's the regression that #37569 introduced. We've never set the directory of the fragment parser, so the parser constructor picks a default directory, the directory of the file containing the span of the first token, or an empty path if there is no such file (e.g. the span is DUMMY_SP).

When I lifted parser construction out of a loop, the initial token changed so that its span became DUMMY_SP, causing the directory path to be empty -- semantically, is the current directory.

Even when the first token's span has a file, its directory isn't always the correct choice since it doesn't take into account inline modules in the file (this is the preexisting bug).

@durka
Copy link
Contributor Author

durka commented Dec 6, 2016

My invocations of group_attr! are all at crate roots.

@durka
Copy link
Contributor Author

durka commented Dec 6, 2016

What I'm not clear about is if mod __internal { mod wrapper; } should ever have worked at all (loading "./wrapper/mod.rs") or whether it should really be looking for "./__internal/wrapper/mod.rs".

@jseyfried
Copy link
Contributor

We load the module's file when we parse mod wrapper; as an item fragment, so we don't know about mod __internal yet.

@jseyfried
Copy link
Contributor

Ideally, we would load the file for a non-inline module more lazily, so that we knew exactly where will end up in the module hierarchy before we look for the file. We might be able to implement this today with negligible breakage.

@jseyfried
Copy link
Contributor

jseyfried commented Dec 6, 2016

Well ideally the directory would be hygienic, so that

mod foo {
    pub macro m($i:item, $id:ident) {
        mod bar {
            mod baz; // `foo/bar/baz.rs` or `foo/bar/baz/mod.rs`
            $i; // `baz/quux.rs` or `baz/quux/mod.rs`
            mod $id; // `baz/bar/quux.rs` or `baz/bar/quux/mod.rs` (?)
        }
    }
}

mod baz {
    ::foo::m!(mod quux;, quux);
}

@jseyfried
Copy link
Contributor

cc @nrc

@durka
Copy link
Contributor Author

durka commented Dec 6, 2016

Oh man, so the interpretation of a mod statement in a macro input depends on the macro pattern, e.g.

macro_rules! m { ($i:item) => { mod x { $i } } }

m! { mod y; } // error: no file y.rs or y/mod.rs
macro_rules! as_item { ($i:item) => { $i } }
macro_rules! m { ($($t:tt)*) => { as_item!(mod x { $($t)* }); } }

m! { mod y; } // error: no file x/y.rs or x/y/mod.rs

Fun! I guess this likely can't be changed due to backcompat.

@jseyfried
Copy link
Contributor

I think changing to #38190 (comment) wouldn't cause breakage in practice. If it does, we'll have to wait for macros 2.0.

@jseyfried
Copy link
Contributor

Fixed in #38205.

@jseyfried jseyfried added the regression-from-stable-to-beta Performance or correctness regression from stable to beta. label Dec 16, 2016
@durka
Copy link
Contributor Author

durka commented Dec 16, 2016

#38205 fixes my project.

bors added a commit that referenced this issue Dec 17, 2016
…ddyb

macros: fix the expected paths for a non-inline module matched by an `item` fragment

Fixes #38190.
r? @nrc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
regression-from-stable-to-beta Performance or correctness regression from stable to beta.
Projects
None yet
Development

No branches or pull requests

2 participants