Skip to content
Closed
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
63 changes: 63 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use rustc_ast::AttrStyle;
use rustc_errors::DiagArgValue;
use rustc_hir::attrs::MacroUseArgs;

Expand Down Expand Up @@ -133,3 +134,65 @@ impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
]);
const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
}

pub(crate) struct MacroExportParser;

impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
const PATH: &[Symbol] = &[sym::macro_export];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const TEMPLATE: AttributeTemplate = template!(Word, List: &["local_inner_macros"]);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::MacroDef),
Error(Target::WherePredicate),
Error(Target::Crate),
]);

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let suggestions = || {
<Self as SingleAttributeParser<S>>::TEMPLATE
.suggestions(AttrStyle::Inner, "macro_export")
};
let local_inner_macros = match args {
ArgParser::NoArgs => false,
ArgParser::List(list) => {
let Some(l) = list.single() else {
let span = cx.attr_span;
cx.emit_lint(
AttributeLintKind::InvalidMacroExportArguments {
suggestions: suggestions(),
},
span,
);
return None;
};
match l.meta_item().and_then(|i| i.path().word_sym()) {
Some(sym::local_inner_macros) => true,
_ => {
let span = cx.attr_span;
cx.emit_lint(
AttributeLintKind::InvalidMacroExportArguments {
suggestions: suggestions(),
},
span,
);
return None;
}
}
}
ArgParser::NameValue(_) => {
let span = cx.attr_span;
let suggestions = suggestions();
cx.emit_err(IllFormedAttributeInputLint {
num_suggestions: suggestions.len(),
suggestions: DiagArgValue::StrListSepByAnd(
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
),
span,
});
return None;
}
};
Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
}
}
3 changes: 2 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use crate::attributes::lint_helpers::{
};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{
AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser,
};
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
Expand Down Expand Up @@ -183,6 +183,7 @@ attribute_parsers!(
Single<LinkOrdinalParser>,
Single<LinkSectionParser>,
Single<LinkageParser>,
Single<MacroExportParser>,
Single<MoveSizeLimitParser>,
Single<MustUseParser>,
Single<ObjcClassParser>,
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_attr_parsing/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<L::Id>, lint_emi
},
);
}
AttributeLintKind::InvalidMacroExportArguments { suggestions } => lint_emitter
.emit_node_span_lint(
rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS,
*id,
*span,
session_diagnostics::IllFormedAttributeInput {
num_suggestions: suggestions.len(),
suggestions: DiagArgValue::StrListSepByAnd(
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
),
},
),
AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint(
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
*id,
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,9 +942,9 @@ impl SyntaxExtension {
.unwrap_or_default();
let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe(_));

let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export)
.and_then(|macro_export| macro_export.meta_item_list())
.is_some_and(|l| ast::attr::list_contains_name(&l, sym::local_inner_macros));
let local_inner_macros =
*find_attr!(attrs, AttributeKind::MacroExport {local_inner_macros: l, ..} => l)
.unwrap_or(&false);
let collapse_debuginfo = Self::get_collapse_debuginfo(sess, attrs, !is_local);
tracing::debug!(?name, ?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,9 @@ pub enum AttributeKind {
/// Represents `#[macro_escape]`.
MacroEscape(Span),

/// Represents [`#[macro_export]`](https://doc.rust-lang.org/reference/macros-by-example.html#r-macro.decl.scope.path).
MacroExport { span: Span, local_inner_macros: bool },

/// Represents `#[rustc_macro_transparency]`.
MacroTransparency(Transparency),

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl AttributeKind {
Linkage(..) => No,
LoopMatch(..) => No,
MacroEscape(..) => No,
MacroExport { .. } => Yes,
MacroTransparency(..) => Yes,
MacroUse { .. } => No,
Marker(..) => No,
Expand Down
35 changes: 30 additions & 5 deletions compiler/rustc_hir/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,34 @@ pub struct AttributeLint<Id> {

#[derive(Clone, Debug, HashStable_Generic)]
pub enum AttributeLintKind {
UnusedDuplicate { this: Span, other: Span, warning: bool },
IllFormedAttributeInput { suggestions: Vec<String> },
EmptyAttribute { first_span: Span },
InvalidTarget { name: AttrPath, target: Target, applied: Vec<String>, only: &'static str },
InvalidStyle { name: AttrPath, is_used_as_inner: bool, target: Target, target_span: Span },
UnusedDuplicate {
this: Span,
other: Span,
warning: bool,
},
IllFormedAttributeInput {
suggestions: Vec<String>,
},
EmptyAttribute {
first_span: Span,
},

/// Copy of `IllFormedAttributeInput`
/// specifically for the `invalid_macro_export_arguments` lint until that is removed,
/// see <https://github.com/rust-lang/rust/pull/143857#issuecomment-3079175663>
InvalidMacroExportArguments {
suggestions: Vec<String>,
},
InvalidTarget {
name: AttrPath,
target: Target,
applied: Vec<String>,
only: &'static str,
},
InvalidStyle {
name: AttrPath,
is_used_as_inner: bool,
target: Target,
target_span: Span,
},
}
10 changes: 7 additions & 3 deletions compiler/rustc_lint/src/non_local_def.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use rustc_errors::MultiSpan;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind};
use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind, find_attr};
use rustc_middle::ty::TyCtxt;
use rustc_session::{declare_lint, impl_lint_pass};
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::{ExpnKind, Span, kw, sym};
use rustc_span::{ExpnKind, Span, kw};

use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
Expand Down Expand Up @@ -241,7 +242,10 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
)
}
ItemKind::Macro(_, _macro, _kinds)
if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
if find_attr!(
cx.tcx.get_all_attrs(item.owner_id.def_id),
AttributeKind::MacroExport { .. }
) =>
{
cx.emit_span_lint(
NON_LOCAL_DEFINITIONS,
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4191,8 +4191,13 @@ declare_lint! {
/// You can't have multiple arguments in a `#[macro_export(..)]`, or mention arguments other than `local_inner_macros`.
///
pub INVALID_MACRO_EXPORT_ARGUMENTS,
Warn,
Deny,
"\"invalid_parameter\" isn't a valid argument for `#[macro_export]`",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseError,
reference: "issue #57571 <https://github.com/rust-lang/rust/issues/57571>",
report_in_deps: true,
};
}

declare_lint! {
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,6 @@ passes_invalid_attr_at_crate_level =
passes_invalid_attr_at_crate_level_item =
the inner attribute doesn't annotate this {$kind}

passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument

passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments

passes_lang_item_fn = {$name ->
[panic_impl] `#[panic_handler]`
*[other] `{$name}` lang item
Expand Down Expand Up @@ -392,9 +388,6 @@ passes_loop_match_attr =
`#[loop_match]` should be applied to a loop
.label = not a loop

passes_macro_export =
`#[macro_export]` only has an effect on macro definitions

passes_macro_export_on_decl_macro =
`#[macro_export]` has no effect on declarative macro definitions
.note = declarative macros follow the same exporting rules as regular items
Expand Down
60 changes: 20 additions & 40 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ use rustc_middle::{bug, span_bug};
use rustc_session::config::CrateType;
use rustc_session::lint;
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
MALFORMED_DIAGNOSTIC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES,
MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
};
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition;
Expand Down Expand Up @@ -217,7 +217,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
},
Attribute::Parsed(AttributeKind::Link(_, attr_span)) => {
self.check_link(hir_id, *attr_span, span, target)
}
},
Attribute::Parsed(AttributeKind::MacroExport { span, .. }) => {
self.check_macro_export(hir_id, *span, target)
},
Attribute::Parsed(
AttributeKind::BodyStability { .. }
| AttributeKind::ConstStabilityIndirect
Expand Down Expand Up @@ -331,7 +334,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
[sym::rustc_has_incoherent_inherent_impls, ..] => {
self.check_has_incoherent_inherent_impls(attr, span, target)
}
[sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
[sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
self.check_autodiff(hir_id, attr, span, target)
}
Expand Down Expand Up @@ -1850,45 +1852,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}

fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
fn check_macro_export(&self, hir_id: HirId, attr_span: Span, target: Target) {
if target != Target::MacroDef {
return;
}

// special case when `#[macro_export]` is applied to a macro 2.0
let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
let is_decl_macro = !macro_definition.macro_rules;

if is_decl_macro {
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
errors::MacroExport::Normal,
attr_span,
errors::MacroExport::OnDeclMacro,
);
} else if let Some(meta_item_list) = attr.meta_item_list()
&& !meta_item_list.is_empty()
{
if meta_item_list.len() > 1 {
self.tcx.emit_node_span_lint(
INVALID_MACRO_EXPORT_ARGUMENTS,
hir_id,
attr.span(),
errors::MacroExport::TooManyItems,
);
} else if !meta_item_list[0].has_name(sym::local_inner_macros) {
self.tcx.emit_node_span_lint(
INVALID_MACRO_EXPORT_ARGUMENTS,
hir_id,
meta_item_list[0].span(),
errors::MacroExport::InvalidArgument,
);
}
} else {
// special case when `#[macro_export]` is applied to a macro 2.0
let (_, macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
let is_decl_macro = !macro_definition.macro_rules;

if is_decl_macro {
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
errors::MacroExport::OnDeclMacro,
);
}
}
}

Expand Down Expand Up @@ -2253,7 +2232,9 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
// In the long run, the checks should be harmonized.
if let ItemKind::Macro(_, macro_def, _) = item.kind {
let def_id = item.owner_id.to_def_id();
if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
if macro_def.macro_rules
&& !find_attr!(self.tcx.get_all_attrs(def_id), AttributeKind::MacroExport { .. })
{
check_non_exported_macro_for_invalid_attrs(self.tcx, item);
}
}
Expand Down Expand Up @@ -2384,7 +2365,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
// which were unsuccessfully resolved due to cannot determine
// resolution for the attribute macro error.
const ATTRS_TO_CHECK: &[Symbol] = &[
sym::macro_export,
sym::rustc_main,
sym::derive,
sym::test,
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,18 +530,9 @@ pub(crate) struct RustcForceInlineCoro {

#[derive(LintDiagnostic)]
pub(crate) enum MacroExport {
#[diag(passes_macro_export)]
Normal,

#[diag(passes_macro_export_on_decl_macro)]
#[note]
OnDeclMacro,

#[diag(passes_invalid_macro_export_arguments)]
InvalidArgument,

#[diag(passes_invalid_macro_export_arguments_too_many_items)]
TooManyItems,
}

#[derive(Subdiagnostic)]
Expand Down
Loading
Loading