thir-unsafeck: print list of missing target features when calling a f… · rust-lang/rust@6b066a9 (original) (raw)
``
1
`+
use std::borrow::Cow;
`
``
2
+
1
3
`use crate::build::ExprCategory;
`
2
4
`use crate::errors::*;
`
3
5
`use rustc_middle::thir::visit::{self, Visitor};
`
4
6
``
``
7
`+
use rustc_errors::DiagnosticArgValue;
`
5
8
`use rustc_hir as hir;
`
6
9
`use rustc_middle::mir::BorrowKind;
`
7
10
`use rustc_middle::thir::*;
`
`@@ -392,15 +395,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
`
392
395
`` // the call requires unsafe
. Don't check this on wasm
``
393
396
`// targets, though. For more information on wasm see the
`
394
397
`// is_like_wasm check in hir_analysis/src/collect.rs
`
``
398
`+
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
`
395
399
`if !self.tcx.sess.target.options.is_like_wasm
`
396
``
`-
&& !self
`
397
``
`-
.tcx
`
398
``
`-
.codegen_fn_attrs(func_did)
`
399
``
`-
.target_features
`
``
400
`+
&& !callee_features
`
400
401
`.iter()
`
401
402
`.all(|feature| self.body_target_features.contains(feature))
`
402
403
`{
`
403
``
`-
self.requires_unsafe(expr.span, CallToFunctionWith(func_did));
`
``
404
`+
let missing: Vec<_> = callee_features
`
``
405
`+
.iter()
`
``
406
`+
.copied()
`
``
407
`+
.filter(|feature| !self.body_target_features.contains(feature))
`
``
408
`+
.collect();
`
``
409
`+
let build_enabled = self
`
``
410
`+
.tcx
`
``
411
`+
.sess
`
``
412
`+
.target_features
`
``
413
`+
.iter()
`
``
414
`+
.copied()
`
``
415
`+
.filter(|feature| missing.contains(feature))
`
``
416
`+
.collect();
`
``
417
`+
self.requires_unsafe(
`
``
418
`+
expr.span,
`
``
419
`+
CallToFunctionWith { function: func_did, missing, build_enabled },
`
``
420
`+
);
`
404
421
`}
`
405
422
`}
`
406
423
`}
`
`@@ -526,7 +543,7 @@ struct UnusedUnsafeWarning {
`
526
543
`enclosing_unsafe: Option,
`
527
544
`}
`
528
545
``
529
``
`-
#[derive(Clone, Copy, PartialEq)]
`
``
546
`+
#[derive(Clone, PartialEq)]
`
530
547
`enum UnsafeOpKind {
`
531
548
`CallToUnsafeFunction(Option),
`
532
549
`UseOfInlineAssembly,
`
`@@ -537,7 +554,15 @@ enum UnsafeOpKind {
`
537
554
`AccessToUnionField,
`
538
555
`MutationOfLayoutConstrainedField,
`
539
556
`BorrowOfLayoutConstrainedField,
`
540
``
`-
CallToFunctionWith(DefId),
`
``
557
`+
CallToFunctionWith {
`
``
558
`+
function: DefId,
`
``
559
`` +
/// Target features enabled in callee's #[target_feature]
but missing in
``
``
560
`` +
/// caller's #[target_feature]
.
``
``
561
`+
missing: Vec,
`
``
562
`` +
/// Target features in missing
that are enabled at compile time
``
``
563
`` +
/// (e.g., with -C target-feature
).
``
``
564
`+
build_enabled: Vec,
`
``
565
`+
},
`
541
566
`}
`
542
567
``
543
568
`use UnsafeOpKind::*;
`
`@@ -658,13 +683,22 @@ impl UnsafeOpKind {
`
658
683
` unsafe_not_inherited_note,
`
659
684
`},
`
660
685
`),
`
661
``
`-
CallToFunctionWith(did) => tcx.emit_spanned_lint(
`
``
686
`+
CallToFunctionWith { function, missing, build_enabled } => tcx.emit_spanned_lint(
`
662
687
`UNSAFE_OP_IN_UNSAFE_FN,
`
663
688
` hir_id,
`
664
689
` span,
`
665
690
`UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
`
666
691
` span,
`
667
``
`-
function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
`
``
692
`+
function: &with_no_trimmed_paths!(tcx.def_path_str(*function)),
`
``
693
`+
missing_target_features: DiagnosticArgValue::StrListSepByAnd(
`
``
694
`+
missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
`
``
695
`+
),
`
``
696
`+
missing_target_features_count: missing.len(),
`
``
697
`+
note: if build_enabled.is_empty() { None } else { Some(()) },
`
``
698
`+
build_target_features: DiagnosticArgValue::StrListSepByAnd(
`
``
699
`+
build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(),
`
``
700
`+
),
`
``
701
`+
build_target_features_count: build_enabled.len(),
`
668
702
` unsafe_not_inherited_note,
`
669
703
`},
`
670
704
`),
`
`@@ -821,18 +855,38 @@ impl UnsafeOpKind {
`
821
855
` unsafe_not_inherited_note,
`
822
856
`});
`
823
857
`}
`
824
``
`-
CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => {
`
``
858
`+
CallToFunctionWith { function, missing, build_enabled }
`
``
859
`+
if unsafe_op_in_unsafe_fn_allowed =>
`
``
860
`+
{
`
825
861
` tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
`
826
862
` span,
`
``
863
`+
missing_target_features: DiagnosticArgValue::StrListSepByAnd(
`
``
864
`+
missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
`
``
865
`+
),
`
``
866
`+
missing_target_features_count: missing.len(),
`
``
867
`+
note: if build_enabled.is_empty() { None } else { Some(()) },
`
``
868
`+
build_target_features: DiagnosticArgValue::StrListSepByAnd(
`
``
869
`+
build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(),
`
``
870
`+
),
`
``
871
`+
build_target_features_count: build_enabled.len(),
`
827
872
` unsafe_not_inherited_note,
`
828
``
`-
function: &tcx.def_path_str(*did),
`
``
873
`+
function: &tcx.def_path_str(*function),
`
829
874
`});
`
830
875
`}
`
831
``
`-
CallToFunctionWith(did) => {
`
``
876
`+
CallToFunctionWith { function, missing, build_enabled } => {
`
832
877
` tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe {
`
833
878
` span,
`
``
879
`+
missing_target_features: DiagnosticArgValue::StrListSepByAnd(
`
``
880
`+
missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
`
``
881
`+
),
`
``
882
`+
missing_target_features_count: missing.len(),
`
``
883
`+
note: if build_enabled.is_empty() { None } else { Some(()) },
`
``
884
`+
build_target_features: DiagnosticArgValue::StrListSepByAnd(
`
``
885
`+
build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(),
`
``
886
`+
),
`
``
887
`+
build_target_features_count: build_enabled.len(),
`
834
888
` unsafe_not_inherited_note,
`
835
``
`-
function: &tcx.def_path_str(*did),
`
``
889
`+
function: &tcx.def_path_str(*function),
`
836
890
`});
`
837
891
`}
`
838
892
`}
`