Skip to content

Commit 8162cf5

Browse files
Rollup merge of #156242 - Jamesbarford:feat/remove-alwaysinline+target-feature, r=RalfJung,saethlin
Remove unsound `target_feature_inline_always` feature ## Summary - Remove `target_feature_inline_always` - Update stdarch generators to only use `#[inline]` & regenerate stdarch. ## Why? Succinctly; the feature relies on LLVMs `AlwaysInlinerPass()` running before LLVMs heuristic based inliner pass. Which is not a basis for sound code. This has been discussed in [the tracking issue](#145574). If the ordering of the passes were to change, of which they have in the past, it is very possible we could inline functions across callsites with mismatching target features leading to unsound code. Checks proposed in; #155426 would only take into account caller -> callee which is not enough to guard against possibly of generating unsound code if the pass ordering were to change. There doesn't seem to be a way, presently, this this mechanism to provide soundness guarantees nor does it seem like `AlwaysInlinerPass()` is a desired feature of LLVM, which this feature relies on. r? @RalfJung
2 parents b954122 + 405214d commit 8162cf5

19 files changed

Lines changed: 49 additions & 448 deletions

File tree

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,13 @@ pub(crate) fn remove_string_attr_from_llfn(llfn: &Value, name: &str) {
4141
}
4242

