Skip to content

Commit df654be

Browse files
committed
Update diagnostic messages
1 parent 58ce116 commit df654be

2 files changed

Lines changed: 97 additions & 35 deletions

File tree

compiler/rustc_mir_transform/src/check_inline_always_target_features.rs

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_hir::attrs::InlineAttr;
2-
use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
2+
use rustc_middle::middle::codegen_fn_attrs::TargetFeatureKind;
33
use rustc_middle::mir::{Body, TerminatorKind};
44
use rustc_middle::ty::{self, TyCtxt};
55

@@ -51,36 +51,83 @@ fn check_inline_always_target_features<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx
5151

5252
// Scan the users defined target features and ensure they
5353
// match the caller.
54-
if tcx.is_target_feature_call_safe(
54+
if tcx.is_call_inline_able_at_callsite(
5555
&callee_codegen_fn_attrs.target_features,
56-
&caller_codegen_fn_attrs
57-
.target_features
58-
.iter()
59-
.cloned()
60-
.chain(tcx.sess.target_features.iter().map(|feat| TargetFeature {
61-
name: *feat,
62-
kind: TargetFeatureKind::Implied,
63-
}))
64-
.collect::<Vec<_>>(),
56+
&caller_codegen_fn_attrs.target_features,
6557
) {
6658
continue;
6759
}
6860

69-
let callee_only: Vec<_> = callee_codegen_fn_attrs
61+
// Use the full target feature sets, including implied and
62+
// command-line features, to classify the mismatch. Diagnostic
63+
// messages should still only mention the non-implied features
64+
// that the user actually enabled.
65+
let caller_features =
66+
tcx.effective_inline_target_features(&caller_codegen_fn_attrs.target_features);
67+
let callee_features =
68+
tcx.effective_inline_target_features(&callee_codegen_fn_attrs.target_features);
69+
70+
let explicit_caller_features: Vec<_> = caller_codegen_fn_attrs
71+
.target_features
72+
.iter()
73+
.cloned()
74+
.filter(|it| it.kind != TargetFeatureKind::Implied)
75+
.collect();
76+
let explicit_callee_features: Vec<_> = callee_codegen_fn_attrs
7077
.target_features
7178
.iter()
72-
.filter(|it| !caller_codegen_fn_attrs.target_features.contains(it))
73-
.filter(|it| !matches!(it.kind, TargetFeatureKind::Implied))
74-
.map(|it| it.name.as_str())
79+
.cloned()
80+
.filter(|it| it.kind != TargetFeatureKind::Implied)
7581
.collect();
7682

77-
crate::errors::emit_inline_always_target_feature_diagnostic(
78-
tcx,
79-
terminator.source_info.span,
80-
callee_def_id,
81-
caller_def_id.into(),
82-
&callee_only,
83-
);
83+
let explicit_caller_features =
84+
tcx.effective_inline_target_features(&explicit_caller_features);
85+
let explicit_callee_features =
86+
tcx.effective_inline_target_features(&explicit_callee_features);
87+
88+
// If the callee's features are otherwise a subset of the
89+
// caller's, then the mismatch is only due to the caller using a
90+
// different vector ABI from the callee.
91+
if callee_features.is_subset(&caller_features) {
92+
// We only want to display the target features the user
93+
// missed out. Not every feature that is possibly enabled.
94+
let caller_abi_features = tcx.abi_target_features(&explicit_caller_features);
95+
let callee_abi_features = tcx.abi_target_features(&explicit_callee_features);
96+
let caller_only = caller_abi_features
97+
.difference(&callee_abi_features)
98+
.map(|it| it.as_str())
99+
.collect::<Vec<_>>()
100+
.join(", ");
101+
102+
// Emit that the issue is caused by a vector ABI mismatch.
103+
crate::errors::emit_inline_always_target_feature_diagnostic(
104+
tcx,
105+
terminator.source_info.span,
106+
callee_def_id,
107+
caller_def_id.into(),
108+
&caller_only,
109+
caller_def_id.into(),
110+
callee_def_id,
111+
);
112+
} else {
113+
let callee_only = explicit_callee_features
114+
.difference(&explicit_caller_features)
115+
.map(|it| it.as_str())
116+
.collect::<Vec<_>>()
117+
.join(", ");
118+
119+
// Emit that the issue stems from the callee having features
120+
// enabled that the caller does not have enabled.
121+
crate::errors::emit_inline_always_target_feature_diagnostic(
122+
tcx,
123+
terminator.source_info.span,
124+
callee_def_id,
125+
caller_def_id.into(),
126+
&callee_only,
127+
callee_def_id,
128+
caller_def_id.into(),
129+
);
130+
}
84131
}
85132
_ => (),
86133
}

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,35 @@ use rustc_session::lint::{self, Lint};
1010
use rustc_span::def_id::DefId;
1111
use rustc_span::{Ident, Span, Symbol};
1212

