Skip to content

Cannot do use cratename at top-level; only in sub-mods. Error message unclear. #13968

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

Closed
pnkfelix opened this issue May 6, 2014 · 1 comment
Labels
A-resolve Area: Name/path resolution done by `rustc_resolve` specifically

Comments

@pnkfelix
Copy link
Member

pnkfelix commented May 6, 2014

Someone on IRC asked how to reference a pub static in an external crate, noting that cratename::value was not resolving (it turned out they were writing this reference in a sub-module, not the top-level library).

While making sample code to illustrate the ways to get such code to work, I found an oddity.

(Note: It is probably just something where our error messages need to be improved. Though there may be a reasonable argument that use cratename should just work anywhere, to ease cut-and-pasting code from sub-modules into the top-level lib.)

It is valid to say use cratename::value and it is valid to say use local_name = cratename;, but it is not valid to say use cratename; in the top-most level of the library/program. (It is valid to say use cratename in an inner module within the lib; just not the lib itself.)

From my tests, it appears that the reason for this is that an extern crate cratename declaration implicitly imports cratename into the relative-path roots for the top-level of the library.

Test code:

// n.rs
#![crate_type="lib"]
pub static C : int = 3;
// end of n.rs

// m.rs
extern crate n;

#[cfg(version1a)] use n::C;
#[cfg(version2a)] use local_n = n;
#[cfg(version3a)] use n;

#[cfg(version1a)] pub fn read() -> int { C }
#[cfg(version2a)] pub fn read() -> int { local_n::C }
#[cfg(version3a)] pub fn read() -> int { n::C }
#[cfg(version4a)] pub fn read() -> int { ::n::C }
#[cfg(version5a)] pub fn read() -> int { n::C }
#[cfg(version6a)] pub fn read() -> int { self::n::C }

#[cfg(version1b)]
#[cfg(version2b)]
#[cfg(version3b)]
#[cfg(version4b)]
#[cfg(version5b)]
pub fn read() -> int { sub_m::read() }

mod sub_m {
    #[cfg(version1b)] use n::C;
    #[cfg(version2b)] use local_n = n;
    #[cfg(version3b)] use n;

    #[cfg(version1b)] pub fn read() -> int { C }
    #[cfg(version2b)] pub fn read() -> int { local_n::C }
    #[cfg(version3b)] pub fn read() -> int { n::C }
    #[cfg(version4b)] pub fn read() -> int { ::n::C }
    #[cfg(version5b)] pub fn read() -> int { super::n::C }
}

pub fn main() {
    println!("n::C is {}", read());
}
// end of m.rs

Here's what currently happens:

% rustc -L/tmp /tmp/n.rs
% rustc --out-dir /tmp /tmp/n.rs
% for v in version{1a,2a,4a,5a,6a,1b,2b,3b,4b,5b,3a} ; do echo $v; rustc -L/tmp --cfg $v /tmp/m.rs && ./m ; done
version1a
n::C is 3
version2a
n::C is 3
version4a
n::C is 3
version5a
n::C is 3
version6a
n::C is 3
version1b
n::C is 3
version2b
n::C is 3
version3b
n::C is 3
version4b
n::C is 3
version5b
n::C is 3
version3a
/tmp/m.rs:6:23: 6:24 error: unresolved import (maybe you meant `n::*`?)
/tmp/m.rs:6 #[cfg(version3a)] use n;
                                  ^
error: aborting due to previous error
% 

This is a hint that the problem is probably that we end up with some sort of resolve collision when we do use n at the top-level. It is possible that the fix here would simply be a better error message explaining the problem.

@pnkfelix pnkfelix changed the title Cannot do use cratename, forcing various workarounds to import it as mod Cannot do use cratename at top-level; only in sub-mods. Error message unclear. May 6, 2014
@tamird
Copy link
Contributor

tamird commented Apr 22, 2015

With minor updates to get this code compiling:

// n.rs
#![crate_type="lib"]
pub static C : i8 = 3;
// m.rs
extern crate n;

#[cfg(version1a)] use n::C;
#[cfg(version2a)] use n as local_n;
#[cfg(version3a)] use n;

#[cfg(version1a)] pub fn read() -> i8 { C }
#[cfg(version2a)] pub fn read() -> i8 { local_n::C }
#[cfg(version3a)] pub fn read() -> i8 { n::C }
#[cfg(version4a)] pub fn read() -> i8 { ::n::C }
#[cfg(version5a)] pub fn read() -> i8 { n::C }
#[cfg(version6a)] pub fn read() -> i8 { self::n::C }

#[cfg(any(version1b,
          version2b,
          version3b,
          version4b,
          version5b,))]
pub fn read() -> i8 { sub_m::read() }

mod sub_m {
    #[cfg(version1b)] use n::C;
    #[cfg(version2b)] use n as local_n;
    #[cfg(version3b)] use n;

    #[cfg(version1b)] pub fn read() -> i8 { C }
    #[cfg(version2b)] pub fn read() -> i8 { local_n::C }
    #[cfg(version3b)] pub fn read() -> i8 { n::C }
    #[cfg(version4b)] pub fn read() -> i8 { ::n::C }
    #[cfg(version5b)] pub fn read() -> i8 { super::n::C }
}

pub fn main() {
    println!("n::C is {}", read());
}

The result is:

$ for v in version{1a,2a,4a,5a,6a,1b,2b,3b,4b,5b,3a} ; do echo $v; rustc -L. --cfg $v m.rs && ./m ; done
version1a
n::C is 3
version2a
n::C is 3
version4a
n::C is 3
version5a
n::C is 3
version6a
n::C is 3
version1b
n::C is 3
version2b
n::C is 3
version3b
n::C is 3
version4b
n::C is 3
version5b
n::C is 3
version3a
m.rs:5:23: 5:24 error: import `n` conflicts with imported crate in this module (maybe you meant `use n::*`?) [E0254]
m.rs:5 #[cfg(version3a)] use n;
                             ^
error: aborting due to previous error

Which seems like a pretty good error message. This might be good to close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-resolve Area: Name/path resolution done by `rustc_resolve` specifically
Projects
None yet
Development

No branches or pull requests

4 participants