exclude unexported macro bindings from extern crate
This commit is contained in:
parent
cb25c5bc3d
commit
9c3091e9cf
@ -4604,3 +4604,50 @@ declare_lint! {
|
|||||||
reference: "issue #X <https://github.com/rust-lang/rust/issues/X>",
|
reference: "issue #X <https://github.com/rust-lang/rust/issues/X>",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `private_macro_use` lint detects private macros that are imported
|
||||||
|
/// with `#[macro_use]`.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,ignore (needs extern crate)
|
||||||
|
/// // extern_macro.rs
|
||||||
|
/// macro_rules! foo_ { () => {}; }
|
||||||
|
/// use foo_ as foo;
|
||||||
|
///
|
||||||
|
/// // code.rs
|
||||||
|
///
|
||||||
|
/// #![deny(private_macro_use)]
|
||||||
|
///
|
||||||
|
/// #[macro_use]
|
||||||
|
/// extern crate extern_macro;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// foo!();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This will produce:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// error: cannot find macro `foo` in this scope
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// This lint arises from overlooking visibility checks for macros
|
||||||
|
/// in an external crate.
|
||||||
|
///
|
||||||
|
/// This is a [future-incompatible] lint to transition this to a
|
||||||
|
/// hard error in the future.
|
||||||
|
///
|
||||||
|
/// [future-incompatible]: ../index.md#future-incompatible-lints
|
||||||
|
pub PRIVATE_MACRO_USE,
|
||||||
|
Warn,
|
||||||
|
"detects certain macro bindings that should not be re-exported",
|
||||||
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
|
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
|
||||||
|
reference: "issue #120192 <https://github.com/rust-lang/rust/issues/120192>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1029,9 +1029,9 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let macro_use_import = |this: &Self, span| {
|
let macro_use_import = |this: &Self, span, warn_private| {
|
||||||
this.r.arenas.alloc_import(ImportData {
|
this.r.arenas.alloc_import(ImportData {
|
||||||
kind: ImportKind::MacroUse,
|
kind: ImportKind::MacroUse { warn_private },
|
||||||
root_id: item.id,
|
root_id: item.id,
|
||||||
parent_scope: this.parent_scope,
|
parent_scope: this.parent_scope,
|
||||||
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
|
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
|
||||||
@ -1048,11 +1048,25 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
let allow_shadowing = self.parent_scope.expansion == LocalExpnId::ROOT;
|
let allow_shadowing = self.parent_scope.expansion == LocalExpnId::ROOT;
|
||||||
if let Some(span) = import_all {
|
if let Some(span) = import_all {
|
||||||
let import = macro_use_import(self, span);
|
let import = macro_use_import(self, span, false);
|
||||||
self.r.potentially_unused_imports.push(import);
|
self.r.potentially_unused_imports.push(import);
|
||||||
module.for_each_child(self, |this, ident, ns, binding| {
|
module.for_each_child(self, |this, ident, ns, binding| {
|
||||||
if ns == MacroNS {
|
if ns == MacroNS {
|
||||||
let imported_binding = this.r.import(binding, import);
|
let imported_binding =
|
||||||
|
if this.r.is_accessible_from(binding.vis, this.parent_scope.module) {
|
||||||
|
this.r.import(binding, import)
|
||||||
|
} else if !this.r.is_builtin_macro(binding.res())
|
||||||
|
&& !this.r.macro_use_prelude.contains_key(&ident.name)
|
||||||
|
{
|
||||||
|
// - `!r.is_builtin_macro(res)` excluding the built-in macros such as `Debug` or `Hash`.
|
||||||
|
// - `!r.macro_use_prelude.contains_key(name)` excluding macros defined in other extern
|
||||||
|
// crates such as `std`.
|
||||||
|
// FIXME: This branch should eventually be removed.
|
||||||
|
let import = macro_use_import(this, span, true);
|
||||||
|
this.r.import(binding, import)
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
this.add_macro_use_binding(ident.name, imported_binding, span, allow_shadowing);
|
this.add_macro_use_binding(ident.name, imported_binding, span, allow_shadowing);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1065,7 +1079,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||||||
&self.parent_scope,
|
&self.parent_scope,
|
||||||
);
|
);
|
||||||
if let Ok(binding) = result {
|
if let Ok(binding) = result {
|
||||||
let import = macro_use_import(self, ident.span);
|
let import = macro_use_import(self, ident.span, false);
|
||||||
self.r.potentially_unused_imports.push(import);
|
self.r.potentially_unused_imports.push(import);
|
||||||
let imported_binding = self.r.import(binding, import);
|
let imported_binding = self.r.import(binding, import);
|
||||||
self.add_macro_use_binding(
|
self.add_macro_use_binding(
|
||||||
|
@ -290,7 +290,7 @@ impl Resolver<'_, '_> {
|
|||||||
|| import.expect_vis().is_public()
|
|| import.expect_vis().is_public()
|
||||||
|| import.span.is_dummy() =>
|
|| import.span.is_dummy() =>
|
||||||
{
|
{
|
||||||
if let ImportKind::MacroUse = import.kind {
|
if let ImportKind::MacroUse { .. } = import.kind {
|
||||||
if !import.span.is_dummy() {
|
if !import.span.is_dummy() {
|
||||||
self.lint_buffer.buffer_lint(
|
self.lint_buffer.buffer_lint(
|
||||||
MACRO_USE_EXTERN_CRATE,
|
MACRO_USE_EXTERN_CRATE,
|
||||||
@ -315,7 +315,7 @@ impl Resolver<'_, '_> {
|
|||||||
maybe_unused_extern_crates.insert(id, import.span);
|
maybe_unused_extern_crates.insert(id, import.span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImportKind::MacroUse => {
|
ImportKind::MacroUse { .. } => {
|
||||||
let msg = "unused `#[macro_use]` import";
|
let msg = "unused `#[macro_use]` import";
|
||||||
self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg);
|
self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg);
|
||||||
}
|
}
|
||||||
|
@ -285,7 +285,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
use NameBindingKind::Import;
|
use NameBindingKind::Import;
|
||||||
let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| {
|
let can_suggest = |binding: NameBinding<'_>, import: self::Import<'_>| {
|
||||||
!binding.span.is_dummy()
|
!binding.span.is_dummy()
|
||||||
&& !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport)
|
&& !matches!(import.kind, ImportKind::MacroUse { .. } | ImportKind::MacroExport)
|
||||||
};
|
};
|
||||||
let import = match (&new_binding.kind, &old_binding.kind) {
|
let import = match (&new_binding.kind, &old_binding.kind) {
|
||||||
// If there are two imports where one or both have attributes then prefer removing the
|
// If there are two imports where one or both have attributes then prefer removing the
|
||||||
@ -1819,9 +1819,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
next_ident = source;
|
next_ident = source;
|
||||||
Some(binding)
|
Some(binding)
|
||||||
}
|
}
|
||||||
ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => {
|
ImportKind::Glob { .. }
|
||||||
Some(binding)
|
| ImportKind::MacroUse { .. }
|
||||||
}
|
| ImportKind::MacroExport => Some(binding),
|
||||||
ImportKind::ExternCrate { .. } => None,
|
ImportKind::ExternCrate { .. } => None,
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -80,7 +80,11 @@ pub(crate) enum ImportKind<'a> {
|
|||||||
target: Ident,
|
target: Ident,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
},
|
},
|
||||||
MacroUse,
|
MacroUse {
|
||||||
|
/// A field has been added indicating whether it should be reported as a lint,
|
||||||
|
/// addressing issue#119301.
|
||||||
|
warn_private: bool,
|
||||||
|
},
|
||||||
MacroExport,
|
MacroExport,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +131,7 @@ impl<'a> std::fmt::Debug for ImportKind<'a> {
|
|||||||
.field("target", target)
|
.field("target", target)
|
||||||
.field("id", id)
|
.field("id", id)
|
||||||
.finish(),
|
.finish(),
|
||||||
MacroUse => f.debug_struct("MacroUse").finish(),
|
MacroUse { .. } => f.debug_struct("MacroUse").finish(),
|
||||||
MacroExport => f.debug_struct("MacroExport").finish(),
|
MacroExport => f.debug_struct("MacroExport").finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,7 +201,7 @@ impl<'a> ImportData<'a> {
|
|||||||
ImportKind::Single { id, .. }
|
ImportKind::Single { id, .. }
|
||||||
| ImportKind::Glob { id, .. }
|
| ImportKind::Glob { id, .. }
|
||||||
| ImportKind::ExternCrate { id, .. } => Some(id),
|
| ImportKind::ExternCrate { id, .. } => Some(id),
|
||||||
ImportKind::MacroUse | ImportKind::MacroExport => None,
|
ImportKind::MacroUse { .. } | ImportKind::MacroExport => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +211,7 @@ impl<'a> ImportData<'a> {
|
|||||||
ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)),
|
ImportKind::Single { id, .. } => Reexport::Single(to_def_id(id)),
|
||||||
ImportKind::Glob { id, .. } => Reexport::Glob(to_def_id(id)),
|
ImportKind::Glob { id, .. } => Reexport::Glob(to_def_id(id)),
|
||||||
ImportKind::ExternCrate { id, .. } => Reexport::ExternCrate(to_def_id(id)),
|
ImportKind::ExternCrate { id, .. } => Reexport::ExternCrate(to_def_id(id)),
|
||||||
ImportKind::MacroUse => Reexport::MacroUse,
|
ImportKind::MacroUse { .. } => Reexport::MacroUse,
|
||||||
ImportKind::MacroExport => Reexport::MacroExport,
|
ImportKind::MacroExport => Reexport::MacroExport,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1482,7 +1486,7 @@ fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String {
|
|||||||
ImportKind::Single { source, .. } => source.to_string(),
|
ImportKind::Single { source, .. } => source.to_string(),
|
||||||
ImportKind::Glob { .. } => "*".to_string(),
|
ImportKind::Glob { .. } => "*".to_string(),
|
||||||
ImportKind::ExternCrate { .. } => "<extern crate>".to_string(),
|
ImportKind::ExternCrate { .. } => "<extern crate>".to_string(),
|
||||||
ImportKind::MacroUse => "#[macro_use]".to_string(),
|
ImportKind::MacroUse { .. } => "#[macro_use]".to_string(),
|
||||||
ImportKind::MacroExport => "#[macro_export]".to_string(),
|
ImportKind::MacroExport => "#[macro_export]".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ use rustc_middle::span_bug;
|
|||||||
use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt};
|
use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt};
|
||||||
use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
|
use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
|
||||||
use rustc_query_system::ich::StableHashingContext;
|
use rustc_query_system::ich::StableHashingContext;
|
||||||
|
use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
|
||||||
use rustc_session::lint::LintBuffer;
|
use rustc_session::lint::LintBuffer;
|
||||||
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
|
use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
@ -1799,6 +1800,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind {
|
if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind {
|
||||||
|
if let ImportKind::MacroUse { warn_private: true } = import.kind {
|
||||||
|
let msg = format!("macro `{ident}` is private");
|
||||||
|
self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg);
|
||||||
|
}
|
||||||
// Avoid marking `extern crate` items that refer to a name from extern prelude,
|
// Avoid marking `extern crate` items that refer to a name from extern prelude,
|
||||||
// but not introduce it, as used if they are accessed from lexical scope.
|
// but not introduce it, as used if they are accessed from lexical scope.
|
||||||
if is_lexical_scope {
|
if is_lexical_scope {
|
||||||
|
3
tests/ui/extern/auxiliary/issue-80074-macro-2.rs
vendored
Normal file
3
tests/ui/extern/auxiliary/issue-80074-macro-2.rs
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// edition:2018
|
||||||
|
|
||||||
|
macro_rules! m { () => {}; }
|
@ -2,3 +2,5 @@
|
|||||||
|
|
||||||
macro_rules! foo_ { () => {}; }
|
macro_rules! foo_ { () => {}; }
|
||||||
use foo_ as foo;
|
use foo_ as foo;
|
||||||
|
|
||||||
|
macro_rules! bar { () => {}; }
|
||||||
|
12
tests/ui/extern/issue-80074.rs
vendored
12
tests/ui/extern/issue-80074.rs
vendored
@ -1,10 +1,20 @@
|
|||||||
// edition:2018
|
// edition:2018
|
||||||
// build-pass
|
|
||||||
// aux-crate:issue_80074=issue-80074-macro.rs
|
// aux-crate:issue_80074=issue-80074-macro.rs
|
||||||
|
// aux-crate:issue_80074_2=issue-80074-macro-2.rs
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate issue_80074;
|
extern crate issue_80074;
|
||||||
|
|
||||||
|
#[macro_use(m)]
|
||||||
|
extern crate issue_80074_2;
|
||||||
|
//~^^ ERROR: imported macro not found
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo!();
|
foo!();
|
||||||
|
//~^ WARN: macro `foo` is private
|
||||||
|
//~| WARN: it will become a hard error in a future release!
|
||||||
|
bar!();
|
||||||
|
//~^ ERROR: cannot find macro `bar` in this scope
|
||||||
|
m!();
|
||||||
|
//~^ ERROR: cannot find macro `m` in this scope
|
||||||
}
|
}
|
||||||
|
31
tests/ui/extern/issue-80074.stderr
vendored
Normal file
31
tests/ui/extern/issue-80074.stderr
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
error[E0469]: imported macro not found
|
||||||
|
--> $DIR/issue-80074.rs:8:13
|
||||||
|
|
|
||||||
|
LL | #[macro_use(m)]
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: cannot find macro `bar` in this scope
|
||||||
|
--> $DIR/issue-80074.rs:16:5
|
||||||
|
|
|
||||||
|
LL | bar!();
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: cannot find macro `m` in this scope
|
||||||
|
--> $DIR/issue-80074.rs:18:5
|
||||||
|
|
|
||||||
|
LL | m!();
|
||||||
|
| ^
|
||||||
|
|
||||||
|
warning: macro `foo` is private
|
||||||
|
--> $DIR/issue-80074.rs:13:5
|
||||||
|
|
|
||||||
|
LL | foo!();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
|
= note: for more information, see issue #120192 <https://github.com/rust-lang/rust/issues/120192>
|
||||||
|
= note: `#[warn(private_macro_use)]` on by default
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors; 1 warning emitted
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0469`.
|
2
tests/ui/imports/auxiliary/issue-119369-extern.rs
Normal file
2
tests/ui/imports/auxiliary/issue-119369-extern.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
use std::vec;
|
||||||
|
use std::hash::Hash;
|
14
tests/ui/imports/issue-119369.rs
Normal file
14
tests/ui/imports/issue-119369.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// check-pass
|
||||||
|
// aux-build: issue-119369-extern.rs
|
||||||
|
|
||||||
|
// https://github.com/rust-lang/rust/pull/119369#issuecomment-1874905662
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate issue_119369_extern;
|
||||||
|
|
||||||
|
#[derive(Hash)]
|
||||||
|
struct A;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _: Vec<i32> = vec![];
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user