Port #[export_name] to the new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
This commit is contained in:
parent
bc4376fa73
commit
287d9afce7
13 changed files with 84 additions and 46 deletions
|
|
@ -231,6 +231,14 @@ pub enum AttributeKind {
|
|||
/// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
|
||||
DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
|
||||
|
||||
/// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
|
||||
ExportName {
|
||||
/// The name to export this item with.
|
||||
/// It may not contain \0 bytes as it will be converted to a null-terminated string.
|
||||
name: Symbol,
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[inline]` and `#[rustc_force_inline]`.
|
||||
Inline(InlineAttr, Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ impl AttributeKind {
|
|||
ConstStabilityIndirect => No,
|
||||
Deprecation { .. } => Yes,
|
||||
DocComment { .. } => Yes,
|
||||
ExportName { .. } => Yes,
|
||||
Inline(..) => No,
|
||||
MacroTransparency(..) => Yes,
|
||||
Repr(..) => No,
|
||||
|
|
|
|||
|
|
@ -93,9 +93,12 @@ attr_parsing_naked_functions_incompatible_attribute =
|
|||
attribute incompatible with `#[unsafe(naked)]`
|
||||
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
|
||||
.naked_attribute = function marked with `#[unsafe(naked)]` here
|
||||
|
||||
attr_parsing_non_ident_feature =
|
||||
'feature' is not an identifier
|
||||
|
||||
attr_parsing_null_on_export = `export_name` may not contain null characters
|
||||
|
||||
attr_parsing_repr_ident =
|
||||
meta item in `repr` must be an identifier
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use rustc_span::{Span, Symbol, sym};
|
|||
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics::NakedFunctionIncompatibleAttribute;
|
||||
use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
|
||||
|
||||
pub(crate) struct OptimizeParser;
|
||||
|
||||
|
|
@ -59,6 +59,33 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ExportNameParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
let Some(name) = nv.value_as_str() else {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
if name.as_str().contains('\0') {
|
||||
// `#[export_name = ...]` will be converted to a null-terminated string,
|
||||
// so it may not contain any null characters.
|
||||
cx.emit_err(NullOnExport { span: cx.attr_span });
|
||||
return None;
|
||||
}
|
||||
Some(AttributeKind::ExportName { name, span: cx.attr_span })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct NakedParser {
|
||||
span: Option<Span>,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
|||
|
||||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
|
||||
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
|
|
@ -117,6 +117,7 @@ attribute_parsers!(
|
|||
Single<ConstContinueParser>,
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<ExportNameParser>,
|
||||
Single<InlineParser>,
|
||||
Single<LoopMatchParser>,
|
||||
Single<MayDangleParser>,
|
||||
|
|
|
|||
|
|
@ -445,6 +445,13 @@ pub(crate) struct MustUseIllFormedAttributeInput {
|
|||
pub suggestions: DiagArgValue,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_null_on_export, code = E0648)]
|
||||
pub(crate) struct NullOnExport {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_stability_outside_std, code = E0734)]
|
||||
pub(crate) struct StabilityOutsideStd {
|
||||
|
|
|
|||
|
|
@ -230,8 +230,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
|
|||
|
||||
codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't
|
||||
|
||||
codegen_ssa_null_on_export = `export_name` may not contain null characters
|
||||
|
||||
codegen_ssa_out_of_range_integer = integer value out of range
|
||||
.label = value must be between `0` and `255`
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
.max();
|
||||
}
|
||||
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
|
||||
AttributeKind::ExportName { name, span: attr_span } => {
|
||||
codegen_fn_attrs.export_name = Some(*name);
|
||||
mixed_export_name_no_mangle_lint_state.track_export_name(*attr_span);
|
||||
}
|
||||
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
|
||||
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
|
||||
AttributeKind::NoMangle(attr_span) => {
|
||||
|
|
@ -223,17 +227,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
||||
sym::export_name => {
|
||||
if let Some(s) = attr.value_str() {
|
||||
if s.as_str().contains('\0') {
|
||||
// `#[export_name = ...]` will be converted to a null-terminated string,
|
||||
// so it may not contain any null characters.
|
||||
tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() });
|
||||
}
|
||||
codegen_fn_attrs.export_name = Some(s);
|
||||
mixed_export_name_no_mangle_lint_state.track_export_name(attr.span());
|
||||
}
|
||||
}
|
||||
sym::target_feature => {
|
||||
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||
tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn");
|
||||
|
|
|
|||
|
|
@ -140,13 +140,6 @@ pub(crate) struct RequiresRustAbi {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_null_on_export, code = E0648)]
|
||||
pub(crate) struct NullOnExport {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_unsupported_instruction_set, code = E0779)]
|
||||
pub(crate) struct UnsupportedInstructionSet {
|
||||
|
|
|
|||
|
|
@ -977,9 +977,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
|||
};
|
||||
match it.kind {
|
||||
hir::ItemKind::Fn { generics, .. } => {
|
||||
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
|
||||
.map(|at| at.span())
|
||||
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
|
||||
if let Some(attr_span) =
|
||||
find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
|
||||
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
|
||||
{
|
||||
check_no_mangle_on_generic_fn(attr_span, None, generics, it.span);
|
||||
}
|
||||
|
|
@ -1010,9 +1010,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
|||
for it in *items {
|
||||
if let hir::AssocItemKind::Fn { .. } = it.kind {
|
||||
let attrs = cx.tcx.hir_attrs(it.id.hir_id());
|
||||
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
|
||||
.map(|at| at.span())
|
||||
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
|
||||
if let Some(attr_span) =
|
||||
find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
|
||||
.or_else(
|
||||
|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span),
|
||||
)
|
||||
{
|
||||
check_no_mangle_on_generic_fn(
|
||||
attr_span,
|
||||
|
|
|
|||
|
|
@ -169,6 +169,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::Cold(attr_span)) => {
|
||||
self.check_cold(hir_id, *attr_span, span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::ExportName { span: attr_span, .. }) => {
|
||||
self.check_export_name(hir_id, *attr_span, span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
|
||||
self.check_align(span, target, *align, *repr_span)
|
||||
}
|
||||
|
|
@ -223,7 +226,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
&mut doc_aliases,
|
||||
),
|
||||
[sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
|
||||
[sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
|
||||
[sym::rustc_layout_scalar_valid_range_start, ..]
|
||||
| [sym::rustc_layout_scalar_valid_range_end, ..] => {
|
||||
self.check_rustc_layout_scalar_valid_range(attr, span, target)
|
||||
|
|
@ -1653,7 +1655,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
|
||||
/// Checks if `#[export_name]` is applied to a function or static.
|
||||
fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
|
||||
fn check_export_name(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
|
||||
match target {
|
||||
Target::Static | Target::Fn => {}
|
||||
Target::Method(..) if self.is_impl_item(hir_id) => {}
|
||||
|
|
@ -1662,10 +1664,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
// erroneously allowed it and some crates used it accidentally, to be compatible
|
||||
// with crates depending on them, we can't throw an error here.
|
||||
Target::Field | Target::Arm | Target::MacroDef => {
|
||||
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name");
|
||||
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "export_name");
|
||||
}
|
||||
_ => {
|
||||
self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span });
|
||||
self.dcx().emit_err(errors::ExportName { attr_span, span });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -755,8 +755,11 @@ impl Item {
|
|||
.filter_map(|attr| {
|
||||
// NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
|
||||
// It is also used by cargo-semver-checks.
|
||||
if matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..))) {
|
||||
if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
|
||||
Some("#[no_mangle]".to_string())
|
||||
} else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
|
||||
{
|
||||
Some(format!("#[export_name = \"{name}\"]"))
|
||||
} else if is_json {
|
||||
match attr {
|
||||
// rustdoc-json stores this in `Item::deprecation`, so we
|
||||
|
|
|
|||
|
|
@ -89,19 +89,6 @@ note: attribute also specified here
|
|||
LL | #[automatically_derived]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unused attribute
|
||||
--> $DIR/unused-attr-duplicate.rs:92:1
|
||||
|
|
||||
LL | #[export_name = "exported_symbol_name"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/unused-attr-duplicate.rs:94:1
|
||||
|
|
||||
LL | #[export_name = "exported_symbol_name2"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
error: unused attribute
|
||||
--> $DIR/unused-attr-duplicate.rs:102:1
|
||||
|
|
||||
|
|
@ -277,6 +264,19 @@ note: attribute also specified here
|
|||
LL | #[track_caller]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: unused attribute
|
||||
--> $DIR/unused-attr-duplicate.rs:92:1
|
||||
|
|
||||
LL | #[export_name = "exported_symbol_name"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/unused-attr-duplicate.rs:94:1
|
||||
|
|
||||
LL | #[export_name = "exported_symbol_name2"]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
||||
error: unused attribute
|
||||
--> $DIR/unused-attr-duplicate.rs:98:1
|
||||
|
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue