about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs22
-rw-r--r--compiler/rustc_hir/src/hir.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs35
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs3
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs14
-rw-r--r--compiler/rustc_lint/src/traits.rs5
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs2
-rw-r--r--src/librustdoc/clean/mod.rs4
-rw-r--r--src/librustdoc/clean/types.rs19
-rw-r--r--src/librustdoc/html/format.rs14
-rw-r--r--src/librustdoc/json/conversions.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs14
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs14
-rw-r--r--tests/ui/stats/hir-stats.stderr16
18 files changed, 116 insertions, 117 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 02cb6f188a7..8e4f4c8e71a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2697,7 +2697,7 @@ impl fmt::Debug for ImplPolarity {
 }
 
 /// The polarity of a trait bound.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
 #[derive(HashStable_Generic)]
 pub enum BoundPolarity {
     /// `Type: Trait`
@@ -2719,7 +2719,7 @@ impl BoundPolarity {
 }
 
 /// The constness of a trait bound.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash)]
 #[derive(HashStable_Generic)]
 pub enum BoundConstness {
     /// `Type: Trait`
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 4d8d22e09d9..28523bcb3bf 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1956,7 +1956,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         hir::GenericBound::Trait(hir::PolyTraitRef {
             bound_generic_params: &[],
-            modifiers: hir::TraitBoundModifier::None,
+            modifiers: hir::TraitBoundModifiers::NONE,
             trait_ref: hir::TraitRef {
                 path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)),
                 hir_ref_id: self.next_id(),
@@ -2445,22 +2445,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_trait_bound_modifiers(
         &mut self,
         modifiers: TraitBoundModifiers,
-    ) -> hir::TraitBoundModifier {
-        // Invalid modifier combinations will cause an error during AST validation.
-        // Arbitrarily pick a placeholder for them to make compilation proceed.
-        match (modifiers.constness, modifiers.polarity) {
-            (BoundConstness::Never, BoundPolarity::Positive) => hir::TraitBoundModifier::None,
-            (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
-            (BoundConstness::Never, BoundPolarity::Negative(_)) => {
-                if self.tcx.features().negative_bounds {
-                    hir::TraitBoundModifier::Negative
-                } else {
-                    hir::TraitBoundModifier::None
-                }
-            }
-            (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
-            (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
-        }
+    ) -> hir::TraitBoundModifiers {
+        hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity }
     }
 
     // Helper methods for building HIR.
@@ -2626,7 +2612,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
                         let principal = hir::PolyTraitRef {
                             bound_generic_params: &[],
-                            modifiers: hir::TraitBoundModifier::None,
+                            modifiers: hir::TraitBoundModifiers::NONE,
                             trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
                             span: self.lower_span(span),
                         };
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 009c6c4aea5..45be04c6db9 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -6,8 +6,8 @@ use rustc_ast::{
     LitKind, TraitObjectSyntax, UintTy,
 };
 pub use rustc_ast::{
-    BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability,
-    Mutability, UnOp,
+    BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
+    ImplPolarity, IsAuto, Movability, Mutability, UnOp,
 };
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
@@ -502,19 +502,16 @@ pub enum GenericArgsParentheses {
     ParenSugar,
 }
 
-/// A modifier on a trait bound.
+/// The modifiers on a trait bound.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
-pub enum TraitBoundModifier {
-    /// `Type: Trait`
-    None,
-    /// `Type: !Trait`
-    Negative,
-    /// `Type: ?Trait`
-    Maybe,
-    /// `Type: const Trait`
-    Const,
-    /// `Type: ~const Trait`
-    MaybeConst,
+pub struct TraitBoundModifiers {
+    pub constness: BoundConstness,
+    pub polarity: BoundPolarity,
+}
+
+impl TraitBoundModifiers {
+    pub const NONE: Self =
+        TraitBoundModifiers { constness: BoundConstness::Never, polarity: BoundPolarity::Positive };
 }
 
 #[derive(Clone, Copy, Debug, HashStable_Generic)]
@@ -3180,7 +3177,7 @@ pub struct PolyTraitRef<'hir> {
     /// The constness and polarity of the trait ref.
     ///
     /// The `async` modifier is lowered directly into a different trait for now.
-    pub modifiers: TraitBoundModifier,
+    pub modifiers: TraitBoundModifiers,
 
     /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`.
     pub trait_ref: TraitRef<'hir>,
@@ -4085,7 +4082,7 @@ mod size_asserts {
     static_assert_size!(ForeignItem<'_>, 88);
     static_assert_size!(ForeignItemKind<'_>, 56);
     static_assert_size!(GenericArg<'_>, 16);
-    static_assert_size!(GenericBound<'_>, 48);
+    static_assert_size!(GenericBound<'_>, 64);
     static_assert_size!(Generics<'_>, 56);
     static_assert_size!(Impl<'_>, 80);
     static_assert_size!(ImplItem<'_>, 88);
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 4721a3a0cf5..a8b2b9b7c0a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -45,23 +45,22 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let hir::GenericBound::Trait(ptr) = hir_bound else {
                     continue;
                 };
-                match ptr.modifiers {
-                    hir::TraitBoundModifier::Maybe => unbounds.push(ptr),
-                    hir::TraitBoundModifier::Negative => {
+                match ptr.modifiers.polarity {
+                    hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
+                    hir::BoundPolarity::Negative(_) => {
                         if let Some(sized_def_id) = sized_def_id
                             && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
                         {
                             seen_negative_sized_bound = true;
                         }
                     }
-                    hir::TraitBoundModifier::None => {
+                    hir::BoundPolarity::Positive => {
                         if let Some(sized_def_id) = sized_def_id
                             && ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
                         {
                             seen_positive_sized_bound = true;
                         }
                     }
-                    _ => {}
                 }
             }
         };
@@ -169,20 +168,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
             match hir_bound {
                 hir::GenericBound::Trait(poly_trait_ref) => {
-                    let (constness, polarity) = match poly_trait_ref.modifiers {
-                        hir::TraitBoundModifier::Const => {
-                            (Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive)
-                        }
-                        hir::TraitBoundModifier::MaybeConst => (
-                            Some(ty::BoundConstness::ConstIfConst),
-                            ty::PredicatePolarity::Positive,
-                        ),
-                        hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive),
-                        hir::TraitBoundModifier::Negative => {
-                            (None, ty::PredicatePolarity::Negative)
-                        }
-                        hir::TraitBoundModifier::Maybe => continue,
+                    let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers;
+                    // FIXME: We could pass these directly into `lower_poly_trait_ref`
+                    // so that we could use these spans in diagnostics within that function...
+                    let constness = match constness {
+                        hir::BoundConstness::Never => None,
+                        hir::BoundConstness::Always(_) => Some(ty::BoundConstness::Const),
+                        hir::BoundConstness::Maybe(_) => Some(ty::BoundConstness::ConstIfConst),
                     };
+                    let polarity = match polarity {
+                        rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
+                        rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
+                        rustc_ast::BoundPolarity::Maybe(_) => continue,
+                    };
+
                     let _ = self.lower_poly_trait_ref(
                         &poly_trait_ref.trait_ref,
                         poly_trait_ref.span,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 4cb55ec8c89..2cee7c77aa5 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -40,8 +40,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let mut potential_assoc_types = Vec::new();
         let dummy_self = self.tcx().types.trait_object_dummy_self;
         for trait_bound in hir_trait_bounds.iter().rev() {
-            // FIXME: This doesn't handle `? const`.
-            if trait_bound.modifiers == hir::TraitBoundModifier::Maybe {
+            if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
                 continue;
             }
             if let GenericArgCountResult {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 9ebfd4f15ab..3ba9c76bcee 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -16,7 +16,6 @@ use rustc_ast_pretty::pprust::{Comments, PrintState};
 use rustc_hir::{
     BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
     HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
-    TraitBoundModifier,
 };
 use rustc_span::FileName;
 use rustc_span::source_map::SourceMap;
@@ -676,9 +675,16 @@ impl<'a> State<'a> {
     }
 
     fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
-        // FIXME: This isn't correct!
-        if t.modifiers == TraitBoundModifier::Maybe {
-            self.word("?");
+        let hir::TraitBoundModifiers { constness, polarity } = t.modifiers;
+        match constness {
+            hir::BoundConstness::Never => {}
+            hir::BoundConstness::Always(_) => self.word("const"),
+            hir::BoundConstness::Maybe(_) => self.word("~const"),
+        }
+        match polarity {
+            hir::BoundPolarity::Positive => {}
+            hir::BoundPolarity::Negative(_) => self.word("!"),
+            hir::BoundPolarity::Maybe(_) => self.word("?"),
         }
         self.print_formal_generic_params(t.bound_generic_params);
         self.print_trait_ref(&t.trait_ref);
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 5a3666dcbd4..b793ec6a493 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -114,10 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
         let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
         for bound in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
-            if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop))
-                // FIXME: ?Drop is not a thing.
-                && bound.modifiers != hir::TraitBoundModifier::Maybe
-            {
+            if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) {
                 let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return };
                 cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });
             }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 4f408ee1574..8bd2ae9128f 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -193,7 +193,7 @@ fn suggest_changing_unsized_bound(
             .enumerate()
             .filter(|(_, bound)| {
                 if let hir::GenericBound::Trait(poly) = bound
-                    && poly.modifiers == hir::TraitBoundModifier::Maybe
+                    && let hir::BoundPolarity::Maybe(_) = poly.modifiers.polarity
                     && poly.trait_ref.trait_def_id() == def_id
                 {
                     true
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 62204f63dd0..0cf7c43beb5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -894,7 +894,7 @@ fn foo(&self) -> Self::T { String::new() }
         // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
 
         let trait_bounds = bounds.iter().filter_map(|bound| match bound {
-            hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifier::None => {
+            hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifiers::NONE => {
                 Some(ptr)
             }
             _ => None,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7d4d8d8941d..848f2abe6a9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -216,7 +216,7 @@ fn clean_generic_bound<'tcx>(
         hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
         hir::GenericBound::Trait(ref t) => {
             // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
-            if t.modifiers == hir::TraitBoundModifier::MaybeConst
+            if let hir::BoundConstness::Maybe(_) = t.modifiers.constness
                 && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
             {
                 return None;
@@ -263,7 +263,7 @@ fn clean_poly_trait_ref_with_constraints<'tcx>(
             trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints),
             generic_params: clean_bound_vars(poly_trait_ref.bound_vars()),
         },
-        hir::TraitBoundModifier::None,
+        hir::TraitBoundModifiers::NONE,
     )
 }
 
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 675507a44c9..2e3050eee2f 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1257,7 +1257,7 @@ impl Eq for Attributes {}
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) enum GenericBound {
-    TraitBound(PolyTrait, hir::TraitBoundModifier),
+    TraitBound(PolyTrait, hir::TraitBoundModifiers),
     Outlives(Lifetime),
     /// `use<'a, T>` precise-capturing bound syntax
     Use(Vec<Symbol>),
@@ -1265,19 +1265,22 @@ pub(crate) enum GenericBound {
 
 impl GenericBound {
     pub(crate) fn sized(cx: &mut DocContext<'_>) -> GenericBound {
-        Self::sized_with(cx, hir::TraitBoundModifier::None)
+        Self::sized_with(cx, hir::TraitBoundModifiers::NONE)
     }
 
     pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
-        Self::sized_with(cx, hir::TraitBoundModifier::Maybe)
+        Self::sized_with(cx, hir::TraitBoundModifiers {
+            polarity: hir::BoundPolarity::Maybe(DUMMY_SP),
+            constness: hir::BoundConstness::Never,
+        })
     }
 
-    fn sized_with(cx: &mut DocContext<'_>, modifier: hir::TraitBoundModifier) -> GenericBound {
+    fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = ty::Binder::dummy(ty::GenericArgs::empty());
         let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
-        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifier)
+        GenericBound::TraitBound(PolyTrait { trait_: path, generic_params: Vec::new() }, modifiers)
     }
 
     pub(crate) fn is_trait_bound(&self) -> bool {
@@ -1285,8 +1288,10 @@ impl GenericBound {
     }
 
     pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
-        use rustc_hir::TraitBoundModifier as TBM;
-        if let GenericBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self
+        if let GenericBound::TraitBound(
+            PolyTrait { ref trait_, .. },
+            rustc_hir::TraitBoundModifiers::NONE,
+        ) = *self
             && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait()
         {
             return true;
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 2e70a8c080d..5c599f20f9f 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -399,13 +399,13 @@ impl clean::GenericBound {
     ) -> impl Display + 'a + Captures<'tcx> {
         display_fn(move |f| match self {
             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
-            clean::GenericBound::TraitBound(ty, modifier) => {
-                f.write_str(match modifier {
-                    hir::TraitBoundModifier::None => "",
-                    hir::TraitBoundModifier::Maybe => "?",
-                    hir::TraitBoundModifier::Negative => "!",
-                    // `const` and `~const` trait bounds are experimental; don't render them.
-                    hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "",
+            clean::GenericBound::TraitBound(ty, modifiers) => {
+                // `const` and `~const` trait bounds are experimental; don't render them.
+                let hir::TraitBoundModifiers { polarity, constness: _ } = modifiers;
+                f.write_str(match polarity {
+                    hir::BoundPolarity::Positive => "",
+                    hir::BoundPolarity::Maybe(_) => "?",
+                    hir::BoundPolarity::Negative(_) => "!",
                 })?;
                 ty.print(cx).fmt(f)
             }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 0130f2ce517..7270f170780 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -552,20 +552,18 @@ impl FromClean<clean::GenericBound> for GenericBound {
 }
 
 pub(crate) fn from_trait_bound_modifier(
-    modifier: rustc_hir::TraitBoundModifier,
+    modifiers: rustc_hir::TraitBoundModifiers,
 ) -> TraitBoundModifier {
-    use rustc_hir::TraitBoundModifier::*;
-    match modifier {
-        None => TraitBoundModifier::None,
-        Maybe => TraitBoundModifier::Maybe,
-        MaybeConst => TraitBoundModifier::MaybeConst,
-        // FIXME(const_trait_impl): Create rjt::TBM::Const and map to it once always-const bounds
-        // are less experimental.
-        Const => TraitBoundModifier::None,
-        // FIXME(negative-bounds): This bound should be rendered negative, but
-        // since that's experimental, maybe let's not add it to the rustdoc json
-        // API just now...
-        Negative => TraitBoundModifier::None,
+    use rustc_hir as hir;
+    let hir::TraitBoundModifiers { constness, polarity } = modifiers;
+    match (constness, polarity) {
+        (hir::BoundConstness::Never, hir::BoundPolarity::Positive) => TraitBoundModifier::None,
+        (hir::BoundConstness::Never, hir::BoundPolarity::Maybe(_)) => TraitBoundModifier::Maybe,
+        (hir::BoundConstness::Maybe(_), hir::BoundPolarity::Positive) => {
+            TraitBoundModifier::MaybeConst
+        }
+        // FIXME: Fill out the rest of this matrix.
+        _ => TraitBoundModifier::None,
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 00f83237224..65fdc93e0ed 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet;
 use rustc_errors::{Applicability, SuggestionStyle};
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
-    AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifier, TyKind,
+    AssocItemConstraint, GenericArg, GenericBound, GenericBounds, PredicateOrigin, TraitBoundModifiers, TyKind,
     WherePredicate,
 };
 use rustc_hir_analysis::lower_ty;
@@ -234,7 +234,7 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
         .iter()
         .filter_map(|bound| {
             if let GenericBound::Trait(poly_trait) = bound
-                && let TraitBoundModifier::None = poly_trait.modifiers
+                && let TraitBoundModifiers::NONE = poly_trait.modifiers
                 && let [.., path] = poly_trait.trait_ref.path.segments
                 && poly_trait.bound_generic_params.is_empty()
                 && let Some(trait_def_id) = path.res.opt_def_id()
@@ -300,7 +300,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
     // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
     for (index, bound) in bounds.iter().enumerate() {
         if let GenericBound::Trait(poly_trait) = bound
-            && let TraitBoundModifier::None = poly_trait.modifiers
+            && let TraitBoundModifiers::NONE = poly_trait.modifiers
             && let [.., path] = poly_trait.trait_ref.path.segments
             && let implied_args = path.args.map_or([].as_slice(), |a| a.args)
             && let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints)
diff --git a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
index 68c9af07465..9a1c397b5b2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_maybe_sized.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifier, WherePredicate};
+use rustc_hir::{GenericBound, Generics, PolyTraitRef, TraitBoundModifiers, BoundPolarity, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{ClauseKind, PredicatePolarity};
 use rustc_session::declare_lint_pass;
@@ -118,13 +118,13 @@ impl LateLintPass<'_> for NeedlessMaybeSized {
         let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics)
             .filter(|bound| {
                 bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait)
-                    && bound.trait_bound.modifiers == TraitBoundModifier::Maybe
+                    && matches!(bound.trait_bound.modifiers.polarity, BoundPolarity::Maybe(_))
             })
             .map(|bound| (bound.param, bound))
             .collect();
 
         for bound in type_param_bounds(generics) {
-            if bound.trait_bound.modifiers == TraitBoundModifier::None
+            if bound.trait_bound.modifiers == TraitBoundModifiers::NONE
                 && let Some(sized_bound) = maybe_sized_params.get(&bound.param)
                 && let Some(path) = path_to_sized_bound(cx, bound.trait_bound)
             {
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 7f528b9d17b..3da4bf67558 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -11,7 +11,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
     GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
-    TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
+    TraitBoundModifiers, TraitItem, TraitRef, Ty, TyKind, WherePredicate, BoundPolarity,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -233,7 +233,7 @@ impl TraitBounds {
     fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool {
         if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE)
             && let GenericBound::Trait(tr) = bound
-            && let TraitBoundModifier::Maybe = tr.modifiers
+            && let BoundPolarity::Maybe(_) = tr.modifiers.polarity
         {
             cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id()
         } else {
@@ -374,12 +374,12 @@ fn check_trait_bound_duplication<'tcx>(cx: &LateContext<'tcx>, generics: &'_ Gen
 struct ComparableTraitRef<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     trait_ref: &'tcx TraitRef<'tcx>,
-    modifier: TraitBoundModifier,
+    modifiers: TraitBoundModifiers,
 }
 
 impl PartialEq for ComparableTraitRef<'_, '_> {
     fn eq(&self, other: &Self) -> bool {
-        self.modifier == other.modifier
+        SpanlessEq::new(self.cx).eq_modifiers(self.modifiers, other.modifiers)
             && SpanlessEq::new(self.cx)
                 .paths_by_resolution()
                 .eq_path(self.trait_ref.path, other.trait_ref.path)
@@ -390,8 +390,8 @@ impl Hash for ComparableTraitRef<'_, '_> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         let mut s = SpanlessHash::new(self.cx).paths_by_resolution();
         s.hash_path(self.trait_ref.path);
+        s.hash_modifiers(self.modifiers);
         state.write_u64(s.finish());
-        self.modifier.hash(state);
     }
 }
 
@@ -400,7 +400,7 @@ fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'
         let trait_path = t.trait_ref.path;
         let trait_span = {
             let path_span = trait_path.span;
-            if let TraitBoundModifier::Maybe = t.modifiers {
+            if let BoundPolarity::Maybe(_) = t.modifiers.polarity {
                 path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?`
             } else {
                 path_span
@@ -427,7 +427,7 @@ fn rollup_traits<'cx, 'tcx>(
                 ComparableTraitRef {
                     cx,
                     trait_ref: &t.trait_ref,
-                    modifier: t.modifiers,
+                    modifiers: t.modifiers,
                 },
                 t.span,
             ))
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 27c57808ece..181d414cbbd 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -9,7 +9,8 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
     ArrayLen, AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr,
     ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime,
-    LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Ty, TyKind,
+    LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty,
+    TyKind,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::LateContext;
@@ -126,6 +127,11 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
     pub fn eq_path_segments(&mut self, left: &[PathSegment<'_>], right: &[PathSegment<'_>]) -> bool {
         self.inter_expr().eq_path_segments(left, right)
     }
+
+    pub fn eq_modifiers(&mut self, left: TraitBoundModifiers, right: TraitBoundModifiers) -> bool {
+        std::mem::discriminant(&left.constness) == std::mem::discriminant(&right.constness)
+            && std::mem::discriminant(&left.polarity) == std::mem::discriminant(&right.polarity)
+    }
 }
 
 pub struct HirEqInterExpr<'a, 'b, 'tcx> {
@@ -1143,6 +1149,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         }
     }
 
+    pub fn hash_modifiers(&mut self, modifiers: TraitBoundModifiers) {
+        let TraitBoundModifiers { constness, polarity } = modifiers;
+        std::mem::discriminant(&polarity).hash(&mut self.s);
+        std::mem::discriminant(&constness).hash(&mut self.s);
+    }
+
     pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
         std::mem::discriminant(&b.kind).hash(&mut self.s);
 
diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr
index 3a2d4df3bee..bd0c8cbc3b1 100644
--- a/tests/ui/stats/hir-stats.stderr
+++ b/tests/ui/stats/hir-stats.stderr
@@ -141,10 +141,10 @@ hir-stats FnDecl                   120 ( 1.3%)             3            40
 hir-stats Attribute                128 ( 1.4%)             4            32
 hir-stats GenericArgs              144 ( 1.6%)             3            48
 hir-stats Variant                  144 ( 1.6%)             2            72
-hir-stats GenericBound             192 ( 2.1%)             4            48
-hir-stats - Trait                    192 ( 2.1%)             4
 hir-stats WherePredicate           192 ( 2.1%)             3            64
 hir-stats - BoundPredicate           192 ( 2.1%)             3
+hir-stats GenericBound             256 ( 2.8%)             4            64
+hir-stats - Trait                    256 ( 2.8%)             4
 hir-stats Block                    288 ( 3.2%)             6            48
 hir-stats GenericParam             360 ( 4.0%)             5            72
 hir-stats Pat                      360 ( 4.0%)             5            72
@@ -155,15 +155,15 @@ hir-stats Generics                 560 ( 6.2%)            10            56
 hir-stats Ty                       720 ( 8.0%)            15            48
 hir-stats - Ref                       48 ( 0.5%)             1
 hir-stats - Ptr                       48 ( 0.5%)             1
-hir-stats - Path                     624 ( 7.0%)            13
-hir-stats Expr                     768 ( 8.6%)            12            64
+hir-stats - Path                     624 ( 6.9%)            13
+hir-stats Expr                     768 ( 8.5%)            12            64
 hir-stats - Path                      64 ( 0.7%)             1
 hir-stats - Match                     64 ( 0.7%)             1
 hir-stats - Struct                    64 ( 0.7%)             1
 hir-stats - InlineAsm                 64 ( 0.7%)             1
 hir-stats - Lit                      128 ( 1.4%)             2
 hir-stats - Block                    384 ( 4.3%)             6
-hir-stats Item                     968 (10.8%)            11            88
+hir-stats Item                     968 (10.7%)            11            88
 hir-stats - Enum                      88 ( 1.0%)             1
 hir-stats - Trait                     88 ( 1.0%)             1
 hir-stats - Impl                      88 ( 1.0%)             1
@@ -171,8 +171,8 @@ hir-stats - ExternCrate               88 ( 1.0%)             1
 hir-stats - ForeignMod                88 ( 1.0%)             1
 hir-stats - Fn                       176 ( 2.0%)             2
 hir-stats - Use                      352 ( 3.9%)             4
-hir-stats Path                   1_240 (13.8%)            31            40
-hir-stats PathSegment            1_920 (21.4%)            40            48
+hir-stats Path                   1_240 (13.7%)            31            40
+hir-stats PathSegment            1_920 (21.3%)            40            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  8_960
+hir-stats Total                  9_024
 hir-stats