diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 2966e9ec9d9f1..0fa41cb484fc9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -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 { diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 103331894ff1e..9c1860fb82ee4 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -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(); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2402de5a816b7..d0c4d1c7dce0a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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! ( diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f13bb7df0b444..33715f206dedf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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; diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_self.rs b/src/test/ui/feature-gates/feature-gate-extern_crate_self.rs new file mode 100644 index 0000000000000..2161932c2f6aa --- /dev/null +++ b/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() {} diff --git a/src/test/ui/feature-gates/feature-gate-extern_crate_self.stderr b/src/test/ui/feature-gates/feature-gate-extern_crate_self.stderr new file mode 100644 index 0000000000000..61cc68477830d --- /dev/null +++ b/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`. diff --git a/src/test/ui/imports/extern-crate-self-fail.rs b/src/test/ui/imports/extern-crate-self-fail.rs new file mode 100644 index 0000000000000..eab7b7032aa07 --- /dev/null +++ b/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() {} diff --git a/src/test/ui/imports/extern-crate-self-fail.stderr b/src/test/ui/imports/extern-crate-self-fail.stderr new file mode 100644 index 0000000000000..0ca0d89eaf08e --- /dev/null +++ b/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 + diff --git a/src/test/ui/imports/extern-crate-self-pass.rs b/src/test/ui/imports/extern-crate-self-pass.rs new file mode 100644 index 0000000000000..bf255bb6b8194 --- /dev/null +++ b/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() {}