1
Fork 0

Rollup merge of #118333 - eduardosm:print-missing-target-features, r=est31

Print list of missing target features when calling a function with target features outside an unsafe block

Fixes https://github.com/rust-lang/rust/issues/108680

Supersedes https://github.com/rust-lang/rust/pull/109710. I used the same wording for the messages, but the implementation is different.

r? `@est31`
This commit is contained in:
Matthias Krüger 2023-11-29 12:34:50 +01:00 committed by GitHub
commit 911a5ee7ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 375 additions and 124 deletions

View file

@ -1,7 +1,10 @@
use std::borrow::Cow;
use crate::build::ExprCategory;
use crate::errors::*;
use rustc_middle::thir::visit::{self, Visitor};
use rustc_errors::DiagnosticArgValue;
use rustc_hir as hir;
use rustc_middle::mir::BorrowKind;
use rustc_middle::thir::*;
@ -393,15 +396,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
// the call requires `unsafe`. Don't check this on wasm
// targets, though. For more information on wasm see the
// is_like_wasm check in hir_analysis/src/collect.rs
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
if !self.tcx.sess.target.options.is_like_wasm
&& !self
.tcx
.codegen_fn_attrs(func_did)
.target_features
&& !callee_features
.iter()
.all(|feature| self.body_target_features.contains(feature))
{
self.requires_unsafe(expr.span, CallToFunctionWith(func_did));
let missing: Vec<_> = callee_features
.iter()
.copied()
.filter(|feature| !self.body_target_features.contains(feature))
.collect();
let build_enabled = self
.tcx
.sess
.target_features
.iter()
.copied()
.filter(|feature| missing.contains(feature))
.collect();
self.requires_unsafe(
expr.span,
CallToFunctionWith { function: func_did, missing, build_enabled },
);
}
}
}
@ -527,7 +544,7 @@ struct UnusedUnsafeWarning {
enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
}
#[derive(Clone, Copy, PartialEq)]
#[derive(Clone, PartialEq)]
enum UnsafeOpKind {
CallToUnsafeFunction(Option<DefId>),
UseOfInlineAssembly,
@ -538,7 +555,15 @@ enum UnsafeOpKind {
AccessToUnionField,
MutationOfLayoutConstrainedField,
BorrowOfLayoutConstrainedField,
CallToFunctionWith(DefId),
CallToFunctionWith {
function: DefId,
/// Target features enabled in callee's `#[target_feature]` but missing in
/// caller's `#[target_feature]`.
missing: Vec<Symbol>,
/// Target features in `missing` that are enabled at compile time
/// (e.g., with `-C target-feature`).
build_enabled: Vec<Symbol>,
},
}
use UnsafeOpKind::*;
@ -659,13 +684,22 @@ impl UnsafeOpKind {
unsafe_not_inherited_note,
},
),
CallToFunctionWith(did) => tcx.emit_spanned_lint(
CallToFunctionWith { function, missing, build_enabled } => tcx.emit_spanned_lint(
UNSAFE_OP_IN_UNSAFE_FN,
hir_id,
span,
UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
span,
function: &with_no_trimmed_paths!(tcx.def_path_str(*did)),
function: &with_no_trimmed_paths!(tcx.def_path_str(*function)),
missing_target_features: DiagnosticArgValue::StrListSepByAnd(
missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
),
missing_target_features_count: missing.len(),
note: if build_enabled.is_empty() { None } else { Some(()) },
build_target_features: DiagnosticArgValue::StrListSepByAnd(
build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(),
),
build_target_features_count: build_enabled.len(),
unsafe_not_inherited_note,
},
),
@ -822,18 +856,38 @@ impl UnsafeOpKind {
unsafe_not_inherited_note,
});
}
CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => {
CallToFunctionWith { function, missing, build_enabled }
if unsafe_op_in_unsafe_fn_allowed =>
{
tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
span,
missing_target_features: DiagnosticArgValue::StrListSepByAnd(
missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
),
missing_target_features_count: missing.len(),
note: if build_enabled.is_empty() { None } else { Some(()) },
build_target_features: DiagnosticArgValue::StrListSepByAnd(
build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(),
),
build_target_features_count: build_enabled.len(),
unsafe_not_inherited_note,
function: &tcx.def_path_str(*did),
function: &tcx.def_path_str(*function),
});
}
CallToFunctionWith(did) => {
CallToFunctionWith { function, missing, build_enabled } => {
tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe {
span,
missing_target_features: DiagnosticArgValue::StrListSepByAnd(
missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
),
missing_target_features_count: missing.len(),
note: if build_enabled.is_empty() { None } else { Some(()) },
build_target_features: DiagnosticArgValue::StrListSepByAnd(
build_enabled.iter().map(|feature| Cow::from(feature.as_str())).collect(),
),
build_target_features_count: build_enabled.len(),
unsafe_not_inherited_note,
function: &tcx.def_path_str(*did),
function: &tcx.def_path_str(*function),
});
}
}

View file

@ -2,6 +2,7 @@ use crate::{
fluent_generated as fluent,
thir::pattern::{deconstruct_pat::WitnessPat, MatchCheckCtxt},
};
use rustc_errors::DiagnosticArgValue;
use rustc_errors::{
error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
@ -124,11 +125,17 @@ pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
#[derive(LintDiagnostic)]
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)]
#[note]
#[help]
pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
#[label]
pub span: Span,
pub function: &'a str,
pub missing_target_features: DiagnosticArgValue<'a>,
pub missing_target_features_count: usize,
#[note]
pub note: Option<()>,
pub build_target_features: DiagnosticArgValue<'a>,
pub build_target_features_count: usize,
#[subdiagnostic]
pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
}
@ -369,24 +376,36 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed
#[derive(Diagnostic)]
#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")]
#[note]
#[help]
pub struct CallToFunctionWithRequiresUnsafe<'a> {
#[primary_span]
#[label]
pub span: Span,
pub function: &'a str,
pub missing_target_features: DiagnosticArgValue<'a>,
pub missing_target_features_count: usize,
#[note]
pub note: Option<()>,
pub build_target_features: DiagnosticArgValue<'a>,
pub build_target_features_count: usize,
#[subdiagnostic]
pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}
#[derive(Diagnostic)]
#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
#[note]
#[help]
pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
#[primary_span]
#[label]
pub span: Span,
pub function: &'a str,
pub missing_target_features: DiagnosticArgValue<'a>,
pub missing_target_features_count: usize,
#[note]
pub note: Option<()>,
pub build_target_features: DiagnosticArgValue<'a>,
pub build_target_features_count: usize,
#[subdiagnostic]
pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}