Rollup merge of #138842 - Noratrieb:inline-exported, r=me,saethlin

Emit `unused_attributes` for `#[inline]` on exported functions

I saw someone post a code sample that contained these two attributes, which immediately made me suspicious.
My suspicions were confirmed when I did a small test and checked the compiler source code to confirm that in these cases, `#[inline]` is indeed ignored (because you can't exactly `LocalCopy`an unmangled symbol since that would lead to duplicate symbols, and doing a mix of an unmangled `GloballyShared` and mangled `LocalCopy` instantiation is too complicated for our current instatiation mode logic, which I don't want to change right now).

So instead, emit the usual unused attribute lint with a message saying that the attribute is ignored in this position.

I think this is not 100% true, since I expect LLVM `inlinehint` to still be applied to such a function, but that's not why people use this attribute, they use it for the `LocalCopy` instantiation mode, where it doesn't work.

r? saethlin as the instantiation guy

Procedurally, I think this should be fine to merge without any lang involvement, as this only does a very minor extension to an existing lint.
This commit is contained in:
Matthias Krüger 2025-03-31 14:36:22 +02:00 committed by GitHub
commit ac05597cd7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 96 additions and 6 deletions

View file

@ -383,6 +383,10 @@ passes_inline_ignored_constants =
.warn = {-passes_previously_accepted}
.note = {-passes_see_issue(issue: "65833")}
passes_inline_ignored_for_exported =
`#[inline]` is ignored on externally exported functions
.help = externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
passes_inline_ignored_function_prototype =
`#[inline]` is ignored on function prototypes

View file

@ -451,6 +451,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
});
}
}
// `#[inline]` is ignored if the symbol must be codegened upstream because it's exported.
if let Some(did) = hir_id.as_owner()
&& self.tcx.def_kind(did).has_codegen_attrs()
&& !matches!(attr.meta_item_list().as_deref(), Some([item]) if item.has_name(sym::never))
{
let attrs = self.tcx.codegen_fn_attrs(did);
// Not checking naked as `#[inline]` is forbidden for naked functions anyways.
if attrs.contains_extern_indicator() {
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
errors::InlineIgnoredForExported {},
);
}
}
}
/// Checks that `#[coverage(..)]` is applied to a function/closure/method,

View file

@ -1441,6 +1441,11 @@ pub(crate) struct OnlyHasEffectOn {
pub target_name: String,
}
#[derive(LintDiagnostic)]
#[diag(passes_inline_ignored_for_exported)]
#[help]
pub(crate) struct InlineIgnoredForExported {}
#[derive(Diagnostic)]
#[diag(passes_object_lifetime_err)]
pub(crate) struct ObjectLifetimeErr {