Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Jun 17, 2024
1 parent 67d0e5b commit 60f733e
Show file tree
Hide file tree
Showing 14 changed files with 240 additions and 75 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ lint_opaque_hidden_inferred_bound_sugg = add this bound
lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
.suggestion = use pat_param to preserve semantics
lint_out_of_scope_macro_calls = cannot find macro `{$path}` in this scope
lint_overflowing_bin_hex = literal out of range for `{$ty}`
.negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
.negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}`
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_lint/src/context/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,5 +424,8 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
lints::InnerAttributeUnstable::CustomInnerAttribute
}
.decorate_lint(diag),
BuiltinLintDiag::OutOfScopeMacroCalls { path } => {
lints::OutOfScopeMacroCalls { path }.decorate_lint(diag)
}
}
}
6 changes: 6 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2888,3 +2888,9 @@ pub struct RedundantImportVisibility {
pub import_vis: String,
pub max_vis: String,
}

#[derive(LintDiagnostic)]
#[diag(lint_out_of_scope_macro_calls)]
pub struct OutOfScopeMacroCalls {
pub path: String,
}
37 changes: 37 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4902,3 +4902,40 @@ declare_lint! {
reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>",
};
}

declare_lint! {
/// The `missing_unsafe_on_extern` lint detects missing unsafe keyword on extern declarations.
///
/// ### Example
///
/// ```rust
/// #![feature(unsafe_extern_blocks)]
/// #![warn(missing_unsafe_on_extern)]
/// #![allow(dead_code)]
///
/// extern "C" {
/// fn foo(_: i32);
/// }
///
/// fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Declaring extern items, even without ever using them, can cause Undefined Behavior. We
/// should consider all sources of Undefined Behavior to be unsafe.
///
/// This is a [future-incompatible] lint to transition this to a
/// hard error in the future.
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub OUT_OF_SCOPE_MACRO_CALLS,
Deny,
"detects out of scope calls to `macro_rules` in key-value attributes",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>",
};
}
3 changes: 3 additions & 0 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,9 @@ pub enum BuiltinLintDiag {
InnerAttributeUnstable {
is_macro: bool,
},
OutOfScopeMacroCalls {
path: String,
},
}

/// Lints that are buffered up early on in the `Session` before the
Expand Down
19 changes: 16 additions & 3 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, Modul
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError};
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError};

use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
use rustc_ast::{Block, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_attr as attr;
Expand Down Expand Up @@ -1312,7 +1312,17 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
_ => {
let orig_macro_rules_scope = self.parent_scope.macro_rules;
self.build_reduced_graph_for_item(item);
visit::walk_item(self, item);
match item.kind {
ItemKind::Mod(..) => {
// Visit attributes after items for backward compatibility.
// This way they can use `macro_rules` defined later.
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
item.kind.walk(item, AssocCtxt::Trait, self);
visit::walk_list!(self, visit_attribute, &item.attrs);
}
_ => visit::walk_item(self, item),
}
match item.kind {
ItemKind::Mod(..) if self.contains_macro_use(&item.attrs) => {
self.parent_scope.macro_rules
Expand Down Expand Up @@ -1502,7 +1512,10 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
if krate.is_placeholder {
self.visit_invoc_in_module(krate.id);
} else {
visit::walk_crate(self, krate);
// Visit attributes after items for backward compatibility.
// This way they can use `macro_rules` defined later.
visit::walk_list!(self, visit_item, &krate.items);
visit::walk_list!(self, visit_attribute, &krate.attrs);
self.contains_macro_use(&krate.attrs);
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
false,
false,
None,
) {
suggestions.extend(
ext.helper_attrs
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
parent_scope,
true,
force,
None,
) {
Ok((Some(ext), _)) => {
if ext.helper_attrs.contains(&ident.name) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4144,7 +4144,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
if let Ok((_, res)) =
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false)
self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
{
return Ok(Some(PartialRes::new(res)));
}
Expand Down
73 changes: 63 additions & 10 deletions compiler/rustc_resolve/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
use crate::Namespace::*;
use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
use crate::{BuiltinMacroState, Determinacy, MacroData, NameBindingKind, Used};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::expand::StrippedCfgItem;
Expand All @@ -18,15 +18,18 @@ use rustc_errors::{Applicability, StashKey};
use rustc_expand::base::{Annotatable, DeriveResolution, Indeterminate, ResolverExpand};
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
use rustc_expand::expand::{
AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion,
};
use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
use rustc_middle::middle::stability;
use rustc_middle::ty::RegisteredTools;
use rustc_middle::ty::{TyCtxt, Visibility};
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE};
use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
use rustc_session::lint::builtin::{
LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, SOFT_UNSTABLE,
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACROS, UNUSED_MACRO_RULES,
};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::parse::feature_err;
use rustc_span::edit_distance::edit_distance;
Expand Down Expand Up @@ -277,6 +280,15 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
let parent_scope = &ParentScope { derives, ..parent_scope };
let supports_macro_expansion = invoc.fragment_kind.supports_macro_expansion();
let node_id = invoc.expansion_data.lint_node_id;
let invoc_in_mod_inert_attr = self
.invocation_parents
.get(&invoc_id)
.or_else(|| self.invocation_parents.get(&eager_expansion_root))
.map(|&(mod_def_id, _)| mod_def_id)
.filter(|&mod_def_id| {
invoc.fragment_kind == AstFragmentKind::Expr
&& self.tcx.def_kind(mod_def_id) == DefKind::Mod
});
let (ext, res) = self.smart_resolve_macro_path(
path,
kind,
Expand All @@ -286,6 +298,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
node_id,
force,
soft_custom_inner_attributes_gate(path, invoc),
invoc_in_mod_inert_attr,
)?;

let span = invoc.span();
Expand Down Expand Up @@ -366,6 +379,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
&parent_scope,
true,
force,
None,
) {
Ok((Some(ext), _)) => {
if !ext.helper_attrs.is_empty() {
Expand Down Expand Up @@ -468,9 +482,16 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
node_id: NodeId,
force: bool,
soft_custom_inner_attributes_gate: bool,
invoc_in_mod_inert_attr: Option<LocalDefId>,
) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_path(path, Some(kind), parent_scope, true, force)
{
let (ext, res) = match self.resolve_macro_path(
path,
Some(kind),
parent_scope,
true,
force,
invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
) {
Ok((Some(ext), res)) => (ext, res),
Ok((None, res)) => (self.dummy_ext(kind), res),
Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err),
Expand Down Expand Up @@ -600,14 +621,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {

pub(crate) fn resolve_macro_path(
&mut self,
path: &ast::Path,
ast_path: &ast::Path,
kind: Option<MacroKind>,
parent_scope: &ParentScope<'a>,
trace: bool,
force: bool,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
) -> Result<(Option<Lrc<SyntaxExtension>>, Res), Determinacy> {
let path_span = path.span;
let mut path = Segment::from_path(path);
let path_span = ast_path.span;
let mut path = Segment::from_path(ast_path);

// Possibly apply the macro helper hack
if kind == Some(MacroKind::Bang)
Expand Down Expand Up @@ -667,6 +689,37 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {

let res = binding.map(|binding| binding.res());
self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span);
if let Ok(binding) = binding
&& matches!(binding.kind, NameBindingKind::Res(..))
&& let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr
&& let Ok(Res::Def(DefKind::Macro(MacroKind::Bang), def_id)) = res
&& self.tcx.parent(def_id) == mod_def_id.to_def_id()
{
let tralala = self.early_resolve_ident_in_lexical_scope(
path[0].ident,
scope_set,
&ParentScope {
macro_rules: self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty),
..*parent_scope
},
None,
false,
None,
);

if tralala.ok().and_then(|binding| binding.res().opt_def_id()) == Some(def_id) {
// Nothing
} else {
self.tcx.sess.psess.buffer_lint(
OUT_OF_SCOPE_MACRO_CALLS,
path_span,
node_id,
BuiltinLintDiag::OutOfScopeMacroCalls {
path: pprust::path_to_string(ast_path),
},
);
}
}
res
};

Expand Down
16 changes: 16 additions & 0 deletions tests/ui/attributes/key-value-expansion-scope-pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ check-pass
//@ edition:2018

#![doc = in_root!()]

macro_rules! in_root { () => { "" } }
use in_root;

mod macros_stay {
#![doc = in_mod!()]

macro_rules! in_mod { () => { "" } }
use in_mod;
}

fn main() {}
12 changes: 10 additions & 2 deletions tests/ui/attributes/key-value-expansion-scope.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope
//~| WARN this was previously accepted by the compiler
#![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope
#![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope
#![doc = in_mod_escape!()] //FIXME ERROR cannot find macro `in_mod_escape` in this scope
#![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope

#[doc = in_root!()] //~ ERROR cannot find macro `in_root` in this scope
Expand All @@ -16,8 +17,11 @@ fn before() {

macro_rules! in_root { () => { "" } }

#[doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope
//~| WARN this was previously accepted by the compiler
mod macros_stay {
#![doc = in_mod!()] //~ ERROR cannot find macro `in_mod` in this scope
//~| WARN this was previously accepted by the compiler

macro_rules! in_mod { () => { "" } }

Expand All @@ -28,8 +32,11 @@ mod macros_stay {
}

#[macro_use]
#[doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope
//~| WARN this was previously accepted by the compiler
mod macros_escape {
#![doc = in_mod_escape!()] //~ ERROR cannot find macro `in_mod_escape` in this scope
//~| WARN this was previously accepted by the compiler

macro_rules! in_mod_escape { () => { "" } }

Expand All @@ -39,8 +46,9 @@ mod macros_escape {
}
}

#[doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope
fn block() {
#![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope
#![doc = in_block!()] //~ ERROR cannot find macro `in_block` in this scope

macro_rules! in_block { () => { "" } }

Expand Down
Loading

0 comments on commit 60f733e

Please sign in to comment.