4343
/// Get LLVM attribute for the provided inline heuristic.
44-
pub(crate) fn inline_attr<'ll, 'tcx>(
44+
#[inline]
45+
fn inline_attr<'ll>(
4546
cx: &SimpleCx<'ll>,
46-
tcx: TyCtxt<'tcx>,
47-
instance: ty::Instance<'tcx>,
47+
sess: &Session,
48+
inline: InlineAttr,
4849
) -> Option<&'ll Attribute> {
49-
// `optnone` requires `noinline`
50-
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
51-
let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
52-
(_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
53-
(InlineAttr::None, _) if instance.def.requires_inline(tcx) => InlineAttr::Hint,
54-
(inline, _) => inline,
55-
};
56-
57-
if !tcx.sess.opts.unstable_opts.inline_llvm {
50+
if !sess.opts.unstable_opts.inline_llvm {
5851
// disable LLVM inlining
5952
return Some(AttributeKind::NoInline.create_attr(cx.llcx));
6053
}
@@ -64,7 +57,7 @@ pub(crate) fn inline_attr<'ll, 'tcx>(
6457
Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
6558
}
6659
InlineAttr::Never => {
67-
if tcx.sess.target.arch != Arch::AmdGpu {
60+
if sess.target.arch != Arch::AmdGpu {
6861
Some(AttributeKind::NoInline.create_attr(cx.llcx))
6962
} else {
7063
None
@@ -418,6 +411,17 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
418411
OptimizeAttr::Speed => {}
419412
}
420413

414+
if let Some(instance) = instance {
415+
// `optnone` requires `noinline`
416+
let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
417+
(_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
418+
(InlineAttr::None, _) if instance.def.requires_inline(tcx) => InlineAttr::Hint,
419+
(inline, _) => inline,
420+
};
421+
422+
to_add.extend(inline_attr(cx, sess, inline));
423+
}
424+
421425
if sess.must_emit_unwind_tables() {
422426
to_add.push(uwtable_attr(cx.llcx, sess.opts.unstable_opts.use_sync_unwind));
423427
}
@@ -568,16 +572,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
568572
let function_features =
569573
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
570574

571-
// Apply function attributes as per usual if there are no user defined
572-
// target features otherwise this will get applied at the callsite.
573-
if function_features.is_empty() {
574-
if let Some(instance) = instance
575-
&& let Some(inline_attr) = inline_attr(cx, tcx, instance)
576-
{
577-
to_add.push(inline_attr);
578-
}
579-
}
580-
581575
let function_features = function_features
582576
.iter()
583577
// Convert to LLVMFeatures and filter out unavailable ones

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
1515
use rustc_codegen_ssa::traits::*;
1616
use rustc_data_structures::small_c_str::SmallCStr;
1717
use rustc_hir::def_id::DefId;
18-
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature, TargetFeatureKind};
18+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
1919
use rustc_middle::ty::layout::{
2020
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
2121
TyAndLayout,
@@ -1419,32 +1419,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
14191419
)
14201420
};
14211421

1422-
if let Some(callee_instance) = callee_instance {
1423-
// Attributes on the function definition being called
1424-
let callee_attrs = self.cx.tcx.codegen_fn_attrs(callee_instance.def_id());
1425-
if let Some(caller_attrs) = caller_attrs
1426-
// If there is an inline attribute and a target feature that matches
1427-
// we will add the attribute to the callsite otherwise we'll omit
1428-
// this and not add the attribute to prevent soundness issues.
1429-
&& let Some(inlining_rule) = attributes::inline_attr(&self.cx, self.cx.tcx, callee_instance)
1430-
&& self.cx.tcx.is_target_feature_call_safe(
1431-
&callee_attrs.target_features,
1432-
&caller_attrs.target_features.iter().cloned().chain(
1433-
self.cx.tcx.sess.target_features.iter().map(|feat| TargetFeature {
1434-
name: *feat,
1435-
kind: TargetFeatureKind::Implied,
1436-
})
1437-
).collect::<Vec<_>>(),
1438-
)
1439-
{
1440-
attributes::apply_to_callsite(
1441-
call,
1442-
llvm::AttributePlace::Function,
1443-
&[inlining_rule],
1444-
);
1445-
}
1446-
}
1447-
14481422
if let Some(fn_abi) = fn_abi {
14491423
fn_abi.apply_attrs_callsite(self, call);
14501424
}

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -419,16 +419,16 @@ fn check_result(
419419
// llvm/llvm-project#70563).
420420
if !codegen_fn_attrs.target_features.is_empty()
421421
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
422-
&& !tcx.features().target_feature_inline_always()
423422
&& let Some(span) = interesting_spans.inline
424423
{
425-
feature_err(
426-
tcx.sess,
427-
sym::target_feature_inline_always,
428-
span,
429-
"cannot use `#[inline(always)]` with `#[target_feature]`",
430-
)
431-
.emit();
424+
let mut diag = tcx
425+
.dcx()
426+
.struct_span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
427+
diag.note(
428+
"See this issue for full discussion: \
429+
https://github.com/rust-lang/rust/issues/145574",
430+
);
431+
diag.emit();
432432
}
433433

434434
// warn that inline has no effect when no_sanitize is present

compiler/rustc_feature/src/removed.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ declare_features! (
282282
/// Allows string patterns to dereference values to match them.
283283
(removed, string_deref_patterns, "1.94.0", Some(87121), Some("superseded by `deref_patterns`"), 150530),
284284
(removed, struct_inherit, "1.0.0", None, None),
285+
/// Allows the use of target_feature when a function is marked inline(always).
286+
(removed, target_feature_inline_always, "CURRENT_RUSTC_VERSION", Some(145574),
287+
Some("removed because of unfixable soundness issues")),
285288
(removed, test_removed_feature, "1.0.0", None, None),
286289
/// Allows using items which are missing stability attributes
287290
(removed, unmarked_api, "1.0.0", None, None),

compiler/rustc_feature/src/unstable.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,8 +727,6 @@ declare_features! (
727727
(unstable, super_let, "1.88.0", Some(139076)),
728728
/// Allows subtrait items to shadow supertrait items.
729729
(unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
730-
/// Allows the use of target_feature when a function is marked inline(always).
731-
(unstable, target_feature_inline_always, "1.91.0", Some(145574)),
732730
/// Allows using `#[thread_local]` on `static` items.
733731
(unstable, thread_local, "1.0.0", Some(29594)),
734732
/// Allows defining `trait X = A + B;` alias items.

compiler/rustc_lint/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,10 @@ fn register_builtins(store: &mut LintStore) {
644644
);
645645
store.register_removed("wasm_c_abi", "the wasm C ABI has been fixed");
646646
store.register_removed("soft_unstable", "the general soft-unstable mechanism has been removed");
647+
store.register_removed(
648+
"inline_always_mismatching_target_features",
649+
"replaced by a hard error for `#[inline(always)]` with `#[target_feature]`",
650+
);
647651
}
648652

649653
fn register_internals(store: &mut LintStore) {

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ declare_lint_pass! {
5656
ILL_FORMED_ATTRIBUTE_INPUT,
5757
INCOMPLETE_INCLUDE,
5858
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
59-
INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
6059
INLINE_NO_SANITIZE,
6160
INVALID_DOC_ATTRIBUTES,
6261
INVALID_MACRO_EXPORT_ARGUMENTS,
@@ -5492,61 +5491,6 @@ declare_lint! {
54925491
"detects tail calls of functions marked with `#[track_caller]`",
54935492
@feature_gate = explicit_tail_calls;
54945493
}
5495-
declare_lint! {
5496-
/// The `inline_always_mismatching_target_features` lint will trigger when a
5497-
/// function with the `#[inline(always)]` and `#[target_feature(enable = "...")]`
5498-
/// attributes is called and cannot be inlined due to missing target features in the caller.
5499-
///
5500-
/// ### Example
5501-
///
5502-
/// ```rust,ignore (fails on x86_64)
5503-
/// #[inline(always)]
5504-
/// #[target_feature(enable = "fp16")]
5505-
/// unsafe fn callee() {
5506-
/// // operations using fp16 types
5507-
/// }
5508-
///
5509-
/// // Caller does not enable the required target feature
5510-
/// fn caller() {
5511-
/// unsafe { callee(); }
5512-
/// }
5513-
///
5514-
/// fn main() {
5515-
/// caller();
5516-
/// }
5517-
/// ```
5518-
///
5519-
/// This will produce:
5520-
///
5521-
/// ```text
5522-
/// warning: call to `#[inline(always)]`-annotated `callee` requires the same target features. Function will not have `alwaysinline` attribute applied
5523-
/// --> $DIR/builtin.rs:5192:14
5524-
/// |
5525-
/// 10 | unsafe { callee(); }
5526-
/// | ^^^^^^^^
5527-
/// |
5528-
/// note: `fp16` target feature enabled in `callee` here but missing from `caller`
5529-
/// --> $DIR/builtin.rs:5185:1
5530-
/// |
5531-
/// 3 | #[target_feature(enable = "fp16")]
5532-
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5533-
/// 4 | unsafe fn callee() {
5534-
/// | ------------------
5535-
/// = note: `#[warn(inline_always_mismatching_target_features)]` on by default
5536-
/// warning: 1 warning emitted
5537-
/// ```
5538-
///
5539-
/// ### Explanation
5540-
///
5541-
/// Inlining a function with a target feature attribute into a caller that
5542-
/// lacks the corresponding target feature can lead to unsound behavior.
5543-
/// LLVM may select the wrong instructions or registers, or reorder
5544-
/// operations, potentially resulting in runtime errors.
5545-
pub INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
5546-
Warn,
5547-
r#"detects when a function annotated with `#[inline(always)]` and `#[target_feature(enable = "..")]` is inlined into a caller without the required target feature"#,
5548-
}
5549-
55505494
declare_lint! {
55515495
/// The `repr_c_enums_larger_than_int` lint detects `repr(C)` enums with discriminant
55525496
/// values that do not fit into a C `int` or `unsigned int`.

compiler/rustc_mir_transform/src/check_inline_always_target_features.rs

Lines changed: 0 additions & 88 deletions
This file was deleted.

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,52 +5,11 @@ use rustc_errors::{
55
};
66
use rustc_macros::{Diagnostic, Subdiagnostic};
77
use rustc_middle::mir::AssertKind;
8-
use rustc_middle::query::QueryKey;
98
use rustc_middle::ty::TyCtxt;
109
use rustc_session::lint::{self, Lint};
1110
use rustc_span::def_id::DefId;
1211
use rustc_span::{Ident, Span, Symbol};
1312

14-
/// Emit diagnostic for calls to `#[inline(always)]`-annotated functions with a
15-
/// `#[target_feature]` attribute where the caller enables a different set of target features.
16-
pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>(
17-
tcx: TyCtxt<'tcx>,
18-
call_span: Span,
19-
callee_def_id: DefId,
20-
caller_def_id: DefId,
21-
callee_only: &[&'a str],
22-
) {
23-
tcx.emit_node_span_lint(
24-
lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
25-
tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()),
26-
call_span,
27-
rustc_errors::DiagDecorator(|lint| {
28-
let callee = tcx.def_path_str(callee_def_id);
29-
let caller = tcx.def_path_str(caller_def_id);
30-
31-
lint.primary_message(format!(
32-
"call to `#[inline(always)]`-annotated `{callee}` \
33-
requires the same target features to be inlined"
34-
));
35-
lint.note("function will not be inlined");
36-
37-
lint.note(format!(
38-
"the following target features are on `{callee}` but missing from `{caller}`: {}",
39-
callee_only.join(", ")
40-
));
41-
lint.span_note(callee_def_id.default_span(tcx), format!("`{callee}` is defined here"));
42-
43-
let feats = callee_only.join(",");
44-
lint.span_suggestion(
45-
tcx.def_span(caller_def_id).shrink_to_lo(),
46-
format!("add `#[target_feature]` attribute to `{caller}`"),
47-
format!("#[target_feature(enable = \"{feats}\")]\n"),
48-
lint::Applicability::MaybeIncorrect,
49-
);
50-
}),
51-
);
52-
}
53-
5413
#[derive(Diagnostic)]
5514
#[diag("function cannot return without recursing")]
5615
#[help("a `loop` may express intention better if this is on purpose")]

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ declare_passes! {
122122
mod add_subtyping_projections : Subtyper;
123123
mod check_inline : CheckForceInline;
124124
mod check_call_recursion : CheckCallRecursion, CheckDropRecursion;
125-
mod check_inline_always_target_features: CheckInlineAlwaysTargetFeature;
126125
mod check_alignment : CheckAlignment;
127126
mod check_enums : CheckEnums;
128127
mod check_const_item_mutation : CheckConstItemMutation;
@@ -403,9 +402,6 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
403402
// MIR-level lints.
404403
&Lint(check_inline::CheckForceInline),
405404
&Lint(check_call_recursion::CheckCallRecursion),
406-
// Check callee's target features match callers target features when
407-
// using `#[inline(always)]`
408-
&Lint(check_inline_always_target_features::CheckInlineAlwaysTargetFeature),
409405
&Lint(check_packed_ref::CheckPackedRef),
410406
&Lint(check_const_item_mutation::CheckConstItemMutation),
411407
&Lint(function_item_references::FunctionItemReferences),

0 commit comments

Comments
 (0)