Skip to content

Commit 7042c26

Browse files
committed
Auto merge of rust-lang#125645 - RalfJung:unclear_local_imports, r=nnethercote
add unqualified_local_imports lint This lint helps deal with rust-lang/rustfmt#4709 by having the compiler detect imports of local items that are not syntactically distinguishable from imports from other cates. Making them syntactically distinguishable ensures rustfmt can consistently apply the desired import grouping.
2 parents 9d6039c + 1eb51e7 commit 7042c26

34 files changed

+230
-53
lines changed

compiler/rustc_const_eval/src/const_eval/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ mod fn_queries;
1616
mod machine;
1717
mod valtrees;
1818

19-
pub use dummy_machine::*;
20-
pub use error::*;
21-
pub use eval_queries::*;
22-
pub use fn_queries::*;
23-
pub use machine::*;
24-
pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value};
19+
pub use self::dummy_machine::*;
20+
pub use self::error::*;
21+
pub use self::eval_queries::*;
22+
pub use self::fn_queries::*;
23+
pub use self::machine::*;
24+
pub(crate) use self::valtrees::{eval_to_valtree, valtree_to_const_value};
2525

2626
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
2727
const VALTREE_MAX_NODES: usize = 100000;

compiler/rustc_const_eval/src/interpret/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ mod util;
1919
mod validity;
2020
mod visitor;
2121

22-
use eval_context::{from_known_layout, mir_assign_valid_types};
2322
#[doc(no_inline)]
2423
pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
2524

