Skip to content

Commit

Permalink
Auto merge of #55275 - petrochenkov:extself, r=eddyb
Browse files Browse the repository at this point in the history
experiment: Support aliasing local crate root in extern prelude

This PR provides some minimally invasive solution for the 2018 edition migration issue described in #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 #54658, thus resolving #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 #54647
  • Loading branch information
bors committed Dec 1, 2018
2 parents d3ed348 + 549bd45 commit d311571
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 10 deletions.
28 changes: 24 additions & 4 deletions src/librustc_resolve/build_reduced_graph.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 6 additions & 5 deletions src/librustc_typeck/check_unused.rs
Expand Up @@ -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();
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/feature_gate.rs
Expand Up @@ -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! (
Expand Down
6 changes: 5 additions & 1 deletion src/libsyntax/parse/parser.rs
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/test/ui/feature-gates/feature-gate-extern_crate_self.rs
@@ -0,0 +1,3 @@
extern crate self as foo; //~ ERROR `extern crate self` is unstable

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/feature-gates/feature-gate-extern_crate_self.stderr
@@ -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`.
8 changes: 8 additions & 0 deletions src/test/ui/imports/extern-crate-self-fail.rs
@@ -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() {}
14 changes: 14 additions & 0 deletions src/test/ui/imports/extern-crate-self-fail.stderr
@@ -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

15 changes: 15 additions & 0 deletions src/test/ui/imports/extern-crate-self-pass.rs
@@ -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() {}

0 comments on commit d311571

Please sign in to comment.