summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_lint
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint')
-rw-r--r--compiler/rustc_lint/Cargo.toml26
-rw-r--r--compiler/rustc_lint/messages.ftl22
-rw-r--r--compiler/rustc_lint/src/async_fn_in_trait.rs127
-rw-r--r--compiler/rustc_lint/src/builtin.rs58
-rw-r--r--compiler/rustc_lint/src/context.rs118
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs21
-rw-r--r--compiler/rustc_lint/src/drop_forget_useless.rs39
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs37
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs6
-rw-r--r--compiler/rustc_lint/src/internal.rs133
-rw-r--r--compiler/rustc_lint/src/invalid_from_utf8.rs34
-rw-r--r--compiler/rustc_lint/src/levels.rs15
-rw-r--r--compiler/rustc_lint/src/lib.rs15
-rw-r--r--compiler/rustc_lint/src/lints.rs35
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs15
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs4
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs10
-rw-r--r--compiler/rustc_lint/src/ptr_nulls.rs21
-rw-r--r--compiler/rustc_lint/src/reference_casting.rs31
-rw-r--r--compiler/rustc_lint/src/types.rs61
-rw-r--r--compiler/rustc_lint/src/unused.rs102
22 files changed, 615 insertions, 317 deletions
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 539eea3d8..fa1133e77 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -4,23 +4,25 @@ version = "0.0.0"
edition = "2021"
[dependencies]
-tracing = "0.1"
-unicode-security = "0.1.0"
-rustc_middle = { path = "../rustc_middle" }
+# tidy-alphabetical-start
+rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
-rustc_errors = { path = "../rustc_errors" }
-rustc_hir = { path = "../rustc_hir" }
-rustc_fluent_macro = { path = "../rustc_fluent_macro" }
-rustc_target = { path = "../rustc_target" }
-rustc_ast = { path = "../rustc_ast" }
-rustc_span = { path = "../rustc_span" }
rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
+rustc_infer = { path = "../rustc_infer" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_parse_format = { path = "../rustc_parse_format" }
rustc_session = { path = "../rustc_session" }
+rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_parse_format = { path = "../rustc_parse_format" }
-rustc_infer = { path = "../rustc_infer" }
rustc_type_ir = { path = "../rustc_type_ir" }
-rustc_macros = { path = "../rustc_macros" }
+tracing = "0.1"
+unicode-security = "0.1.0"
+# tidy-alphabetical-end
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 7377c6e2f..068f1372c 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -5,6 +5,10 @@ lint_array_into_iter =
.use_explicit_into_iter_suggestion =
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
+ .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
+ .suggestion = you can alternatively desugar to a normal `fn` that returns `impl Future` and add any desired bounds such as `Send`, but these cannot be relaxed without a breaking API change
+
lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering
.help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
@@ -319,6 +323,8 @@ lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undef
lint_invalid_reference_casting_note_book = for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
+lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
+
lint_lintpass_by_hand = implementing `LintPass` by hand
.help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
@@ -488,6 +494,8 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
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
@@ -543,19 +551,19 @@ lint_unused_closure =
lint_unused_comparisons = comparison is useless due to type limits
+lint_unused_coroutine =
+ unused {$pre}{$count ->
+ [one] coroutine
+ *[other] coroutine
+ }{$post} that must be used
+ .note = coroutines are lazy and do nothing unless resumed
+
lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
.suggestion = use `let _ = ...` to ignore the resulting value
lint_unused_delim = unnecessary {$delim} around {$item}
.suggestion = remove these {$delim}
-lint_unused_generator =
- unused {$pre}{$count ->
- [one] generator
- *[other] generator
- }{$post} that must be used
- .note = generators are lazy and do nothing unless resumed
-
lint_unused_import_braces = braces around {$node} is unnecessary
lint_unused_op = unused {$op} that must be used
diff --git a/compiler/rustc_lint/src/async_fn_in_trait.rs b/compiler/rustc_lint/src/async_fn_in_trait.rs
new file mode 100644
index 000000000..512136473
--- /dev/null
+++ b/compiler/rustc_lint/src/async_fn_in_trait.rs
@@ -0,0 +1,127 @@
+use crate::lints::AsyncFnInTraitDiag;
+use crate::LateContext;
+use crate::LateLintPass;
+use rustc_hir as hir;
+use rustc_trait_selection::traits::error_reporting::suggestions::suggest_desugaring_async_fn_to_impl_future_in_trait;
+
+declare_lint! {
+ /// The `async_fn_in_trait` lint detects use of `async fn` in the
+ /// definition of a publicly-reachable trait.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// pub trait Trait {
+ /// async fn method(&self);
+ /// }
+ /// # fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// When `async fn` is used in a trait definition, the trait does not
+ /// promise that the opaque [`Future`] returned by the associated function
+ /// or method will implement any [auto traits] such as [`Send`]. This may
+ /// be surprising and may make the associated functions or methods on the
+ /// trait less useful than intended. On traits exposed publicly from a
+ /// crate, this may affect downstream crates whose authors cannot alter
+ /// the trait definition.
+ ///
+ /// For example, this code is invalid:
+ ///
+ /// ```rust,compile_fail
+ /// pub trait Trait {
+ /// async fn method(&self) {}
+ /// }
+ ///
+ /// fn test<T: Trait>(x: T) {
+ /// fn spawn<T: Send>(_: T) {}
+ /// spawn(x.method()); // Not OK.
+ /// }
+ /// ```
+ ///
+ /// This lint exists to warn authors of publicly-reachable traits that
+ /// they may want to consider desugaring the `async fn` to a normal `fn`
+ /// that returns an opaque `impl Future<..> + Send` type.
+ ///
+ /// For example, instead of:
+ ///
+ /// ```rust
+ /// pub trait Trait {
+ /// async fn method(&self) {}
+ /// }
+ /// ```
+ ///
+ /// The author of the trait may want to write:
+ ///
+ ///
+ /// ```rust
+ /// use core::future::Future;
+ /// pub trait Trait {
+ /// fn method(&self) -> impl Future<Output = ()> + Send { async {} }
+ /// }
+ /// ```
+ ///
+ /// This still allows the use of `async fn` within impls of the trait.
+ /// However, it also means that the trait will never be compatible with
+ /// impls where the returned [`Future`] of the method does not implement
+ /// `Send`.
+ ///
+ /// Conversely, if the trait is used only locally, if it is never used in
+ /// generic functions, or if it is only used in single-threaded contexts
+ /// that do not care whether the returned [`Future`] implements [`Send`],
+ /// then the lint may be suppressed.
+ ///
+ /// [`Future`]: https://doc.rust-lang.org/core/future/trait.Future.html
+ /// [`Send`]: https://doc.rust-lang.org/core/marker/trait.Send.html
+ /// [auto traits]: https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits
+ pub ASYNC_FN_IN_TRAIT,
+ Warn,
+ "use of `async fn` in definition of a publicly-reachable trait"
+}
+
+declare_lint_pass!(
+ /// Lint for use of `async fn` in the definition of a publicly-reachable
+ /// trait.
+ AsyncFnInTrait => [ASYNC_FN_IN_TRAIT]
+);
+
+impl<'tcx> LateLintPass<'tcx> for AsyncFnInTrait {
+ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'tcx>) {
+ if let hir::TraitItemKind::Fn(sig, body) = item.kind
+ && let hir::IsAsync::Async(async_span) = sig.header.asyncness
+ {
+ // RTN can be used to bound `async fn` in traits in a better way than "always"
+ if cx.tcx.features().return_type_notation {
+ return;
+ }
+
+ // Only need to think about library implications of reachable traits
+ if !cx.tcx.effective_visibilities(()).is_reachable(item.owner_id.def_id) {
+ return;
+ }
+
+ let hir::FnRetTy::Return(hir::Ty { kind: hir::TyKind::OpaqueDef(def, ..), .. }) =
+ sig.decl.output
+ else {
+ // This should never happen, but let's not ICE.
+ return;
+ };
+ let sugg = suggest_desugaring_async_fn_to_impl_future_in_trait(
+ cx.tcx,
+ sig,
+ body,
+ def.owner_id.def_id,
+ " + Send",
+ );
+ cx.tcx.emit_spanned_lint(
+ ASYNC_FN_IN_TRAIT,
+ item.hir_id(),
+ async_span,
+ AsyncFnInTraitDiag { sugg },
+ );
+ }
+ }
+}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 536f78a73..6f6150a41 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -121,16 +121,14 @@ impl EarlyLintPass for WhileTrue {
{
let condition_span = e.span.with_hi(cond.span.hi());
let replace = format!(
- "{}loop",
- label.map_or_else(String::new, |label| format!(
- "{}: ",
- label.ident,
- ))
- );
- cx.emit_spanned_lint(WHILE_TRUE, condition_span, BuiltinWhileTrue {
- suggestion: condition_span,
- replace,
- });
+ "{}loop",
+ label.map_or_else(String::new, |label| format!("{}: ", label.ident,))
+ );
+ cx.emit_spanned_lint(
+ WHILE_TRUE,
+ condition_span,
+ BuiltinWhileTrue { suggestion: condition_span, replace },
+ );
}
}
}
@@ -164,7 +162,9 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
impl BoxPointers {
fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
for leaf in ty.walk() {
- if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() {
+ if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
+ && leaf_ty.is_box()
+ {
cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
}
}
@@ -677,11 +677,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) {
return;
}
+ if def.is_variant_list_non_exhaustive()
+ || def.variants().iter().any(|variant| variant.is_field_list_non_exhaustive())
+ {
+ return;
+ }
// We shouldn't recommend implementing `Copy` on stateful things,
// such as iterators.
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
- && cx.tcx
+ && cx
+ .tcx
.infer_ctxt()
.build()
.type_implements_trait(iter_trait, [ty], param_env)
@@ -1298,10 +1304,14 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
// Now, check if the function has the `#[track_caller]` attribute
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
{
- cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller {
- label: span,
- parse_sess: &cx.tcx.sess.parse_sess,
- });
+ cx.emit_spanned_lint(
+ UNGATED_ASYNC_FN_TRACK_CALLER,
+ attr.span,
+ BuiltinUngatedAsyncFnTrackCaller {
+ label: span,
+ parse_sess: &cx.tcx.sess.parse_sess,
+ },
+ );
}
}
}
@@ -2244,7 +2254,7 @@ declare_lint! {
}
declare_lint_pass!(
- /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/active.rs`.
+ /// Check for used feature gates in `INCOMPLETE_FEATURES` in `rustc_feature/src/unstable.rs`.
IncompleteInternalFeatures => [INCOMPLETE_FEATURES, INTERNAL_FEATURES]
);
@@ -2258,23 +2268,19 @@ impl EarlyLintPass for IncompleteInternalFeatures {
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
.filter(|(&name, _)| features.incomplete(name) || features.internal(name))
.for_each(|(&name, &span)| {
- let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
- .map(|n| BuiltinFeatureIssueNote { n });
-
if features.incomplete(name) {
+ let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
+ .map(|n| BuiltinFeatureIssueNote { n });
let help =
HAS_MIN_FEATURES.contains(&name).then_some(BuiltinIncompleteFeaturesHelp);
+
cx.emit_spanned_lint(
INCOMPLETE_FEATURES,
span,
BuiltinIncompleteFeatures { name, note, help },
);
} else {
- cx.emit_spanned_lint(
- INTERNAL_FEATURES,
- span,
- BuiltinInternalFeatures { name, note },
- );
+ cx.emit_spanned_lint(INTERNAL_FEATURES, span, BuiltinInternalFeatures { name });
}
});
}
@@ -2469,7 +2475,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
ty: Ty<'tcx>,
init: InitKind,
) -> Option<InitError> {
- use rustc_type_ir::sty::TyKind::*;
+ use rustc_type_ir::TyKind::*;
match ty.kind() {
// Primitive types that don't like 0 as a value.
Ref(..) => Some("references must be non-null".into()),
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 3c5cde430..a5f4c5ff0 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -31,7 +31,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError};
use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, TyCtxt};
use rustc_session::config::ExpectedValues;
use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
@@ -109,7 +109,7 @@ struct LintAlias {
struct LintGroup {
lint_ids: Vec<LintId>,
- from_plugin: bool,
+ is_loaded: bool,
depr: Option<LintAlias>,
}
@@ -160,9 +160,7 @@ impl LintStore {
// Don't display deprecated lint groups.
depr.is_none()
})
- .map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
- (*k, lint_ids.clone(), *from_plugin)
- })
+ .map(|(k, LintGroup { lint_ids, is_loaded, .. })| (*k, lint_ids.clone(), *is_loaded))
}
pub fn register_early_pass(
@@ -221,7 +219,7 @@ impl LintStore {
.entry(edition.lint_name())
.or_insert(LintGroup {
lint_ids: vec![],
- from_plugin: lint.is_plugin,
+ is_loaded: lint.is_loaded,
depr: None,
})
.lint_ids
@@ -234,7 +232,7 @@ impl LintStore {
.entry("future_incompatible")
.or_insert(LintGroup {
lint_ids: vec![],
- from_plugin: lint.is_plugin,
+ is_loaded: lint.is_loaded,
depr: None,
})
.lint_ids
@@ -249,7 +247,7 @@ impl LintStore {
alias,
LintGroup {
lint_ids: vec![],
- from_plugin: false,
+ is_loaded: false,
depr: Some(LintAlias { name: lint_name, silent: true }),
},
);
@@ -257,21 +255,21 @@ impl LintStore {
pub fn register_group(
&mut self,
- from_plugin: bool,
+ is_loaded: bool,
name: &'static str,
deprecated_name: Option<&'static str>,
to: Vec<LintId>,
) {
let new = self
.lint_groups
- .insert(name, LintGroup { lint_ids: to, from_plugin, depr: None })
+ .insert(name, LintGroup { lint_ids: to, is_loaded, depr: None })
.is_none();
if let Some(deprecated) = deprecated_name {
self.lint_groups.insert(
deprecated,
LintGroup {
lint_ids: vec![],
- from_plugin,
+ is_loaded,
depr: Some(LintAlias { name, silent: false }),
},
);
@@ -727,11 +725,14 @@ pub trait LintContext: Sized {
.collect::<Vec<_>>();
possibilities.sort();
+ let mut should_print_possibilities = true;
if let Some((value, value_span)) = value {
if best_match_values.contains(&Some(value)) {
db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect);
+ should_print_possibilities = false;
} else if best_match_values.contains(&None) {
db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect);
+ should_print_possibilities = false;
} else if let Some(first_value) = possibilities.first() {
db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect);
} else {
@@ -741,13 +742,25 @@ pub trait LintContext: Sized {
db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
}
- if !possibilities.is_empty() {
+ if !possibilities.is_empty() && should_print_possibilities {
let possibilities = possibilities.join("`, `");
db.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
}
} else {
db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
}
+ } else if !possibilities.is_empty() {
+ let mut possibilities = possibilities.iter()
+ .map(Symbol::as_str)
+ .collect::<Vec<_>>();
+ possibilities.sort();
+ let possibilities = possibilities.join("`, `");
+
+ // The list of expected names can be long (even by default) and
+ // so the diagnostic produced can take a lot of space. To avoid
+ // cloging the user output we only want to print that diagnostic
+ // once.
+ db.help_once(format!("expected names are: `{possibilities}`"));
}
},
BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {
@@ -1185,51 +1198,45 @@ impl<'tcx> LateContext<'tcx> {
/// }
/// ```
pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
- pub struct AbsolutePathPrinter<'tcx> {
- pub tcx: TyCtxt<'tcx>,
+ struct AbsolutePathPrinter<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ path: Vec<Symbol>,
}
impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
- type Error = !;
-
- type Path = Vec<Symbol>;
- type Region = ();
- type Type = ();
- type DynExistential = ();
- type Const = ();
-
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
- fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+ fn print_region(&mut self, _region: ty::Region<'_>) -> Result<(), PrintError> {
Ok(())
}
- fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+ fn print_type(&mut self, _ty: Ty<'tcx>) -> Result<(), PrintError> {
Ok(())
}
fn print_dyn_existential(
- self,
+ &mut self,
_predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
- ) -> Result<Self::DynExistential, Self::Error> {
+ ) -> Result<(), PrintError> {
Ok(())
}
- fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(&mut self, _ct: ty::Const<'tcx>) -> Result<(), PrintError> {
Ok(())
}
- fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- Ok(vec![self.tcx.crate_name(cnum)])
+ fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+ self.path = vec![self.tcx.crate_name(cnum)];
+ Ok(())
}
fn path_qualified(
- self,
+ &mut self,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
+ ) -> Result<(), PrintError> {
if trait_ref.is_none() {
if let ty::Adt(def, args) = self_ty.kind() {
return self.print_def_path(def.did(), args);
@@ -1238,24 +1245,25 @@ impl<'tcx> LateContext<'tcx> {
// This shouldn't ever be needed, but just in case:
with_no_trimmed_paths!({
- Ok(vec![match trait_ref {
+ self.path = vec![match trait_ref {
Some(trait_ref) => Symbol::intern(&format!("{trait_ref:?}")),
None => Symbol::intern(&format!("<{self_ty}>")),
- }])
+ }];
+ Ok(())
})
}
fn path_append_impl(
- self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ &mut self,
+ print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_disambiguated_data: &DisambiguatedDefPathData,
self_ty: Ty<'tcx>,
trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
- let mut path = print_prefix(self)?;
+ ) -> Result<(), PrintError> {
+ print_prefix(self)?;
// This shouldn't ever be needed, but just in case:
- path.push(match trait_ref {
+ self.path.push(match trait_ref {
Some(trait_ref) => {
with_no_trimmed_paths!(Symbol::intern(&format!(
"<impl {} for {}>",
@@ -1268,35 +1276,37 @@ impl<'tcx> LateContext<'tcx> {
}
});
- Ok(path)
+ Ok(())
}
fn path_append(
- self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ &mut self,
+ print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
disambiguated_data: &DisambiguatedDefPathData,
- ) -> Result<Self::Path, Self::Error> {
- let mut path = print_prefix(self)?;
+ ) -> Result<(), PrintError> {
+ print_prefix(self)?;
// Skip `::{{extern}}` blocks and `::{{constructor}}` on tuple/unit structs.
if let DefPathData::ForeignMod | DefPathData::Ctor = disambiguated_data.data {
- return Ok(path);
+ return Ok(());
}
- path.push(Symbol::intern(&disambiguated_data.data.to_string()));
- Ok(path)
+ self.path.push(Symbol::intern(&disambiguated_data.data.to_string()));
+ Ok(())
}
fn path_generic_args(
- self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ &mut self,
+ print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
_args: &[GenericArg<'tcx>],
- ) -> Result<Self::Path, Self::Error> {
+ ) -> Result<(), PrintError> {
print_prefix(self)
}
}
- AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap()
+ let mut printer = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
+ printer.print_def_path(def_id, &[]).unwrap();
+ printer.path
}
/// Returns the associated type `name` for `self_ty` as an implementation of `trait_id`.
@@ -1342,7 +1352,7 @@ impl<'tcx> LateContext<'tcx> {
&& let Some(init) = match parent_node {
hir::Node::Expr(expr) => Some(expr),
hir::Node::Local(hir::Local { init, .. }) => *init,
- _ => None
+ _ => None,
}
{
expr = init.peel_blocks();
@@ -1391,9 +1401,9 @@ impl<'tcx> LateContext<'tcx> {
hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
Some(self.tcx.hir().body(body_id).value)
}
- _ => None
- }
- _ => None
+ _ => None,
+ },
+ _ => None,
}
{
expr = init.peel_blocks();
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index 9be2edf84..d2d99bc0d 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -4,9 +4,10 @@ use crate::{
};
use rustc_hir as hir;
-use rustc_middle::{traits::util::supertraits, ty};
+use rustc_middle::ty;
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_span::sym;
+use rustc_trait_selection::traits::supertraits;
declare_lint! {
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
@@ -75,14 +76,16 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
&& 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 label = impl_.items.iter().find_map(|i| (i.ident.name == sym::Target).then_some(i.span)).map(|label| SupertraitAsDerefTargetLabel {
- label,
- });
- cx.emit_spanned_lint(DEREF_INTO_DYN_SUPERTRAIT, cx.tcx.def_span(item.owner_id.def_id), SupertraitAsDerefTarget {
- t,
- target_principal,
- label,
- });
+ let label = impl_
+ .items
+ .iter()
+ .find_map(|i| (i.ident.name == sym::Target).then_some(i.span))
+ .map(|label| SupertraitAsDerefTargetLabel { label });
+ cx.emit_spanned_lint(
+ DEREF_INTO_DYN_SUPERTRAIT,
+ cx.tcx.def_span(item.owner_id.def_id),
+ SupertraitAsDerefTarget { t, target_principal, label },
+ );
}
}
}
diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs
index 467f53d44..390a1620a 100644
--- a/compiler/rustc_lint/src/drop_forget_useless.rs
+++ b/compiler/rustc_lint/src/drop_forget_useless.rs
@@ -149,18 +149,37 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
match fn_name {
sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => {
- cx.emit_spanned_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span });
- },
+ cx.emit_spanned_lint(
+ DROPPING_REFERENCES,
+ expr.span,
+ DropRefDiag { arg_ty, label: arg.span },
+ );
+ }
sym::mem_forget if arg_ty.is_ref() => {
- cx.emit_spanned_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span });
- },
+ cx.emit_spanned_lint(
+ FORGETTING_REFERENCES,
+ expr.span,
+ ForgetRefDiag { arg_ty, label: arg.span },
+ );
+ }
sym::mem_drop if is_copy && !drop_is_single_call_in_arm => {
- cx.emit_spanned_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span });
+ cx.emit_spanned_lint(
+ DROPPING_COPY_TYPES,
+ expr.span,
+ DropCopyDiag { arg_ty, label: arg.span },
+ );
}
sym::mem_forget if is_copy => {
- cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span });
+ cx.emit_spanned_lint(
+ FORGETTING_COPY_TYPES,
+ expr.span,
+ ForgetCopyDiag { arg_ty, label: arg.span },
+ );
}
- sym::mem_drop if let ty::Adt(adt, _) = arg_ty.kind() && adt.is_manually_drop() => {
+ sym::mem_drop
+ if let ty::Adt(adt, _) = arg_ty.kind()
+ && adt.is_manually_drop() =>
+ {
cx.emit_spanned_lint(
UNDROPPED_MANUALLY_DROPS,
expr.span,
@@ -169,9 +188,9 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
label: arg.span,
suggestion: UndroppedManuallyDropsSuggestion {
start_span: arg.span.shrink_to_lo(),
- end_span: arg.span.shrink_to_hi()
- }
- }
+ end_span: arg.span.shrink_to_hi(),
+ },
+ },
);
}
_ => return,
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index b1266b58a..740c90757 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -11,7 +11,7 @@ pub(crate) fn provide(providers: &mut Providers) {
}
fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
- if !tcx.features().enabled(sym::lint_reasons) {
+ if !tcx.features().active(sym::lint_reasons) {
return;
}
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index c299e3884..c8ec0458b 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -59,13 +59,20 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
_ => return,
};
- let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
+ let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
&& let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
- {
- ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip }
- } else {
- ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var }
- } ;
+ {
+ ForLoopsOverFalliblesLoopSub::RemoveNext {
+ suggestion: recv.span.between(arg.span.shrink_to_hi()),
+ recv_snip,
+ }
+ } else {
+ ForLoopsOverFalliblesLoopSub::UseWhileLet {
+ start_span: expr.span.with_hi(pat.span.lo()),
+ end_span: pat.span.between(arg.span),
+ var,
+ }
+ };
let question_mark = suggest_question_mark(cx, adt, args, expr.span)
.then(|| ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() });
let suggestion = ForLoopsOverFalliblesSuggestion {
@@ -84,13 +91,13 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>)> {
if let hir::ExprKind::DropTemps(e) = expr.kind
- && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind
- && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind
- && let hir::ExprKind::Loop(block, ..) = arm.body.kind
- && let [stmt] = block.stmts
- && let hir::StmtKind::Expr(e) = stmt.kind
- && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind
- && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind
+ && let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind
+ && let hir::ExprKind::Call(_, [arg]) = iterexpr.kind
+ && let hir::ExprKind::Loop(block, ..) = arm.body.kind
+ && let [stmt] = block.stmts
+ && let hir::StmtKind::Expr(e) = stmt.kind
+ && let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind
+ && let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind
{
Some((field.pat, arg))
} else {
@@ -104,11 +111,11 @@ fn extract_iterator_next_call<'tcx>(
) -> Option<&'tcx Expr<'tcx>> {
// This won't work for `Iterator::next(iter)`, is this an issue?
if let hir::ExprKind::MethodCall(_, recv, _, _) = expr.kind
- && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn()
+ && cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn()
{
Some(recv)
} else {
- return None
+ return None;
}
}
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index e1df69bda..86b3b4ad0 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -262,7 +262,7 @@ fn structurally_same_type_impl<'tcx>(
true
} else {
// Do a full, depth-first comparison between the two.
- use rustc_type_ir::sty::TyKind::*;
+ use rustc_type_ir::TyKind::*;
let a_kind = a.kind();
let b_kind = b.kind();
@@ -369,8 +369,8 @@ fn structurally_same_type_impl<'tcx>(
(Dynamic(..), Dynamic(..))
| (Error(..), Error(..))
| (Closure(..), Closure(..))
- | (Generator(..), Generator(..))
- | (GeneratorWitness(..), GeneratorWitness(..))
+ | (Coroutine(..), Coroutine(..))
+ | (CoroutineWitness(..), CoroutineWitness(..))
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
| (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 4b803621f..2d86129c4 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -3,14 +3,14 @@
use crate::lints::{
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
- QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
+ QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
UntranslatableDiagnosticTrivial,
};
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_hir::def::Res;
use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
-use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
+use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -62,13 +62,11 @@ fn typeck_results_of_method_fn<'tcx>(
if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) =>
{
Some((segment.ident.span, def_id, cx.typeck_results().node_args(expr.hir_id)))
- },
- _ => {
- match cx.typeck_results().node_type(expr.hir_id).kind() {
- &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)),
- _ => None,
- }
}
+ _ => match cx.typeck_results().node_type(expr.hir_id).kind() {
+ &ty::FnDef(def_id, args) => Some((expr.span, def_id, args)),
+ _ => None,
+ },
}
}
@@ -134,14 +132,11 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
_: rustc_hir::HirId,
) {
if let Some(segment) = path.segments.iter().nth_back(1)
- && lint_ty_kind_usage(cx, &segment.res)
+ && lint_ty_kind_usage(cx, &segment.res)
{
- let span = path.span.with_hi(
- segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
- );
- cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind {
- suggestion: span,
- });
+ let span =
+ path.span.with_hi(segment.args.map_or(segment.ident.span, |a| a.span_ext).hi());
+ cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span });
}
}
@@ -166,10 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
None
}
}
- Some(Node::Expr(Expr {
- kind: ExprKind::Path(qpath),
- ..
- })) => {
+ Some(Node::Expr(Expr { kind: ExprKind::Path(qpath), .. })) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
@@ -180,10 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
}
// Can't unify these two branches because qpath below is `&&` and above is `&`
// and `A | B` paths don't play well together with adjustments, apparently.
- Some(Node::Expr(Expr {
- kind: ExprKind::Struct(qpath, ..),
- ..
- })) => {
+ Some(Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. })) => {
if let QPath::TypeRelative(qpath_ty, ..) = qpath
&& qpath_ty.hir_id == ty.hir_id
{
@@ -192,22 +181,28 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
None
}
}
- _ => None
+ _ => None,
};
match span {
Some(span) => {
- cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind {
- suggestion: span,
- });
- },
+ cx.emit_spanned_lint(
+ USAGE_OF_TY_TYKIND,
+ path.span,
+ TykindKind { suggestion: span },
+ );
+ }
None => cx.emit_spanned_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
}
- } else if !ty.span.from_expansion() && path.segments.len() > 1 && let Some(ty) = is_ty_or_ty_ctxt(cx, &path) {
- cx.emit_spanned_lint(USAGE_OF_QUALIFIED_TY, path.span, TyQualified {
- ty,
- suggestion: path.span,
- });
+ } else if !ty.span.from_expansion()
+ && path.segments.len() > 1
+ && let Some(ty) = is_ty_or_ty_ctxt(cx, &path)
+ {
+ cx.emit_spanned_lint(
+ USAGE_OF_QUALIFIED_TY,
+ path.span,
+ TyQualified { ty, suggestion: path.span },
+ );
}
}
_ => {}
@@ -398,11 +393,11 @@ impl LateLintPass<'_> for Diagnostics {
}
debug!(?parent);
- if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent &&
- let Impl { of_trait: Some(of_trait), .. } = impl_ &&
- let Some(def_id) = of_trait.trait_def_id() &&
- let Some(name) = cx.tcx.get_diagnostic_name(def_id) &&
- matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint)
+ if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent
+ && let Impl { of_trait: Some(of_trait), .. } = impl_
+ && let Some(def_id) = of_trait.trait_def_id()
+ && let Some(name) = cx.tcx.get_diagnostic_name(def_id)
+ && matches!(name, sym::IntoDiagnostic | sym::AddToDiagnostic | sym::DecorateLint)
{
found_impl = true;
break;
@@ -416,9 +411,9 @@ impl LateLintPass<'_> for Diagnostics {
let mut found_diagnostic_message = false;
for ty in args.types() {
debug!(?ty);
- if let Some(adt_def) = ty.ty_adt_def() &&
- let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did()) &&
- matches!(name, sym::DiagnosticMessage | sym::SubdiagnosticMessage)
+ if let Some(adt_def) = ty.ty_adt_def()
+ && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
+ && matches!(name, sym::DiagnosticMessage | sym::SubdiagnosticMessage)
{
found_diagnostic_message = true;
break;
@@ -486,8 +481,9 @@ impl EarlyLintPass for Diagnostics {
}
};
if let ast::ExprKind::Lit(lit) = arg.kind
- && let ast::token::LitKind::Str = lit.kind {
- true
+ && let ast::token::LitKind::Str = lit.kind
+ {
+ true
} else {
false
}
@@ -524,17 +520,50 @@ impl LateLintPass<'_> for BadOptAccess {
}
for field in adt_def.all_fields() {
- if field.name == target.name &&
- let Some(attr) = cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access) &&
- let Some(items) = attr.meta_item_list() &&
- let Some(item) = items.first() &&
- let Some(lit) = item.lit() &&
- let ast::LitKind::Str(val, _) = lit.kind
+ if field.name == target.name
+ && let Some(attr) =
+ cx.tcx.get_attr(field.did, sym::rustc_lint_opt_deny_field_access)
+ && let Some(items) = attr.meta_item_list()
+ && let Some(item) = items.first()
+ && let Some(lit) = item.lit()
+ && let ast::LitKind::Str(val, _) = lit.kind
{
- cx.emit_spanned_lint(BAD_OPT_ACCESS, expr.span, BadOptAccessDiag {
- msg: val.as_str(),
- });
+ cx.emit_spanned_lint(
+ BAD_OPT_ACCESS,
+ expr.span,
+ BadOptAccessDiag { msg: val.as_str() },
+ );
}
}
}
}
+
+declare_tool_lint! {
+ pub rustc::SPAN_USE_EQ_CTXT,
+ Allow,
+ "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead",
+ report_in_external_macro: true
+}
+
+declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
+
+impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+ if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind {
+ if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
+ cx.emit_spanned_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
+ }
+ }
+ }
+}
+
+fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ match &expr.kind {
+ ExprKind::MethodCall(..) => cx
+ .typeck_results()
+ .type_dependent_def_id(expr.hir_id)
+ .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)),
+
+ _ => false,
+ }
+}
diff --git a/compiler/rustc_lint/src/invalid_from_utf8.rs b/compiler/rustc_lint/src/invalid_from_utf8.rs
index e398059ad..0b91b77a9 100644
--- a/compiler/rustc_lint/src/invalid_from_utf8.rs
+++ b/compiler/rustc_lint/src/invalid_from_utf8.rs
@@ -64,8 +64,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
&& 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)
- && [sym::str_from_utf8, sym::str_from_utf8_mut,
- sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item)
+ && [
+ sym::str_from_utf8,
+ sym::str_from_utf8_mut,
+ sym::str_from_utf8_unchecked,
+ sym::str_from_utf8_unchecked_mut,
+ ]
+ .contains(&diag_item)
{
let lint = |label, utf8_error: Utf8Error| {
let method = diag_item.as_str().strip_prefix("str_").unwrap();
@@ -74,13 +79,17 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
let is_unchecked_variant = diag_item.as_str().contains("unchecked");
cx.emit_spanned_lint(
- if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 },
+ if is_unchecked_variant {
+ INVALID_FROM_UTF8_UNCHECKED
+ } else {
+ INVALID_FROM_UTF8
+ },
expr.span,
if is_unchecked_variant {
InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label }
} else {
InvalidFromUtf8Diag::Checked { method, valid_up_to, label }
- }
+ },
)
};
@@ -95,18 +104,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
{
lint(init.span, utf8_error);
}
- },
+ }
ExprKind::Array(args) => {
- let elements = args.iter().map(|e|{
- match &e.kind {
+ let elements = args
+ .iter()
+ .map(|e| match &e.kind {
ExprKind::Lit(Spanned { node: lit, .. }) => match lit {
LitKind::Byte(b) => Some(*b),
LitKind::Int(b, _) => Some(*b as u8),
- _ => None
- }
- _ => None
- }
- }).collect::<Option<Vec<_>>>();
+ _ => None,
+ },
+ _ => None,
+ })
+ .collect::<Option<Vec<_>>>();
if let Some(elements) = elements
&& let Err(utf8_error) = std::str::from_utf8(&elements)
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index ba521b969..0d20f6232 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -634,7 +634,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
/// 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);
- if let Level::Expect(id) = &mut level && let LintExpectationId::Stable { .. } = id {
+ if let Level::Expect(id) = &mut level
+ && let LintExpectationId::Stable { .. } = id
+ {
*id = id.normalize();
}
// Setting to a non-forbid level is an error if the lint previously had
@@ -706,7 +708,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
// The lint `unfulfilled_lint_expectations` can't be expected, as it would suppress itself.
// Handling expectations of this lint would add additional complexity with little to no
// benefit. The expect level for this lint will therefore be ignored.
- if let Level::Expect(_) = level && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS) {
+ if let Level::Expect(_) = level
+ && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS)
+ {
return;
}
@@ -747,8 +751,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
None => continue,
// This is the only lint level with a `LintExpectationId` that can be created from an attribute
Some(Level::Expect(unstable_id)) if let Some(hir_id) = source_hir_id => {
- let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id
- else { bug!("stable id Level::from_attr") };
+ let LintExpectationId::Unstable { attr_id, lint_index } = unstable_id else {
+ bug!("stable id Level::from_attr")
+ };
let stable_id = LintExpectationId::Stable {
hir_id,
@@ -1057,7 +1062,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
#[track_caller]
fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
if let Some(feature) = lint_id.lint.feature_gate {
- if !self.features.enabled(feature) {
+ if !self.features.active(feature) {
let lint = builtin::UNKNOWN_LINTS;
let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
struct_lint_level(
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 72c103f2d..54adedd3c 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -10,7 +10,7 @@
//! all other analyses. The `LintPass`es built into rustc are defined
//! within [rustc_session::lint::builtin],
//! which has further comments on how to add such a lint.
-//! rustc can also load user-defined lint plugins via the plugin mechanism.
+//! rustc can also load external lint plugins, as is done for Clippy.
//!
//! Some of rustc's lints are defined elsewhere in the compiler and work by
//! calling `add_lint()` on the overall `Session` object. This works when
@@ -27,6 +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))]
#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
@@ -50,6 +52,7 @@ extern crate rustc_session;
extern crate tracing;
mod array_into_iter;
+mod async_fn_in_trait;
pub mod builtin;
mod context;
mod deref_into_dyn_supertrait;
@@ -96,6 +99,7 @@ use rustc_session::lint::builtin::{
};
use array_into_iter::ArrayIntoIter;
+use async_fn_in_trait::AsyncFnInTrait;
use builtin::*;
use deref_into_dyn_supertrait::*;
use drop_forget_useless::*;
@@ -234,6 +238,7 @@ late_lint_methods!(
MapUnitFn: MapUnitFn,
MissingDebugImplementations: MissingDebugImplementations,
MissingDoc: MissingDoc,
+ AsyncFnInTrait: AsyncFnInTrait,
]
]
);
@@ -501,6 +506,11 @@ fn register_builtins(store: &mut LintStore) {
"replaced with another group of lints, see RFC \
<https://rust-lang.github.io/rfcs/2145-type-privacy.html> for more information",
);
+ store.register_removed(
+ "invalid_alignment",
+ "converted into hard error, see PR #104616 \
+ <https://github.com/rust-lang/rust/pull/104616> for more information",
+ );
}
fn register_internals(store: &mut LintStore) {
@@ -521,6 +531,8 @@ fn register_internals(store: &mut LintStore) {
store.register_late_mod_pass(|_| Box::new(BadOptAccess));
store.register_lints(&PassByValue::get_lints());
store.register_late_mod_pass(|_| Box::new(PassByValue));
+ store.register_lints(&SpanUseEqCtxt::get_lints());
+ store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
// FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
// `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
// these lints will trigger all of the time - change this once migration to diagnostic structs
@@ -538,6 +550,7 @@ fn register_internals(store: &mut LintStore) {
LintId::of(USAGE_OF_QUALIFIED_TY),
LintId::of(EXISTING_DOC_KEYWORD),
LintId::of(BAD_OPT_ACCESS),
+ LintId::of(SPAN_USE_EQ_CTXT),
],
);
}
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index c091c260a..756899e50 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -412,8 +412,6 @@ pub struct BuiltinIncompleteFeatures {
#[note]
pub struct BuiltinInternalFeatures {
pub name: Symbol,
- #[subdiagnostic]
- pub note: Option<BuiltinFeatureIssueNote>,
}
#[derive(Subdiagnostic)]
@@ -771,12 +769,16 @@ pub enum InvalidReferenceCastingDiag {
BorrowAsMut {
#[label]
orig_cast: Option<Span>,
+ #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
+ ty_has_interior_mutability: Option<()>,
},
#[diag(lint_invalid_reference_casting_assign_to_ref)]
#[note(lint_invalid_reference_casting_note_book)]
AssignToRef {
#[label]
orig_cast: Option<Span>,
+ #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)]
+ ty_has_interior_mutability: Option<()>,
},
}
@@ -899,6 +901,10 @@ pub struct QueryInstability {
}
#[derive(LintDiagnostic)]
+#[diag(lint_span_use_eq_ctxt)]
+pub struct SpanUseEqCtxtDiag;
+
+#[derive(LintDiagnostic)]
#[diag(lint_tykind_kind)]
pub struct TykindKind {
#[suggestion(code = "ty", applicability = "maybe-incorrect")]
@@ -1694,9 +1700,9 @@ pub struct UnusedClosure<'a> {
// FIXME(davidtwco): this isn't properly translatable because of the
// pre/post strings
#[derive(LintDiagnostic)]
-#[diag(lint_unused_generator)]
+#[diag(lint_unused_coroutine)]
#[note]
-pub struct UnusedGenerator<'a> {
+pub struct UnusedCoroutine<'a> {
pub count: usize,
pub pre: &'a str,
pub post: &'a str,
@@ -1818,3 +1824,24 @@ pub struct UnusedAllocationDiag;
#[derive(LintDiagnostic)]
#[diag(lint_unused_allocation_mut)]
pub struct UnusedAllocationMutDiag;
+
+pub struct AsyncFnInTraitDiag {
+ pub sugg: Option<Vec<(Span, String)>>,
+}
+
+impl<'a> DecorateLint<'a, ()> for AsyncFnInTraitDiag {
+ fn decorate_lint<'b>(
+ self,
+ diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
+ ) -> &'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
+ }
+}
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index 84558ee1f..dfefaf82f 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -42,18 +42,17 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind
&& cx.tcx.object_safety_violations(def_id).is_empty()
{
- let direct_super_traits_iter = cx.tcx
- .super_predicates_of(def_id)
- .predicates
- .into_iter()
- .filter_map(|(pred, _)| pred.as_trait_clause());
+ let direct_super_traits_iter = cx
+ .tcx
+ .super_predicates_of(def_id)
+ .predicates
+ .into_iter()
+ .filter_map(|(pred, _)| pred.as_trait_clause());
if direct_super_traits_iter.count() > 1 {
cx.emit_spanned_lint(
MULTIPLE_SUPERTRAIT_UPCASTABLE,
cx.tcx.def_span(def_id),
- crate::lints::MultipleSupertraitUpcastable {
- ident: item.ident
- },
+ crate::lints::MultipleSupertraitUpcastable { ident: item.ident },
);
}
}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 145de4948..66dc726df 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -511,7 +511,9 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) {
- if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) {
+ if let hir::ImplItemKind::Const(..) = ii.kind
+ && !assoc_item_in_trait_impl(cx, ii)
+ {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident);
}
}
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 79b0b32be..c24846ca9 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -37,8 +37,6 @@ declare_lint! {
/// type Assoc: Duh;
/// }
///
- /// struct Struct;
- ///
/// impl<F: Duh> Trait for F {
/// type Assoc = F;
/// }
@@ -53,12 +51,12 @@ declare_lint! {
/// {{produces}}
///
/// In this example, `test` declares that the associated type `Assoc` for
- /// `impl Trait` is `impl Sized`, which does not satisfy the `Send` bound
+ /// `impl Trait` is `impl Sized`, which does not satisfy the bound `Duh`
/// on the associated type.
///
/// Although the hidden type, `i32` does satisfy this bound, we do not
/// consider the return type to be well-formed with this lint. It can be
- /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Send`.
+ /// fixed by changing `Tait = impl Sized` into `Tait = impl Sized + Duh`.
pub OPAQUE_HIDDEN_INFERRED_BOUND,
Warn,
"detects the use of nested `impl Trait` types in associated type bounds that are not general enough"
@@ -79,9 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
for (pred, pred_span) in
cx.tcx.explicit_item_bounds(def_id).instantiate_identity_iter_copied()
{
- // Liberate bound regions in the predicate since we
- // don't actually care about lifetimes in this check.
- let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind());
+ let predicate = infcx.instantiate_binder_with_placeholders(pred.kind());
let ty::ClauseKind::Projection(proj) = predicate else {
continue;
};
diff --git a/compiler/rustc_lint/src/ptr_nulls.rs b/compiler/rustc_lint/src/ptr_nulls.rs
index 0de72d8d3..4ac8a5ceb 100644
--- a/compiler/rustc_lint/src/ptr_nulls.rs
+++ b/compiler/rustc_lint/src/ptr_nulls.rs
@@ -46,22 +46,26 @@ fn incorrect_check<'a, 'tcx: 'a>(
if let ExprKind::MethodCall(_, _expr, [], _) = e.kind
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
- && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
+ && let Some(fn_name) = cx.tcx.opt_item_ident(def_id)
+ {
return Some(PtrNullChecksDiag::FnRet { fn_name });
} else if let ExprKind::Call(path, _args) = e.kind
&& let ExprKind::Path(ref qpath) = path.kind
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
- && let Some(fn_name) = cx.tcx.opt_item_ident(def_id) {
+ && let Some(fn_name) = cx.tcx.opt_item_ident(def_id)
+ {
return Some(PtrNullChecksDiag::FnRet { fn_name });
}
e = if let ExprKind::Cast(expr, t) = e.kind
- && let TyKind::Ptr(_) = t.kind {
+ && let TyKind::Ptr(_) = t.kind
+ {
had_at_least_one_cast = true;
expr
} else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
- && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut)) {
+ && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_cast | sym::ptr_cast_mut))
+ {
had_at_least_one_cast = true;
expr
} else if had_at_least_one_cast {
@@ -127,10 +131,11 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
// (fn_ptr as *<const/mut> <ty>) == (0 as <ty>)
ExprKind::Cast(cast_expr, _)
if let ExprKind::Lit(spanned) = cast_expr.kind
- && let LitKind::Int(v, _) = spanned.node && v == 0 =>
+ && let LitKind::Int(v, _) = spanned.node
+ && v == 0 =>
{
cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
- },
+ }
// Catching:
// (fn_ptr as *<const/mut> <ty>) == std::ptr::null()
@@ -141,9 +146,9 @@ impl<'tcx> LateLintPass<'tcx> for PtrNullChecks {
&& (diag_item == sym::ptr_null || diag_item == sym::ptr_null_mut) =>
{
cx.emit_spanned_lint(USELESS_PTR_NULL_CHECKS, expr.span, diag)
- },
+ }
- _ => {},
+ _ => {}
}
}
_ => {}
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 39def599b..d44691b5e 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -43,19 +43,19 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
let init = cx.expr_or_init(e);
- let orig_cast = if is_cast_from_const_to_mut(cx, init) {
- if init.span != e.span { Some(init.span) } else { None }
- } else {
+ 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 }
+ InvalidReferenceCastingDiag::AssignToRef { orig_cast, ty_has_interior_mutability }
} else {
- InvalidReferenceCastingDiag::BorrowAsMut { orig_cast }
+ InvalidReferenceCastingDiag::BorrowAsMut { orig_cast, ty_has_interior_mutability }
},
);
}
@@ -93,7 +93,10 @@ fn is_operation_we_care_about<'tcx>(
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()
- && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned))
+ && matches!(
+ cx.tcx.get_diagnostic_name(def_id),
+ Some(sym::ptr_write | sym::ptr_write_volatile | sym::ptr_write_unaligned)
+ )
{
Some((true, arg_ptr))
} else {
@@ -104,7 +107,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>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr<'tcx>) -> bool {
+fn is_cast_from_const_to_mut<'tcx>(
+ cx: &LateContext<'tcx>,
+ orig_expr: &'tcx Expr<'tcx>,
+) -> Option<bool> {
let mut need_check_freeze = false;
let mut e = orig_expr;
@@ -112,7 +118,7 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr
// Bail out early if the end type is **not** a mutable pointer.
if !matches!(end_ty.kind(), ty::RawPtr(TypeAndMut { ty: _, mutbl: Mutability::Mut })) {
- return false;
+ return None;
}
loop {
@@ -155,10 +161,11 @@ fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, orig_expr: &'tcx Expr
//
// 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.
- !need_check_freeze
- || inner_ty.is_freeze(cx.tcx, cx.param_env)
- || !inner_ty.has_concrete_skeleton()
+ 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 {
- false
+ None
}
}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 44cf1591c..c04053d18 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -140,13 +140,15 @@ declare_lint! {
pub struct TypeLimits {
/// Id of the last visited negated expression
negated_expr_id: Option<hir::HirId>,
+ /// Span of the last visited negated expression
+ negated_expr_span: Option<Span>,
}
impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS, INVALID_NAN_COMPARISONS]);
impl TypeLimits {
pub fn new() -> TypeLimits {
- TypeLimits { negated_expr_id: None }
+ TypeLimits { negated_expr_id: None, negated_expr_span: None }
}
}
@@ -161,8 +163,10 @@ fn lint_overflowing_range_endpoint<'tcx>(
ty: &str,
) -> 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))
- && let ExprKind::Cast(_, _) = par_expr.kind {
+ let (expr, lit_span) = if let Node::Expr(par_expr) =
+ cx.tcx.hir().get(cx.tcx.hir().parent_id(expr.hir_id))
+ && let ExprKind::Cast(_, _) = par_expr.kind
+ {
(par_expr, expr.span)
} else {
(expr, expr.span)
@@ -426,17 +430,15 @@ fn lint_int_literal<'tcx>(
return;
}
- let lit = cx
- .sess()
- .source_map()
- .span_to_snippet(lit.span)
- .expect("must get snippet from literal");
+ let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span };
+ let lit =
+ cx.sess().source_map().span_to_snippet(span).expect("must get snippet from literal");
let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
.map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
cx.emit_spanned_lint(
OVERFLOWING_LITERALS,
- e.span,
+ span,
OverflowingInt { ty: t.name_str(), lit, min, max, help },
);
}
@@ -580,8 +582,8 @@ fn lint_nan<'tcx>(
) -> InvalidNanComparisons {
// FIXME(#72505): This suggestion can be restored if `f{32,64}::is_nan` is made const.
let suggestion = (!cx.tcx.hir().is_inside_const_context(e.hir_id)).then(|| {
- if let Some(l_span) = l.span.find_ancestor_inside(e.span) &&
- let Some(r_span) = r.span.find_ancestor_inside(e.span)
+ if let Some(l_span) = l.span.find_ancestor_inside(e.span)
+ && let Some(r_span) = r.span.find_ancestor_inside(e.span)
{
f(l_span, r_span)
} else {
@@ -622,9 +624,10 @@ 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) => {
- // propagate negation, if the negation itself isn't negated
+ // 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);
+ self.negated_expr_span = Some(e.span);
}
}
hir::ExprKind::Binary(binop, ref l, ref r) => {
@@ -1269,8 +1272,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
| ty::Bound(..)
| ty::Error(_)
| ty::Closure(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Placeholder(..)
| ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
}
@@ -1292,11 +1295,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
CItemKind::Definition => "fn",
};
let span_note = if let ty::Adt(def, _) = ty.kind()
- && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
- Some(sp)
- } else {
- None
- };
+ && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did())
+ {
+ Some(sp)
+ } else {
+ None
+ };
self.cx.emit_spanned_lint(
lint,
sp,
@@ -1459,7 +1463,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
type BreakTy = Ty<'tcx>;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) {
+ if let ty::FnPtr(sig) = ty.kind()
+ && !self.visitor.is_internal_abi(sig.abi())
+ {
self.tys.push(ty);
}
@@ -1733,7 +1739,8 @@ impl InvalidAtomicOrdering {
}
fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
- if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
+ if let Some((method, args)) =
+ Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
&& let Some((ordering_arg, invalid_ordering)) = match method {
sym::load => Some((&args[0], sym::Release)),
sym::store => Some((&args[1], sym::Acquire)),
@@ -1743,9 +1750,17 @@ impl InvalidAtomicOrdering {
&& (ordering == invalid_ordering || ordering == sym::AcqRel)
{
if method == sym::load {
- cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingLoad);
+ cx.emit_spanned_lint(
+ INVALID_ATOMIC_ORDERING,
+ ordering_arg.span,
+ AtomicOrderingLoad,
+ );
} else {
- cx.emit_spanned_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, AtomicOrderingStore);
+ cx.emit_spanned_lint(
+ INVALID_ATOMIC_ORDERING,
+ ordering_arg.span,
+ AtomicOrderingStore,
+ );
};
}
}
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index d5beff4f1..355855b8e 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1,7 +1,7 @@
use crate::lints::{
PathStatementDrop, PathStatementDropSub, PathStatementNoEffect, UnusedAllocationDiag,
- UnusedAllocationMutDiag, UnusedClosure, UnusedDef, UnusedDefSuggestion, UnusedDelim,
- UnusedDelimSuggestion, UnusedGenerator, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
+ UnusedAllocationMutDiag, UnusedClosure, UnusedCoroutine, UnusedDef, UnusedDefSuggestion,
+ UnusedDelim, UnusedDelimSuggestion, UnusedImportBracesDiag, UnusedOp, UnusedOpSuggestion,
UnusedResult,
};
use crate::Lint;
@@ -257,8 +257,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
Array(Box<Self>, u64),
/// The root of the unused_closures lint.
Closure(Span),
- /// The root of the unused_generators lint.
- Generator(Span),
+ /// The root of the unused_coroutines lint.
+ Coroutine(Span),
}
#[instrument(skip(cx, expr), level = "debug", ret)]
@@ -350,16 +350,16 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
.map(|inner| MustUsePath::Array(Box::new(inner), len)),
},
ty::Closure(..) => Some(MustUsePath::Closure(span)),
- ty::Generator(def_id, ..) => {
+ ty::Coroutine(def_id, ..) => {
// async fn should be treated as "implementor of `Future`"
- let must_use = if cx.tcx.generator_is_async(def_id) {
- let def_id = cx.tcx.lang_items().future_trait().unwrap();
+ let must_use = if cx.tcx.coroutine_is_async(def_id) {
+ let def_id = cx.tcx.lang_items().future_trait()?;
is_def_must_use(cx, def_id, span)
.map(|inner| MustUsePath::Opaque(Box::new(inner)))
} else {
None
};
- must_use.or(Some(MustUsePath::Generator(span)))
+ must_use.or(Some(MustUsePath::Coroutine(span)))
}
_ => None,
}
@@ -482,11 +482,11 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
UnusedClosure { count: plural_len, pre: descr_pre, post: descr_post },
);
}
- MustUsePath::Generator(span) => {
+ MustUsePath::Coroutine(span) => {
cx.emit_spanned_lint(
UNUSED_MUST_USE,
*span,
- UnusedGenerator { count: plural_len, pre: descr_pre, post: descr_post },
+ UnusedCoroutine { count: plural_len, pre: descr_pre, post: descr_post },
);
}
MustUsePath::Def(span, def_id, reason) => {
@@ -782,21 +782,23 @@ trait UnusedDelimLint {
};
let suggestion = spans.map(|(lo, hi)| {
let sm = cx.sess().source_map();
- let lo_replace =
- if (keep_space.0 || is_kw) &&
- let Ok(snip) = sm.span_to_prev_source(lo) && !snip.ends_with(' ') {
- " "
- } else {
- ""
- };
+ let lo_replace = if (keep_space.0 || is_kw)
+ && let Ok(snip) = sm.span_to_prev_source(lo)
+ && !snip.ends_with(' ')
+ {
+ " "
+ } else {
+ ""
+ };
- let hi_replace =
- if keep_space.1 &&
- let Ok(snip) = sm.span_to_next_source(hi) && !snip.starts_with(' ') {
- " "
- } else {
- ""
- };
+ let hi_replace = if keep_space.1
+ && let Ok(snip) = sm.span_to_next_source(hi)
+ && !snip.starts_with(' ')
+ {
+ " "
+ } else {
+ ""
+ };
UnusedDelimSuggestion {
start_span: lo,
start_replace: lo_replace,
@@ -1056,10 +1058,10 @@ impl UnusedParens {
impl EarlyLintPass for UnusedParens {
#[inline]
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
- if let ExprKind::Binary(op, lhs, _rhs) = &e.kind &&
- (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) &&
- let ExprKind::Cast(_expr, ty) = &lhs.kind &&
- let ast::TyKind::Paren(_) = &ty.kind
+ if let ExprKind::Binary(op, lhs, _rhs) = &e.kind
+ && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl)
+ && let ExprKind::Cast(_expr, ty) = &lhs.kind
+ && let ast::TyKind::Paren(_) = &ty.kind
{
self.parens_in_cast_in_lt.push(ty.id);
}
@@ -1111,13 +1113,19 @@ impl EarlyLintPass for UnusedParens {
}
fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) {
- if let ExprKind::Binary(op, lhs, _rhs) = &e.kind &&
- (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl) &&
- let ExprKind::Cast(_expr, ty) = &lhs.kind &&
- let ast::TyKind::Paren(_) = &ty.kind
+ if let ExprKind::Binary(op, lhs, _rhs) = &e.kind
+ && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl)
+ && let ExprKind::Cast(_expr, ty) = &lhs.kind
+ && let ast::TyKind::Paren(_) = &ty.kind
{
- let id = self.parens_in_cast_in_lt.pop().expect("check_expr and check_expr_post must balance");
- assert_eq!(id, ty.id, "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor");
+ let id = self
+ .parens_in_cast_in_lt
+ .pop()
+ .expect("check_expr and check_expr_post must balance");
+ assert_eq!(
+ id, ty.id,
+ "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"
+ );
}
}
@@ -1146,7 +1154,7 @@ impl EarlyLintPass for UnusedParens {
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
if let StmtKind::Local(ref local) = s.kind {
- self.check_unused_parens_pat(cx, &local.pat, true, false, (false, false));
+ self.check_unused_parens_pat(cx, &local.pat, true, false, (true, false));
}
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
@@ -1161,8 +1169,8 @@ impl EarlyLintPass for UnusedParens {
}
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
- if let ast::TyKind::Paren(_) = ty.kind &&
- Some(&ty.id) == self.parens_in_cast_in_lt.last()
+ if let ast::TyKind::Paren(_) = ty.kind
+ && Some(&ty.id) == self.parens_in_cast_in_lt.last()
{
return;
}
@@ -1206,13 +1214,14 @@ impl EarlyLintPass for UnusedParens {
fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
use rustc_ast::{WhereBoundPredicate, WherePredicate};
if let WherePredicate::BoundPredicate(WhereBoundPredicate {
- bounded_ty,
- bound_generic_params,
- ..
- }) = pred &&
- let ast::TyKind::Paren(_) = &bounded_ty.kind &&
- bound_generic_params.is_empty() {
- self.with_self_ty_parens = true;
+ bounded_ty,
+ bound_generic_params,
+ ..
+ }) = pred
+ && let ast::TyKind::Paren(_) = &bounded_ty.kind
+ && bound_generic_params.is_empty()
+ {
+ self.with_self_ty_parens = true;
}
}
@@ -1516,9 +1525,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
match e.kind {
hir::ExprKind::Call(path_expr, [_])
if let hir::ExprKind::Path(qpath) = &path_expr.kind
- && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()
- && cx.tcx.is_diagnostic_item(sym::box_new, did)
- => {}
+ && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::box_new, did) => {}
_ => return,
}