Convert to inline diagnostics in rustc_lint
This commit is contained in:
parent
c7f5f3e0d5
commit
c814f76c06
17 changed files with 1307 additions and 1813 deletions
|
|
@ -4143,7 +4143,6 @@ dependencies = [
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_feature",
|
"rustc_feature",
|
||||||
"rustc_fluent_macro",
|
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
"rustc_infer",
|
"rustc_infer",
|
||||||
|
|
|
||||||
|
|
@ -111,11 +111,7 @@ pub fn default_translator() -> Translator {
|
||||||
Translator::with_fallback_bundle(DEFAULT_LOCALE_RESOURCES.to_vec(), false)
|
Translator::with_fallback_bundle(DEFAULT_LOCALE_RESOURCES.to_vec(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
|
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[];
|
||||||
// tidy-alphabetical-start
|
|
||||||
rustc_lint::DEFAULT_LOCALE_RESOURCE,
|
|
||||||
// tidy-alphabetical-end
|
|
||||||
];
|
|
||||||
|
|
||||||
/// Exit status code used for successful compilation and help output.
|
/// Exit status code used for successful compilation and help output.
|
||||||
pub const EXIT_SUCCESS: i32 = 0;
|
pub const EXIT_SUCCESS: i32 = 0;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_errors = { path = "../rustc_errors" }
|
rustc_errors = { path = "../rustc_errors" }
|
||||||
rustc_feature = { path = "../rustc_feature" }
|
rustc_feature = { path = "../rustc_feature" }
|
||||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
|
||||||
rustc_hir = { path = "../rustc_hir" }
|
rustc_hir = { path = "../rustc_hir" }
|
||||||
rustc_index = { path = "../rustc_index" }
|
rustc_index = { path = "../rustc_index" }
|
||||||
rustc_infer = { path = "../rustc_infer" }
|
rustc_infer = { path = "../rustc_infer" }
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -108,16 +108,18 @@ impl<'tcx> LateLintPass<'tcx> for AsyncClosureUsage {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_closure_returning_async_block)]
|
#[diag("closure returning async block can be made into an async closure")]
|
||||||
struct ClosureReturningAsyncBlock {
|
struct ClosureReturningAsyncBlock {
|
||||||
#[label]
|
#[label(
|
||||||
|
"this async block can be removed, and the closure can be turned into an async closure"
|
||||||
|
)]
|
||||||
async_decl_span: Span,
|
async_decl_span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
sugg: AsyncClosureSugg,
|
sugg: AsyncClosureSugg,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[multipart_suggestion(lint_suggestion, applicability = "maybe-incorrect")]
|
#[multipart_suggestion("turn this into an async closure", applicability = "maybe-incorrect")]
|
||||||
struct AsyncClosureSugg {
|
struct AsyncClosureSugg {
|
||||||
#[suggestion_part(code = "")]
|
#[suggestion_part(code = "")]
|
||||||
deletion_span: Span,
|
deletion_span: Span,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind};
|
||||||
use rustc_ast::{self as ast, *};
|
use rustc_ast::{self as ast, *};
|
||||||
use rustc_ast_pretty::pprust::expr_to_string;
|
use rustc_ast_pretty::pprust::expr_to_string;
|
||||||
use rustc_attr_parsing::AttributeParser;
|
use rustc_attr_parsing::AttributeParser;
|
||||||
use rustc_errors::{Applicability, LintDiagnostic};
|
use rustc_errors::{Applicability, LintDiagnostic, inline_fluent};
|
||||||
use rustc_feature::GateIssue;
|
use rustc_feature::GateIssue;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::attrs::{AttributeKind, DocAttribute};
|
use rustc_hir::attrs::{AttributeKind, DocAttribute};
|
||||||
|
|
@ -61,10 +61,7 @@ use crate::lints::{
|
||||||
BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
|
BuiltinUnreachablePub, BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment,
|
||||||
BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
|
BuiltinUnusedDocCommentSub, BuiltinWhileTrue, InvalidAsmLabel,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext};
|
||||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
|
|
||||||
fluent_generated as fluent,
|
|
||||||
};
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `while_true` lint detects `while true { }`.
|
/// The `while_true` lint detects `while true { }`.
|
||||||
///
|
///
|
||||||
|
|
@ -2655,8 +2652,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
|
||||||
let conjured_ty = cx.typeck_results().expr_ty(expr);
|
let conjured_ty = cx.typeck_results().expr_ty(expr);
|
||||||
if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
|
if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
|
||||||
let msg = match init {
|
let msg = match init {
|
||||||
InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
|
InitKind::Zeroed => {
|
||||||
InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit,
|
inline_fluent!("the type `{$ty}` does not permit zero-initialization")
|
||||||
|
}
|
||||||
|
InitKind::Uninit => {
|
||||||
|
inline_fluent!("the type `{$ty}` does not permit being left uninitialized")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let sub = BuiltinUnpermittedTypeInitSub { err };
|
let sub = BuiltinUnpermittedTypeInitSub { err };
|
||||||
cx.emit_span_lint(
|
cx.emit_span_lint(
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
|
use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic, inline_fluent};
|
||||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
|
|
||||||
use crate::fluent_generated as fluent;
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(lint_overruled_attribute, code = E0453)]
|
#[diag("{$lint_level}({$lint_source}) incompatible with previous forbid", code = E0453)]
|
||||||
pub(crate) struct OverruledAttribute<'a> {
|
pub(crate) struct OverruledAttribute<'a> {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[label]
|
#[label("overruled by previous forbid")]
|
||||||
pub overruled: Span,
|
pub overruled: Span,
|
||||||
pub lint_level: &'a str,
|
pub lint_level: &'a str,
|
||||||
pub lint_source: Symbol,
|
pub lint_source: Symbol,
|
||||||
|
|
@ -29,24 +27,24 @@ impl Subdiagnostic for OverruledAttributeSub {
|
||||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||||
match self {
|
match self {
|
||||||
OverruledAttributeSub::DefaultSource { id } => {
|
OverruledAttributeSub::DefaultSource { id } => {
|
||||||
diag.note(fluent::lint_default_source);
|
diag.note(inline_fluent!("`forbid` lint level is the default for {$id}"));
|
||||||
diag.arg("id", id);
|
diag.arg("id", id);
|
||||||
}
|
}
|
||||||
OverruledAttributeSub::NodeSource { span, reason } => {
|
OverruledAttributeSub::NodeSource { span, reason } => {
|
||||||
diag.span_label(span, fluent::lint_node_source);
|
diag.span_label(span, inline_fluent!("`forbid` level set here"));
|
||||||
if let Some(rationale) = reason {
|
if let Some(rationale) = reason {
|
||||||
diag.note(rationale.to_string());
|
diag.note(rationale.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OverruledAttributeSub::CommandLineSource => {
|
OverruledAttributeSub::CommandLineSource => {
|
||||||
diag.note(fluent::lint_command_line_source);
|
diag.note(inline_fluent!("`forbid` lint level was set on command line"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(lint_malformed_attribute, code = E0452)]
|
#[diag("malformed lint attribute input", code = E0452)]
|
||||||
pub(crate) struct MalformedAttribute {
|
pub(crate) struct MalformedAttribute {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
@ -56,50 +54,55 @@ pub(crate) struct MalformedAttribute {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
pub(crate) enum MalformedAttributeSub {
|
pub(crate) enum MalformedAttributeSub {
|
||||||
#[label(lint_bad_attribute_argument)]
|
#[label("bad attribute argument")]
|
||||||
BadAttributeArgument(#[primary_span] Span),
|
BadAttributeArgument(#[primary_span] Span),
|
||||||
#[label(lint_reason_must_be_string_literal)]
|
#[label("reason must be a string literal")]
|
||||||
ReasonMustBeStringLiteral(#[primary_span] Span),
|
ReasonMustBeStringLiteral(#[primary_span] Span),
|
||||||
#[label(lint_reason_must_come_last)]
|
#[label("reason in lint attribute must come last")]
|
||||||
ReasonMustComeLast(#[primary_span] Span),
|
ReasonMustComeLast(#[primary_span] Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(lint_unknown_tool_in_scoped_lint, code = E0710)]
|
#[diag("unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`", code = E0710)]
|
||||||
pub(crate) struct UnknownToolInScopedLint {
|
pub(crate) struct UnknownToolInScopedLint {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Option<Span>,
|
pub span: Option<Span>,
|
||||||
pub tool_name: Symbol,
|
pub tool_name: Symbol,
|
||||||
pub lint_name: String,
|
pub lint_name: String,
|
||||||
#[help]
|
#[help("add `#![register_tool({$tool_name})]` to the crate root")]
|
||||||
pub is_nightly_build: bool,
|
pub is_nightly_build: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = E0783)]
|
#[diag("`...` range patterns are deprecated", code = E0783)]
|
||||||
pub(crate) struct BuiltinEllipsisInclusiveRangePatterns {
|
pub(crate) struct BuiltinEllipsisInclusiveRangePatterns {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
#[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
|
#[suggestion(
|
||||||
|
"use `..=` for an inclusive range",
|
||||||
|
style = "short",
|
||||||
|
code = "{replace}",
|
||||||
|
applicability = "machine-applicable"
|
||||||
|
)]
|
||||||
pub suggestion: Span,
|
pub suggestion: Span,
|
||||||
pub replace: String,
|
pub replace: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[note(lint_requested_level)]
|
#[note("requested on the command line with `{$level} {$lint_name}`")]
|
||||||
pub(crate) struct RequestedLevel<'a> {
|
pub(crate) struct RequestedLevel<'a> {
|
||||||
pub level: Level,
|
pub level: Level,
|
||||||
pub lint_name: &'a str,
|
pub lint_name: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(lint_unsupported_group, code = E0602)]
|
#[diag("`{$lint_group}` lint group is not supported with ´--force-warn´", code = E0602)]
|
||||||
pub(crate) struct UnsupportedGroup {
|
pub(crate) struct UnsupportedGroup {
|
||||||
pub lint_group: String,
|
pub lint_group: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(lint_check_name_unknown_tool, code = E0602)]
|
#[diag("unknown lint tool: `{$tool_name}`", code = E0602)]
|
||||||
pub(crate) struct CheckNameUnknownTool<'a> {
|
pub(crate) struct CheckNameUnknownTool<'a> {
|
||||||
pub tool_name: Symbol,
|
pub tool_name: Symbol,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ use std::ops::ControlFlow;
|
||||||
|
|
||||||
use hir::intravisit::{self, Visitor};
|
use hir::intravisit::{self, Visitor};
|
||||||
use rustc_ast::Recovered;
|
use rustc_ast::Recovered;
|
||||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle};
|
use rustc_errors::{
|
||||||
|
Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle, inline_fluent,
|
||||||
|
};
|
||||||
use rustc_hir::{self as hir, HirIdSet};
|
use rustc_hir::{self as hir, HirIdSet};
|
||||||
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||||
use rustc_middle::ty::adjustment::Adjust;
|
use rustc_middle::ty::adjustment::Adjust;
|
||||||
|
|
@ -303,13 +305,15 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_if_let_rescope)]
|
#[diag("`if let` assigns a shorter lifetime since Edition 2024")]
|
||||||
struct IfLetRescopeLint {
|
struct IfLetRescopeLint {
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
destructors: Vec<DestructorLabel>,
|
destructors: Vec<DestructorLabel>,
|
||||||
#[label]
|
#[label(
|
||||||
|
"this value has a significant drop implementation which may observe a major change in drop order and requires your discretion"
|
||||||
|
)]
|
||||||
significant_droppers: Vec<Span>,
|
significant_droppers: Vec<Span>,
|
||||||
#[help]
|
#[help("the value is now dropped here in Edition 2024")]
|
||||||
lifetime_ends: Vec<Span>,
|
lifetime_ends: Vec<Span>,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
rewrite: Option<IfLetRescopeRewrite>,
|
rewrite: Option<IfLetRescopeRewrite>,
|
||||||
|
|
@ -352,7 +356,9 @@ impl Subdiagnostic for IfLetRescopeRewrite {
|
||||||
.chain(repeat_n('}', closing_brackets.count))
|
.chain(repeat_n('}', closing_brackets.count))
|
||||||
.collect(),
|
.collect(),
|
||||||
));
|
));
|
||||||
let msg = diag.eagerly_translate(crate::fluent_generated::lint_suggestion);
|
let msg = diag.eagerly_translate(inline_fluent!(
|
||||||
|
"a `match` with a single arm can preserve the drop order up to Edition 2021"
|
||||||
|
));
|
||||||
diag.multipart_suggestion_with_style(
|
diag.multipart_suggestion_with_style(
|
||||||
msg,
|
msg,
|
||||||
suggestions,
|
suggestions,
|
||||||
|
|
@ -363,7 +369,12 @@ impl Subdiagnostic for IfLetRescopeRewrite {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[note(lint_if_let_dtor)]
|
#[note(
|
||||||
|
"{$dtor_kind ->
|
||||||
|
[dyn] value may invoke a custom destructor because it contains a trait object
|
||||||
|
*[concrete] value invokes this custom destructor
|
||||||
|
}"
|
||||||
|
)]
|
||||||
struct DestructorLabel {
|
struct DestructorLabel {
|
||||||
#[primary_span]
|
#[primary_span]
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use std::cell::LazyCell;
|
||||||
use rustc_data_structures::debug_assert_matches;
|
use rustc_data_structures::debug_assert_matches;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||||
use rustc_data_structures::unord::UnordSet;
|
use rustc_data_structures::unord::UnordSet;
|
||||||
use rustc_errors::{LintDiagnostic, Subdiagnostic};
|
use rustc_errors::{LintDiagnostic, Subdiagnostic, inline_fluent};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
|
@ -28,7 +28,7 @@ use rustc_trait_selection::errors::{
|
||||||
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
|
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
|
||||||
use rustc_trait_selection::traits::ObligationCtxt;
|
use rustc_trait_selection::traits::ObligationCtxt;
|
||||||
|
|
||||||
use crate::{LateContext, LateLintPass, fluent_generated as fluent};
|
use crate::{LateContext, LateLintPass};
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `impl_trait_overcaptures` lint warns against cases where lifetime
|
/// The `impl_trait_overcaptures` lint warns against cases where lifetime
|
||||||
|
|
@ -435,11 +435,23 @@ struct ImplTraitOvercapturesLint<'tcx> {
|
||||||
|
|
||||||
impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
|
impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
|
||||||
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
|
fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
|
||||||
diag.primary_message(fluent::lint_impl_trait_overcaptures);
|
diag.primary_message(inline_fluent!(
|
||||||
|
"`{$self_ty}` will capture more lifetimes than possibly intended in edition 2024"
|
||||||
|
));
|
||||||
diag.arg("self_ty", self.self_ty.to_string())
|
diag.arg("self_ty", self.self_ty.to_string())
|
||||||
.arg("num_captured", self.num_captured)
|
.arg("num_captured", self.num_captured)
|
||||||
.span_note(self.uncaptured_spans, fluent::lint_note)
|
.span_note(
|
||||||
.note(fluent::lint_note2);
|
self.uncaptured_spans,
|
||||||
|
inline_fluent!(
|
||||||
|
"specifically, {$num_captured ->
|
||||||
|
[one] this lifetime is
|
||||||
|
*[other] these lifetimes are
|
||||||
|
} in scope but not mentioned in the type's bounds"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.note(inline_fluent!(
|
||||||
|
"all lifetimes in scope will be captured by `impl Trait`s in edition 2024"
|
||||||
|
));
|
||||||
if let Some(suggestion) = self.suggestion {
|
if let Some(suggestion) = self.suggestion {
|
||||||
suggestion.add_to_diag(diag);
|
suggestion.add_to_diag(diag);
|
||||||
}
|
}
|
||||||
|
|
@ -447,9 +459,9 @@ impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_impl_trait_redundant_captures)]
|
#[diag("all possible in-scope parameters are already captured, so `use<...>` syntax is redundant")]
|
||||||
struct ImplTraitRedundantCapturesLint {
|
struct ImplTraitRedundantCapturesLint {
|
||||||
#[suggestion(lint_suggestion, code = "", applicability = "machine-applicable")]
|
#[suggestion("remove the `use<...>` syntax", code = "", applicability = "machine-applicable")]
|
||||||
capturing_span: Span,
|
capturing_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use rustc_ast::attr::AttributeExt;
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||||
use rustc_data_structures::unord::UnordSet;
|
use rustc_data_structures::unord::UnordSet;
|
||||||
use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
|
use rustc_errors::{Diag, LintDiagnostic, MultiSpan, inline_fluent};
|
||||||
use rustc_feature::{Features, GateIssue};
|
use rustc_feature::{Features, GateIssue};
|
||||||
use rustc_hir::HirId;
|
use rustc_hir::HirId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
|
|
@ -31,7 +31,6 @@ use crate::errors::{
|
||||||
CheckNameUnknownTool, MalformedAttribute, MalformedAttributeSub, OverruledAttribute,
|
CheckNameUnknownTool, MalformedAttribute, MalformedAttributeSub, OverruledAttribute,
|
||||||
OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
|
OverruledAttributeSub, RequestedLevel, UnknownToolInScopedLint, UnsupportedGroup,
|
||||||
};
|
};
|
||||||
use crate::fluent_generated as fluent;
|
|
||||||
use crate::late::unerased_lint_store;
|
use crate::late::unerased_lint_store;
|
||||||
use crate::lints::{
|
use crate::lints::{
|
||||||
DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
|
DeprecatedLintName, DeprecatedLintNameFromCommandLine, IgnoredUnlessCrateSpecified,
|
||||||
|
|
@ -942,9 +941,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
||||||
let lint = builtin::UNKNOWN_LINTS;
|
let lint = builtin::UNKNOWN_LINTS;
|
||||||
let level = self.lint_level(builtin::UNKNOWN_LINTS);
|
let level = self.lint_level(builtin::UNKNOWN_LINTS);
|
||||||
lint_level(self.sess, lint, level, Some(span.into()), |lint| {
|
lint_level(self.sess, lint, level, Some(span.into()), |lint| {
|
||||||
lint.primary_message(fluent::lint_unknown_gated_lint);
|
lint.primary_message(inline_fluent!("unknown lint: `{$name}`"));
|
||||||
lint.arg("name", lint_id.lint.name_lower());
|
lint.arg("name", lint_id.lint.name_lower());
|
||||||
lint.note(fluent::lint_note);
|
lint.note(inline_fluent!("the `{$name}` lint is unstable"));
|
||||||
rustc_session::parse::add_feature_diagnostics_for_issue(
|
rustc_session::parse::add_feature_diagnostics_for_issue(
|
||||||
lint,
|
lint,
|
||||||
&self.sess,
|
&self.sess,
|
||||||
|
|
|
||||||
|
|
@ -139,8 +139,6 @@ pub use rustc_errors::BufferedEarlyLint;
|
||||||
pub use rustc_session::lint::Level::{self, *};
|
pub use rustc_session::lint::Level::{self, *};
|
||||||
pub use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec};
|
pub use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec};
|
||||||
|
|
||||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
levels::provide(providers);
|
levels::provide(providers);
|
||||||
expect::provide(providers);
|
expect::provide(providers);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::{Applicability, inline_fluent};
|
||||||
use rustc_hir::{self as hir, LangItem};
|
use rustc_hir::{self as hir, LangItem};
|
||||||
use rustc_infer::infer::TyCtxtInferExt;
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
use rustc_middle::{bug, ty};
|
use rustc_middle::{bug, ty};
|
||||||
|
|
@ -10,7 +10,7 @@ use rustc_span::{InnerSpan, Span, Symbol, hygiene, sym};
|
||||||
use rustc_trait_selection::infer::InferCtxtExt;
|
use rustc_trait_selection::infer::InferCtxtExt;
|
||||||
|
|
||||||
use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
|
use crate::lints::{NonFmtPanicBraces, NonFmtPanicUnused};
|
||||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first
|
/// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first
|
||||||
|
|
@ -121,20 +121,20 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.span_lint(NON_FMT_PANICS, arg_span, |lint| {
|
cx.span_lint(NON_FMT_PANICS, arg_span, |lint| {
|
||||||
lint.primary_message(fluent::lint_non_fmt_panic);
|
lint.primary_message(inline_fluent!("panic message is not a string literal"));
|
||||||
lint.arg("name", symbol);
|
lint.arg("name", symbol);
|
||||||
lint.note(fluent::lint_note);
|
lint.note(inline_fluent!("this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021"));
|
||||||
lint.note(fluent::lint_more_info_note);
|
lint.note(inline_fluent!("for more information, see <https://doc.rust-lang.org/edition-guide/rust-2021/panic-macro-consistency.html>"));
|
||||||
if !is_arg_inside_call(arg_span, span) {
|
if !is_arg_inside_call(arg_span, span) {
|
||||||
// No clue where this argument is coming from.
|
// No clue where this argument is coming from.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
|
if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
|
||||||
// A case of `panic!(format!(..))`.
|
// A case of `panic!(format!(..))`.
|
||||||
lint.note(fluent::lint_supports_fmt_note);
|
lint.note(inline_fluent!("the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here"));
|
||||||
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
|
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
|
||||||
lint.multipart_suggestion(
|
lint.multipart_suggestion(
|
||||||
fluent::lint_supports_fmt_suggestion,
|
inline_fluent!("remove the `format!(..)` macro call"),
|
||||||
vec![
|
vec![
|
||||||
(arg_span.until(open.shrink_to_hi()), "".into()),
|
(arg_span.until(open.shrink_to_hi()), "".into()),
|
||||||
(close.until(arg_span.shrink_to_hi()), "".into()),
|
(close.until(arg_span.shrink_to_hi()), "".into()),
|
||||||
|
|
@ -178,7 +178,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
||||||
if suggest_display {
|
if suggest_display {
|
||||||
lint.span_suggestion_verbose(
|
lint.span_suggestion_verbose(
|
||||||
arg_span.shrink_to_lo(),
|
arg_span.shrink_to_lo(),
|
||||||
fluent::lint_display_suggestion,
|
inline_fluent!(r#"add a "{"{"}{"}"}" format string to `Display` the message"#),
|
||||||
"\"{}\", ",
|
"\"{}\", ",
|
||||||
fmt_applicability,
|
fmt_applicability,
|
||||||
);
|
);
|
||||||
|
|
@ -186,7 +186,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
||||||
lint.arg("ty", ty);
|
lint.arg("ty", ty);
|
||||||
lint.span_suggestion_verbose(
|
lint.span_suggestion_verbose(
|
||||||
arg_span.shrink_to_lo(),
|
arg_span.shrink_to_lo(),
|
||||||
fluent::lint_debug_suggestion,
|
inline_fluent!(r#"add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}`"#),
|
||||||
"\"{:?}\", ",
|
"\"{:?}\", ",
|
||||||
fmt_applicability,
|
fmt_applicability,
|
||||||
);
|
);
|
||||||
|
|
@ -196,7 +196,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
||||||
if let Some((open, close, del)) = find_delimiters(cx, span) {
|
if let Some((open, close, del)) = find_delimiters(cx, span) {
|
||||||
lint.arg("already_suggested", suggest_display || suggest_debug);
|
lint.arg("already_suggested", suggest_display || suggest_debug);
|
||||||
lint.multipart_suggestion(
|
lint.multipart_suggestion(
|
||||||
fluent::lint_panic_suggestion,
|
inline_fluent!("{$already_suggested ->
|
||||||
|
[true] or use
|
||||||
|
*[false] use
|
||||||
|
} std::panic::panic_any instead"),
|
||||||
if del == '(' {
|
if del == '(' {
|
||||||
vec![(span.until(open), "std::panic::panic_any".into())]
|
vec![(span.until(open), "std::panic::panic_any".into())]
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use rustc_errors::MultiSpan;
|
use rustc_errors::{MultiSpan, inline_fluent};
|
||||||
use rustc_hir::attrs::AttributeKind;
|
use rustc_hir::attrs::AttributeKind;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
|
use rustc_hir::intravisit::{self, Visitor, VisitorExt};
|
||||||
|
|
@ -9,7 +9,7 @@ use rustc_span::def_id::{DefId, LOCAL_CRATE};
|
||||||
use rustc_span::{ExpnKind, Span, kw};
|
use rustc_span::{ExpnKind, Span, kw};
|
||||||
|
|
||||||
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
|
use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
|
||||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `non_local_definitions` lint checks for `impl` blocks and `#[macro_export]`
|
/// The `non_local_definitions` lint checks for `impl` blocks and `#[macro_export]`
|
||||||
|
|
@ -210,7 +210,12 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
|
||||||
if !doctest {
|
if !doctest {
|
||||||
ms.push_span_label(
|
ms.push_span_label(
|
||||||
cx.tcx.def_span(parent),
|
cx.tcx.def_span(parent),
|
||||||
fluent::lint_non_local_definitions_impl_move_help,
|
inline_fluent!(
|
||||||
|
"move the `impl` block outside of this {$body_kind_descr} {$depth ->
|
||||||
|
[one] `{$body_name}`
|
||||||
|
*[other] `{$body_name}` and up {$depth} bodies
|
||||||
|
}"
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -202,11 +202,11 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_opaque_hidden_inferred_bound)]
|
#[diag("opaque type `{$ty}` does not satisfy its associated type bounds")]
|
||||||
struct OpaqueHiddenInferredBoundLint<'tcx> {
|
struct OpaqueHiddenInferredBoundLint<'tcx> {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
proj_ty: Ty<'tcx>,
|
proj_ty: Ty<'tcx>,
|
||||||
#[label(lint_specifically)]
|
#[label("this associated type bound is unsatisfied for `{$proj_ty}`")]
|
||||||
assoc_pred_span: Span,
|
assoc_pred_span: Span,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
add_bound: Option<AddBound<'tcx>>,
|
add_bound: Option<AddBound<'tcx>>,
|
||||||
|
|
@ -214,7 +214,7 @@ struct OpaqueHiddenInferredBoundLint<'tcx> {
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
lint_opaque_hidden_inferred_bound_sugg,
|
"add this bound",
|
||||||
style = "verbose",
|
style = "verbose",
|
||||||
applicability = "machine-applicable",
|
applicability = "machine-applicable",
|
||||||
code = " + {trait_ref}"
|
code = " + {trait_ref}"
|
||||||
|
|
|
||||||
|
|
@ -369,8 +369,10 @@ fn check_unnecessary_transmute<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_undefined_transmute)]
|
#[diag("pointers cannot be transmuted to integers during const eval")]
|
||||||
#[note]
|
#[note("at compile-time, pointers do not have an integer value")]
|
||||||
#[note(lint_note2)]
|
#[note(
|
||||||
#[help]
|
"avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior"
|
||||||
|
)]
|
||||||
|
#[help("for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html")]
|
||||||
pub(crate) struct UndefinedTransmuteLint;
|
pub(crate) struct UndefinedTransmuteLint;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use std::ops::ControlFlow;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use rustc_abi::VariantIdx;
|
use rustc_abi::VariantIdx;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::DiagMessage;
|
use rustc_errors::{DiagMessage, inline_fluent};
|
||||||
use rustc_hir::def::CtorKind;
|
use rustc_hir::def::CtorKind;
|
||||||
use rustc_hir::intravisit::VisitorExt;
|
use rustc_hir::intravisit::VisitorExt;
|
||||||
use rustc_hir::{self as hir, AmbigArg};
|
use rustc_hir::{self as hir, AmbigArg};
|
||||||
|
|
@ -21,7 +21,7 @@ use tracing::debug;
|
||||||
|
|
||||||
use super::repr_nullable_ptr;
|
use super::repr_nullable_ptr;
|
||||||
use crate::lints::{ImproperCTypes, UsesPowerAlignment};
|
use crate::lints::{ImproperCTypes, UsesPowerAlignment};
|
||||||
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
declare_lint! {
|
declare_lint! {
|
||||||
/// The `improper_ctypes` lint detects incorrect use of types in foreign
|
/// The `improper_ctypes` lint detects incorrect use of types in foreign
|
||||||
|
|
@ -158,12 +158,12 @@ pub(crate) fn check_non_exhaustive_variant(
|
||||||
// with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
|
// with an enum like `#[repr(u8)] enum Enum { A(DataA), B(DataB), }`
|
||||||
// but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
|
// but exempt enums with unit ctors like C's (e.g. from rust-bindgen)
|
||||||
if variant_has_complex_ctor(variant) {
|
if variant_has_complex_ctor(variant) {
|
||||||
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive);
|
return ControlFlow::Break(inline_fluent!("this enum is non-exhaustive"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if variant.field_list_has_applicable_non_exhaustive() {
|
if variant.field_list_has_applicable_non_exhaustive() {
|
||||||
return ControlFlow::Break(fluent::lint_improper_ctypes_non_exhaustive_variant);
|
return ControlFlow::Break(inline_fluent!("this enum has non-exhaustive variants"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
|
|
@ -424,7 +424,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
if all_phantom {
|
if all_phantom {
|
||||||
FfiPhantom(ty)
|
FfiPhantom(ty)
|
||||||
} else if transparent_with_all_zst_fields {
|
} else if transparent_with_all_zst_fields {
|
||||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_struct_zst, help: None }
|
FfiUnsafe {
|
||||||
|
ty,
|
||||||
|
reason: inline_fluent!("this struct contains only zero-sized fields"),
|
||||||
|
help: None,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
FfiSafe
|
FfiSafe
|
||||||
}
|
}
|
||||||
|
|
@ -460,7 +464,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
} else {
|
} else {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_box,
|
reason: inline_fluent!("box cannot be represented as a single pointer"),
|
||||||
help: None,
|
help: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -476,8 +480,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_cstr_reason,
|
reason: inline_fluent!(
|
||||||
help: Some(fluent::lint_improper_ctypes_cstr_help),
|
"`CStr`/`CString` do not have a guaranteed layout"
|
||||||
|
),
|
||||||
|
help: Some(inline_fluent!(
|
||||||
|
"consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()`"
|
||||||
|
)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -485,14 +493,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: if def.is_struct() {
|
reason: if def.is_struct() {
|
||||||
fluent::lint_improper_ctypes_struct_layout_reason
|
inline_fluent!("this struct has unspecified layout")
|
||||||
} else {
|
} else {
|
||||||
fluent::lint_improper_ctypes_union_layout_reason
|
inline_fluent!("this union has unspecified layout")
|
||||||
},
|
},
|
||||||
help: if def.is_struct() {
|
help: if def.is_struct() {
|
||||||
Some(fluent::lint_improper_ctypes_struct_layout_help)
|
Some(inline_fluent!(
|
||||||
|
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct"
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Some(fluent::lint_improper_ctypes_union_layout_help)
|
Some(inline_fluent!(
|
||||||
|
"consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union"
|
||||||
|
))
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -501,9 +513,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: if def.is_struct() {
|
reason: if def.is_struct() {
|
||||||
fluent::lint_improper_ctypes_struct_non_exhaustive
|
inline_fluent!("this struct is non-exhaustive")
|
||||||
} else {
|
} else {
|
||||||
fluent::lint_improper_ctypes_union_non_exhaustive
|
inline_fluent!("this union is non-exhaustive")
|
||||||
},
|
},
|
||||||
help: None,
|
help: None,
|
||||||
};
|
};
|
||||||
|
|
@ -513,14 +525,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: if def.is_struct() {
|
reason: if def.is_struct() {
|
||||||
fluent::lint_improper_ctypes_struct_fieldless_reason
|
inline_fluent!("this struct has no fields")
|
||||||
} else {
|
} else {
|
||||||
fluent::lint_improper_ctypes_union_fieldless_reason
|
inline_fluent!("this union has no fields")
|
||||||
},
|
},
|
||||||
help: if def.is_struct() {
|
help: if def.is_struct() {
|
||||||
Some(fluent::lint_improper_ctypes_struct_fieldless_help)
|
Some(inline_fluent!("consider adding a member to this struct"))
|
||||||
} else {
|
} else {
|
||||||
Some(fluent::lint_improper_ctypes_union_fieldless_help)
|
Some(inline_fluent!("consider adding a member to this union"))
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -545,8 +557,10 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_enum_repr_reason,
|
reason: inline_fluent!("enum has no representation hint"),
|
||||||
help: Some(fluent::lint_improper_ctypes_enum_repr_help),
|
help: Some(inline_fluent!(
|
||||||
|
"consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum"
|
||||||
|
)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -572,8 +586,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
ty::Char => FfiUnsafe {
|
ty::Char => FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_char_reason,
|
reason: inline_fluent!("the `char` type has no C equivalent"),
|
||||||
help: Some(fluent::lint_improper_ctypes_char_help),
|
help: Some(inline_fluent!("consider using `u32` or `libc::wchar_t` instead")),
|
||||||
},
|
},
|
||||||
|
|
||||||
// It's just extra invariants on the type that you need to uphold,
|
// It's just extra invariants on the type that you need to uphold,
|
||||||
|
|
@ -585,24 +599,26 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
ty::Slice(_) => FfiUnsafe {
|
ty::Slice(_) => FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_slice_reason,
|
reason: inline_fluent!("slices have no C equivalent"),
|
||||||
help: Some(fluent::lint_improper_ctypes_slice_help),
|
help: Some(inline_fluent!("consider using a raw pointer instead")),
|
||||||
},
|
},
|
||||||
|
|
||||||
ty::Dynamic(..) => {
|
ty::Dynamic(..) => FfiUnsafe {
|
||||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_dyn, help: None }
|
ty,
|
||||||
}
|
reason: inline_fluent!("trait objects have no C equivalent"),
|
||||||
|
help: None,
|
||||||
|
},
|
||||||
|
|
||||||
ty::Str => FfiUnsafe {
|
ty::Str => FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_str_reason,
|
reason: inline_fluent!("string slices have no C equivalent"),
|
||||||
help: Some(fluent::lint_improper_ctypes_str_help),
|
help: Some(inline_fluent!("consider using `*const u8` and a length instead")),
|
||||||
},
|
},
|
||||||
|
|
||||||
ty::Tuple(..) => FfiUnsafe {
|
ty::Tuple(..) => FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_tuple_reason,
|
reason: inline_fluent!("tuples have unspecified layout"),
|
||||||
help: Some(fluent::lint_improper_ctypes_tuple_help),
|
help: Some(inline_fluent!("consider using a struct instead")),
|
||||||
},
|
},
|
||||||
|
|
||||||
ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
|
ty::RawPtr(ty, _) | ty::Ref(_, ty, _)
|
||||||
|
|
@ -632,8 +648,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
if sig.abi().is_rustic_abi() {
|
if sig.abi().is_rustic_abi() {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_fnptr_reason,
|
reason: inline_fluent!(
|
||||||
help: Some(fluent::lint_improper_ctypes_fnptr_help),
|
"this function pointer has Rust-specific calling convention"
|
||||||
|
),
|
||||||
|
help: Some(inline_fluent!(
|
||||||
|
"consider using an `extern fn(...) -> ...` function pointer instead"
|
||||||
|
)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -657,9 +677,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
|
|
||||||
// While opaque types are checked for earlier, if a projection in a struct field
|
// While opaque types are checked for earlier, if a projection in a struct field
|
||||||
// normalizes to an opaque type, then it will reach this branch.
|
// normalizes to an opaque type, then it will reach this branch.
|
||||||
ty::Alias(ty::Opaque, ..) => {
|
ty::Alias(ty::Opaque, ..) => FfiUnsafe {
|
||||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_opaque, help: None }
|
ty,
|
||||||
}
|
reason: inline_fluent!("opaque types have no C equivalent"),
|
||||||
|
help: None,
|
||||||
|
},
|
||||||
|
|
||||||
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
|
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
|
||||||
// so they are currently ignored for the purposes of this lint.
|
// so they are currently ignored for the purposes of this lint.
|
||||||
|
|
@ -669,9 +691,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
FfiSafe
|
FfiSafe
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::UnsafeBinder(_) => {
|
ty::UnsafeBinder(_) => FfiUnsafe {
|
||||||
FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_unsafe_binder, help: None }
|
ty,
|
||||||
}
|
reason: inline_fluent!(
|
||||||
|
"unsafe binders are incompatible with foreign function interfaces"
|
||||||
|
),
|
||||||
|
help: None,
|
||||||
|
},
|
||||||
|
|
||||||
ty::Param(..)
|
ty::Param(..)
|
||||||
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
|
| ty::Alias(ty::Projection | ty::Inherent | ty::Free, ..)
|
||||||
|
|
@ -715,7 +741,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
Some(FfiResult::FfiUnsafe {
|
Some(FfiResult::FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_opaque,
|
reason: inline_fluent!("opaque types have no C equivalent"),
|
||||||
help: None,
|
help: None,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -728,8 +754,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
if let ty::Array(..) = ty.kind() {
|
if let ty::Array(..) = ty.kind() {
|
||||||
Some(FfiResult::FfiUnsafe {
|
Some(FfiResult::FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: fluent::lint_improper_ctypes_array_reason,
|
reason: inline_fluent!("passing raw arrays by value is not FFI-safe"),
|
||||||
help: Some(fluent::lint_improper_ctypes_array_help),
|
help: Some(inline_fluent!("consider passing a pointer to the array")),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -908,7 +934,7 @@ impl<'tcx> ImproperCTypesLint {
|
||||||
cx,
|
cx,
|
||||||
ty,
|
ty,
|
||||||
sp,
|
sp,
|
||||||
fluent::lint_improper_ctypes_only_phantomdata,
|
inline_fluent!("composed only of `PhantomData`"),
|
||||||
None,
|
None,
|
||||||
fn_mode,
|
fn_mode,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue