Skip to content

Commit 741df34

Browse files
committed
Fix redundant import errors for preload extern crate
1 parent 62415e2 commit 741df34

10 files changed

+194
-72
lines changed

compiler/rustc_lint/src/context/diagnostics.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
143143
BuiltinLintDiag::RedundantImport(spans, ident) => {
144144
for (span, is_imported) in spans {
145145
let introduced = if is_imported { "imported" } else { "defined" };
146-
diag.span_label(span, format!("the item `{ident}` is already {introduced} here"));
146+
let span_msg = if span.is_dummy() { "by prelude" } else { "here" };
147+
diag.span_label(
148+
span,
149+
format!("the item `{ident}` is already {introduced} {span_msg}"),
150+
);
147151
}
148152
}
149153
BuiltinLintDiag::DeprecatedMacro(suggestion, span) => {

compiler/rustc_resolve/src/check_unused.rs

+78-69
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use rustc_session::lint::BuiltinLintDiag;
3939
use rustc_span::symbol::{kw, Ident};
4040
use rustc_span::{Span, DUMMY_SP};
4141

42+
#[derive(Debug)]
4243
struct UnusedImport {
4344
use_tree: ast::UseTree,
4445
use_tree_id: ast::NodeId,
@@ -137,6 +138,81 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
137138
self.check_import_as_underscore(item, *id);
138139
}
139140
}
141+
142+
fn report_unused_extern_crate_items(
143+
&mut self,
144+
maybe_unused_extern_crates: FxHashMap<ast::NodeId, Span>,
145+
) {
146+
let tcx = self.r.tcx();
147+
for extern_crate in &self.extern_crate_items {
148+
let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');
149+
150+
// If the crate is fully unused, we suggest removing it altogether.
151+
// We do this in any edition.
152+
if warn_if_unused {
153+
if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
154+
self.r.lint_buffer.buffer_lint_with_diagnostic(
155+
UNUSED_EXTERN_CRATES,
156+
extern_crate.id,
157+
span,
158+
"unused extern crate",
159+
BuiltinLintDiag::UnusedExternCrate {
160+
removal_span: extern_crate.span_with_attributes,
161+
},
162+
);
163+
continue;
164+
}
165+
}
166+
167+
// If we are not in Rust 2018 edition, then we don't make any further
168+
// suggestions.
169+
if !tcx.sess.at_least_rust_2018() {
170+
continue;
171+
}
172+
173+
// If the extern crate has any attributes, they may have funky
174+
// semantics we can't faithfully represent using `use` (most
175+
// notably `#[macro_use]`). Ignore it.
176+
if extern_crate.has_attrs {
177+
continue;
178+
}
179+
180+
// If the extern crate is renamed, then we cannot suggest replacing it with a use as this
181+
// would not insert the new name into the prelude, where other imports in the crate may be
182+
// expecting it.
183+
if extern_crate.renames {
184+
continue;
185+
}
186+
187+
// If the extern crate isn't in the extern prelude,
188+
// there is no way it can be written as a `use`.
189+
if !self
190+
.r
191+
.extern_prelude
192+
.get(&extern_crate.ident)
193+
.is_some_and(|entry| !entry.introduced_by_item)
194+
{
195+
continue;
196+
}
197+
198+
let vis_span = extern_crate
199+
.vis_span
200+
.find_ancestor_inside(extern_crate.span)
201+
.unwrap_or(extern_crate.vis_span);
202+
let ident_span = extern_crate
203+
.ident
204+
.span
205+
.find_ancestor_inside(extern_crate.span)
206+
.unwrap_or(extern_crate.ident.span);
207+
self.r.lint_buffer.buffer_lint_with_diagnostic(
208+
UNUSED_EXTERN_CRATES,
209+
extern_crate.id,
210+
extern_crate.span,
211+
"`extern crate` is not idiomatic in the new edition",
212+
BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span },
213+
);
214+
}
215+
}
140216
}
141217

142218
impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
@@ -335,6 +411,8 @@ impl Resolver<'_, '_> {
335411
};
336412
visit::walk_crate(&mut visitor, krate);
337413

414+
visitor.report_unused_extern_crate_items(maybe_unused_extern_crates);
415+
338416
for unused in visitor.unused_imports.values() {
339417
let mut fixes = Vec::new();
340418
let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
@@ -416,75 +494,6 @@ impl Resolver<'_, '_> {
416494
);
417495
}
418496

