Skip to content

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

Closed
@pnkfelix

Description

@pnkfelix

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-resolveArea: Name/path resolution done by `rustc_resolve` specifically

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions