Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_resolve/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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}`
Expand Down
77 changes: 51 additions & 26 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,35 +596,47 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
}
} else {
// Disallow `self`
if source.ident.name == kw::SelfLower {
let parent = module_path.last();
match source.ident.name {
kw::Crate => {
if !module_path.is_empty() {
self.r.dcx().span_err(
ident.span,
"`crate` in paths can only be used in start position",
);
return;
}
}
kw::Super => {
type_ns_only = true;
}
kw::SelfLower => {
if let Some(parent) = module_path.pop() {
let span_with_rename = match rename {
Some(rename) => source.ident.span.to(rename.span),
None => source.ident.span,
};

if parent.ident.name != kw::PathRoot {
self.r.report_error(
parent.ident.span.shrink_to_hi().to(source.ident.span),
ResolutionError::SelfImportsOnlyAllowedWithin {
root: false,
span_with_rename,
},
);
}

let span = match parent {
// only `::self` from `use foo::self as bar`
Some(seg) => seg.ident.span.shrink_to_hi().to(source.ident.span),
None => source.ident.span,
};
let span_with_rename = match rename {
// only `self as bar` from `use foo::self as bar`
Some(rename) => source.ident.span.to(rename.span),
None => source.ident.span,
};
self.r.report_error(
span,
ResolutionError::SelfImportsOnlyAllowedWithin {
root: parent.is_none(),
span_with_rename,
},
);

// Error recovery: replace `use foo::self;` with `use foo;`
if let Some(parent) = module_path.pop() {
source = parent;
if rename.is_none() {
ident = source.ident;
let self_span = source.ident.span;
source = parent;
if rename.is_none() {
ident = Ident::new(source.ident.name, self_span);
}
}

type_ns_only = true;
}
kw::DollarCrate => {}
_ => {}
}

// Disallow `use $crate;`
Expand Down Expand Up @@ -655,6 +667,13 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {

if ident.name == kw::Crate {
self.r.dcx().emit_err(errors::UnnamedCrateRootImport { span: ident.span });
return;
} else if source.ident.name == kw::PathRoot {
self.r.dcx().span_err(ident.span, "{{root}} cannot be imported");
return;
} else if ident.is_path_segment_keyword() {
self.r.dcx().emit_err(errors::UnnamedImports { span: ident.span, ident });
return;
}

let kind = ImportKind::Single {
Expand Down Expand Up @@ -708,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 {
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
20 changes: 19 additions & 1 deletion compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ignore_import: Option<Import<'ra>>,
) -> Result<NameBinding<'ra>, (Determinacy, Weak)> {
let module = match module {
ModuleOrUniformRoot::Module(module) => module,
ModuleOrUniformRoot::Module(module) => {
if ns == TypeNS {
if ident.name == kw::Super {
if let Some(parent) = module.parent {
return Ok(parent.self_binding.unwrap());
}
}
}

module
}
ModuleOrUniformRoot::ModuleAndExternPrelude(module) => {
assert_eq!(shadowing, Shadowing::Unrestricted);
let binding = self.resolve_ident_in_scope_set(
Expand Down Expand Up @@ -869,6 +879,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());
}
}
}

Expand Down
9 changes: 9 additions & 0 deletions tests/ui/dollar-crate/use-dollar-crate-self.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
macro_rules! foo {
() => {
use $crate::{self}; //~ ERROR `$crate` may not be imported
};
}

foo!();

fn main() {}
13 changes: 13 additions & 0 deletions tests/ui/dollar-crate/use-dollar-crate-self.stderr
Original file line number Diff line number Diff line change
@@ -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

95 changes: 95 additions & 0 deletions tests/ui/use/use-path-segment-kw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//@ edition: 2021

// 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
// use $crate; // bad
// use $crate as name; // good

// mod foo;
// use foo::crate; // bad
// use crate::crate; // bad
// use foo::super; // bad
// use super::super; // bad
// use foo::self; // good
// use self::self; // bad
// use self::self as name; // good
// }

fn outer() {}

mod foo {
pub mod bar {
pub mod foobar {
pub mod qux {
pub use super::inner;
}

pub fn inner() {}
}

pub use crate as _crate; // Good
use crate; //~ ERROR crate root imports need to be explicitly named: `use crate as name;`
use ::crate; //~ ERROR `crate` in paths can only be used in start position
use foobar::crate; //~ ERROR `crate` in paths can only be used in start position
use crate::crate; //~ ERROR `crate` in paths can only be used in start position
use super::crate; //~ ERROR `crate` in paths can only be used in start position
use self::crate; //~ ERROR `crate` in paths can only be used in start position
use ::crate as _crate2; //~ ERROR `crate` in paths can only be used in start position
use foobar::crate as _crate3; //~ ERROR `crate` in paths can only be used in start position
use crate::crate as _crate4; //~ ERROR `crate` in paths can only be used in start position
use super::crate as _crate5; //~ ERROR `crate` in paths can only be used in start position
use self::crate as _crate6; //~ ERROR `crate` in paths can only be used in start position

pub use super as _super; // Good
pub use foobar::super as _super3; // Good
pub use super::super as _super5; // Good
pub use self::super as _super6; // Good
use super; //~ ERROR imports need to be explicitly named: `use super as name;`
use ::super; //~ ERROR imports need to be explicitly named: `use super as name;`
use foobar::super; //~ ERROR imports need to be explicitly named: `use super as name;`
use crate::super; //~ ERROR imports need to be explicitly named: `use super as name;`
use super::super; //~ ERROR imports need to be explicitly named: `use super as name;`
use self::super; //~ ERROR imports need to be explicitly named: `use super as name;`
use ::super as _super2; //~ ERROR unresolved import `super`
use crate::super as _super4; //~ ERROR unresolved import `crate::super`

pub use self as _self; // Good
use self; //~ ERROR imports need to be explicitly named: `use self as name;`
use ::self; //~ ERROR {{root}} cannot be imported
pub use foobar::qux::self; //~ ERROR `self` imports are only allowed within a { } list
use crate::self; //~ ERROR crate root imports need to be explicitly named: `use crate as name;`
//~^ ERROR `self` imports are only allowed within a { } list
use super::self; //~ ERROR imports need to be explicitly named: `use super as name;`
//~^ ERROR `self` imports are only allowed within a { } list
use self::self; //~ ERROR imports need to be explicitly named: `use self as name;`
//~^ ERROR `self` imports are only allowed within a { } list
use ::self as _self2; //~ ERROR {{root}} cannot be imported
pub use foobar::self as _self3; //~ ERROR `self` imports are only allowed within a { } list
pub use crate::self as _self4; //~ ERROR `self` imports are only allowed within a { } list
pub use super::self as _self5; //~ ERROR `self` imports are only allowed within a { } list
pub use self::self as _self6; //~ ERROR `self` imports are only allowed within a { } list
}
}

fn main() {
foo::bar::_crate::outer();
foo::bar::_crate::foo::bar::foobar::inner();

foo::bar::_super::bar::foobar::inner();
foo::bar::_super3::foobar::qux::inner();
foo::bar::_super5::outer();
foo::bar::_super6::bar::foobar::inner();

foo::bar::_self::foobar::inner();
// Belows work after recovery
foo::bar::qux::inner();
foo::bar::_self3::inner();
foo::bar::_self4::outer();
foo::bar::_self5::bar::foobar::inner();
foo::bar::_self6::foobar::inner();
}
Loading
Loading