Skip to content
Open
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
4 changes: 3 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0429.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#### Note: this error code is no longer emitted by the compiler.

The `self` keyword cannot appear alone as the last segment in a `use`
declaration.

Erroneous code example:

```compile_fail,E0429
```ignore (error is no longer emitted)
use std::fmt::self; // error: `self` imports are only allowed within a { } list
```

Expand Down
93 changes: 46 additions & 47 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef};
use crate::ref_mut::CmCell;
use crate::{
BindingKey, Decl, DeclData, DeclKind, ExternPreludeEntry, Finalize, IdentKey, MacroData,
Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, ResolutionError, Resolver,
Segment, Used, VisResolutionError, errors,
Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, Resolver, Segment, Used,
VisResolutionError, errors,
};

type Res = def::Res<NodeId>;
Expand Down Expand Up @@ -622,41 +622,27 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {

match use_tree.kind {
ast::UseTreeKind::Simple(rename) => {
let mut ident = use_tree.ident();
let mut module_path = prefix;
let mut source = module_path.pop().unwrap();
let source = module_path.pop().unwrap();

// `true` for `...::{self [as target]}` imports, `false` otherwise.
let type_ns_only = nested && source.ident.name == kw::SelfLower;

if source.ident.name == kw::SelfLower
&& let Some(parent) = module_path.pop()
{
// Suggest `use prefix::{self};` for `use prefix::self;`
if !type_ns_only
&& (parent.ident.name != kw::PathRoot
|| self.r.path_root_is_crate_root(parent.ident))
// normalize `self::self` to `self`
if source.ident.name == kw::SelfLower {
while let Some(parent) = module_path.last()
&& parent.ident.name == kw::SelfLower
{
let span_with_rename = match rename {
Some(rename) => source.ident.span.to(rename.span),
None => source.ident.span,
};

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

let ident = if source.ident.name == kw::SelfLower
&& rename.is_none()
&& let Some(parent) = module_path.last()
{
let self_span = source.ident.span;
source = parent;
if rename.is_none() {
ident = Ident::new(source.ident.name, self_span);
}
}
Ident::new(parent.ident.name, self_span)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So things like foo::self::self are still unsupported and will be reported by UnnamedImport.
Seems fine for a start.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, use foo::self::self as name is probably supported now, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

This comment was marked as outdated.

This comment was marked as outdated.

This comment was marked as outdated.

Copy link
Contributor Author

@mu001999 mu001999 Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, use foo::self::self; is allowed.

} else {
use_tree.ident()
};

match source.ident.name {
kw::DollarCrate => {
Expand Down Expand Up @@ -693,35 +679,48 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
return;
}
}
// Deny `use ::{self};` after edition 2015
kw::PathRoot if !self.r.path_root_is_crate_root(source.ident) => {
self.r.dcx().span_err(use_tree.span, "extern prelude cannot be imported");
return;
kw::SelfLower => {
// Deny `use ::{self};` after edition 2015
if let Some(parent) = module_path.last()
&& parent.ident.name == kw::PathRoot
&& !self.r.path_root_is_crate_root(parent.ident)
{
self.r
.dcx()
.span_err(use_tree.span, "extern prelude cannot be imported");
return;
}
}
_ => {
// Deny `use ...::self::foo [as name];`
if module_path.len() > 1
&& let Some(parent) = module_path.last()
&& parent.ident.name == kw::SelfLower
{
self.r.dcx().span_err(
parent.ident.span,
"`self` in paths can only be used in start position",
);
return;
}
}
_ => {}
}

// Deny importing path-kw without renaming
if rename.is_none() && ident.is_path_segment_keyword() {
let ident = use_tree.ident();

// Don't suggest `use xx::self as name;` for `use xx::self;`
// But it's OK to suggest `use xx::{self as name};` for `use xx::{self};`
let sugg = if !type_ns_only && ident.name == kw::SelfLower {
None
} else {
Some(errors::UnnamedImportSugg { span: ident.span, ident })
};

self.r.dcx().emit_err(errors::UnnamedImport { span: ident.span, sugg });
self.r.dcx().emit_err(errors::UnnamedImport {
span: ident.span,
sugg: errors::UnnamedImportSugg { span: ident.span, ident },
});
return;
}

let kind = ImportKind::Single {
source: source.ident,
target: ident,
decls: Default::default(),
type_ns_only,
type_ns_only: source.ident.is_path_segment_keyword(),
nested,
id,
};
Expand Down
26 changes: 0 additions & 26 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let mut suggestion = None;
let mut span = binding_span;
match import.kind {
ImportKind::Single { type_ns_only: true, .. } => {
suggestion = Some(format!("self as {suggested_name}"))
}
ImportKind::Single { source, .. } => {
if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span)
Expand Down Expand Up @@ -870,29 +867,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
sub_unreachable,
})
}
ResolutionError::SelfImportsOnlyAllowedWithin { root, span_with_rename } => {
// None of the suggestions below would help with a case like `use self`.
let (suggestion, mpart_suggestion) = if root {
(None, None)
} else {
// use foo::bar::self -> foo::bar
// use foo::bar::self as abc -> foo::bar as abc
let suggestion = errs::SelfImportsOnlyAllowedWithinSuggestion { span };

// use foo::bar::self -> foo::bar::{self}
// use foo::bar::self as abc -> foo::bar::{self as abc}
let mpart_suggestion = errs::SelfImportsOnlyAllowedWithinMultipartSuggestion {
multipart_start: span_with_rename.shrink_to_lo(),
multipart_end: span_with_rename.shrink_to_hi(),
};
(Some(suggestion), Some(mpart_suggestion))
};
self.dcx().create_err(errs::SelfImportsOnlyAllowedWithin {
span,
suggestion,
mpart_suggestion,
})
}
ResolutionError::FailedToResolve { segment, label, suggestion, module, message } => {
let mut err = struct_span_code_err!(self.dcx(), span, E0433, "{message}");
err.span_label(span, label);
Expand Down
36 changes: 1 addition & 35 deletions compiler/rustc_resolve/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,40 +300,6 @@ pub(crate) struct AttemptToUseNonConstantValueInConstantWithoutSuggestion<'a> {
pub(crate) suggestion: &'a str,
}

#[derive(Diagnostic)]
#[diag("`self` imports are only allowed within a {\"{\"} {\"}\"} list", code = E0429)]
pub(crate) struct SelfImportsOnlyAllowedWithin {
#[primary_span]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) suggestion: Option<SelfImportsOnlyAllowedWithinSuggestion>,
#[subdiagnostic]
pub(crate) mpart_suggestion: Option<SelfImportsOnlyAllowedWithinMultipartSuggestion>,
}

#[derive(Subdiagnostic)]
#[suggestion(
"consider importing the module directly",
code = "",
applicability = "machine-applicable"
)]
pub(crate) struct SelfImportsOnlyAllowedWithinSuggestion {
#[primary_span]
pub(crate) span: Span,
}

#[derive(Subdiagnostic)]
#[multipart_suggestion(
"alternatively, use the multi-path `use` syntax to import `self`",
applicability = "machine-applicable"
)]
pub(crate) struct SelfImportsOnlyAllowedWithinMultipartSuggestion {
#[suggestion_part(code = "{{")]
pub(crate) multipart_start: Span,
#[suggestion_part(code = "}}")]
pub(crate) multipart_end: Span,
}

#[derive(Diagnostic)]
#[diag("{$shadowing_binding}s cannot shadow {$shadowed_binding}s", code = E0530)]
pub(crate) struct BindingShadowsSomethingUnacceptable<'a> {
Expand Down Expand Up @@ -978,7 +944,7 @@ pub(crate) struct UnnamedImport {
#[primary_span]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) sugg: Option<UnnamedImportSugg>,
pub(crate) sugg: UnnamedImportSugg,
}

#[derive(Diagnostic)]
Expand Down
29 changes: 22 additions & 7 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,12 +953,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) -> Result<Decl<'ra>, Determinacy> {
match module {
ModuleOrUniformRoot::Module(module) => {
if ns == TypeNS
&& ident.name == kw::Super
&& let Some(module) =
self.resolve_super_in_module(ident, Some(module), parent_scope)
{
return Ok(module.self_decl.unwrap());
if ns == TypeNS {
if ident.name == kw::SelfLower {
return Ok(module.self_decl.unwrap());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why doesn't this enable paths like foo::self in non-import positions?
Is there some separate check in resolve_path or similar reporting an error for this case?

Copy link
Contributor Author

@mu001999 mu001999 Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, resolve_path_with_ribs will check any path-kw used in the middle

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we can support foo::self in non-import paths if we remove that check for self at last position.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, foo::self is allowed in non-import positions now.

}
if ident.name == kw::Super
&& let Some(module) =
self.resolve_super_in_module(ident, Some(module), parent_scope)
{
return Ok(module.self_decl.unwrap());
}
}

let (ident_key, def) = IdentKey::new_adjusted(ident, module.expansion);
Expand Down Expand Up @@ -1018,7 +1022,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
{
let module = self.resolve_crate_root(ident);
return Ok(module.self_decl.unwrap());
} else if ident.name == kw::Super || ident.name == kw::SelfLower {
} else if ident.name == kw::Super {
// 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_...`.
Expand Down Expand Up @@ -1827,6 +1831,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
},
);
}