13-
/// Emit diagnostic for calls to `#[inline(always)]`-annotated functions with a
14-
/// `#[target_feature]` attribute where the caller enables a different set of target features.
15-
pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>(
13+
/// Emit the `inline_always_mismatching_target_features` lint for a call to an
14+
/// `#[inline(always)]` function that cannot be inlined at the call site.
15+
///
16+
/// This is used for both direct caller/callee target feature mismatches and
17+
/// vector ABI mismatches. `feature_source_def_id` identifies the side that
18+
/// contributes the missing features, while `feature_target_def_id` identifies
19+
/// the side that should be updated by the suggestion.
20+
pub(crate) fn emit_inline_always_target_feature_diagnostic<'tcx>(
1621
tcx: TyCtxt<'tcx>,
1722
call_span: Span,
1823
callee_def_id: DefId,
1924
caller_def_id: DefId,
20-
callee_only: &[&'a str],
25+
missing_features: &str,
26+
feature_source_def_id: DefId,
27+
feature_target_def_id: DefId,
2128
) {
2229
tcx.emit_node_span_lint(
2330
lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
2431
tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()),
2532
call_span,
2633
rustc_errors::DiagDecorator(|lint| {
34+
// These calls to `tcx.def_path_str(...)` need to live inside this
35+
// closure otherwise can cause an ICE, see;
36+
// https://github.com/rust-lang/rust/pull/150805
2737
let callee = tcx.def_path_str(callee_def_id);
28-
let caller = tcx.def_path_str(caller_def_id);
38+
let feature_target = tcx.def_path_str(feature_target_def_id);
39+
let feature_source = tcx.def_path_str(feature_source_def_id);
40+
41+
let suggested_features = missing_features.replace(", ", ",");
2942

3043
lint.primary_message(format!(
3144
"call to `#[inline(always)]`-annotated `{callee}` \
@@ -34,17 +47,19 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>(
3447
lint.note("function will not be inlined");
3548

3649
lint.note(format!(
37-
"the following target features are on `{callee}` but missing from `{caller}`: {}",
38-
callee_only.join(", ")
50+
"the following target features are on `{feature_source}` but missing from \
51+
`{feature_target}`: {missing_features}"
3952
));
40-
lint.span_note(callee_def_id.default_span(tcx), format!("`{callee}` is defined here"));
53+
lint.span_note(
54+
feature_source_def_id.default_span(tcx),
55+
format!("`{feature_source}` is defined here"),
56+
);
4157

42-
let feats = callee_only.join(",");
4358
lint.span_suggestion(
44-
tcx.def_span(caller_def_id).shrink_to_lo(),
45-
format!("add `#[target_feature]` attribute to `{caller}`"),
46-
format!("#[target_feature(enable = \"{feats}\")]\n"),
47-
lint::Applicability::MaybeIncorrect,
59+
tcx.def_span(feature_target_def_id).shrink_to_lo(),
60+
format!("add `#[target_feature]` attribute to `{feature_target}`"),
61+
format!("#[target_feature(enable = \"{suggested_features}\")]\n"),
62+
Applicability::MaybeIncorrect,
4863
);
4964
}),
5065
);

0 commit comments

Comments
 (0)