Port #[no_mangle] to new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
This commit is contained in:
parent
111e9bc64b
commit
2084831cd5
17 changed files with 120 additions and 80 deletions
|
|
@ -244,6 +244,9 @@ pub enum AttributeKind {
|
|||
reason: Option<Symbol>,
|
||||
},
|
||||
|
||||
/// Represents `#[no_mangle]`
|
||||
NoMangle(Span),
|
||||
|
||||
/// Represents `#[optimize(size|speed)]`
|
||||
Optimize(OptimizeAttr, Span),
|
||||
|
||||
|
|
|
|||
|
|
@ -56,3 +56,21 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
|
|||
Some(AttributeKind::Cold(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct NoMangleParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for NoMangleParser {
|
||||
const PATH: &[rustc_span::Symbol] = &[sym::no_mangle];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
if !args.no_args() {
|
||||
cx.expected_no_args(args.span().unwrap_or(cx.attr_span));
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(AttributeKind::NoMangle(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_session::Session;
|
|||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||
use crate::attributes::codegen_attrs::{ColdParser, OptimizeParser};
|
||||
use crate::attributes::codegen_attrs::{ColdParser, NoMangleParser, OptimizeParser};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
|
|
@ -114,6 +114,7 @@ attribute_parsers!(
|
|||
Single<InlineParser>,
|
||||
Single<MayDangleParser>,
|
||||
Single<MustUseParser>,
|
||||
Single<NoMangleParser>,
|
||||
Single<OptimizeParser>,
|
||||
Single<PubTransparentParser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
|
|
|
|||
|
|
@ -221,6 +221,8 @@ codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple time
|
|||
|
||||
codegen_ssa_no_field = no field `{$name}`
|
||||
|
||||
codegen_ssa_no_mangle_nameless = `#[no_mangle]` cannot be used on {$definition} as it has no name
|
||||
|
||||
codegen_ssa_no_module_named =
|
||||
no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ use rustc_span::{Ident, Span, sym};
|
|||
use rustc_target::spec::SanitizerSet;
|
||||
|
||||
use crate::errors;
|
||||
use crate::errors::NoMangleNameless;
|
||||
use crate::target_features::{
|
||||
check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr,
|
||||
};
|
||||
|
|
@ -87,7 +88,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
let mut link_ordinal_span = None;
|
||||
let mut no_sanitize_span = None;
|
||||
let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
|
||||
let mut no_mangle_span = None;
|
||||
|
||||
for attr in attrs.iter() {
|
||||
// In some cases, attribute are only valid on functions, but it's the `check_attr`
|
||||
|
|
@ -122,6 +122,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
|
||||
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
|
||||
AttributeKind::NoMangle(attr_span) => {
|
||||
if tcx.opt_item_name(did.to_def_id()).is_some() {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
mixed_export_name_no_mangle_lint_state.track_no_mangle(
|
||||
*attr_span,
|
||||
tcx.local_def_id_to_hir_id(did),
|
||||
attr,
|
||||
);
|
||||
} else {
|
||||
tcx.dcx().emit_err(NoMangleNameless {
|
||||
span: *attr_span,
|
||||
definition: format!(
|
||||
"{} {}",
|
||||
tcx.def_descr_article(did.to_def_id()),
|
||||
tcx.def_descr(did.to_def_id())
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -141,28 +160,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
|
||||
}
|
||||
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
|
||||
sym::no_mangle => {
|
||||
no_mangle_span = Some(attr.span());
|
||||
if tcx.opt_item_name(did.to_def_id()).is_some() {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
mixed_export_name_no_mangle_lint_state.track_no_mangle(
|
||||
attr.span(),
|
||||
tcx.local_def_id_to_hir_id(did),
|
||||
attr,
|
||||
);
|
||||
} else {
|
||||
tcx.dcx()
|
||||
.struct_span_err(
|
||||
attr.span(),
|
||||
format!(
|
||||
"`#[no_mangle]` cannot be used on {} {} as it has no name",
|
||||
tcx.def_descr_article(did.to_def_id()),
|
||||
tcx.def_descr(did.to_def_id()),
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
sym::rustc_std_internal_symbol => {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
|
||||
}
|
||||
|
|
@ -544,12 +541,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
&& codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
||||
{
|
||||
let no_mangle_span =
|
||||
find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span)
|
||||
.unwrap_or_default();
|
||||
let lang_item =
|
||||
lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name));
|
||||
let mut err = tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
no_mangle_span.unwrap_or_default(),
|
||||
no_mangle_span,
|
||||
"`#[no_mangle]` cannot be used on internal language items",
|
||||
)
|
||||
.with_note("Rustc requires this item to have a specific mangled name.")
|
||||
|
|
|
|||
|
|
@ -1310,3 +1310,11 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_
|
|||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_no_mangle_nameless)]
|
||||
pub(crate) struct NoMangleNameless {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub definition: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
|||
use rustc_ast::visit::{FnCtxt, FnKind};
|
||||
use rustc_ast::{self as ast, *};
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_errors::{Applicability, LintDiagnostic};
|
||||
use rustc_feature::GateIssue;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -954,7 +955,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN
|
|||
impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
let attrs = cx.tcx.hir_attrs(it.hir_id());
|
||||
let check_no_mangle_on_generic_fn = |attr: &hir::Attribute,
|
||||
let check_no_mangle_on_generic_fn = |attr_span: Span,
|
||||
impl_generics: Option<&hir::Generics<'_>>,
|
||||
generics: &hir::Generics<'_>,
|
||||
span| {
|
||||
|
|
@ -967,7 +968,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
|||
cx.emit_span_lint(
|
||||
NO_MANGLE_GENERIC_ITEMS,
|
||||
span,
|
||||
BuiltinNoMangleGeneric { suggestion: attr.span() },
|
||||
BuiltinNoMangleGeneric { suggestion: attr_span },
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
@ -976,14 +977,15 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
|
|||
};
|
||||
match it.kind {
|
||||
hir::ItemKind::Fn { generics, .. } => {
|
||||
if let Some(attr) = attr::find_by_name(attrs, sym::export_name)
|
||||
.or_else(|| attr::find_by_name(attrs, sym::no_mangle))
|
||||
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))
|
||||
{
|
||||
check_no_mangle_on_generic_fn(attr, None, generics, it.span);
|
||||
check_no_mangle_on_generic_fn(attr_span, None, generics, it.span);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Const(..) => {
|
||||
if attr::contains_name(attrs, sym::no_mangle) {
|
||||
if find_attr!(attrs, AttributeKind::NoMangle(..)) {
|
||||
// account for "pub const" (#45562)
|
||||
let start = cx
|
||||
.tcx
|
||||
|
|
@ -1008,11 +1010,12 @@ 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) = attr::find_by_name(attrs, sym::export_name)
|
||||
.or_else(|| attr::find_by_name(attrs, sym::no_mangle))
|
||||
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))
|
||||
{
|
||||
check_no_mangle_on_generic_fn(
|
||||
attr,
|
||||
attr_span,
|
||||
Some(generics),
|
||||
cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(),
|
||||
it.span,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_abi::ExternAbi;
|
||||
use rustc_attr_data_structures::{AttributeKind, ReprAttr};
|
||||
use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
|
||||
use rustc_attr_parsing::AttributeParser;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::intravisit::FnKind;
|
||||
|
|
@ -396,7 +396,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
|||
match &fk {
|
||||
FnKind::Method(ident, sig, ..) => match method_context(cx, id) {
|
||||
MethodLateContext::PlainImpl => {
|
||||
if sig.header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) {
|
||||
if sig.header.abi != ExternAbi::Rust
|
||||
&& find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..))
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.check_snake_case(cx, "method", ident);
|
||||
|
|
@ -408,7 +410,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
|
|||
},
|
||||
FnKind::ItemFn(ident, _, header) => {
|
||||
// Skip foreign-ABI #[no_mangle] functions (Issue #31924)
|
||||
if header.abi != ExternAbi::Rust && cx.tcx.has_attr(id, sym::no_mangle) {
|
||||
if header.abi != ExternAbi::Rust
|
||||
&& find_attr!(cx.tcx.get_all_attrs(id), AttributeKind::NoMangle(..))
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.check_snake_case(cx, "function", ident);
|
||||
|
|
@ -514,7 +518,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
|
|||
let attrs = cx.tcx.hir_attrs(it.hir_id());
|
||||
match it.kind {
|
||||
hir::ItemKind::Static(_, ident, ..)
|
||||
if !ast::attr::contains_name(attrs, sym::no_mangle) =>
|
||||
if !find_attr!(attrs, AttributeKind::NoMangle(..)) =>
|
||||
{
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &ident);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,6 +174,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
Attribute::Parsed(AttributeKind::MustUse { span, .. }) => {
|
||||
self.check_must_use(hir_id, *span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::NoMangle(attr_span)) => {
|
||||
self.check_no_mangle(hir_id, *attr_span, span, target)
|
||||
}
|
||||
Attribute::Unparsed(attr_item) => {
|
||||
style = Some(attr_item.style);
|
||||
match attr.path().as_slice() {
|
||||
|
|
@ -261,7 +264,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
[sym::link, ..] => self.check_link(hir_id, attr, span, target),
|
||||
[sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
|
||||
[sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
|
||||
[sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
|
||||
[sym::macro_use, ..] | [sym::macro_escape, ..] => {
|
||||
self.check_macro_use(hir_id, attr, target)
|
||||
}
|
||||
|
|
@ -698,6 +700,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
AttributeKind::Deprecation { .. }
|
||||
| AttributeKind::Repr { .. }
|
||||
| AttributeKind::Align { .. }
|
||||
| AttributeKind::NoMangle(..)
|
||||
| AttributeKind::Cold(..)
|
||||
| AttributeKind::MustUse { .. },
|
||||
) => {
|
||||
|
|
@ -1952,7 +1955,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
|
||||
/// Checks if `#[no_mangle]` is applied to a function or static.
|
||||
fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
|
||||
fn check_no_mangle(&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) => {}
|
||||
|
|
@ -1961,7 +1964,7 @@ 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(), "no_mangle");
|
||||
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "no_mangle");
|
||||
}
|
||||
// FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error
|
||||
// The error should specify that the item that is wrong is specifically a *foreign* fn/static
|
||||
|
|
@ -1975,8 +1978,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.tcx.emit_node_span_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span(),
|
||||
errors::NoMangleForeign { span, attr_span: attr.span(), foreign_item_kind },
|
||||
attr_span,
|
||||
errors::NoMangleForeign { span, attr_span, foreign_item_kind },
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -1985,7 +1988,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
self.tcx.emit_node_span_lint(
|
||||
UNUSED_ATTRIBUTES,
|
||||
hir_id,
|
||||
attr.span(),
|
||||
attr_span,
|
||||
errors::NoMangle { span },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -746,15 +746,17 @@ impl Item {
|
|||
Some(tcx.visibility(def_id))
|
||||
}
|
||||
|
||||
pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
|
||||
fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
|
||||
const ALLOWED_ATTRIBUTES: &[Symbol] =
|
||||
&[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
|
||||
|
||||
self.attrs
|
||||
.other_attrs
|
||||
.iter()
|
||||
.filter_map(|attr| {
|
||||
if is_json {
|
||||
// NoMangle is special-cased because cargo-semver-checks uses it
|
||||
if matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..))) {
|
||||
Some("#[no_mangle]".to_string())
|
||||
} else if is_json {
|
||||
match attr {
|
||||
// rustdoc-json stores this in `Item::deprecation`, so we
|
||||
// don't want it it `Item::attrs`.
|
||||
|
|
@ -767,26 +769,22 @@ impl Item {
|
|||
s
|
||||
}),
|
||||
}
|
||||
} else if attr.has_any_name(ALLOWED_ATTRIBUTES) {
|
||||
} else {
|
||||
if !attr.has_any_name(ALLOWED_ATTRIBUTES) {
|
||||
return None;
|
||||
}
|
||||
Some(
|
||||
rustc_hir_pretty::attribute_to_string(&tcx, attr)
|
||||
.replace("\\\n", "")
|
||||
.replace('\n', "")
|
||||
.replace(" ", " "),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn attributes_and_repr(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
cache: &Cache,
|
||||
is_json: bool,
|
||||
) -> Vec<String> {
|
||||
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
|
||||
let mut attrs = self.attributes_without_repr(tcx, is_json);
|
||||
|
||||
if let Some(repr_attr) = self.repr(tcx, cache, is_json) {
|
||||
|
|
|
|||
|
|
@ -1194,7 +1194,7 @@ fn render_assoc_item(
|
|||
// a whitespace prefix and newline.
|
||||
fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| {
|
||||
for a in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
|
||||
for a in it.attributes(cx.tcx(), cx.cache(), false) {
|
||||
writeln!(f, "{prefix}{a}")?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -1210,7 +1210,7 @@ fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) {
|
|||
// When an attribute is rendered inside a <code> tag, it is formatted using
|
||||
// a div to produce a newline after it.
|
||||
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
|
||||
for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
|
||||
for attr in it.attributes(cx.tcx(), cx.cache(), false) {
|
||||
render_code_attribute(CodeAttribute(attr), w);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1491,7 +1491,7 @@ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
|
|||
writeln!(f, "{repr}")?;
|
||||
};
|
||||
} else {
|
||||
for a in self.it.attributes_and_repr(self.cx.tcx(), self.cx.cache(), false) {
|
||||
for a in self.it.attributes(self.cx.tcx(), self.cx.cache(), false) {
|
||||
writeln!(f, "{a}")?;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ impl JsonRenderer<'_> {
|
|||
})
|
||||
.collect();
|
||||
let docs = item.opt_doc_value();
|
||||
let attrs = item.attributes_and_repr(self.tcx, &self.cache, true);
|
||||
let attrs = item.attributes(self.tcx, &self.cache, true);
|
||||
let span = item.span(self.tcx);
|
||||
let visibility = item.visibility(self.tcx);
|
||||
let clean::ItemInner { name, item_id, .. } = *item.inner;
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
|
|||
// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
|
||||
// are deliberately not in a doc comment, because they need not be in public docs.)
|
||||
//
|
||||
// Latest feature: Pretty printing of must_use attributes changed
|
||||
pub const FORMAT_VERSION: u32 = 52;
|
||||
// Latest feature: Pretty printing of no_mangle attributes changed
|
||||
pub const FORMAT_VERSION: u32 = 53;
|
||||
|
||||
/// The root of the emitted JSON blob.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@ use clippy_utils::ty::is_must_use_ty;
|
|||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{return_ty, trait_ref_of_method};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_span::Symbol;
|
||||
use rustc_attr_data_structures::find_attr;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
|
|||
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
|
||||
if let Some((attr_span, reason)) = attr {
|
||||
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, *attr_span, *reason, attrs, sig);
|
||||
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
|
||||
} else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) {
|
||||
check_must_use_candidate(
|
||||
cx,
|
||||
sig.decl,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use rustc_hir::{Item, ItemKind};
|
|||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::{BytePos, Pos};
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_hir::Attribute;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -44,8 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
|
|||
let mut app = Applicability::MaybeIncorrect;
|
||||
let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app);
|
||||
for attr in attrs {
|
||||
if let Some(ident) = attr.ident()
|
||||
&& ident.name == rustc_span::sym::no_mangle
|
||||
if let Attribute::Parsed(AttributeKind::NoMangle(attr_span)) = attr
|
||||
&& fn_sig.header.abi == ExternAbi::Rust
|
||||
&& let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn")
|
||||
&& !fn_attrs.contains("extern")
|
||||
|
|
@ -54,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
|
|||
.span
|
||||
.with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
|
||||
.shrink_to_lo();
|
||||
let attr_snippet = snippet(cx, attr.span(), "..");
|
||||
let attr_snippet = snippet(cx, *attr_span, "..");
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -114,18 +114,6 @@ 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
|
||||
|
|
||||
LL | #[no_mangle]
|
||||
| ^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/unused-attr-duplicate.rs:97:1
|
||||
|
|
||||
LL | #[no_mangle]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: unused attribute
|
||||
--> $DIR/unused-attr-duplicate.rs:102:1
|
||||
|
|
||||
|
|
@ -289,5 +277,17 @@ note: attribute also specified here
|
|||
LL | #[cold]
|
||||
| ^^^^^^^
|
||||
|
||||
error: unused attribute
|
||||
--> $DIR/unused-attr-duplicate.rs:98:1
|
||||
|
|
||||
LL | #[no_mangle]
|
||||
| ^^^^^^^^^^^^ help: remove this attribute
|
||||
|
|
||||
note: attribute also specified here
|
||||
--> $DIR/unused-attr-duplicate.rs:97:1
|
||||
|
|
||||
LL | #[no_mangle]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 23 previous errors
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue