diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index cc8fbc18b7377..4b7dab9770a81 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -463,6 +463,9 @@ resolve_unexpected_res_use_at_op_in_slice_pat_with_range_sugg = resolve_unnamed_crate_root_import = crate root imports need to be explicitly named: `use crate as name;` +resolve_unnamed_imports = + imports need to be explicitly named: `use {$ident} as name;` + resolve_unreachable_label = use of unreachable label `{$name}` .label = unreachable label `{$name}` diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index fa3c06059b3da..859aac62e4f15 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -594,8 +594,29 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } } } else { + if matches!(source.ident.name, kw::Crate | kw::Super) { + // Disallow `use foo::crate;` and `use crate::crate;` + if !module_path.is_empty() { + // FIXME: use other errors + self.r + .dcx() + .emit_err(errors::UnnamedImports { span: ident.span, ident }); + return; + } + + // Disallow `use crate;` and `use super;` + if rename.is_none() { + self.r + .dcx() + .emit_err(errors::UnnamedImports { span: ident.span, ident }); + return; + } + + // Allow `use super as name;` + type_ns_only = true; + } // Disallow `self` - if source.ident.name == kw::SelfLower { + else if source.ident.name == kw::SelfLower { let parent = module_path.last(); let span = match parent { @@ -706,6 +727,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } e.emit(); + } else if let &[self_span] = &self_spans[..] + && prefix.len() == 1 + && prefix[0].ident.name == kw::DollarCrate + { + // Disallow `use $crate::{self};` + self.r.dcx().emit_err(errors::CrateImported { span: self_span }); } for &(ref tree, id) in items { diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index f0ea97ba8a0c0..10aaf0cef7a3c 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -898,6 +898,14 @@ pub(crate) struct UnnamedCrateRootImport { pub(crate) span: Span, } +#[derive(Diagnostic)] +#[diag(resolve_unnamed_imports)] +pub(crate) struct UnnamedImports { + #[primary_span] + pub(crate) span: Span, + pub(crate) ident: Ident, +} + #[derive(Diagnostic)] #[diag(resolve_macro_expanded_extern_crate_cannot_shadow_extern_arguments)] pub(crate) struct MacroExpandedExternCrateCannotShadowExternArguments { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 35051675fd8dc..e0547c5ccee3b 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -861,6 +861,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // FIXME: Implement these with renaming requirements so that e.g. // `use super;` doesn't work, but `use super as name;` does. // Fall through here to get an error from `early_resolve_...`. + + if ident.name == kw::Super { + if let Some(parent) = parent_scope.module.parent { + return Ok(parent.self_binding.unwrap()); + } + } else { + return Ok(parent_scope.module.self_binding.unwrap()); + } } } diff --git a/tests/ui/dollar-crate/use-dollar-crate-self.rs b/tests/ui/dollar-crate/use-dollar-crate-self.rs new file mode 100644 index 0000000000000..fc9898ef151ac --- /dev/null +++ b/tests/ui/dollar-crate/use-dollar-crate-self.rs @@ -0,0 +1,9 @@ +macro_rules! foo { + () => { + use $crate::{self}; //~ ERROR `$crate` may not be imported + }; +} + +foo!(); + +fn main() {} diff --git a/tests/ui/dollar-crate/use-dollar-crate-self.stderr b/tests/ui/dollar-crate/use-dollar-crate-self.stderr new file mode 100644 index 0000000000000..262bb56dc50b7 --- /dev/null +++ b/tests/ui/dollar-crate/use-dollar-crate-self.stderr @@ -0,0 +1,13 @@ +error: `$crate` may not be imported + --> $DIR/use-dollar-crate-self.rs:3:22 + | +LL | use $crate::{self}; + | ^^^^ +... +LL | foo!(); + | ------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/use/use-path-segment-kw.rs b/tests/ui/use/use-path-segment-kw.rs new file mode 100644 index 0000000000000..1cca0f4bcf743 --- /dev/null +++ b/tests/ui/use/use-path-segment-kw.rs @@ -0,0 +1,35 @@ +// mod x { +// use super; // bad +// use super as name; // good +// use self; // bad +// use self as name; // good +// use crate; // bad +// use crate as name; // good + +// mod y; +// use y::crate; // bad +// use crate::crate; // bad + +// // use $crate; // bad +// // use $crate as name; // good + +// // use super::{self}; // bad +// // use super::{self as name}; // good +// // use crate::{self}; // bad +// // use crate::{self as name}; // good +// // use $crate::{self}; // bad +// // use $crate::{self as name}; // good +// } + +mod foo { + pub mod foobar { + pub use super as x; + } + pub fn bar() { + println!("hello"); + } +} + +fn main() { + foo::foobar::x::bar(); +}