2625
pub use self::call::FnArg;
2726
pub use self::eval_context::{InterpCx, format_interp_error};
27+
use self::eval_context::{from_known_layout, mir_assign_valid_types};
2828
pub use self::intern::{
2929
HasStaticRootDefId, InternKind, InternResult, intern_const_alloc_for_constprop,
3030
intern_const_alloc_recursive,

compiler/rustc_const_eval/src/lib.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// tidy-alphabetical-start
22
#![allow(internal_features)]
33
#![allow(rustc::diagnostic_outside_of_impl)]
4+
#![cfg_attr(not(bootstrap), feature(unqualified_local_imports))]
5+
#![cfg_attr(not(bootstrap), warn(unqualified_local_imports))]
46
#![doc(rust_logo)]
57
#![feature(assert_matches)]
68
#![feature(box_patterns)]
@@ -25,10 +27,11 @@ pub mod util;
2527

2628
use std::sync::atomic::AtomicBool;
2729

28-
pub use errors::ReportErrorExt;
2930
use rustc_middle::ty;
3031
use rustc_middle::util::Providers;
3132

33+
pub use self::errors::ReportErrorExt;
34+
3235
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
3336

3437
pub fn provide(providers: &mut Providers) {

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ declare_features! (
227227
(internal, staged_api, "1.0.0", None),
228228
/// Added for testing unstable lints; perma-unstable.
229229
(internal, test_unstable_lint, "1.60.0", None),
230+
/// Helps with formatting for `group_imports = "StdExternalCrate"`.
231+
(unstable, unqualified_local_imports, "CURRENT_RUSTC_VERSION", None),
230232
/// Use for stable + negative coherence and strict coherence depending on trait's
231233
/// rustc_strict_coherence value.
232234
(unstable, with_negative_coherence, "1.60.0", None),

compiler/rustc_lint/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,8 @@ lint_unnameable_test_items = cannot test inner items
899899
lint_unnecessary_qualification = unnecessary qualification
900900
.suggestion = remove the unnecessary path segments
901901
902+
lint_unqualified_local_imports = `use` of a local item without leading `self::`, `super::`, or `crate::`
903+
902904
lint_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
903905
.label = usage of unsafe attribute
904906
lint_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`

compiler/rustc_lint/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ mod tail_expr_drop_order;
8686
mod traits;
8787
mod types;
8888
mod unit_bindings;
89+
mod unqualified_local_imports;
8990
mod unused;
9091

9192
use async_closures::AsyncClosureUsage;
@@ -126,6 +127,7 @@ use tail_expr_drop_order::TailExprDropOrder;
126127
use traits::*;
127128
use types::*;
128129
use unit_bindings::*;
130+
use unqualified_local_imports::*;
129131
use unused::*;
130132

131133
#[rustfmt::skip]
@@ -249,6 +251,7 @@ late_lint_methods!(
249251
TailExprDropOrder: TailExprDropOrder,
250252
IfLetRescope: IfLetRescope::default(),
251253
StaticMutRefs: StaticMutRefs,
254+
UnqualifiedLocalImports: UnqualifiedLocalImports,
252255
]
253256
]
254257
);

compiler/rustc_lint/src/lints.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3093,3 +3093,7 @@ pub(crate) enum MutRefSugg {
30933093
span: Span,
30943094
},
30953095
}
3096+
3097+
#[derive(LintDiagnostic)]
3098+
#[diag(lint_unqualified_local_imports)]
3099+
pub(crate) struct UnqualifiedLocalImportsDiag {}

compiler/rustc_lint/src/passes.rs

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ macro_rules! late_lint_methods {
1414
fn check_mod(a: &'tcx rustc_hir::Mod<'tcx>, b: rustc_hir::HirId);
1515
fn check_foreign_item(a: &'tcx rustc_hir::ForeignItem<'tcx>);
1616
fn check_item(a: &'tcx rustc_hir::Item<'tcx>);
17+
/// This is called *after* recursing into the item
18+
/// (in contrast to `check_item`, which is checked before).
1719
fn check_item_post(a: &'tcx rustc_hir::Item<'tcx>);
1820
fn check_local(a: &'tcx rustc_hir::LetStmt<'tcx>);
1921
fn check_block(a: &'tcx rustc_hir::Block<'tcx>);
@@ -135,6 +137,8 @@ macro_rules! early_lint_methods {
135137
fn check_crate(a: &rustc_ast::Crate);
136138
fn check_crate_post(a: &rustc_ast::Crate);
137139
fn check_item(a: &rustc_ast::Item);
140+
/// This is called *after* recursing into the item
141+
/// (in contrast to `check_item`, which is checked before).
138142
fn check_item_post(a: &rustc_ast::Item);
139143
fn check_local(a: &rustc_ast::Local);
140144
fn check_block(a: &rustc_ast::Block);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use rustc_hir::def::{DefKind, Res};
2+
use rustc_hir::{self as hir};
3+
use rustc_session::{declare_lint, declare_lint_pass};
4+
use rustc_span::symbol::kw;
5+
6+
use crate::{LateContext, LateLintPass, LintContext, lints};
7+
8+
declare_lint! {
9+
/// The `unqualified_local_imports` lint checks for `use` items that import a local item using a
10+
/// path that does not start with `self::`, `super::`, or `crate::`.
11+
///
12+
/// ### Example
13+
///
14+
/// ```rust,edition2018
15+
/// #![warn(unqualified_local_imports)]
16+
///
17+
/// mod localmod {
18+
/// pub struct S;
19+
/// }
20+
///
21+
/// use localmod::S;
22+
/// # // We have to actually use `S`, or else the `unused` warnings suppress the lint we care about.
23+
/// # pub fn main() {
24+
/// # let _x = S;
25+
/// # }
26+
/// ```
27+
///
28+
/// {{produces}}
29+
///
30+
/// ### Explanation
31+
///
32+
/// This lint is meant to be used with the (unstable) rustfmt setting `group_imports = "StdExternalCrate"`.
33+
/// That setting makes rustfmt group `self::`, `super::`, and `crate::` imports separately from those
34+
/// refering to other crates. However, rustfmt cannot know whether `use c::S;` refers to a local module `c`
35+
/// or an external crate `c`, so it always gets categorized as an import from another crate.
36+
/// To ensure consistent grouping of imports from the local crate, all local imports must
37+
/// start with `self::`, `super::`, or `crate::`. This lint can be used to enforce that style.
38+
pub UNQUALIFIED_LOCAL_IMPORTS,
39+
Allow,
40+
"`use` of a local item without leading `self::`, `super::`, or `crate::`",
41+
@feature_gate = unqualified_local_imports;
42+
}
43+
44+
declare_lint_pass!(UnqualifiedLocalImports => [UNQUALIFIED_LOCAL_IMPORTS]);
45+
46+
impl<'tcx> LateLintPass<'tcx> for UnqualifiedLocalImports {
47+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
48+
let hir::ItemKind::Use(path, _kind) = item.kind else { return };
49+
// `path` has three resolutions for the type, module, value namespaces.
50+
// Check if any of them qualifies: local crate, and not a macro.
51+
// (Macros can't be imported any other way so we don't complain about them.)
52+
let is_local_import = |res: &Res| {
53+
matches!(
54+
res,
55+
hir::def::Res::Def(def_kind, def_id)
56+
if def_id.is_local() && !matches!(def_kind, DefKind::Macro(_)),
57+
)
58+
};
59+
if !path.res.iter().any(is_local_import) {
60+
return;
61+
}
62+
// So this does refer to something local. Let's check whether it starts with `self`,
63+
// `super`, or `crate`. If the path is empty, that means we have a `use *`, which is
64+
// equivalent to `use crate::*` so we don't fire the lint in that case.
65+
let Some(first_seg) = path.segments.first() else { return };
66+
if matches!(first_seg.ident.name, kw::SelfLower | kw::Super | kw::Crate) {
67+
return;
68+
}
69+
70+
let encl_item_id = cx.tcx.hir().get_parent_item(item.hir_id());
71+
let encl_item = cx.tcx.hir_node_by_def_id(encl_item_id.def_id);
72+
if encl_item.fn_kind().is_some() {
73+
// `use` in a method -- don't lint, that leads to too many undesirable lints
74+
// when a function imports all variants of an enum.
75+
return;
76+
}
77+
78+
// This `use` qualifies for our lint!
79+
cx.emit_span_lint(
80+
UNQUALIFIED_LOCAL_IMPORTS,
81+
first_seg.ident.span,
82+
lints::UnqualifiedLocalImportsDiag {},
83+
);
84+
}
85+
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2058,6 +2058,7 @@ symbols! {
20582058
unmarked_api,
20592059
unnamed_fields,
20602060
unpin,
2061+
unqualified_local_imports,
20612062
unreachable,
20622063
unreachable_2015,
20632064
unreachable_2015_macro,

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ use crate::borrow_tracker::{
2222
use crate::concurrency::data_race::{NaReadType, NaWriteType};
2323
use crate::*;
2424

25-
use diagnostics::{RetagCause, RetagInfo};
26-
pub use item::{Item, Permission};
27-
pub use stack::Stack;
25+
use self::diagnostics::{RetagCause, RetagInfo};
26+
pub use self::item::{Item, Permission};
27+
pub use self::stack::Stack;
2828

2929
pub type AllocState = Stacks;
3030

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ mod unimap;
1919
#[cfg(test)]
2020
mod exhaustive;
2121

22-
use perms::Permission;
23-
pub use tree::Tree;
22+
use self::perms::Permission;
23+
pub use self::tree::Tree;
2424

2525
pub type AllocState = Tree;
2626

src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ enum PermissionPriv {
4747
/// rejects: all child accesses (UB).
4848
Disabled,
4949
}
50-
use PermissionPriv::*;
50+
use self::PermissionPriv::*;
5151

5252
impl PartialOrd for PermissionPriv {
5353
/// PermissionPriv is ordered by the reflexive transitive closure of

src/tools/miri/src/concurrency/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ pub mod thread;
77
mod vector_clock;
88
pub mod weak_memory;
99

10-
pub use vector_clock::VClock;
10+
pub use self::vector_clock::VClock;

src/tools/miri/src/intrinsics/atomic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_middle::{mir, mir::BinOp, ty};
22

33
use crate::*;
4-
use helpers::check_arg_count;
4+
use self::helpers::check_arg_count;
55

66
pub enum AtomicOp {
77
/// The `bool` indicates whether the result of the operation should be negated (`UnOp::Not`,

src/tools/miri/src/intrinsics/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use rustc_span::{Symbol, sym};
1313
use rustc_target::abi::Size;
1414

1515
use crate::*;
16-
use atomic::EvalContextExt as _;
17-
use helpers::{ToHost, ToSoft, check_arg_count};
18-
use simd::EvalContextExt as _;
16+
use self::atomic::EvalContextExt as _;
17+
use self::helpers::{ToHost, ToSoft, check_arg_count};
18+
use self::simd::EvalContextExt as _;
1919

2020
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
2121
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {

src/tools/miri/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
clippy::cast_lossless,
5252
clippy::cast_possible_truncation,
5353
)]
54+
#![cfg_attr(not(bootstrap), feature(unqualified_local_imports))]
55+
#![cfg_attr(not(bootstrap), warn(unqualified_local_imports))]
5456
// Needed for rustdoc from bootstrap (with `-Znormalize-docs`).
5557
#![recursion_limit = "256"]
5658

src/tools/miri/src/shims/env.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ffi::{OsStr, OsString};
33
use rustc_data_structures::fx::FxHashMap;
44

55
use crate::*;
6-
use shims::{unix::UnixEnvVars, windows::WindowsEnvVars};
6+
use self::shims::{unix::UnixEnvVars, windows::WindowsEnvVars};
77

88
#[derive(Default)]
99
pub enum EnvVars<'tcx> {

src/tools/miri/src/shims/foreign_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_target::{
1515
use super::alloc::EvalContextExt as _;
1616
use super::backtrace::EvalContextExt as _;
1717
use crate::*;
18-
use helpers::{ToHost, ToSoft};
18+
use self::helpers::{ToHost, ToSoft};
1919

2020
/// Type of dynamic symbols (for `dlsym` et al)
2121
#[derive(Debug, Copy, Clone)]

src/tools/miri/src/shims/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod panic;
1717
pub mod time;
1818
pub mod tls;
1919

20-
pub use unix::{DirTable, EpollInterestTable, FdTable};
20+
pub use self::unix::{DirTable, EpollInterestTable, FdTable};
2121

2222
/// What needs to be done after emulating an item (a shim or an intrinsic) is done.
2323
pub enum EmulateItemResult {

src/tools/miri/src/shims/panic.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_target::spec::PanicStrategy;
1717
use rustc_target::spec::abi::Abi;
1818

1919
use crate::*;
20-
use helpers::check_arg_count;
20+
use self::helpers::check_arg_count;
2121

2222
/// Holds all of the relevant data for when unwinding hits a `try` frame.
2323
#[derive(Debug)]

src/tools/miri/src/shims/unix/foreign_items.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ use crate::shims::alloc::EvalContextExt as _;
1111
use crate::shims::unix::*;
1212
use crate::*;
1313

14-
use shims::unix::android::foreign_items as android;
15-
use shims::unix::freebsd::foreign_items as freebsd;
16-
use shims::unix::linux::foreign_items as linux;
17-
use shims::unix::macos::foreign_items as macos;
18-
use shims::unix::solarish::foreign_items as solarish;
14+
use self::shims::unix::android::foreign_items as android;
15+
use self::shims::unix::freebsd::foreign_items as freebsd;
16+
use self::shims::unix::linux::foreign_items as linux;
17+
use self::shims::unix::macos::foreign_items as macos;
18+
use self::shims::unix::solarish::foreign_items as solarish;
1919

2020
pub fn is_dyn_sym(name: &str, target_os: &str) -> bool {
2121
match name {

src/tools/miri/src/shims/unix/fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::shims::os_str::bytes_to_os_str;
1515
use crate::shims::unix::fd::FileDescriptionRef;
1616
use crate::shims::unix::*;
1717
use crate::*;
18-
use shims::time::system_time_to_duration;
18+
use self::shims::time::system_time_to_duration;
1919

2020
use self::fd::FlockOp;
2121

src/tools/miri/src/shims/unix/linux/foreign_items.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use crate::machine::SIGRTMAX;
55
use crate::machine::SIGRTMIN;
66
use crate::shims::unix::*;
77
use crate::*;
8-
use shims::unix::linux::epoll::EvalContextExt as _;
9-
use shims::unix::linux::eventfd::EvalContextExt as _;
10-
use shims::unix::linux::mem::EvalContextExt as _;
11-
use shims::unix::linux::sync::futex;
8+
use self::shims::unix::linux::epoll::EvalContextExt as _;
9+
use self::shims::unix::linux::eventfd::EvalContextExt as _;
10+
use self::shims::unix::linux::mem::EvalContextExt as _;
11+
use self::shims::unix::linux::sync::futex;
1212

1313
pub fn is_dyn_sym(name: &str) -> bool {
1414
matches!(name, "statx")

src/tools/miri/src/shims/unix/mod.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ mod linux;
1414
mod macos;
1515
mod solarish;
1616

17-
pub use env::UnixEnvVars;
18-
pub use fd::{FdTable, FileDescription};
19-
pub use fs::DirTable;
20-
pub use linux::epoll::EpollInterestTable;
17+
pub use self::env::UnixEnvVars;
18+
pub use self::fd::{FdTable, FileDescription};
19+
pub use self::fs::DirTable;
20+
pub use self::linux::epoll::EpollInterestTable;
2121
// All the Unix-specific extension traits
22-
pub use env::EvalContextExt as _;
23-
pub use fd::EvalContextExt as _;
24-
pub use fs::EvalContextExt as _;
25-
pub use mem::EvalContextExt as _;
26-
pub use sync::EvalContextExt as _;
27-
pub use thread::EvalContextExt as _;
28-
pub use unnamed_socket::EvalContextExt as _;
22+
pub use self::env::EvalContextExt as _;
23+
pub use self::fd::EvalContextExt as _;
24+
pub use self::fs::EvalContextExt as _;
25+
pub use self::mem::EvalContextExt as _;
26+
pub use self::sync::EvalContextExt as _;
27+
pub use self::thread::EvalContextExt as _;
28+
pub use self::unnamed_socket::EvalContextExt as _;
2929

3030
// Make up some constants.
3131
const UID: u32 = 1000;

0 commit comments

Comments
 (0)