Skip to content

Commit 73fd02f

Browse files
committed
fixed target_feature 1.1 should print the list of missing target features
1 parent adc719d commit 73fd02f

File tree

4 files changed

+177
-39
lines changed

4 files changed

+177
-39
lines changed

compiler/rustc_middle/src/mir/query.rs

+77-6
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use crate::mir::ConstantKind;
44
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
55
use rustc_data_structures::fx::FxIndexMap;
66
use rustc_data_structures::unord::UnordSet;
7-
use rustc_errors::ErrorGuaranteed;
7+
use rustc_errors::{pluralize, ErrorGuaranteed};
88
use rustc_hir as hir;
99
use rustc_hir::def_id::LocalDefId;
1010
use rustc_index::bit_set::BitMatrix;
1111
use rustc_index::{Idx, IndexVec};
12-
use rustc_span::Span;
12+
use rustc_span::{Span, Symbol};
1313
use rustc_target::abi::{FieldIdx, VariantIdx};
1414
use smallvec::SmallVec;
1515
use std::cell::Cell;
@@ -26,7 +26,7 @@ pub enum UnsafetyViolationKind {
2626
UnsafeFn,
2727
}
2828

29-
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
29+
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
3030
pub enum UnsafetyViolationDetails {
3131
CallToUnsafeFunction,
3232
UseOfInlineAssembly,
@@ -38,10 +38,81 @@ pub enum UnsafetyViolationDetails {
3838
AccessToUnionField,
3939
MutationOfLayoutConstrainedField,
4040
BorrowOfLayoutConstrainedField,
41-
CallToFunctionWith,
41+
CallToFunctionWith { missing_features: Vec<Symbol>, target_features: Vec<Symbol> },
4242
}
4343

4444
impl UnsafetyViolationDetails {
45+
fn missing_features(&self) -> Vec<Symbol> {
46+
match self {
47+
UnsafetyViolationDetails::CallToFunctionWith {
48+
missing_features,
49+
target_features: _,
50+
} => missing_features.to_vec(),
51+
_ => Vec::<Symbol>::new(),
52+
}
53+
}
54+
55+
fn target_features(&self) -> Vec<Symbol> {
56+
match self {
57+
UnsafetyViolationDetails::CallToFunctionWith {
58+
missing_features: _,
59+
target_features,
60+
} => target_features.to_vec(),
61+
_ => Vec::<Symbol>::new(),
62+
}
63+
}
64+
65+
pub fn note_missing_features(&self) -> Option<String> {
66+
let target_features_symbol = self.target_features();
67+
let target_features =
68+
target_features_symbol.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
69+
70+
if !target_features.is_empty() {
71+
let target_features_str = if target_features.len() > 1 {
72+
let l_target_features = target_features[..target_features.len() - 1].join(", ");
73+
let last_target_feature = target_features.last().unwrap();
74+
format!("{} and {}", l_target_features, last_target_feature)
75+
} else {
76+
target_features.last().unwrap().to_string()
77+
};
78+
79+
Some(format!(
80+
"the {} target feature{} being enabled in the build configuration does not remove the requirement to list {} in `#[target_feature]`",
81+
target_features_str,
82+
pluralize!(target_features.len()),
83+
if target_features.len() == 1 { "it" } else { "them" },
84+
))
85+
} else {
86+
None
87+
}
88+
}
89+
90+
pub fn help_missing_features(&self) -> Option<String> {
91+
let missing_features = self.missing_features();
92+
93+
if !missing_features.is_empty() {
94+
let missing_features_str = if missing_features.len() > 1 {
95+
let l_missing_features = missing_features[..missing_features.len() - 1]
96+
.iter()
97+
.map(|feature| feature.as_str())
98+
.collect::<Vec<&str>>()
99+
.join(", ");
100+
let last_missing_feature = missing_features.last().unwrap().as_str();
101+
format!("{} and {}", l_missing_features, last_missing_feature)
102+
} else {
103+
missing_features.last().unwrap().to_string()
104+
};
105+
106+
Some(format!(
107+
"in order for the call to be safe, the context requires the following additional target feature{}: {}.",
108+
pluralize!(missing_features.len()),
109+
missing_features_str,
110+
))
111+
} else {
112+
None
113+
}
114+
}
115+
45116
pub fn description_and_note(&self) -> (&'static str, &'static str) {
46117
use UnsafetyViolationDetails::*;
47118
match self {
@@ -91,15 +162,15 @@ impl UnsafetyViolationDetails {
91162
"references to fields of layout constrained fields lose the constraints. Coupled \
92163
with interior mutability, the field can be changed to invalid values",
93164
),
94-
CallToFunctionWith => (
165+
CallToFunctionWith { missing_features: _, target_features: _ } => (
95166
"call to function with `#[target_feature]`",
96167
"can only be called if the required target features are available",
97168
),
98169
}
99170
}
100171
}
101172

102-
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
173+
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
103174
pub struct UnsafetyViolation {
104175
pub source_info: SourceInfo,
105176
pub lint_root: hir::HirId,

compiler/rustc_mir_transform/src/check_unsafety.rs

+36-14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_middle::query::Providers;
1111
use rustc_middle::ty::{self, TyCtxt};
1212
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
1313
use rustc_session::lint::Level;
14+
use rustc_span::Symbol;
1415

1516
use std::ops::Bound;
1617

@@ -287,22 +288,23 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
287288
.safety;
288289
match safety {
289290
// `unsafe` blocks are required in safe code
290-
Safety::Safe => violations.into_iter().for_each(|&violation| {
291+
Safety::Safe => violations.into_iter().for_each(|violation| {
291292
match violation.kind {
292293
UnsafetyViolationKind::General => {}
293294
UnsafetyViolationKind::UnsafeFn => {
294295
bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
295296
}
296297
}
297298
if !self.violations.contains(&violation) {
298-
self.violations.push(violation)
299+
self.violations.push(violation.clone())
299300
}
300301
}),
301302
// With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
302-
Safety::FnUnsafe => violations.into_iter().for_each(|&(mut violation)| {
303-
violation.kind = UnsafetyViolationKind::UnsafeFn;
304-
if !self.violations.contains(&violation) {
305-
self.violations.push(violation)
303+
Safety::FnUnsafe => violations.into_iter().for_each(|violation| {
304+
let mut violation_copy = violation.clone();
305+
violation_copy.kind = UnsafetyViolationKind::UnsafeFn;
306+
if !self.violations.contains(&violation_copy) {
307+
self.violations.push(violation_copy)
306308
}
307309
}),
308310
Safety::BuiltinUnsafe => {}
@@ -367,9 +369,22 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
367369

368370
// Is `callee_features` a subset of `calling_features`?
369371
if !callee_features.iter().all(|feature| self_features.contains(feature)) {
372+
let missing_features = callee_features
373+
.iter()
374+
.filter(|feature| !self_features.contains(feature))
375+
.cloned()
376+
.collect::<Vec<Symbol>>();
377+
let target_features = self
378+
.tcx
379+
.sess
380+
.target_features
381+
.iter()
382+
.filter(|feature| missing_features.contains(feature))
383+
.cloned()
384+
.collect::<Vec<Symbol>>();
370385
self.require_unsafe(
371386
UnsafetyViolationKind::General,
372-
UnsafetyViolationDetails::CallToFunctionWith,
387+
UnsafetyViolationDetails::CallToFunctionWith { missing_features, target_features },
373388
)
374389
}
375390
}
@@ -526,13 +541,14 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
526541

527542
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
528543

529-
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
530-
let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };
544+
for UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
545+
let unsafe_details =
546+
errors::RequiresUnsafeDetail { violation: details.clone(), span: source_info.span };
531547

532548
match kind {
533549
UnsafetyViolationKind::General => {
534-
let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
535-
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
550+
let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, *lint_root);
551+
let note_non_inherited = tcx.hir().parent_iter(*lint_root).find(|(id, node)| {
536552
if let Node::Expr(block) = node
537553
&& let ExprKind::Block(block, _) = block.kind
538554
&& let BlockCheckMode::UnsafeBlock(_) = block.rules
@@ -555,15 +571,21 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
555571
tcx.sess.emit_err(errors::RequiresUnsafe {
556572
span: source_info.span,
557573
enclosing,
558-
details,
574+
details: unsafe_details,
559575
op_in_unsafe_fn_allowed,
576+
help: details.help_missing_features(),
577+
note_missing_features: details.note_missing_features(),
560578
});
561579
}
562580
UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
563581
UNSAFE_OP_IN_UNSAFE_FN,
564-
lint_root,
582+
*lint_root,
565583
source_info.span,
566-
errors::UnsafeOpInUnsafeFn { details },
584+
errors::UnsafeOpInUnsafeFn {
585+
details: unsafe_details,
586+
help: details.help_missing_features(),
587+
note_missing_features: details.note_missing_features(),
588+
},
567589
),
568590
}
569591
}

compiler/rustc_mir_transform/src/errors.rs

+50-9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ pub(crate) struct RequiresUnsafe {
4949
pub details: RequiresUnsafeDetail,
5050
pub enclosing: Option<Span>,
5151
pub op_in_unsafe_fn_allowed: bool,
52+
pub help: Option<String>,
53+
pub note_missing_features: Option<String>,
5254
}
5355

5456
// The primary message for this diagnostic should be '{$label} is unsafe and...',
@@ -62,9 +64,27 @@ impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe {
6264
handler.struct_diagnostic(crate::fluent_generated::mir_transform_requires_unsafe);
6365
diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
6466
diag.set_span(self.span);
65-
diag.span_label(self.span, self.details.label());
66-
diag.note(self.details.note());
67-
let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
67+
diag.span_label(self.span, self.details.clone().label());
68+
if let Some(help) = self.help {
69+
diag.help(help);
70+
}
71+
72+
match self.details.violation {
73+
UnsafetyViolationDetails::CallToFunctionWith {
74+
missing_features: _,
75+
target_features: _,
76+
} => {
77+
if let Some(note_missing_features) = self.note_missing_features {
78+
diag.note(note_missing_features);
79+
}
80+
}
81+
_ => {
82+
diag.note(self.details.clone().note());
83+
}
84+
}
85+
86+
let desc =
87+
handler.eagerly_translate_to_string(self.details.clone().label(), [].into_iter());
6888
diag.set_arg("details", desc);
6989
diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
7090
if let Some(sp) = self.enclosing {
@@ -74,7 +94,7 @@ impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe {
7494
}
7595
}
7696

77-
#[derive(Copy, Clone)]
97+
#[derive(Clone)]
7898
pub(crate) struct RequiresUnsafeDetail {
7999
pub span: Span,
80100
pub violation: UnsafetyViolationDetails,
@@ -100,7 +120,9 @@ impl RequiresUnsafeDetail {
100120
BorrowOfLayoutConstrainedField => {
101121
crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_note
102122
}
103-
CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_note,
123+
CallToFunctionWith { missing_features: _, target_features: _ } => {
124+
crate::fluent_generated::mir_transform_target_feature_call_note
125+
}
104126
}
105127
}
106128

@@ -123,13 +145,17 @@ impl RequiresUnsafeDetail {
123145
BorrowOfLayoutConstrainedField => {
124146
crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_label
125147
}
126-
CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_label,
148+
CallToFunctionWith { missing_features: _, target_features: _ } => {
149+
crate::fluent_generated::mir_transform_target_feature_call_label
150+
}
127151
}
128152
}
129153
}
130154

131155
pub(crate) struct UnsafeOpInUnsafeFn {
132156
pub details: RequiresUnsafeDetail,
157+
pub help: Option<String>,
158+
pub note_missing_features: Option<String>,
133159
}
134160

135161
impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
@@ -141,10 +167,25 @@ impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
141167
let desc = diag
142168
.handler()
143169
.expect("lint should not yet be emitted")
144-
.eagerly_translate_to_string(self.details.label(), [].into_iter());
170+
.eagerly_translate_to_string(self.details.clone().label(), [].into_iter());
145171
diag.set_arg("details", desc);
146-
diag.span_label(self.details.span, self.details.label());
147-
diag.note(self.details.note());
172+
diag.span_label(self.details.clone().span, self.details.clone().label());
173+
if let Some(help) = self.help {
174+
diag.help(help);
175+
}
176+
match self.details.violation {
177+
UnsafetyViolationDetails::CallToFunctionWith {
178+
missing_features: _,
179+
target_features: _,
180+
} => {
181+
if let Some(note_missing_features) = self.note_missing_features {
182+
diag.note(note_missing_features);
183+
}
184+
}
185+
_ => {
186+
diag.note(self.details.note());
187+
}
188+
}
148189
diag
149190
}
150191

0 commit comments

Comments
 (0)