Auto merge of #55275 - petrochenkov:extself, r=eddyb

experiment: Support aliasing local crate root in extern prelude

This PR provides some minimally invasive solution for the 2018 edition migration issue described in https://github.com/rust-lang/rust/issues/54647 and affecting proc macro crates.

`extern crate NAME as RENAME;` now accepts `NAME`=`self` and interprets it as referring to the local crate.
As with other `extern crate` items, `RENAME` in this case gets into extern prelude in accordance with https://github.com/rust-lang/rust/pull/54658, thus resolving https://github.com/rust-lang/rust/issues/54647.
```rust
extern crate self as serde; // Adds local crate to extern prelude as `serde`
```
This solution doesn't introduce any new syntax and has minimal maintenance cost, so it can be easily deprecated if something better is found in the future.

Closes https://github.com/rust-lang/rust/issues/54647
This commit is contained in:
bors 2018-12-01 12:45:52 +00:00
commit d311571906
9 changed files with 89 additions and 10 deletions

View File

@ -40,7 +40,7 @@ use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::base::Determinacy::Undetermined;
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::is_builtin_attr;
use syntax::feature_gate::{is_builtin_attr, emit_feature_err, GateIssue};
use syntax::parse::token::{self, Token};
use syntax::std_inject::injected_crate_name;
use syntax::symbol::keywords;
@ -344,9 +344,23 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
}
ItemKind::ExternCrate(orig_name) => {
let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions);
let module =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
let module = if orig_name.is_none() && ident.name == keywords::SelfValue.name() {
self.session
.struct_span_err(item.span, "`extern crate self;` requires renaming")
.span_suggestion(item.span, "try", "extern crate self as name;".into())
.emit();
return;
} else if orig_name == Some(keywords::SelfValue.name()) {
if !self.session.features_untracked().extern_crate_self {
emit_feature_err(&self.session.parse_sess, "extern_crate_self", item.span,
GateIssue::Language, "`extern crate self` is unstable");
}
self.graph_root
} else {
let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions);
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
};
self.populate_module_if_necessary(module);
if injected_crate_name().map_or(false, |name| ident.name == name) {
self.injected_crate = Some(module);
@ -768,6 +782,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> {
span_err!(self.session, item.span, E0468,
"an `extern crate` loading macros must be at the crate root");
}
if let ItemKind::ExternCrate(Some(orig_name)) = item.node {
if orig_name == keywords::SelfValue.name() {
self.session.span_err(attr.span,
"`macro_use` is not supported on `extern crate self`");
}
}
let ill_formed = |span| span_err!(self.session, span, E0466, "bad macro import");
match attr.meta() {
Some(meta) => match meta.node {

View File

@ -113,11 +113,12 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) {
true
})
.filter(|&&(def_id, _)| {
let cnum = tcx.extern_mod_stmt_cnum(def_id).unwrap();
!tcx.is_compiler_builtins(cnum)
&& !tcx.is_panic_runtime(cnum)
&& !tcx.has_global_allocator(cnum)
&& !tcx.has_panic_handler(cnum)
tcx.extern_mod_stmt_cnum(def_id).map_or(true, |cnum| {
!tcx.is_compiler_builtins(cnum) &&
!tcx.is_panic_runtime(cnum) &&
!tcx.has_global_allocator(cnum) &&
!tcx.has_panic_handler(cnum)
})
})
.cloned()
.collect();

View File

@ -492,6 +492,9 @@ declare_features! (
// `reason = ` in lint attributes and `expect` lint attribute
(active, lint_reasons, "1.31.0", Some(54503), None),
// `extern crate self as foo;` puts local crate root into extern prelude under name `foo`.
(active, extern_crate_self, "1.31.0", Some(54658), None),
);
declare_features! (

View File

@ -6783,7 +6783,11 @@ impl<'a> Parser<'a> {
let error_msg = "crate name using dashes are not valid in `extern crate` statements";
let suggestion_msg = "if the original crate name uses dashes you need to use underscores \
in the code";
let mut ident = self.parse_ident()?;
let mut ident = if self.token.is_keyword(keywords::SelfValue) {
self.parse_path_segment_ident()
} else {
self.parse_ident()
}?;
let mut idents = vec![];
let mut replacement = vec![];
let mut fixed_crate_name = false;

View File

@ -0,0 +1,3 @@
extern crate self as foo; //~ ERROR `extern crate self` is unstable
fn main() {}

View File

@ -0,0 +1,11 @@
error[E0658]: `extern crate self` is unstable (see issue #54658)
--> $DIR/feature-gate-extern_crate_self.rs:1:1
|
LL | extern crate self as foo; //~ ERROR `extern crate self` is unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(extern_crate_self)] to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,8 @@
#![feature(extern_crate_self)]
extern crate self; //~ ERROR `extern crate self;` requires renaming
#[macro_use] //~ ERROR `macro_use` is not supported on `extern crate self`
extern crate self as foo;
fn main() {}

View File

@ -0,0 +1,14 @@
error: `extern crate self;` requires renaming
--> $DIR/extern-crate-self-fail.rs:3:1
|
LL | extern crate self; //~ ERROR `extern crate self;` requires renaming
| ^^^^^^^^^^^^^^^^^^ help: try: `extern crate self as name;`
error: `macro_use` is not supported on `extern crate self`
--> $DIR/extern-crate-self-fail.rs:5:1
|
LL | #[macro_use] //~ ERROR `macro_use` is not supported on `extern crate self`
| ^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,15 @@
// compile-pass
#![feature(extern_crate_self)]
extern crate self as foo;
struct S;
mod m {
fn check() {
foo::S; // OK
}
}
fn main() {}