419-
for extern_crate in visitor.extern_crate_items {
420-
let warn_if_unused = !extern_crate.ident.name.as_str().starts_with('_');
421-
422-
// If the crate is fully unused, we suggest removing it altogether.
423-
// We do this in any edition.
424-
if warn_if_unused {
425-
if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
426-
visitor.r.lint_buffer.buffer_lint_with_diagnostic(
427-
UNUSED_EXTERN_CRATES,
428-
extern_crate.id,
429-
span,
430-
"unused extern crate",
431-
BuiltinLintDiag::UnusedExternCrate {
432-
removal_span: extern_crate.span_with_attributes,
433-
},
434-
);
435-
continue;
436-
}
437-
}
438-
439-
// If we are not in Rust 2018 edition, then we don't make any further
440-
// suggestions.
441-
if !tcx.sess.at_least_rust_2018() {
442-
continue;
443-
}
444-
445-
// If the extern crate has any attributes, they may have funky
446-
// semantics we can't faithfully represent using `use` (most
447-
// notably `#[macro_use]`). Ignore it.
448-
if extern_crate.has_attrs {
449-
continue;
450-
}
451-
452-
// If the extern crate is renamed, then we cannot suggest replacing it with a use as this
453-
// would not insert the new name into the prelude, where other imports in the crate may be
454-
// expecting it.
455-
if extern_crate.renames {
456-
continue;
457-
}
458-
459-
// If the extern crate isn't in the extern prelude,
460-
// there is no way it can be written as a `use`.
461-
if !visitor
462-
.r
463-
.extern_prelude
464-
.get(&extern_crate.ident)
465-
.is_some_and(|entry| !entry.introduced_by_item)
466-
{
467-
continue;
468-
}
469-
470-
let vis_span = extern_crate
471-
.vis_span
472-
.find_ancestor_inside(extern_crate.span)
473-
.unwrap_or(extern_crate.vis_span);
474-
let ident_span = extern_crate
475-
.ident
476-
.span
477-
.find_ancestor_inside(extern_crate.span)
478-
.unwrap_or(extern_crate.ident.span);
479-
visitor.r.lint_buffer.buffer_lint_with_diagnostic(
480-
UNUSED_EXTERN_CRATES,
481-
extern_crate.id,
482-
extern_crate.span,
483-
"`extern crate` is not idiomatic in the new edition",
484-
BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span },
485-
);
486-
}
487-
488497
let unused_imports = visitor.unused_imports;
489498
let mut check_redundant_imports = FxIndexSet::default();
490499
for module in self.arenas.local_modules().iter() {

compiler/rustc_resolve/src/imports.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1336,9 +1336,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
13361336
}
13371337

13381338
let mut is_redundant = true;
1339-
13401339
let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None };
1341-
13421340
self.per_ns(|this, ns| {
13431341
if is_redundant && let Ok(binding) = source_bindings[ns].get() {
13441342
if binding.res() == Res::Err {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn item() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ compile-flags: --extern aux_issue_121915 --edition 2015
2+
//@ aux-build: aux-issue-121915.rs
3+
4+
extern crate aux_issue_121915;
5+
6+
#[deny(unused_imports)]
7+
fn main() {
8+
use aux_issue_121915;
9+
//~^ ERROR the item `aux_issue_121915` is imported redundantly
10+
aux_issue_121915::item();
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: the item `aux_issue_121915` is imported redundantly
2+
--> $DIR/redundant-import-issue-121915-2015.rs:8:9
3+
|
4+
LL | extern crate aux_issue_121915;
5+
| ------------------------------ the item `aux_issue_121915` is already imported here
6+
...
7+
LL | use aux_issue_121915;
8+
| ^^^^^^^^^^^^^^^^
9+
|
10+
note: the lint level is defined here
11+
--> $DIR/redundant-import-issue-121915-2015.rs:6:8
12+
|
13+
LL | #[deny(unused_imports)]
14+
| ^^^^^^^^^^^^^^
15+
16+
error: aborting due to 1 previous error
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ compile-flags: --extern aux_issue_121915 --edition 2018
2+
//@ aux-build: aux-issue-121915.rs
3+
4+
#[deny(unused_imports)]
5+
fn main() {
6+
use aux_issue_121915;
7+
//~^ ERROR the item `aux_issue_121915` is imported redundantly
8+
aux_issue_121915::item();
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: the item `aux_issue_121915` is imported redundantly
2+
--> $DIR/redundant-import-issue-121915.rs:6:9
3+
|
4+
LL | use aux_issue_121915;
5+
| ^^^^^^^^^^^^^^^^ the item `aux_issue_121915` is already defined by prelude
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/redundant-import-issue-121915.rs:4:8
9+
|
10+
LL | #[deny(unused_imports)]
11+
| ^^^^^^^^^^^^^^
12+
13+
error: aborting due to 1 previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//@ compile-flags: --edition 2021
2+
#![deny(unused_imports)]
3+
#![allow(dead_code)]
4+
5+
fn test0() {
6+
// Test remove FlatUnused
7+
use std::convert::TryFrom;
8+
//~^ ERROR the item `TryFrom` is imported redundantly
9+
let _ = u32::try_from(5i32);
10+
}
11+
12+
fn test1() {
13+
// FIXME(yukang) Test remove NestedFullUnused
14+
// use std::convert::{TryFrom, TryInto};
15+
16+
// let _ = u32::try_from(5i32);
17+
// let _a: i32 = u32::try_into(5u32).unwrap();
18+
}
19+
20+
fn test2() {
21+
// FIXME(yukang): Test remove both redundant and unused
22+
// use std::convert::{AsMut, Into};
23+
24+
// let _a: u32 = (5u8).into();
25+
}
26+
27+
fn test3() {
28+
// Test remove NestedPartialUnused
29+
use std::convert::{From, Infallible};
30+
//~^ ERROR unused import: `From`
31+
32+
trait MyTrait {}
33+
impl MyTrait for fn() -> Infallible {}
34+
}
35+
36+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: the item `TryFrom` is imported redundantly
2+
--> $DIR/suggest-remove-issue-121315.rs:7:9
3+
|
4+
LL | use std::convert::TryFrom;
5+
| ^^^^^^^^^^^^^^^^^^^^^
6+
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
7+
|
8+
= note: the item `TryFrom` is already defined here
9+
|
10+
note: the lint level is defined here
11+
--> $DIR/suggest-remove-issue-121315.rs:2:9
12+
|
13+
LL | #![deny(unused_imports)]
14+
| ^^^^^^^^^^^^^^
15+
16+
error: unused import: `From`
17+
--> $DIR/suggest-remove-issue-121315.rs:29:24
18+
|
19+
LL | use std::convert::{From, Infallible};
20+
| ^^^^
21+
22+
error: aborting due to 2 previous errors
23+

0 commit comments

Comments
 (0)