Skip to content

Commit ac05597

Browse files
authored
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.
2 parents 0a579d5 + 1aed58c commit ac05597

File tree

8 files changed

+96
-6
lines changed

8 files changed

+96
-6
lines changed

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ impl CodegenFnAttrs {
172172
/// * `#[no_mangle]` is present
173173
/// * `#[export_name(...)]` is present
174174
/// * `#[linkage]` is present
175+
///
176+
/// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint.
175177
pub fn contains_extern_indicator(&self) -> bool {
176178
self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
177179
|| self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)

compiler/rustc_middle/src/mir/mono.rs

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ impl<'tcx> MonoItem<'tcx> {
150150

151151
// If the function is #[naked] or contains any other attribute that requires exactly-once
152152
// instantiation:
153+
// We emit an unused_attributes lint for this case, which should be kept in sync if possible.
153154
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
154155
if codegen_fn_attrs.contains_extern_indicator()
155156
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)

compiler/rustc_passes/messages.ftl

+4
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ passes_inline_ignored_constants =
383383
.warn = {-passes_previously_accepted}
384384
.note = {-passes_see_issue(issue: "65833")}
385385
386+
passes_inline_ignored_for_exported =
387+
`#[inline]` is ignored on externally exported functions
388+
.help = externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
389+
386390
passes_inline_ignored_function_prototype =
387391
`#[inline]` is ignored on function prototypes
388392

compiler/rustc_passes/src/check_attr.rs

+17
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
451451
});
452452
}
453453
}
454+
455+
// `#[inline]` is ignored if the symbol must be codegened upstream because it's exported.
456+
if let Some(did) = hir_id.as_owner()
457+
&& self.tcx.def_kind(did).has_codegen_attrs()
458+
&& !matches!(attr.meta_item_list().as_deref(), Some([item]) if item.has_name(sym::never))
459+
{
460+
let attrs = self.tcx.codegen_fn_attrs(did);
461+
// Not checking naked as `#[inline]` is forbidden for naked functions anyways.
462+
if attrs.contains_extern_indicator() {
463+
self.tcx.emit_node_span_lint(
464+
UNUSED_ATTRIBUTES,
465+
hir_id,
466+
attr.span(),
467+
errors::InlineIgnoredForExported {},
468+
);
469+
}
470+
}
454471
}
455472

456473
/// Checks that `#[coverage(..)]` is applied to a function/closure/method,

compiler/rustc_passes/src/errors.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1441,6 +1441,11 @@ pub(crate) struct OnlyHasEffectOn {
14411441
pub target_name: String,
14421442
}
14431443

1444+
#[derive(LintDiagnostic)]
1445+
#[diag(passes_inline_ignored_for_exported)]
1446+
#[help]
1447+
pub(crate) struct InlineIgnoredForExported {}
1448+
14441449
#[derive(Diagnostic)]
14451450
#[diag(passes_object_lifetime_err)]
14461451
pub(crate) struct ObjectLifetimeErr {

tests/ui/lint/inline-exported.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//! Ensure the unused_attributes lint fires for externally exported functions with `#[inline]`,
2+
//! because `#[inline]` is ignored for such functions.
3+
4+
#![crate_type = "lib"]
5+
6+
#![feature(linkage)]
7+
#![feature(naked_functions)]
8+
#![deny(unused_attributes)]
9+
10+
#[inline]
11+
//~^ ERROR: `#[inline]` is ignored on externally exported functions
12+
#[no_mangle]
13+
fn no_mangle() {}
14+
15+
#[inline]
16+
//~^ ERROR: `#[inline]` is ignored on externally exported functions
17+
#[export_name = "export_name"]
18+
fn export_name() {}
19+
20+
#[inline]
21+
//~^ ERROR: `#[inline]` is ignored on externally exported functions
22+
#[linkage = "external"]
23+
fn external_linkage() {}
24+
25+
#[inline]
26+
fn normal() {}
27+
28+
#[inline]
29+
#[linkage = "internal"] // not exported
30+
fn internal_linkage() {}

tests/ui/lint/inline-exported.stderr

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error: `#[inline]` is ignored on externally exported functions
2+
--> $DIR/inline-exported.rs:10:1
3+
|
4+
LL | #[inline]
5+
| ^^^^^^^^^
6+
|
7+
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
8+
note: the lint level is defined here
9+
--> $DIR/inline-exported.rs:8:9
10+
|
11+
LL | #![deny(unused_attributes)]
12+
| ^^^^^^^^^^^^^^^^^
13+
14+
error: `#[inline]` is ignored on externally exported functions
15+
--> $DIR/inline-exported.rs:15:1
16+
|
17+
LL | #[inline]
18+
| ^^^^^^^^^
19+
|
20+
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
21+
22+
error: `#[inline]` is ignored on externally exported functions
23+
--> $DIR/inline-exported.rs:20:1
24+
|
25+
LL | #[inline]
26+
| ^^^^^^^^^
27+
|
28+
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
29+
30+
error: aborting due to 3 previous errors
31+

tests/ui/target-feature/invalid-attribute.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ LL |
9898
LL | trait Baz {}
9999
| ------------ not a function definition
100100

101+
error: cannot use `#[inline(always)]` with `#[target_feature]`
102+
--> $DIR/invalid-attribute.rs:69:1
103+
|
104+
LL | #[inline(always)]
105+
| ^^^^^^^^^^^^^^^^^
106+
101107
error: attribute should be applied to a function definition
102108
--> $DIR/invalid-attribute.rs:74:1
103109
|
@@ -163,12 +169,6 @@ error: malformed `target_feature` attribute input
163169
LL | #[target_feature(disable = "baz")]
164170
| ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."`
165171

166-
error: cannot use `#[inline(always)]` with `#[target_feature]`
167-
--> $DIR/invalid-attribute.rs:69:1
168-
|
169-
LL | #[inline(always)]
170-
| ^^^^^^^^^^^^^^^^^
171-
172172
error[E0046]: not all trait items implemented, missing: `foo`
173173
--> $DIR/invalid-attribute.rs:81:1
174174
|

0 commit comments

Comments
 (0)