summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_lint
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint')
-rw-r--r--compiler/rustc_lint/messages.ftl19
-rw-r--r--compiler/rustc_lint/src/builtin.rs76
-rw-r--r--compiler/rustc_lint/src/context.rs146
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs40
-rw-r--r--compiler/rustc_lint/src/early.rs22
-rw-r--r--compiler/rustc_lint/src/expect.rs4
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs2
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs4
-rw-r--r--compiler/rustc_lint/src/internal.rs4
-rw-r--r--compiler/rustc_lint/src/late.rs34
-rw-r--r--compiler/rustc_lint/src/levels.rs36
-rw-r--r--compiler/rustc_lint/src/lib.rs21
-rw-r--r--compiler/rustc_lint/src/lints.rs159
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs2
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs19
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs12
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs2
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs2
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs138
-rw-r--r--compiler/rustc_lint/src/types.rs218
-rw-r--r--compiler/rustc_lint/src/unit_bindings.rs72
-rw-r--r--compiler/rustc_lint/src/unused.rs62
22 files changed, 699 insertions, 395 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 068f1372c..40e6b1b57 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -1,3 +1,7 @@
+lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
+ .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
+ .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
+
lint_array_into_iter =
this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
@@ -128,12 +132,6 @@ lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not en
lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases
.suggestion = the clause will not be checked when the type alias is used, and should be removed
-lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
- .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
-
-lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
- .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
-
lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
@@ -496,8 +494,10 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name}
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
-lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
- .label = target type is set here
+lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
+ .label = `{$self_ty}` implements `Deref<Target = dyn {$target_principal}>` which conflicts with supertrait `{$supertrait_principal}`
+ .label2 = target type is a supertrait of `{$self_ty}`
+ .help = consider removing this implementation or replacing it with a method instead
lint_suspicious_double_ref_clone =
using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type
@@ -523,6 +523,9 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual
lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
.label = this function will not propagate the caller location
+lint_unit_bindings = binding has unit type `()`
+ .label = this pattern is inferred to be the unit type `()`
+
lint_unknown_gated_lint =
unknown lint: `{$name}`
.note = the `{$name}` lint is unstable
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 6f6150a41..045ff38c0 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -33,7 +33,6 @@ use crate::{
BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
- BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue,
BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
@@ -41,7 +40,6 @@ use crate::{
},
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
};
-use rustc_ast::attr;
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_ast::visit::{FnCtxt, FnKind};
use rustc_ast::{self as ast, *};
@@ -60,7 +58,6 @@ use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
-use rustc_session::config::ExpectedValues;
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
@@ -265,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
continue;
}
if let PatKind::Binding(binding_annot, _, ident, None) = fieldpat.pat.kind {
- if cx.tcx.find_field_index(ident, &variant)
+ if cx.tcx.find_field_index(ident, variant)
== Some(cx.typeck_results().field_index(fieldpat.hir_id))
{
cx.emit_spanned_lint(
@@ -509,7 +506,7 @@ impl MissingDoc {
}
}
- let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
+ let attrs = cx.tcx.hir().attrs(cx.tcx.local_def_id_to_hir_id(def_id));
let has_doc = attrs.iter().any(has_doc);
if !has_doc {
cx.emit_spanned_lint(
@@ -635,21 +632,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
return;
}
let (def, ty) = match item.kind {
- hir::ItemKind::Struct(_, ref ast_generics) => {
+ hir::ItemKind::Struct(_, ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
let def = cx.tcx.adt_def(item.owner_id);
(def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
}
- hir::ItemKind::Union(_, ref ast_generics) => {
+ hir::ItemKind::Union(_, ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
let def = cx.tcx.adt_def(item.owner_id);
(def, Ty::new_adt(cx.tcx, def, ty::List::empty()))
}
- hir::ItemKind::Enum(_, ref ast_generics) => {
+ hir::ItemKind::Enum(_, ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
@@ -1002,8 +999,10 @@ impl EarlyLintPass for UnusedDocComment {
}
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
- let arm_span = arm.pat.span.with_hi(arm.body.span.hi());
- warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
+ if let Some(body) = &arm.body {
+ let arm_span = arm.pat.span.with_hi(body.span.hi());
+ warn_if_doc(cx, arm_span, "match arms", &arm.attrs);
+ }
}
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat) {
@@ -1029,7 +1028,7 @@ impl EarlyLintPass for UnusedDocComment {
}
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) {
- warn_if_doc(cx, block.span, "blocks", &block.attrs());
+ warn_if_doc(cx, block.span, "blocks", block.attrs());
}
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
@@ -1119,7 +1118,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
}
};
match it.kind {
- hir::ItemKind::Fn(.., ref generics, _) => {
+ hir::ItemKind::Fn(.., generics, _) => {
if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) {
check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
}
@@ -1446,10 +1445,10 @@ declare_lint_pass!(
impl TypeAliasBounds {
pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool {
match *qpath {
- hir::QPath::TypeRelative(ref ty, _) => {
+ hir::QPath::TypeRelative(ty, _) => {
// If this is a type variable, we found a `T::Assoc`.
match ty.kind {
- hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
+ hir::TyKind::Path(hir::QPath::Resolved(None, path)) => {
matches!(path.res, Res::Def(DefKind::TyParam, _))
}
_ => false,
@@ -1716,16 +1715,16 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}
let (parentheses, endpoints) = match &pat.kind {
- PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
+ PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(subpat)),
_ => (false, matches_ellipsis_pat(pat)),
};
if let Some((start, end, join)) = endpoints {
if parentheses {
self.node_id = Some(pat.id);
- let end = expr_to_string(&end);
+ let end = expr_to_string(end);
let replace = match start {
- Some(start) => format!("&({}..={})", expr_to_string(&start), end),
+ Some(start) => format!("&({}..={})", expr_to_string(start), end),
None => format!("&(..={end})"),
};
if join.edition() >= Edition::Edition2021 {
@@ -1836,7 +1835,7 @@ impl KeywordIdents {
self.check_ident_token(cx, UnderMacro(true), ident);
}
}
- TokenTree::Delimited(_, _, tts) => self.check_tokens(cx, tts),
+ TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts),
}
}
}
@@ -1910,7 +1909,7 @@ impl ExplicitOutlivesRequirements {
.iter()
.filter_map(|(clause, _)| match clause.kind().skip_binder() {
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
- ty::ReEarlyBound(ebr) if ebr.def_id == def_id => Some(b),
+ ty::ReEarlyParam(ebr) if ebr.def_id == def_id => Some(b),
_ => None,
},
_ => None,
@@ -1953,7 +1952,7 @@ impl ExplicitOutlivesRequirements {
let is_inferred = match tcx.named_bound_var(lifetime.hir_id) {
Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives
.iter()
- .any(|r| matches!(**r, ty::ReEarlyBound(ebr) if { ebr.def_id == def_id })),
+ .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { ebr.def_id == def_id })),
_ => false,
};
@@ -2383,7 +2382,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
/// Determine if this expression is a "dangerous initialization".
fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<InitKind> {
- if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
+ if let hir::ExprKind::Call(path_expr, args) = expr.kind {
// Find calls to `mem::{uninitialized,zeroed}` methods.
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
@@ -2400,7 +2399,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
// This is a call to *some* method named `assume_init`.
// See if the `self` parameter is one of the dangerous constructors.
- if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind {
+ if let hir::ExprKind::Call(path_expr, _) = receiver.kind {
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
match cx.tcx.get_diagnostic_name(def_id) {
@@ -2542,7 +2541,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
return variant_find_init_error(
cx,
ty,
- &first_variant.0,
+ first_variant.0,
args,
"field of the only potentially inhabited enum variant",
init,
@@ -2648,13 +2647,13 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
/// test if expression is a null ptr
fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
match &expr.kind {
- rustc_hir::ExprKind::Cast(ref expr, ref ty) => {
+ rustc_hir::ExprKind::Cast(expr, ty) => {
if let rustc_hir::TyKind::Ptr(_) = ty.kind {
return is_zero(expr) || is_null_ptr(cx, expr);
}
}
// check for call to `core::ptr::null` or `core::ptr::null_mut`
- rustc_hir::ExprKind::Call(ref path, _) => {
+ rustc_hir::ExprKind::Call(path, _) => {
if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
return matches!(
@@ -2672,7 +2671,7 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
/// test if expression is the literal `0`
fn is_zero(expr: &hir::Expr<'_>) -> bool {
match &expr.kind {
- rustc_hir::ExprKind::Lit(ref lit) => {
+ rustc_hir::ExprKind::Lit(lit) => {
if let LitKind::Int(a, _) = lit.node {
return a == 0;
}
@@ -2801,7 +2800,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
NAMED_ASM_LABELS,
Some(target_spans),
fluent::lint_builtin_asm_labels,
- |lint| lint,
+ |_| {},
BuiltinLintDiagnostics::NamedAsmLabel(
"only local labels of the form `<number>:` should be used in inline asm"
.to_string(),
@@ -2889,26 +2888,3 @@ impl EarlyLintPass for SpecialModuleName {
}
}
}
-
-pub use rustc_session::lint::builtin::UNEXPECTED_CFGS;
-
-declare_lint_pass!(UnexpectedCfgs => [UNEXPECTED_CFGS]);
-
-impl EarlyLintPass for UnexpectedCfgs {
- fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
- let cfg = &cx.sess().parse_sess.config;
- let check_cfg = &cx.sess().parse_sess.check_config;
- for &(name, value) in cfg {
- match check_cfg.expecteds.get(&name) {
- Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
- let value = value.unwrap_or(kw::Empty);
- cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigValue { name, value });
- }
- None if check_cfg.exhaustive_names => {
- cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { name });
- }
- _ => { /* expected */ }
- }
- }
- }
-}
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index a5f4c5ff0..c7a9d5e80 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -36,7 +36,7 @@ use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, Ty
use rustc_session::config::ExpectedValues;
use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
-use rustc_session::Session;
+use rustc_session::{LintStoreMarker, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, Span};
@@ -77,6 +77,8 @@ pub struct LintStore {
lint_groups: FxHashMap<&'static str, LintGroup>,
}
+impl LintStoreMarker for LintStore {}
+
/// The target of the `by_name` map, which accounts for renaming/deprecation.
#[derive(Debug)]
enum TargetLint {
@@ -385,7 +387,7 @@ impl LintStore {
};
}
Some(LintGroup { lint_ids, .. }) => {
- return CheckLintNameResult::Tool(Ok(&lint_ids));
+ return CheckLintNameResult::Tool(Ok(lint_ids));
}
},
Some(Id(id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
@@ -406,12 +408,12 @@ impl LintStore {
if let Some(LintAlias { name, silent }) = depr {
let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
return if *silent {
- CheckLintNameResult::Ok(&lint_ids)
+ CheckLintNameResult::Ok(lint_ids)
} else {
- CheckLintNameResult::Tool(Err((Some(&lint_ids), (*name).to_string())))
+ CheckLintNameResult::Tool(Err((Some(lint_ids), (*name).to_string())))
};
}
- CheckLintNameResult::Ok(&lint_ids)
+ CheckLintNameResult::Ok(lint_ids)
}
},
Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
@@ -458,12 +460,12 @@ impl LintStore {
if let Some(LintAlias { name, silent }) = depr {
let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
return if *silent {
- CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
+ CheckLintNameResult::Tool(Err((Some(lint_ids), complete_name)))
} else {
- CheckLintNameResult::Tool(Err((Some(&lint_ids), (*name).to_string())))
+ CheckLintNameResult::Tool(Err((Some(lint_ids), (*name).to_string())))
};
}
- CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
+ CheckLintNameResult::Tool(Err((Some(lint_ids), complete_name)))
}
},
Some(Id(id)) => {
@@ -497,9 +499,6 @@ pub struct LateContext<'tcx> {
/// Items accessible from the crate being checked.
pub effective_visibilities: &'tcx EffectiveVisibilities,
- /// The store of registered lints and the lint levels.
- pub lint_store: &'tcx LintStore,
-
pub last_node_with_lint_attrs: hir::HirId,
/// Generic type parameters in scope for the item we are in.
@@ -515,21 +514,11 @@ pub struct EarlyContext<'a> {
pub buffered: LintBuffer,
}
-pub trait LintPassObject: Sized {}
-
-impl LintPassObject for EarlyLintPassObject {}
-
-impl LintPassObject for LateLintPassObject<'_> {}
-
-pub trait LintContext: Sized {
- type PassObject: LintPassObject;
-
+pub trait LintContext {
fn sess(&self) -> &Session;
- fn lints(&self) -> &LintStore;
- /// Emit a lint at the appropriate level, with an optional associated span and an existing diagnostic.
- ///
- /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
+ /// Emit a lint at the appropriate level, with an optional associated span and an existing
+ /// diagnostic.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
#[rustc_lint_diagnostics]
@@ -538,9 +527,7 @@ pub trait LintContext: Sized {
lint: &'static Lint,
span: Option<impl Into<MultiSpan>>,
msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'b mut DiagnosticBuilder<'a, ()>,
- ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>),
diagnostic: BuiltinLintDiagnostics,
) {
// We first generate a blank diagnostic.
@@ -713,10 +700,14 @@ pub trait LintContext: Sized {
db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
},
BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => {
- let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect();
+ let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().copied().collect();
+ let is_from_cargo = std::env::var_os("CARGO").is_some();
+ let mut is_feature_cfg = name == sym::feature;
+ if is_feature_cfg && is_from_cargo {
+ db.help("consider defining some features in `Cargo.toml`");
// Suggest the most probable if we found one
- if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
+ } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
if let Some(ExpectedValues::Some(best_match_values)) =
sess.parse_sess.check_config.expecteds.get(&best_match) {
let mut possibilities = best_match_values.iter()
@@ -749,6 +740,8 @@ pub trait LintContext: Sized {
} else {
db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
}
+
+ is_feature_cfg |= best_match == sym::feature;
} else if !possibilities.is_empty() {
let mut possibilities = possibilities.iter()
.map(Symbol::as_str)
@@ -762,6 +755,23 @@ pub trait LintContext: Sized {
// once.
db.help_once(format!("expected names are: `{possibilities}`"));
}
+
+ let inst = if let Some((value, _value_span)) = value {
+ let pre = if is_from_cargo { "\\" } else { "" };
+ format!("cfg({name}, values({pre}\"{value}{pre}\"))")
+ } else {
+ format!("cfg({name})")
+ };
+
+ if is_from_cargo {
+ if !is_feature_cfg {
+ db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
+ }
+ db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration");
+ } else {
+ db.help(format!("to expect this configuration use `--check-cfg={inst}`"));
+ db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
+ }
},
BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {
let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else {
@@ -773,6 +783,7 @@ pub trait LintContext: Sized {
.copied()
.flatten()
.collect();
+ let is_from_cargo = std::env::var_os("CARGO").is_some();
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
@@ -793,6 +804,8 @@ pub trait LintContext: Sized {
db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
}
+ } else if name == sym::feature && is_from_cargo {
+ db.help(format!("consider defining `{name}` as feature in `Cargo.toml`"));
} else if let &[first_possibility] = &possibilities[..] {
db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect);
}
@@ -802,6 +815,27 @@ pub trait LintContext: Sized {
db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect);
}
}
+
+ let inst = if let Some((value, _value_span)) = value {
+ let pre = if is_from_cargo { "\\" } else { "" };
+ format!("cfg({name}, values({pre}\"{value}{pre}\"))")
+ } else {
+ format!("cfg({name})")
+ };
+
+ if is_from_cargo {
+ if name == sym::feature {
+ if let Some((value, _value_span)) = value {
+ db.help(format!("consider adding `{value}` as a feature in `Cargo.toml`"));
+ }
+ } else {
+ db.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo:rustc-check-cfg={inst}\");` to the top of a `build.rs`"));
+ }
+ db.note("see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration");
+ } else {
+ db.help(format!("to expect this configuration use `--check-cfg={inst}`"));
+ db.note("see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration");
+ }
},
BuiltinLintDiagnostics::DeprecatedWhereclauseLocation(new_span, suggestion) => {
db.multipart_suggestion(
@@ -932,6 +966,10 @@ pub trait LintContext: Sized {
if elided { "'static " } else { "'static" },
Applicability::MachineApplicable
);
+ },
+ BuiltinLintDiagnostics::RedundantImportVisibility { max_vis, span } => {
+ db.span_note(span, format!("the most public imported item is `{max_vis}`"));
+ db.help("reduce the glob import's visibility or increase visibility of imported items");
}
}
// Rewrap `db`, and pass control to the user.
@@ -943,8 +981,6 @@ pub trait LintContext: Sized {
// set the span in their `decorate` function (preferably using set_span).
/// Emit a lint at the appropriate level, with an optional associated span.
///
- /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
- ///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
#[rustc_lint_diagnostics]
fn lookup<S: Into<MultiSpan>>(
@@ -952,9 +988,7 @@ pub trait LintContext: Sized {
lint: &'static Lint,
span: Option<S>,
msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'b mut DiagnosticBuilder<'a, ()>,
- ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>),
);
/// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
@@ -965,13 +999,13 @@ pub trait LintContext: Sized {
span: S,
decorator: impl for<'a> DecorateLint<'a, ()>,
) {
- self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag));
+ self.lookup(lint, Some(span), decorator.msg(), |diag| {
+ decorator.decorate_lint(diag);
+ });
}
/// Emit a lint at the appropriate level, with an associated span.
///
- /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
- ///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
#[rustc_lint_diagnostics]
fn struct_span_lint<S: Into<MultiSpan>>(
@@ -979,9 +1013,7 @@ pub trait LintContext: Sized {
lint: &'static Lint,
span: S,
msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'b mut DiagnosticBuilder<'a, ()>,
- ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>),
) {
self.lookup(lint, Some(span), msg, decorate);
}
@@ -990,23 +1022,19 @@ pub trait LintContext: Sized {
/// generated by `#[derive(LintDiagnostic)]`).
fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) {
self.lookup(lint, None as Option<Span>, decorator.msg(), |diag| {
- decorator.decorate_lint(diag)
+ decorator.decorate_lint(diag);
});
}
/// Emit a lint at the appropriate level, with no associated span.
///
- /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
- ///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
#[rustc_lint_diagnostics]
fn lint(
&self,
lint: &'static Lint,
msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'b mut DiagnosticBuilder<'a, ()>,
- ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>),
) {
self.lookup(lint, None as Option<Span>, msg, decorate);
}
@@ -1059,15 +1087,9 @@ impl<'a> EarlyContext<'a> {
}
impl<'tcx> LintContext for LateContext<'tcx> {
- type PassObject = LateLintPassObject<'tcx>;
-
/// Gets the overall compiler `Session` object.
fn sess(&self) -> &Session {
- &self.tcx.sess
- }
-
- fn lints(&self) -> &LintStore {
- &*self.lint_store
+ self.tcx.sess
}
#[rustc_lint_diagnostics]
@@ -1076,9 +1098,7 @@ impl<'tcx> LintContext for LateContext<'tcx> {
lint: &'static Lint,
span: Option<S>,
msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'b mut DiagnosticBuilder<'a, ()>,
- ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>),
) {
let hir_id = self.last_node_with_lint_attrs;
@@ -1094,15 +1114,9 @@ impl<'tcx> LintContext for LateContext<'tcx> {
}
impl LintContext for EarlyContext<'_> {
- type PassObject = EarlyLintPassObject;
-
/// Gets the overall compiler `Session` object.
fn sess(&self) -> &Session {
- &self.builder.sess()
- }
-
- fn lints(&self) -> &LintStore {
- self.builder.lint_store()
+ self.builder.sess()
}
#[rustc_lint_diagnostics]
@@ -1111,9 +1125,7 @@ impl LintContext for EarlyContext<'_> {
lint: &'static Lint,
span: Option<S>,
msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'b mut DiagnosticBuilder<'a, ()>,
- ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>),
) {
self.builder.struct_lint(lint, span.map(|s| s.into()), msg, decorate)
}
@@ -1149,7 +1161,7 @@ impl<'tcx> LateContext<'tcx> {
/// bodies (e.g. for paths in `hir::Ty`), without any risk of ICE-ing.
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: hir::HirId) -> Res {
match *qpath {
- hir::QPath::Resolved(_, ref path) => path.res,
+ hir::QPath::Resolved(_, path) => path.res,
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
.maybe_typeck_results()
.filter(|typeck_results| typeck_results.hir_owner == id.owner)
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index d2d99bc0d..4673b801d 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -50,7 +50,7 @@ declare_lint! {
Warn,
"`Deref` implementation usage with a supertrait trait object for output might be shadowed in the future",
@future_incompatible = FutureIncompatibleInfo {
- reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
+ reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
reference: "issue #89460 <https://github.com/rust-lang/rust/issues/89460>",
};
}
@@ -59,32 +59,46 @@ declare_lint_pass!(DerefIntoDynSupertrait => [DEREF_INTO_DYN_SUPERTRAIT]);
impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
+ let tcx = cx.tcx;
// `Deref` is being implemented for `t`
if let hir::ItemKind::Impl(impl_) = item.kind
+ // the trait is a `Deref` implementation
&& let Some(trait_) = &impl_.of_trait
- && let t = cx.tcx.type_of(item.owner_id).instantiate_identity()
- && let opt_did @ Some(did) = trait_.trait_def_id()
- && opt_did == cx.tcx.lang_items().deref_trait()
- // `t` is `dyn t_principal`
- && let ty::Dynamic(data, _, ty::Dyn) = t.kind()
- && let Some(t_principal) = data.principal()
+ && let Some(did) = trait_.trait_def_id()
+ && Some(did) == tcx.lang_items().deref_trait()
+ // the self type is `dyn t_principal`
+ && let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
+ && let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
+ && let Some(self_principal) = data.principal()
// `<T as Deref>::Target` is `dyn target_principal`
- && let Some(target) = cx.get_associated_type(t, did, "Target")
+ && let Some(target) = cx.get_associated_type(self_ty, did, "Target")
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
&& let Some(target_principal) = data.principal()
// `target_principal` is a supertrait of `t_principal`
- && supertraits(cx.tcx, t_principal.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self))
- .any(|sup| sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(cx.tcx, x)) == target_principal)
+ && let Some(supertrait_principal) = supertraits(tcx, self_principal.with_self_ty(tcx, self_ty))
+ .find(|supertrait| supertrait.def_id() == target_principal.def_id())
{
- let label = impl_
+ // erase regions in self type for better diagnostic presentation
+ let (self_ty, target_principal, supertrait_principal) =
+ tcx.erase_regions((self_ty, target_principal, supertrait_principal));
+ let label2 = impl_
.items
.iter()
.find_map(|i| (i.ident.name == sym::Target).then_some(i.span))
.map(|label| SupertraitAsDerefTargetLabel { label });
+ let span = tcx.def_span(item.owner_id.def_id);
cx.emit_spanned_lint(
DEREF_INTO_DYN_SUPERTRAIT,
- cx.tcx.def_span(item.owner_id.def_id),
- SupertraitAsDerefTarget { t, target_principal, label },
+ span,
+ SupertraitAsDerefTarget {
+ self_ty,
+ supertrait_principal: supertrait_principal.map_bound(|trait_ref| {
+ ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+ }),
+ target_principal,
+ label: span,
+ label2,
+ },
);
}
}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index d102e3a6c..b9add9e9f 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -45,13 +45,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
fn inlined_check_id(&mut self, id: ast::NodeId) {
for early_lint in self.context.buffered.take(id) {
let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint;
- self.context.lookup_with_diagnostics(
- lint_id.lint,
- Some(span),
- msg,
- |lint| lint,
- diagnostic,
- );
+ self.context.lookup_with_diagnostics(lint_id.lint, Some(span), msg, |_| {}, diagnostic);
}
}
@@ -162,8 +156,8 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
// Explicitly check for lints associated with 'closure_id', since
// it does not have a corresponding AST node
if let ast_visit::FnKind::Fn(_, _, sig, _, _, _) = fk {
- if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness {
- self.check_id(closure_id);
+ if let Some(coroutine_kind) = sig.header.coroutine_kind {
+ self.check_id(coroutine_kind.closure_id());
}
}
}
@@ -223,9 +217,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
// it does not have a corresponding AST node
match e.kind {
ast::ExprKind::Closure(box ast::Closure {
- asyncness: ast::Async::Yes { closure_id, .. },
+ coroutine_kind: Some(coroutine_kind),
..
- }) => self.check_id(closure_id),
+ }) => {
+ self.check_id(coroutine_kind.closure_id());
+ }
_ => {}
}
lint_callback!(self, check_expr_post, e);
@@ -350,7 +346,7 @@ impl<'a> EarlyCheckNode<'a> for (&'a ast::Crate, &'a [ast::Attribute]) {
where
'a: 'b,
{
- &self.1
+ self.1
}
fn check<'b, T: EarlyLintPass>(self, cx: &mut EarlyContextAndPass<'b, T>)
where
@@ -430,7 +426,7 @@ pub fn check_ast_node_inner<'a, T: EarlyLintPass>(
// that was not lint-checked (perhaps it doesn't exist?). This is a bug.
for (id, lints) in cx.context.buffered.map {
for early_lint in lints {
- sess.delay_span_bug(
+ sess.span_delayed_bug(
early_lint.span,
format!(
"failed to process buffered lint here (dummy = {})",
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 740c90757..5dcc1bce5 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -16,7 +16,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
}
let lint_expectations = tcx.lint_expectations(());
- let fulfilled_expectations = tcx.sess.diagnostic().steal_fulfilled_expectation_ids();
+ let fulfilled_expectations = tcx.sess.dcx().steal_fulfilled_expectation_ids();
tracing::debug!(?lint_expectations, ?fulfilled_expectations);
@@ -24,7 +24,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
// This check will always be true, since `lint_expectations` only
// holds stable ids
if let LintExpectationId::Stable { hir_id, .. } = id {
- if !fulfilled_expectations.contains(&id)
+ if !fulfilled_expectations.contains(id)
&& tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter))
{
let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale });
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index c8ec0458b..ea922785a 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -137,7 +137,7 @@ fn suggest_question_mark<'tcx>(
// Check that the function/closure/constant we are in has a `Result` type.
// Otherwise suggesting using `?` may not be a good idea.
{
- let ty = cx.typeck_results().expr_ty(&cx.tcx.hir().body(body_id).value);
+ let ty = cx.typeck_results().expr_ty(cx.tcx.hir().body(body_id).value);
let ty::Adt(ret_adt, ..) = ty.kind() else { return false };
if !cx.tcx.is_diagnostic_item(sym::Result, ret_adt.did()) {
return false;
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 86b3b4ad0..31d9c0d33 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -341,8 +341,8 @@ fn structurally_same_type_impl<'tcx>(
// We don't compare regions, but leaving bound regions around ICEs, so
// we erase them.
- let a_sig = tcx.erase_late_bound_regions(a_poly_sig);
- let b_sig = tcx.erase_late_bound_regions(b_poly_sig);
+ let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig);
+ let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig);
(a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
== (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 2d86129c4..53d99c7f7 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -34,7 +34,7 @@ declare_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]);
impl LateLintPass<'_> for DefaultHashTypes {
fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
let Res::Def(rustc_hir::def::DefKind::Struct, def_id) = path.res else { return };
- if matches!(cx.tcx.hir().get(hir_id), Node::Item(Item { kind: ItemKind::Use(..), .. })) {
+ if matches!(cx.tcx.hir_node(hir_id), Node::Item(Item { kind: ItemKind::Use(..), .. })) {
// don't lint imports, only actual usages
return;
}
@@ -196,7 +196,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
}
} else if !ty.span.from_expansion()
&& path.segments.len() > 1
- && let Some(ty) = is_ty_or_ty_ctxt(cx, &path)
+ && let Some(ty) = is_ty_or_ty_ctxt(cx, path)
{
cx.emit_spanned_lint(
USAGE_OF_QUALIFIED_TY,
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 6c8b60c8d..caa015565 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -17,22 +17,25 @@
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
use rustc_ast as ast;
use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_data_structures::sync::join;
+use rustc_data_structures::sync::{join, Lrc};
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
use rustc_hir::intravisit as hir_visit;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::LintPass;
+use rustc_session::Session;
use rustc_span::Span;
use std::any::Any;
use std::cell::Cell;
-/// Extract the `LintStore` from the query context.
-/// This function exists because we've erased `LintStore` as `dyn Any` in the context.
-pub fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore {
- let store: &dyn Any = &*tcx.lint_store;
+/// Extract the [`LintStore`] from [`Session`].
+///
+/// This function exists because [`Session::lint_store`] is type-erased.
+pub fn unerased_lint_store(sess: &Session) -> &LintStore {
+ let store: &Lrc<_> = sess.lint_store.as_ref().unwrap();
+ let store: &dyn Any = &**store;
store.downcast_ref().unwrap()
}
@@ -276,7 +279,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
let generics = self.context.generics.take();
- self.context.generics = Some(&trait_item.generics);
+ self.context.generics = Some(trait_item.generics);
self.with_lint_attrs(trait_item.hir_id(), |cx| {
cx.with_param_env(trait_item.owner_id, |cx| {
lint_callback!(cx, check_trait_item, trait_item);
@@ -288,7 +291,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
let generics = self.context.generics.take();
- self.context.generics = Some(&impl_item.generics);
+ self.context.generics = Some(impl_item.generics);
self.with_lint_attrs(impl_item.hir_id(), |cx| {
cx.with_param_env(impl_item.owner_id, |cx| {
lint_callback!(cx, check_impl_item, impl_item);
@@ -352,9 +355,8 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
- effective_visibilities: &tcx.effective_visibilities(()),
- lint_store: unerased_lint_store(tcx),
- last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
+ effective_visibilities: tcx.effective_visibilities(()),
+ last_node_with_lint_attrs: tcx.local_def_id_to_hir_id(module_def_id.into()),
generics: None,
only_module: true,
};
@@ -362,8 +364,11 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>(
// Note: `passes` is often empty. In that case, it's faster to run
// `builtin_lints` directly rather than bundling it up into the
// `RuntimeCombinedLateLintPass`.
- let mut passes: Vec<_> =
- unerased_lint_store(tcx).late_module_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
+ let mut passes: Vec<_> = unerased_lint_store(tcx.sess)
+ .late_module_passes
+ .iter()
+ .map(|mk_pass| (mk_pass)(tcx))
+ .collect();
if passes.is_empty() {
late_lint_mod_inner(tcx, module_def_id, context, builtin_lints);
} else {
@@ -400,7 +405,7 @@ fn late_lint_mod_inner<'tcx, T: LateLintPass<'tcx>>(
fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
// Note: `passes` is often empty.
let mut passes: Vec<_> =
- unerased_lint_store(tcx).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
+ unerased_lint_store(tcx.sess).late_passes.iter().map(|mk_pass| (mk_pass)(tcx)).collect();
if passes.is_empty() {
return;
@@ -411,8 +416,7 @@ fn late_lint_crate<'tcx>(tcx: TyCtxt<'tcx>) {
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
- effective_visibilities: &tcx.effective_visibilities(()),
- lint_store: unerased_lint_store(tcx),
+ effective_visibilities: tcx.effective_visibilities(()),
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
generics: None,
only_module: false,
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 0d20f6232..6eff2bfe1 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -56,7 +56,6 @@ struct LintLevelSets {
}
rustc_index::newtype_index! {
- #[custom_encodable] // we don't need encoding
struct LintStackIndex {
const COMMAND_LINE = 0;
}
@@ -123,7 +122,7 @@ impl LintLevelSets {
}
fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExpectation)> {
- let store = unerased_lint_store(tcx);
+ let store = unerased_lint_store(tcx.sess);
let mut builder = LintLevelsBuilder {
sess: tcx.sess,
@@ -138,21 +137,21 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
},
warn_about_weird_lints: false,
store,
- registered_tools: &tcx.registered_tools(()),
+ registered_tools: tcx.registered_tools(()),
};
builder.add_command_line();
builder.add_id(hir::CRATE_HIR_ID);
tcx.hir().walk_toplevel_module(&mut builder);
- tcx.sess.diagnostic().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
+ tcx.sess.dcx().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
builder.provider.expectations
}
#[instrument(level = "trace", skip(tcx), ret)]
fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
- let store = unerased_lint_store(tcx);
+ let store = unerased_lint_store(tcx.sess);
let attrs = tcx.hir_attrs(owner);
let mut levels = LintLevelsBuilder {
@@ -167,7 +166,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe
},
warn_about_weird_lints: false,
store,
- registered_tools: &tcx.registered_tools(()),
+ registered_tools: tcx.registered_tools(()),
};
if owner == hir::CRATE_OWNER_ID {
@@ -548,10 +547,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
self.features
}
- pub(crate) fn lint_store(&self) -> &LintStore {
- self.store
- }
-
fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
self.provider.current_specs()
}
@@ -609,7 +604,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
let orig_level = level;
let lint_flag_val = Symbol::intern(lint_name);
- let Ok(ids) = self.store.find_lints(&lint_name) else {
+ let Ok(ids) = self.store.find_lints(lint_name) else {
// errors already handled above
continue;
};
@@ -633,7 +628,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
/// (e.g. if a forbid was already inserted on the same scope), then emits a
/// diagnostic with no change to `specs`.
fn insert_spec(&mut self, id: LintId, (mut level, src): LevelAndSource) {
- let (old_level, old_src) = self.provider.get_lint_level(id.lint, &self.sess);
+ let (old_level, old_src) = self.provider.get_lint_level(id.lint, self.sess);
if let Level::Expect(id) = &mut level
&& let LintExpectationId::Stable { .. } = id
{
@@ -741,7 +736,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
if attr.has_name(sym::doc)
&& attr
.meta_item_list()
- .map_or(false, |l| ast::attr::list_contains_name(&l, sym::hidden))
+ .is_some_and(|l| ast::attr::list_contains_name(&l, sym::hidden))
{
self.insert(LintId::of(MISSING_DOCS), (Level::Allow, LintLevelSource::Default));
continue;
@@ -933,12 +928,12 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
DeprecatedLintName {
name,
suggestion: sp,
- replace: &new_lint_name,
+ replace: new_lint_name,
},
);
let src = LintLevelSource::Node {
- name: Symbol::intern(&new_lint_name),
+ name: Symbol::intern(new_lint_name),
span: sp,
reason,
};
@@ -1082,7 +1077,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
GateIssue::Language,
lint_from_cli,
);
- lint
},
);
return false;
@@ -1099,8 +1093,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
/// Used to emit a lint-related diagnostic based on the current state of
/// this lint context.
///
- /// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
- ///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
#[rustc_lint_diagnostics]
#[track_caller]
@@ -1109,9 +1101,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
lint: &'static Lint,
span: Option<MultiSpan>,
msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'b mut DiagnosticBuilder<'a, ()>,
- ) -> &'b mut DiagnosticBuilder<'a, ()>,
+ decorate: impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>),
) {
let (level, src) = self.lint_level(lint);
struct_lint_level(self.sess, lint, level, src, span, msg, decorate)
@@ -1126,7 +1116,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
) {
let (level, src) = self.lint_level(lint);
struct_lint_level(self.sess, lint, level, src, Some(span), decorate.msg(), |lint| {
- decorate.decorate_lint(lint)
+ decorate.decorate_lint(lint);
});
}
@@ -1134,7 +1124,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
pub fn emit_lint(&self, lint: &'static Lint, decorate: impl for<'a> DecorateLint<'a, ()>) {
let (level, src) = self.lint_level(lint);
struct_lint_level(self.sess, lint, level, src, None, decorate.msg(), |lint| {
- decorate.decorate_lint(lint)
+ decorate.decorate_lint(lint);
});
}
}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 54adedd3c..066c88cc6 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -27,8 +27,8 @@
#![allow(rustc::potential_query_instability)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
-#![cfg_attr(not(bootstrap), feature(rustdoc_internals))]
+#![doc(rust_logo)]
+#![feature(rustdoc_internals)]
#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
@@ -39,6 +39,7 @@
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
+#![feature(trait_upcasting)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
@@ -85,18 +86,14 @@ mod redundant_semicolon;
mod reference_casting;
mod traits;
mod types;
+mod unit_bindings;
mod unused;
pub use array_into_iter::ARRAY_INTO_ITER;
-use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_fluent_macro::fluent_messages;
use rustc_hir::def_id::LocalModDefId;
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::builtin::{
- BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
-};
use array_into_iter::ArrayIntoIter;
use async_fn_in_trait::AsyncFnInTrait;
@@ -123,6 +120,7 @@ use redundant_semicolon::*;
use reference_casting::*;
use traits::*;
use types::*;
+use unit_bindings::*;
use unused::*;
/// Useful for other parts of the compiler / Clippy.
@@ -136,7 +134,7 @@ pub use rustc_session::lint::Level::{self, *};
pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
pub use rustc_session::lint::{LintPass, LintVec};
-fluent_messages! { "../messages.ftl" }
+rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
pub fn provide(providers: &mut Providers) {
levels::provide(providers);
@@ -179,7 +177,6 @@ early_lint_methods!(
IncompleteInternalFeatures: IncompleteInternalFeatures,
RedundantSemicolons: RedundantSemicolons,
UnusedDocComment: UnusedDocComment,
- UnexpectedCfgs: UnexpectedCfgs,
]
]
);
@@ -203,6 +200,7 @@ late_lint_methods!(
InvalidReferenceCasting: InvalidReferenceCasting,
// Depends on referenced function signatures in expressions
UnusedResults: UnusedResults,
+ UnitBindings: UnitBindings,
NonUpperCaseGlobals: NonUpperCaseGlobals,
NonShorthandFieldPatterns: NonShorthandFieldPatterns,
UnusedAllocation: UnusedAllocation,
@@ -511,6 +509,11 @@ fn register_builtins(store: &mut LintStore) {
"converted into hard error, see PR #104616 \
<https://github.com/rust-lang/rust/pull/104616> for more information",
);
+ store.register_removed(
+ "implied_bounds_entailment",
+ "converted into hard error, see PR #117984 \
+ <https://github.com/rust-lang/rust/pull/117984> for more information",
+ );
}
fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 756899e50..9c0d3be03 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -134,12 +134,8 @@ pub struct BuiltinMissingDebugImpl<'a> {
// Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for BuiltinMissingDebugImpl<'_> {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("debug", self.tcx.def_path_str(self.def_id));
- diag
}
fn msg(&self) -> DiagnosticMessage {
@@ -243,17 +239,13 @@ pub struct BuiltinUngatedAsyncFnTrackCaller<'a> {
}
impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.span_label(self.label, fluent::lint_label);
rustc_session::parse::add_feature_diagnostics(
diag,
- &self.parse_sess,
+ self.parse_sess,
sym::async_fn_track_caller,
);
- diag
}
fn msg(&self) -> DiagnosticMessage {
@@ -433,10 +425,7 @@ pub struct BuiltinUnpermittedTypeInit<'a> {
}
impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("ty", self.ty);
diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label);
if let InhabitedPredicate::True = self.ty.inhabited_predicate(self.tcx) {
@@ -447,7 +436,6 @@ impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> {
);
}
self.sub.add_to_diagnostic(diag);
- diag
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
@@ -553,33 +541,21 @@ pub enum BuiltinSpecialModuleNameUsed {
Main,
}
-#[derive(LintDiagnostic)]
-#[diag(lint_builtin_unexpected_cli_config_name)]
-#[help]
-pub struct BuiltinUnexpectedCliConfigName {
- pub name: Symbol,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(lint_builtin_unexpected_cli_config_value)]
-#[help]
-pub struct BuiltinUnexpectedCliConfigValue {
- pub name: Symbol,
- pub value: Symbol,
-}
-
// deref_into_dyn_supertrait.rs
#[derive(LintDiagnostic)]
#[diag(lint_supertrait_as_deref_target)]
pub struct SupertraitAsDerefTarget<'a> {
- pub t: Ty<'a>,
+ pub self_ty: Ty<'a>,
+ pub supertrait_principal: PolyExistentialTraitRef<'a>,
pub target_principal: PolyExistentialTraitRef<'a>,
+ #[label]
+ pub label: Span,
#[subdiagnostic]
- pub label: Option<SupertraitAsDerefTargetLabel>,
+ pub label2: Option<SupertraitAsDerefTargetLabel>,
}
#[derive(Subdiagnostic)]
-#[label(lint_label)]
+#[label(lint_label2)]
pub struct SupertraitAsDerefTargetLabel {
#[primary_span]
pub label: Span,
@@ -1170,10 +1146,7 @@ pub struct NonFmtPanicUnused {
// Used because of two suggestions based on one Option<Span>
impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("count", self.count);
diag.note(fluent::lint_note);
if let Some(span) = self.suggestion {
@@ -1190,7 +1163,6 @@ impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
Applicability::MachineApplicable,
);
}
- diag
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
@@ -1369,12 +1341,9 @@ pub struct DropTraitConstraintsDiag<'a> {
// Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("predicate", self.predicate);
- diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
+ diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id));
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
@@ -1389,11 +1358,8 @@ pub struct DropGlue<'a> {
// Needed for def_path_str
impl<'a> DecorateLint<'a, ()> for DropGlue<'_> {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
- diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
+ diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id));
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
@@ -1585,6 +1551,76 @@ pub enum InvalidNanComparisonsSuggestion {
Spanless,
}
+#[derive(LintDiagnostic)]
+pub enum AmbiguousWidePointerComparisons<'a> {
+ #[diag(lint_ambiguous_wide_pointer_comparisons)]
+ Spanful {
+ #[subdiagnostic]
+ addr_suggestion: AmbiguousWidePointerComparisonsAddrSuggestion<'a>,
+ #[subdiagnostic]
+ addr_metadata_suggestion: Option<AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a>>,
+ },
+ #[diag(lint_ambiguous_wide_pointer_comparisons)]
+ #[help(lint_addr_metadata_suggestion)]
+ #[help(lint_addr_suggestion)]
+ Spanless,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+ lint_addr_metadata_suggestion,
+ style = "verbose",
+ applicability = "machine-applicable"
+)]
+pub struct AmbiguousWidePointerComparisonsAddrMetadataSuggestion<'a> {
+ pub ne: &'a str,
+ pub deref_left: &'a str,
+ pub deref_right: &'a str,
+ #[suggestion_part(code = "{ne}std::ptr::eq({deref_left}")]
+ pub left: Span,
+ #[suggestion_part(code = ", {deref_right}")]
+ pub middle: Span,
+ #[suggestion_part(code = ")")]
+ pub right: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub enum AmbiguousWidePointerComparisonsAddrSuggestion<'a> {
+ #[multipart_suggestion(
+ lint_addr_suggestion,
+ style = "verbose",
+ applicability = "machine-applicable"
+ )]
+ AddrEq {
+ ne: &'a str,
+ deref_left: &'a str,
+ deref_right: &'a str,
+ #[suggestion_part(code = "{ne}std::ptr::addr_eq({deref_left}")]
+ left: Span,
+ #[suggestion_part(code = ", {deref_right}")]
+ middle: Span,
+ #[suggestion_part(code = ")")]
+ right: Span,
+ },
+ #[multipart_suggestion(
+ lint_addr_suggestion,
+ style = "verbose",
+ applicability = "machine-applicable"
+ )]
+ Cast {
+ deref_left: &'a str,
+ deref_right: &'a str,
+ #[suggestion_part(code = "{deref_left}")]
+ left_before: Option<Span>,
+ #[suggestion_part(code = " as *const ()")]
+ left: Span,
+ #[suggestion_part(code = "{deref_right}")]
+ right_before: Option<Span>,
+ #[suggestion_part(code = " as *const ()")]
+ right: Span,
+ },
+}
+
pub struct ImproperCTypes<'a> {
pub ty: Ty<'a>,
pub desc: &'a str,
@@ -1596,10 +1632,7 @@ pub struct ImproperCTypes<'a> {
// Used because of the complexity of Option<DiagnosticMessage>, DiagnosticMessage, and Option<Span>
impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("ty", self.ty);
diag.set_arg("desc", self.desc);
diag.span_label(self.label, fluent::lint_label);
@@ -1610,7 +1643,6 @@ impl<'a> DecorateLint<'a, ()> for ImproperCTypes<'_> {
if let Some(note) = self.span_note {
diag.span_note(note, fluent::lint_note);
}
- diag
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
@@ -1743,10 +1775,7 @@ pub enum UnusedDefSuggestion {
// Needed because of def_path_str
impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.set_arg("pre", self.pre);
diag.set_arg("post", self.post);
diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id));
@@ -1757,7 +1786,6 @@ impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
if let Some(sugg) = self.suggestion {
diag.subdiagnostic(sugg);
}
- diag
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
@@ -1830,18 +1858,21 @@ pub struct AsyncFnInTraitDiag {
}
impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag {
- fn decorate_lint<'b>(
- self,
- diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
- ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
+ fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>) {
diag.note(fluent::lint_note);
if let Some(sugg) = self.sugg {
diag.multipart_suggestion(fluent::lint_suggestion, sugg, Applicability::MaybeIncorrect);
}
- diag
}
fn msg(&self) -> rustc_errors::DiagnosticMessage {
fluent::lint_async_fn_in_trait
}
}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unit_bindings)]
+pub struct UnitBindingsDiag {
+ #[label]
+ pub label: Span,
+}
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 62bb8c2c6..4f92fcd71 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -204,7 +204,7 @@ impl EarlyLintPass for NonAsciiIdents {
// Get the skeleton as a `Symbol`.
skeleton_buf.clear();
- skeleton_buf.extend(skeleton(&symbol_str));
+ skeleton_buf.extend(skeleton(symbol_str));
let skeleton_sym = if *symbol_str == *skeleton_buf {
symbol
} else {
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index b218cc578..9fcd70ba0 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -126,7 +126,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
lint.note(fluent::lint_more_info_note);
if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from.
- return lint;
+ return;
}
if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`.
@@ -154,17 +154,13 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
let infcx = cx.tcx.infer_ctxt().build();
let suggest_display = is_str
- || cx
- .tcx
- .get_diagnostic_item(sym::Display)
- .map(|t| infcx.type_implements_trait(t, [ty], cx.param_env).may_apply())
- == Some(true);
+ || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| {
+ infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
+ });
let suggest_debug = !suggest_display
- && cx
- .tcx
- .get_diagnostic_item(sym::Debug)
- .map(|t| infcx.type_implements_trait(t, [ty], cx.param_env).may_apply())
- == Some(true);
+ && cx.tcx.get_diagnostic_item(sym::Debug).is_some_and(|t| {
+ infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
+ });
let suggest_panic_any = !is_str && panic == sym::std_panic_macro;
@@ -211,7 +207,6 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
}
}
}
- lint
});
}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 66dc726df..59f27a88a 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -334,7 +334,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
Some(Ident::from_str(name))
} else {
- attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
+ attr::find_by_name(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
.and_then(|attr| attr.meta())
.and_then(|meta| {
meta.name_value_literal().and_then(|lit| {
@@ -473,7 +473,7 @@ impl NonUpperCaseGlobals {
fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
let name = ident.name.as_str();
if name.chars().any(|c| c.is_lowercase()) {
- let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
+ let uc = NonSnakeCase::to_snake_case(name).to_uppercase();
// We cannot provide meaningful suggestions
// if the characters are in the category of "Lowercase Letter".
let sub = if *name != uc {
@@ -520,7 +520,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
// Lint for constants that look like binding identifiers (#7526)
- if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.kind {
+ if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
if let Res::Def(DefKind::Const, _) = path.res {
if path.segments.len() == 1 {
NonUpperCaseGlobals::check_upper_case(
@@ -534,9 +534,9 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
}
fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) {
- if let GenericParamKind::Const { .. } = param.kind {
- // `rustc_host` params are explicitly allowed to be lowercase.
- if cx.tcx.has_attr(param.def_id, sym::rustc_host) {
+ if let GenericParamKind::Const { is_host_effect, .. } = param.kind {
+ // `host` params are explicitly allowed to be lowercase.
+ if is_host_effect {
return;
}
NonUpperCaseGlobals::check_upper_case(cx, "const parameter", &param.name.ident());
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index c24846ca9..44b23b8bd 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
for (assoc_pred, assoc_pred_span) in cx
.tcx
.explicit_item_bounds(proj.projection_ty.def_id)
- .iter_instantiated_copied(cx.tcx, &proj.projection_ty.args)
+ .iter_instantiated_copied(cx.tcx, proj.projection_ty.args)
{
let assoc_pred = assoc_pred.fold_with(proj_replacer);
let Ok(assoc_pred) = traits::fully_normalize(
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index cad2cd7fa..fce750c9b 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -28,7 +28,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
return;
}
}
- if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
+ if let Some(t) = path_for_pass_by_value(cx, inner_ty) {
cx.emit_spanned_lint(
PASS_BY_VALUE,
ty.span,
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index d44691b5e..96290288f 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -37,59 +37,73 @@ declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]);
impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- let Some((is_assignment, e)) = is_operation_we_care_about(cx, expr) else {
- return;
- };
-
- let init = cx.expr_or_init(e);
-
- let Some(ty_has_interior_mutability) = is_cast_from_const_to_mut(cx, init) else {
- return;
- };
- let orig_cast = if init.span != e.span { Some(init.span) } else { None };
- let ty_has_interior_mutability = ty_has_interior_mutability.then_some(());
-
- cx.emit_spanned_lint(
- INVALID_REFERENCE_CASTING,
- expr.span,
- if is_assignment {
- InvalidReferenceCastingDiag::AssignToRef { orig_cast, ty_has_interior_mutability }
- } else {
- InvalidReferenceCastingDiag::BorrowAsMut { orig_cast, ty_has_interior_mutability }
- },
- );
+ if let Some((e, pat)) = borrow_or_assign(cx, expr) {
+ if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign) {
+ let init = cx.expr_or_init(e);
+
+ let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init) else {
+ return;
+ };
+ let orig_cast = if init.span != e.span { Some(init.span) } else { None };
+ let ty_has_interior_mutability = ty_has_interior_mutability.then_some(());
+
+ cx.emit_spanned_lint(
+ INVALID_REFERENCE_CASTING,
+ expr.span,
+ if pat == PatternKind::Assign {
+ InvalidReferenceCastingDiag::AssignToRef {
+ orig_cast,
+ ty_has_interior_mutability,
+ }
+ } else {
+ InvalidReferenceCastingDiag::BorrowAsMut {
+ orig_cast,
+ ty_has_interior_mutability,
+ }
+ },
+ );
+ }
+ }
}
}
-fn is_operation_we_care_about<'tcx>(
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum PatternKind {
+ Borrow { mutbl: Mutability },
+ Assign,
+}
+
+fn borrow_or_assign<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'tcx>,
-) -> Option<(bool, &'tcx Expr<'tcx>)> {
- fn deref_assign_or_addr_of<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(bool, &'tcx Expr<'tcx>)> {
- // &mut <expr>
- let inner = if let ExprKind::AddrOf(_, Mutability::Mut, expr) = expr.kind {
- expr
+) -> Option<(&'tcx Expr<'tcx>, PatternKind)> {
+ fn deref_assign_or_addr_of<'tcx>(
+ expr: &'tcx Expr<'tcx>,
+ ) -> Option<(&'tcx Expr<'tcx>, PatternKind)> {
+ // &(mut) <expr>
+ let (inner, pat) = if let ExprKind::AddrOf(_, mutbl, expr) = expr.kind {
+ (expr, PatternKind::Borrow { mutbl })
// <expr> = ...
} else if let ExprKind::Assign(expr, _, _) = expr.kind {
- expr
+ (expr, PatternKind::Assign)
// <expr> += ...
} else if let ExprKind::AssignOp(_, expr, _) = expr.kind {
- expr
+ (expr, PatternKind::Assign)
} else {
return None;
};
- if let ExprKind::Unary(UnOp::Deref, e) = &inner.kind {
- Some((!matches!(expr.kind, ExprKind::AddrOf(..)), e))
- } else {
- None
- }
+ // *<inner>
+ let ExprKind::Unary(UnOp::Deref, e) = &inner.kind else {
+ return None;
+ };
+ Some((e, pat))
}
fn ptr_write<'tcx>(
cx: &LateContext<'tcx>,
e: &'tcx Expr<'tcx>,
- ) -> Option<(bool, &'tcx Expr<'tcx>)> {
+ ) -> Option<(&'tcx Expr<'tcx>, PatternKind)> {
if let ExprKind::Call(path, [arg_ptr, _arg_val]) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
@@ -98,7 +112,7 @@ fn is_operation_we_care_about<'tcx>(
Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned)
)
{
- Some((true, arg_ptr))
+ Some((arg_ptr, PatternKind::Assign))
} else {
None
}
@@ -107,13 +121,10 @@ fn is_operation_we_care_about<'tcx>(
deref_assign_or_addr_of(e).or_else(|| ptr_write(cx, e))
}
-fn is_cast_from_const_to_mut<'tcx>(
+fn is_cast_from_ref_to_mut_ptr<'tcx>(
cx: &LateContext<'tcx>,
orig_expr: &'tcx Expr<'tcx>,
) -> Option<bool> {
- let mut need_check_freeze = false;
- let mut e = orig_expr;
-
let end_ty = cx.typeck_results().node_type(orig_expr.hir_id);
// Bail out early if the end type is **not** a mutable pointer.
@@ -121,6 +132,28 @@ fn is_cast_from_const_to_mut<'tcx>(
return None;
}
+ let (e, need_check_freeze) = peel_casts(cx, orig_expr);
+
+ let start_ty = cx.typeck_results().node_type(e.hir_id);
+ if let ty::Ref(_, inner_ty, Mutability::Not) = start_ty.kind() {
+ // If an UnsafeCell method is involved, we need to additionally check the
+ // inner type for the presence of the Freeze trait (ie does NOT contain
+ // an UnsafeCell), since in that case we would incorrectly lint on valid casts.
+ //
+ // Except on the presence of non concrete skeleton types (ie generics)
+ // since there is no way to make it safe for arbitrary types.
+ let inner_ty_has_interior_mutability =
+ !inner_ty.is_freeze(cx.tcx, cx.param_env) && inner_ty.has_concrete_skeleton();
+ (!need_check_freeze || !inner_ty_has_interior_mutability)
+ .then_some(inner_ty_has_interior_mutability)
+ } else {
+ None
+ }
+}
+
+fn peel_casts<'tcx>(cx: &LateContext<'tcx>, mut e: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
+ let mut gone_trough_unsafe_cell_raw_get = false;
+
loop {
e = e.peel_blocks();
// <expr> as ...
@@ -145,27 +178,18 @@ fn is_cast_from_const_to_mut<'tcx>(
)
{
if cx.tcx.is_diagnostic_item(sym::unsafe_cell_raw_get, def_id) {
- need_check_freeze = true;
+ gone_trough_unsafe_cell_raw_get = true;
}
arg
} else {
- break;
+ let init = cx.expr_or_init(e);
+ if init.hir_id != e.hir_id {
+ init
+ } else {
+ break;
+ }
};
}
- let start_ty = cx.typeck_results().node_type(e.hir_id);
- if let ty::Ref(_, inner_ty, Mutability::Not) = start_ty.kind() {
- // If an UnsafeCell method is involved we need to additionaly check the
- // inner type for the presence of the Freeze trait (ie does NOT contain
- // an UnsafeCell), since in that case we would incorrectly lint on valid casts.
- //
- // We also consider non concrete skeleton types (ie generics)
- // to be an issue since there is no way to make it safe for abitrary types.
- let inner_ty_has_interior_mutability =
- !inner_ty.is_freeze(cx.tcx, cx.param_env) && inner_ty.has_concrete_skeleton();
- (!need_check_freeze || !inner_ty_has_interior_mutability)
- .then_some(inner_ty_has_interior_mutability)
- } else {
- None
- }
+ (e, gone_trough_unsafe_cell_raw_get)
}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index c04053d18..6dade43a1 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1,12 +1,13 @@
use crate::{
fluent_generated as fluent,
lints::{
- AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes,
- InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion,
- OnlyCastu8ToChar, OverflowingBinHex, OverflowingBinHexSign, OverflowingBinHexSignBitSub,
- OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral,
- OverflowingUInt, RangeEndpointOutOfRange, UnusedComparisons, UseInclusiveRange,
- VariantSizeDifferencesDiag,
+ AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
+ AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
+ AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
+ InvalidNanComparisonsSuggestion, OnlyCastu8ToChar, OverflowingBinHex,
+ OverflowingBinHexSign, OverflowingBinHexSignBitSub, OverflowingBinHexSub, OverflowingInt,
+ OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange,
+ UnusedComparisons, UseInclusiveRange, VariantSizeDifferencesDiag,
},
};
use crate::{LateContext, LateLintPass, LintContext};
@@ -17,10 +18,10 @@ use rustc_errors::DiagnosticMessage;
use rustc_hir as hir;
use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
-use rustc_middle::ty::GenericArgsRef;
use rustc_middle::ty::{
self, AdtKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
};
+use rustc_middle::ty::{GenericArgsRef, TypeAndMut};
use rustc_span::def_id::LocalDefId;
use rustc_span::source_map;
use rustc_span::symbol::sym;
@@ -28,6 +29,7 @@ use rustc_span::{Span, Symbol};
use rustc_target::abi::{Abi, Size, WrappingRange};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
+use rustc_type_ir::DynKind;
use std::iter;
use std::ops::ControlFlow;
@@ -136,6 +138,37 @@ declare_lint! {
"detects invalid floating point NaN comparisons"
}
+declare_lint! {
+ /// The `ambiguous_wide_pointer_comparisons` lint checks comparison
+ /// of `*const/*mut ?Sized` as the operands.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # struct A;
+ /// # struct B;
+ ///
+ /// # trait T {}
+ /// # impl T for A {}
+ /// # impl T for B {}
+ ///
+ /// let ab = (A, B);
+ /// let a = &ab.0 as *const dyn T;
+ /// let b = &ab.1 as *const dyn T;
+ ///
+ /// let _ = a == b;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The comparison includes metadata which may not be expected.
+ AMBIGUOUS_WIDE_POINTER_COMPARISONS,
+ Warn,
+ "detects ambiguous wide pointer comparisons"
+}
+
#[derive(Copy, Clone)]
pub struct TypeLimits {
/// Id of the last visited negated expression
@@ -144,7 +177,12 @@ pub struct TypeLimits {
negated_expr_span: Option<Span>,
}
-impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS, INVALID_NAN_COMPARISONS]);
+impl_lint_pass!(TypeLimits => [
+ UNUSED_COMPARISONS,
+ OVERFLOWING_LITERALS,
+ INVALID_NAN_COMPARISONS,
+ AMBIGUOUS_WIDE_POINTER_COMPARISONS
+]);
impl TypeLimits {
pub fn new() -> TypeLimits {
@@ -164,7 +202,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
) -> bool {
// Look past casts to support cases like `0..256 as u8`
let (expr, lit_span) = if let Node::Expr(par_expr) =
- cx.tcx.hir().get(cx.tcx.hir().parent_id(expr.hir_id))
+ cx.tcx.hir_node(cx.tcx.hir().parent_id(expr.hir_id))
&& let ExprKind::Cast(_, _) = par_expr.kind
{
(par_expr, expr.span)
@@ -175,7 +213,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
// We only want to handle exclusive (`..`) ranges,
// which are represented as `ExprKind::Struct`.
let par_id = cx.tcx.hir().parent_id(expr.hir_id);
- let Node::ExprField(field) = cx.tcx.hir().get(par_id) else { return false };
+ let Node::ExprField(field) = cx.tcx.hir_node(par_id) else { return false };
let Node::Expr(struct_expr) = cx.tcx.hir().get_parent(field.hir_id) else { return false };
if !is_range_literal(struct_expr) {
return false;
@@ -460,7 +498,7 @@ fn lint_uint_literal<'tcx>(
};
if lit_val < min || lit_val > max {
let parent_id = cx.tcx.hir().parent_id(e.hir_id);
- if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) {
+ if let Node::Expr(par_e) = cx.tcx.hir_node(parent_id) {
match par_e.kind {
hir::ExprKind::Cast(..) => {
if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
@@ -620,10 +658,110 @@ fn lint_nan<'tcx>(
cx.emit_spanned_lint(INVALID_NAN_COMPARISONS, e.span, lint);
}
+fn lint_wide_pointer<'tcx>(
+ cx: &LateContext<'tcx>,
+ e: &'tcx hir::Expr<'tcx>,
+ binop: hir::BinOpKind,
+ l: &'tcx hir::Expr<'tcx>,
+ r: &'tcx hir::Expr<'tcx>,
+) {
+ let ptr_unsized = |mut ty: Ty<'tcx>| -> Option<(usize, bool)> {
+ let mut refs = 0;
+ // here we remove any "implicit" references and count the number
+ // of them to correctly suggest the right number of deref
+ while let ty::Ref(_, inner_ty, _) = ty.kind() {
+ ty = *inner_ty;
+ refs += 1;
+ }
+ match ty.kind() {
+ ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
+ .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))),
+ _ => None,
+ }
+ };
+
+ // PartialEq::{eq,ne} takes references, remove any explicit references
+ let l = l.peel_borrows();
+ let r = r.peel_borrows();
+
+ let Some(l_ty) = cx.typeck_results().expr_ty_opt(l) else {
+ return;
+ };
+ let Some(r_ty) = cx.typeck_results().expr_ty_opt(r) else {
+ return;
+ };
+
+ let Some((l_ty_refs, l_inner_ty_is_dyn)) = ptr_unsized(l_ty) else {
+ return;
+ };
+ let Some((r_ty_refs, r_inner_ty_is_dyn)) = ptr_unsized(r_ty) else {
+ return;
+ };
+
+ let (Some(l_span), Some(r_span)) =
+ (l.span.find_ancestor_inside(e.span), r.span.find_ancestor_inside(e.span))
+ else {
+ return cx.emit_spanned_lint(
+ AMBIGUOUS_WIDE_POINTER_COMPARISONS,
+ e.span,
+ AmbiguousWidePointerComparisons::Spanless,
+ );
+ };
+
+ let ne = if binop == hir::BinOpKind::Ne { "!" } else { "" };
+ let is_eq_ne = matches!(binop, hir::BinOpKind::Eq | hir::BinOpKind::Ne);
+ let is_dyn_comparison = l_inner_ty_is_dyn && r_inner_ty_is_dyn;
+
+ let left = e.span.shrink_to_lo().until(l_span.shrink_to_lo());
+ let middle = l_span.shrink_to_hi().until(r_span.shrink_to_lo());
+ let right = r_span.shrink_to_hi().until(e.span.shrink_to_hi());
+
+ let deref_left = &*"*".repeat(l_ty_refs);
+ let deref_right = &*"*".repeat(r_ty_refs);
+
+ cx.emit_spanned_lint(
+ AMBIGUOUS_WIDE_POINTER_COMPARISONS,
+ e.span,
+ AmbiguousWidePointerComparisons::Spanful {
+ addr_metadata_suggestion: (is_eq_ne && !is_dyn_comparison).then(|| {
+ AmbiguousWidePointerComparisonsAddrMetadataSuggestion {
+ ne,
+ deref_left,
+ deref_right,
+ left,
+ middle,
+ right,
+ }
+ }),
+ addr_suggestion: if is_eq_ne {
+ AmbiguousWidePointerComparisonsAddrSuggestion::AddrEq {
+ ne,
+ deref_left,
+ deref_right,
+ left,
+ middle,
+ right,
+ }
+ } else {
+ AmbiguousWidePointerComparisonsAddrSuggestion::Cast {
+ deref_left,
+ deref_right,
+ // those two Options are required for correctness as having
+ // an empty span and an empty suggestion is not permitted
+ left_before: (l_ty_refs != 0).then_some(left),
+ right_before: (r_ty_refs != 0).then(|| r_span.shrink_to_lo()),
+ left: l_span.shrink_to_hi(),
+ right,
+ }
+ },
+ },
+ );
+}
+
impl<'tcx> LateLintPass<'tcx> for TypeLimits {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
match e.kind {
- hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
+ hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
// Propagate negation, if the negation itself isn't negated
if self.negated_expr_id != Some(e.hir_id) {
self.negated_expr_id = Some(expr.hir_id);
@@ -632,14 +770,30 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
}
hir::ExprKind::Binary(binop, ref l, ref r) => {
if is_comparison(binop) {
- if !check_limits(cx, binop, &l, &r) {
+ if !check_limits(cx, binop, l, r) {
cx.emit_spanned_lint(UNUSED_COMPARISONS, e.span, UnusedComparisons);
} else {
lint_nan(cx, e, binop, l, r);
+ lint_wide_pointer(cx, e, binop.node, l, r);
}
}
}
- hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
+ hir::ExprKind::Lit(lit) => lint_literal(cx, self, e, lit),
+ hir::ExprKind::Call(path, [l, r])
+ if let ExprKind::Path(ref qpath) = path.kind
+ && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+ && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
+ && let Some(binop) = partialeq_binop(diag_item) =>
+ {
+ lint_wide_pointer(cx, e, binop, l, r);
+ }
+ hir::ExprKind::MethodCall(_, l, [r], _)
+ if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
+ && let Some(diag_item) = cx.tcx.get_diagnostic_name(def_id)
+ && let Some(binop) = partialeq_binop(diag_item) =>
+ {
+ lint_wide_pointer(cx, e, binop, l, r);
+ }
_ => {}
};
@@ -685,7 +839,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
ty::Int(int_ty) => {
let (min, max) = int_ty_range(int_ty);
let lit_val: i128 = match lit.kind {
- hir::ExprKind::Lit(ref li) => match li.node {
+ hir::ExprKind::Lit(li) => match li.node {
ast::LitKind::Int(
v,
ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed,
@@ -699,7 +853,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
ty::Uint(uint_ty) => {
let (min, max): (u128, u128) = uint_ty_range(uint_ty);
let lit_val: u128 = match lit.kind {
- hir::ExprKind::Lit(ref li) => match li.node {
+ hir::ExprKind::Lit(li) => match li.node {
ast::LitKind::Int(v, _) => v,
_ => return true,
},
@@ -722,6 +876,16 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
| hir::BinOpKind::Gt
)
}
+
+ fn partialeq_binop(diag_item: Symbol) -> Option<hir::BinOpKind> {
+ if diag_item == sym::cmp_partialeq_eq {
+ Some(hir::BinOpKind::Eq)
+ } else if diag_item == sym::cmp_partialeq_ne {
+ Some(hir::BinOpKind::Ne)
+ } else {
+ None
+ }
+ }
}
}
@@ -1015,7 +1179,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// We can't completely trust `repr(C)` markings, so make sure the fields are actually safe.
let mut all_phantom = !variant.fields.is_empty();
for field in &variant.fields {
- all_phantom &= match self.check_field_type_for_ffi(cache, &field, args) {
+ all_phantom &= match self.check_field_type_for_ffi(cache, field, args) {
FfiSafe => false,
// `()` fields are FFI-safe!
FfiUnsafe { ty, .. } if ty.is_unit() => false,
@@ -1234,7 +1398,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
};
}
- let sig = tcx.erase_late_bound_regions(sig);
+ let sig = tcx.instantiate_bound_regions_with_erased(sig);
for arg in sig.inputs() {
match self.check_type_for_ffi(cache, *arg) {
FfiSafe => {}
@@ -1391,7 +1555,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// types that have external ABIs, as these still need checked.
fn check_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) {
let sig = self.cx.tcx.fn_sig(def_id).instantiate_identity();
- let sig = self.cx.tcx.erase_late_bound_regions(sig);
+ let sig = self.cx.tcx.instantiate_bound_regions_with_erased(sig);
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(input_hir, *input_ty) {
@@ -1399,7 +1563,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
}
- if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
+ if let hir::FnRetTy::Return(ret_hir) = decl.output {
for (fn_ptr_ty, span) in self.find_fn_ptr_ty_with_external_abi(ret_hir, sig.output()) {
self.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, true);
}
@@ -1409,13 +1573,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if a function's argument types and result type are "ffi-safe".
fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &'tcx hir::FnDecl<'_>) {
let sig = self.cx.tcx.fn_sig(def_id).instantiate_identity();
- let sig = self.cx.tcx.erase_late_bound_regions(sig);
+ let sig = self.cx.tcx.instantiate_bound_regions_with_erased(sig);
for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
self.check_type_for_ffi_and_report_errors(input_hir.span, *input_ty, false, false);
}
- if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
+ if let hir::FnRetTy::Return(ret_hir) = decl.output {
self.check_type_for_ffi_and_report_errors(ret_hir.span, sig.output(), false, true);
}
}
@@ -1487,13 +1651,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());
match it.kind {
- hir::ForeignItemKind::Fn(ref decl, _, _) if !vis.is_internal_abi(abi) => {
+ hir::ForeignItemKind::Fn(decl, _, _) if !vis.is_internal_abi(abi) => {
vis.check_foreign_fn(it.owner_id.def_id, decl);
}
- hir::ForeignItemKind::Static(ref ty, _) if !vis.is_internal_abi(abi) => {
+ hir::ForeignItemKind::Static(ty, _) if !vis.is_internal_abi(abi) => {
vis.check_foreign_static(it.owner_id, ty.span);
}
- hir::ForeignItemKind::Fn(ref decl, _, _) => vis.check_fn(it.owner_id.def_id, decl),
+ hir::ForeignItemKind::Fn(decl, _, _) => vis.check_fn(it.owner_id.def_id, decl),
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
}
}
@@ -1705,7 +1869,7 @@ impl InvalidAtomicOrdering {
sym::AtomicI64,
sym::AtomicI128,
];
- if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind
+ if let ExprKind::MethodCall(method_path, _, args, _) = &expr.kind
&& recognized_names.contains(&method_path.ident.name)
&& let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
&& let Some(impl_did) = cx.tcx.impl_of_method(m_def_id)
@@ -1766,7 +1930,7 @@ impl InvalidAtomicOrdering {
}
fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if let ExprKind::Call(ref func, ref args) = expr.kind
+ if let ExprKind::Call(func, args) = expr.kind
&& let ExprKind::Path(ref func_qpath) = func.kind
&& let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
&& matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
diff --git a/compiler/rustc_lint/src/unit_bindings.rs b/compiler/rustc_lint/src/unit_bindings.rs
new file mode 100644
index 000000000..c80889f3a
--- /dev/null
+++ b/compiler/rustc_lint/src/unit_bindings.rs
@@ -0,0 +1,72 @@
+use crate::lints::UnitBindingsDiag;
+use crate::{LateLintPass, LintContext};
+use rustc_hir as hir;
+use rustc_middle::ty::Ty;
+
+declare_lint! {
+ /// The `unit_bindings` lint detects cases where bindings are useless because they have
+ /// the unit type `()` as their inferred type. The lint is suppressed if the user explicitly
+ /// annotates the let binding with the unit type `()`, or if the let binding uses an underscore
+ /// wildcard pattern, i.e. `let _ = expr`, or if the binding is produced from macro expansions.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unit_bindings)]
+ ///
+ /// fn foo() {
+ /// println!("do work");
+ /// }
+ ///
+ /// pub fn main() {
+ /// let x = foo(); // useless binding
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Creating a local binding with the unit type `()` does not do much and can be a sign of a
+ /// user error, such as in this example:
+ ///
+ /// ```rust,no_run
+ /// fn main() {
+ /// let mut x = [1, 2, 3];
+ /// x[0] = 5;
+ /// let y = x.sort(); // useless binding as `sort` returns `()` and not the sorted array.
+ /// println!("{:?}", y); // prints "()"
+ /// }
+ /// ```
+ pub UNIT_BINDINGS,
+ Allow,
+ "binding is useless because it has the unit `()` type"
+}
+
+declare_lint_pass!(UnitBindings => [UNIT_BINDINGS]);
+
+impl<'tcx> LateLintPass<'tcx> for UnitBindings {
+ fn check_local(&mut self, cx: &crate::LateContext<'tcx>, local: &'tcx hir::Local<'tcx>) {
+ // Suppress warning if user:
+ // - explicitly ascribes a type to the pattern
+ // - explicitly wrote `let pat = ();`
+ // - explicitly wrote `let () = init;`.
+ if !local.span.from_expansion()
+ && let Some(tyck_results) = cx.maybe_typeck_results()
+ && let Some(init) = local.init
+ && let init_ty = tyck_results.expr_ty(init)
+ && let local_ty = tyck_results.node_type(local.hir_id)
+ && init_ty == Ty::new_unit(cx.tcx)
+ && local_ty == Ty::new_unit(cx.tcx)
+ && local.ty.is_none()
+ && !matches!(init.kind, hir::ExprKind::Tup([]))
+ && !matches!(local.pat.kind, hir::PatKind::Tuple([], ..))
+ {
+ cx.emit_spanned_lint(
+ UNIT_BINDINGS,
+ local.span,
+ UnitBindingsDiag { label: local.pat.span },
+ );
+ }
+ }
+}
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 355855b8e..34cdee4ec 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
if let hir::ExprKind::Match(await_expr, _arms, hir::MatchSource::AwaitDesugar) = expr.kind
- && let ty = cx.typeck_results().expr_ty(&await_expr)
+ && let ty = cx.typeck_results().expr_ty(await_expr)
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind()
&& cx.tcx.ty_is_opaque_future(ty)
&& let async_fn_def_id = cx.tcx.parent(*future_def_id)
@@ -132,9 +132,9 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
return;
}
- let ty = cx.typeck_results().expr_ty(&expr);
+ let ty = cx.typeck_results().expr_ty(expr);
- let must_use_result = is_ty_must_use(cx, ty, &expr, expr.span);
+ let must_use_result = is_ty_must_use(cx, ty, expr, expr.span);
let type_lint_emitted_or_suppressed = match must_use_result {
Some(path) => {
emit_must_use_untranslated(cx, &path, "", "", 1, false, expr_is_from_block);
@@ -211,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
expr_is_from_block: bool,
) -> bool {
let maybe_def_id = match expr.kind {
- hir::ExprKind::Call(ref callee, _) => {
+ hir::ExprKind::Call(callee, _) => {
match callee.kind {
hir::ExprKind::Path(ref qpath) => {
match cx.qpath_res(qpath, callee.hir_id) {
@@ -251,6 +251,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
/// The root of the normal must_use lint with an optional message.
Def(Span, DefId, Option<Symbol>),
Boxed(Box<Self>),
+ Pinned(Box<Self>),
Opaque(Box<Self>),
TraitObject(Box<Self>),
TupleElement(Vec<(usize, Self)>),
@@ -284,8 +285,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
is_ty_must_use(cx, boxed_ty, expr, span)
.map(|inner| MustUsePath::Boxed(Box::new(inner)))
}
+ ty::Adt(def, args) if cx.tcx.lang_items().pin_type() == Some(def.did()) => {
+ let pinned_ty = args.type_at(0);
+ is_ty_must_use(cx, pinned_ty, expr, span)
+ .map(|inner| MustUsePath::Pinned(Box::new(inner)))
+ }
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
- ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
+ ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
elaborate(
cx.tcx,
cx.tcx.explicit_item_bounds(def).instantiate_identity_iter_copied(),
@@ -425,6 +431,18 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
expr_is_from_block,
);
}
+ MustUsePath::Pinned(path) => {
+ let descr_pre = &format!("{descr_pre}pinned ");
+ emit_must_use_untranslated(
+ cx,
+ path,
+ descr_pre,
+ descr_post,
+ plural_len,
+ true,
+ expr_is_from_block,
+ );
+ }
MustUsePath::Opaque(path) => {
let descr_pre = &format!("{descr_pre}implementer{plural_suffix} of ");
emit_must_use_untranslated(
@@ -638,7 +656,7 @@ trait UnusedDelimLint {
) -> bool {
if followed_by_else {
match inner.kind {
- ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true,
+ ast::ExprKind::Binary(op, ..) if op.node.is_lazy() => return true,
_ if classify::expr_trailing_brace(inner).is_some() => return true,
_ => {}
}
@@ -674,7 +692,7 @@ trait UnusedDelimLint {
innermost = match &innermost.kind {
ExprKind::AddrOf(_, _, expr) => expr,
_ => {
- if parser::contains_exterior_struct_lit(&innermost) {
+ if parser::contains_exterior_struct_lit(innermost) {
return true;
} else {
break;
@@ -703,7 +721,7 @@ trait UnusedDelimLint {
return matches!(rhs.kind, ExprKind::Block(..));
}
- _ => return parser::contains_exterior_struct_lit(&inner),
+ _ => return parser::contains_exterior_struct_lit(inner),
}
}
}
@@ -878,7 +896,7 @@ trait UnusedDelimLint {
};
self.check_unused_delims_expr(
cx,
- &value,
+ value,
ctx,
followed_by_block,
left_pos,
@@ -901,7 +919,7 @@ trait UnusedDelimLint {
StmtKind::Expr(ref expr) => {
self.check_unused_delims_expr(
cx,
- &expr,
+ expr,
UnusedDelimsCtx::BlockRetValue,
false,
None,
@@ -998,7 +1016,7 @@ impl UnusedDelimLint for UnusedParens {
rustc_span::source_map::Spanned { node, .. },
_,
_,
- ) if node.lazy()))
+ ) if node.is_lazy()))
{
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
}
@@ -1095,15 +1113,17 @@ impl EarlyLintPass for UnusedParens {
}
ExprKind::Match(ref _expr, ref arm) => {
for a in arm {
- self.check_unused_delims_expr(
- cx,
- &a.body,
- UnusedDelimsCtx::MatchArmExpr,
- false,
- None,
- None,
- true,
- );
+ if let Some(body) = &a.body {
+ self.check_unused_delims_expr(
+ cx,
+ body,
+ UnusedDelimsCtx::MatchArmExpr,
+ false,
+ None,
+ None,
+ true,
+ );
+ }
}
}
_ => {}
@@ -1136,7 +1156,7 @@ impl EarlyLintPass for UnusedParens {
// Do not lint on `(..)` as that will result in the other arms being useless.
Paren(_)
// The other cases do not contain sub-patterns.
- | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
+ | Wild | Never | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
// These are list-like patterns; parens can always be removed.
TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
self.check_unused_parens_pat(cx, p, false, false, keep_space);