if segment_idx == 0 {
if name == kw::SelfLower {
let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
Expand Down Expand Up @@ -1860,6 +1865,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
continue;
}
}

// Support `...::self`, but deny `::self` after edition 2018
if is_last
&& name == kw::SelfLower
&& segment_idx > 0
&& (path[segment_idx - 1].ident.name != kw::PathRoot
|| self.path_root_is_crate_root(path[segment_idx - 1].ident))
{
continue;
}
}

// Report special messages for path segment keywords in wrong positions.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub(crate) enum ImportKind<'ra> {
target: Ident,
/// Name declarations introduced by the import.
decls: PerNS<CmCell<PendingDecl<'ra>>>,
/// `true` for `...::{self [as target]}` imports, `false` otherwise.
/// `true` for `crate`/`$crate`/`super`/`self` imports, `false` otherwise.
type_ns_only: bool,
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
nested: bool,
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,6 @@ enum ResolutionError<'ra> {
IdentifierBoundMoreThanOnceInSamePattern(Ident),
/// Error E0426: use of undeclared label.
UndeclaredLabel { name: Symbol, suggestion: Option<LabelSuggestion> },
/// Error E0429: `self` imports are only allowed within a `{ }` list.
SelfImportsOnlyAllowedWithin { root: bool, span_with_rename: Span },
/// Error E0433: failed to resolve.
FailedToResolve {
segment: Symbol,
Expand Down Expand Up @@ -2504,7 +2502,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {

fn names_to_string(names: impl Iterator<Item = Symbol>) -> String {
let mut result = String::new();
for (i, name) in names.filter(|name| *name != kw::PathRoot).enumerate() {
for (i, name) in names.enumerate() {
if name == kw::PathRoot {
continue;
}

if i > 0 {
result.push_str("::");
}
Expand Down
4 changes: 3 additions & 1 deletion tests/ui/error-codes/E0429.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::fmt::self; //~ ERROR E0429
//@ check-pass

use std::fmt::self;

fn main () {
}
19 changes: 0 additions & 19 deletions tests/ui/error-codes/E0429.stderr

This file was deleted.

12 changes: 6 additions & 6 deletions tests/ui/imports/absolute-paths-in-nested-use-groups.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
error: `self` in paths can only be used in start position
--> $DIR/absolute-paths-in-nested-use-groups.rs:10:5
|
LL | self::bar,
| ^^^^

error[E0433]: the crate root in paths can only be used in start position
--> $DIR/absolute-paths-in-nested-use-groups.rs:6:5
|
Expand All @@ -10,12 +16,6 @@ error[E0433]: `super` in paths can only be used in start position
LL | super::bar,
| ^^^^^ can only be used in path start position

error[E0433]: `self` in paths can only be used in start position
--> $DIR/absolute-paths-in-nested-use-groups.rs:10:5
|
LL | self::bar,
| ^^^^ can only be used in path start position

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0433`.
10 changes: 6 additions & 4 deletions tests/ui/imports/cycle-import-in-std-1.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
error[E0432]: unresolved import `ops`
--> $DIR/cycle-import-in-std-1.rs:5:11
--> $DIR/cycle-import-in-std-1.rs:5:5
|
LL | use ops::{self as std};
| ^^^^^^^^^^^ no external crate `ops`
| ^^^
|
= help: consider importing this module instead:
std::ops
help: a similar path exists
|
LL | use core::ops::{self as std};
| ++++++

error: aborting due to 1 previous error

Expand Down
Loading
Loading