diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3496cfc38c84e..9a9c769fd7c1a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2481,15 +2481,6 @@ pub enum Const {
     No,
 }
 
-impl From<BoundConstness> for Const {
-    fn from(constness: BoundConstness) -> Self {
-        match constness {
-            BoundConstness::Maybe(span) => Self::Yes(span),
-            BoundConstness::Never => Self::No,
-        }
-    }
-}
-
 /// Item defaultness.
 /// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
 #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -2543,6 +2534,8 @@ impl BoundPolarity {
 pub enum BoundConstness {
     /// `Type: Trait`
     Never,
+    /// `Type: const Trait`
+    Always(Span),
     /// `Type: ~const Trait`
     Maybe(Span),
 }
@@ -2551,6 +2544,7 @@ impl BoundConstness {
     pub fn as_str(self) -> &'static str {
         match self {
             Self::Never => "",
+            Self::Always(_) => "const",
             Self::Maybe(_) => "~const",
         }
     }
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index b0cd2ec981592..d62462b1ae33b 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -528,15 +528,6 @@ impl Token {
         }
     }
 
-    /// Returns `true` if the token can appear at the start of a generic bound.
-    pub fn can_begin_bound(&self) -> bool {
-        self.is_path_start()
-            || self.is_lifetime()
-            || self.is_keyword(kw::For)
-            || self == &Question
-            || self == &OpenDelim(Delimiter::Parenthesis)
-    }
-
     /// Returns `true` if the token can appear at the start of an item.
     pub fn can_begin_item(&self) -> bool {
         match self.kind {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index b70b935622635..3848f3b778298 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -339,9 +339,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let itctx = ImplTraitContext::Universal;
                 let (generics, (trait_ref, lowered_ty)) =
                     self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
+                        let constness = match *constness {
+                            Const::Yes(span) => BoundConstness::Maybe(span),
+                            Const::No => BoundConstness::Never,
+                        };
+
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
                             this.lower_trait_ref(
-                                *constness,
+                                constness,
                                 trait_ref,
                                 &ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
                             )
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e395411628886..4c4cf593bdaec 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1324,7 +1324,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         span: t.span,
                     },
                     itctx,
-                    ast::Const::No,
+                    ast::BoundConstness::Never,
                 );
                 let bounds = this.arena.alloc_from_iter([bound]);
                 let lifetime_bound = this.elided_dyn_bound(t.span);
@@ -1435,7 +1435,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                     polarity: BoundPolarity::Positive | BoundPolarity::Negative(_),
                                     constness,
                                 },
-                            ) => Some(this.lower_poly_trait_ref(ty, itctx, (*constness).into())),
+                            ) => Some(this.lower_poly_trait_ref(ty, itctx, *constness)),
                             // We can safely ignore constness here, since AST validation
                             // will take care of invalid modifier combinations.
                             GenericBound::Trait(
@@ -2174,7 +2174,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     fn lower_trait_ref(
         &mut self,
-        constness: ast::Const,
+        constness: ast::BoundConstness,
         p: &TraitRef,
         itctx: &ImplTraitContext,
     ) -> hir::TraitRef<'hir> {
@@ -2197,7 +2197,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &mut self,
         p: &PolyTraitRef,
         itctx: &ImplTraitContext,
-        constness: ast::Const,
+        constness: ast::BoundConstness,
     ) -> hir::PolyTraitRef<'hir> {
         let bound_generic_params =
             self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
@@ -2322,9 +2322,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         &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,
-            (BoundConstness::Never, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
+            (_, BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
             (BoundConstness::Never, BoundPolarity::Negative(_)) => {
                 if self.tcx.features().negative_bounds {
                     hir::TraitBoundModifier::Negative
@@ -2332,15 +2334,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     hir::TraitBoundModifier::None
                 }
             }
-            (BoundConstness::Maybe(_), BoundPolarity::Positive) => {
-                hir::TraitBoundModifier::MaybeConst
-            }
-            // Invalid modifier combinations will cause an error during AST validation.
-            // Arbitrarily pick a placeholder for compilation to proceed.
-            (BoundConstness::Maybe(_), BoundPolarity::Maybe(_)) => hir::TraitBoundModifier::Maybe,
-            (BoundConstness::Maybe(_), BoundPolarity::Negative(_)) => {
-                hir::TraitBoundModifier::MaybeConst
-            }
+            (BoundConstness::Always(_), _) => hir::TraitBoundModifier::Const,
+            (BoundConstness::Maybe(_), _) => hir::TraitBoundModifier::MaybeConst,
         }
     }
 
@@ -2558,45 +2553,62 @@ struct GenericArgsCtor<'hir> {
 }
 
 impl<'hir> GenericArgsCtor<'hir> {
-    fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
+    fn push_constness(
+        &mut self,
+        lcx: &mut LoweringContext<'_, 'hir>,
+        constness: ast::BoundConstness,
+    ) {
         if !lcx.tcx.features().effects {
             return;
         }
 
-        // if bound is non-const, don't add host effect param
-        let ast::Const::Yes(span) = constness else { return };
+        let (span, body) = match constness {
+            BoundConstness::Never => return,
+            BoundConstness::Always(span) => {
+                let span = lcx.lower_span(span);
 
-        let span = lcx.lower_span(span);
+                let body = hir::ExprKind::Lit(
+                    lcx.arena.alloc(hir::Lit { node: LitKind::Bool(false), span }),
+                );
 
-        let id = lcx.next_node_id();
-        let hir_id = lcx.next_id();
+                (span, body)
+            }
+            BoundConstness::Maybe(span) => {
+                let span = lcx.lower_span(span);
 
-        let Some(host_param_id) = lcx.host_param_id else {
-            lcx.dcx().span_delayed_bug(
-                span,
-                "no host param id for call in const yet no errors reported",
-            );
-            return;
-        };
+                let Some(host_param_id) = lcx.host_param_id else {
+                    lcx.dcx().span_delayed_bug(
+                        span,
+                        "no host param id for call in const yet no errors reported",
+                    );
+                    return;
+                };
 
-        let body = lcx.lower_body(|lcx| {
-            (&[], {
                 let hir_id = lcx.next_id();
                 let res = Res::Def(DefKind::ConstParam, host_param_id.to_def_id());
-                let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
+                let body = hir::ExprKind::Path(hir::QPath::Resolved(
                     None,
                     lcx.arena.alloc(hir::Path {
                         span,
                         res,
-                        segments: arena_vec![lcx; hir::PathSegment::new(Ident {
-                            name: sym::host,
-                            span,
-                        }, hir_id, res)],
+                        segments: arena_vec![
+                            lcx;
+                            hir::PathSegment::new(
+                                Ident { name: sym::host, span },
+                                hir_id,
+                                res
+                            )
+                        ],
                     }),
                 ));
-                lcx.expr(span, expr_kind)
-            })
-        });
+
+                (span, body)
+            }
+        };
+        let body = lcx.lower_body(|lcx| (&[], lcx.expr(span, body)));
+
+        let id = lcx.next_node_id();
+        let hir_id = lcx.next_id();
 
         let def_id = lcx.create_def(
             lcx.current_hir_id_owner.def_id,
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 130eb3521c3f4..c679ee56fcd8b 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -25,7 +25,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         param_mode: ParamMode,
         itctx: &ImplTraitContext,
         // constness of the impl/bound if this is a trait path
-        constness: Option<ast::Const>,
+        constness: Option<ast::BoundConstness>,
     ) -> hir::QPath<'hir> {
         let qself_position = qself.as_ref().map(|q| q.position);
         let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@@ -179,7 +179,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         param_mode: ParamMode,
         parenthesized_generic_args: ParenthesizedGenericArgs,
         itctx: &ImplTraitContext,
-        constness: Option<ast::Const>,
+        constness: Option<ast::BoundConstness>,
     ) -> hir::PathSegment<'hir> {
         debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
         let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index ea3cd3e4bee2c..b5612c1820d0c 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -46,6 +46,8 @@ ast_passes_const_and_c_variadic = functions cannot be both `const` and C-variadi
     .const = `const` because of this
     .variadic = C-variadic because of this
 
+ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types
+
 ast_passes_const_without_body =
     free constant item without body
     .suggestion = provide a definition for the constant
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 3600e4960afd2..bc5cf463f1204 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1207,6 +1207,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 (BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
                     self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
                 }
+                (BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
+                    self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
+                }
                 (_, BoundConstness::Maybe(span), BoundPolarity::Positive)
                     if let Some(reason) = &self.disallow_tilde_const =>
                 {
@@ -1237,8 +1240,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 (
                     _,
-                    BoundConstness::Maybe(_),
-                    BoundPolarity::Maybe(_) | BoundPolarity::Negative(_),
+                    BoundConstness::Always(_) | BoundConstness::Maybe(_),
+                    BoundPolarity::Negative(_) | BoundPolarity::Maybe(_),
                 ) => {
                     self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers {
                         span: bound.span(),
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index a5b842b320e09..0cec4374be2ee 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -540,6 +540,13 @@ pub struct OptionalTraitObject {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(ast_passes_const_bound_trait_object)]
+pub struct ConstBoundTraitObject {
+    #[primary_span]
+    pub span: Span,
+}
+
 #[derive(Diagnostic)]
 #[diag(ast_passes_tilde_const_disallowed)]
 pub struct TildeConstDisallowed {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 12d37cf5a7a4f..0543c8e1d44e0 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1561,7 +1561,7 @@ impl<'a> State<'a> {
                 GenericBound::Trait(tref, modifier) => {
                     match modifier.constness {
                         ast::BoundConstness::Never => {}
-                        ast::BoundConstness::Maybe(_) => {
+                        ast::BoundConstness::Always(_) | ast::BoundConstness::Maybe(_) => {
                             self.word_space(modifier.constness.as_str());
                         }
                     }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 2b8408601663c..b76edd554f873 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -420,9 +420,15 @@ pub enum GenericArgsParentheses {
 /// A modifier 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,
 }
 
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 139e1c0ac5fdc..d8b6b9a1272fb 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -70,7 +70,7 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s
 hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found
 
 hir_analysis_const_bound_for_non_const_trait =
-    ~const can only be applied to `#[const_trait]` traits
+    `{$modifier}` can only be applied to `#[const_trait]` traits
 
 hir_analysis_const_impl_for_non_const_trait =
     const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 6e71cf16ee8b4..91b3807d74462 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -112,6 +112,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             match ast_bound {
                 hir::GenericBound::Trait(poly_trait_ref, modifier) => {
                     let (constness, polarity) = match modifier {
+                        hir::TraitBoundModifier::Const => {
+                            (ty::BoundConstness::Const, ty::ImplPolarity::Positive)
+                        }
                         hir::TraitBoundModifier::MaybeConst => {
                             (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
                         }
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 8197fea5b298e..092df257dbfae 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -560,11 +560,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             inferred_params: vec![],
             infer_args,
         };
-        if let ty::BoundConstness::ConstIfConst = constness
+        if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
             && generics.has_self
             && !tcx.has_attr(def_id, sym::const_trait)
         {
-            let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span });
+            let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
+                span,
+                modifier: constness.as_str(),
+            });
             arg_count.correct =
                 Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
         }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 41f30057902b6..75e7a5524a744 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -408,6 +408,7 @@ pub struct ConstImplForNonConstTrait {
 pub struct ConstBoundForNonConstTrait {
     #[primary_span]
     pub span: Span,
+    pub modifier: &'static str,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 9f1ff4538aa24..0653796ec7fc3 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -309,23 +309,22 @@ impl Visibility {
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
 pub enum BoundConstness {
-    /// `T: Trait`
+    /// `Type: Trait`
     NotConst,
-    /// `T: ~const Trait`
+    /// `Type: const Trait`
+    Const,
+    /// `Type: ~const Trait`
     ///
     /// Requires resolving to const only when we are in a const context.
     ConstIfConst,
 }
 
 impl BoundConstness {
-    /// Reduce `self` and `constness` to two possible combined states instead of four.
-    pub fn and(&mut self, constness: hir::Constness) -> hir::Constness {
-        match (constness, self) {
-            (hir::Constness::Const, BoundConstness::ConstIfConst) => hir::Constness::Const,
-            (_, this) => {
-                *this = BoundConstness::NotConst;
-                hir::Constness::NotConst
-            }
+    pub fn as_str(self) -> &'static str {
+        match self {
+            Self::NotConst => "",
+            Self::Const => "const",
+            Self::ConstIfConst => "~const",
         }
     }
 }
@@ -334,7 +333,7 @@ impl fmt::Display for BoundConstness {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::NotConst => f.write_str("normal"),
-            Self::ConstIfConst => f.write_str("`~const`"),
+            _ => write!(f, "`{self}`"),
         }
     }
 }
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 363b8f4bfb9cc..c6bddbfacd6ec 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -95,9 +95,6 @@ parse_compound_assignment_expression_in_let = can't reassign to an uninitialized
     .suggestion = initialize the variable
     .help = if you meant to overwrite, remove the `let` binding
 
-parse_const_bounds_missing_tilde = const bounds must start with `~`
-    .suggestion = add `~`
-
 parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
     .suggestion = enclose the `const` expression in braces
 
@@ -555,8 +552,8 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl
     .suggestion_add_trait = add a trait here
     .suggestion_remove_for = for an inherent impl, drop this `for`
 
-parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
-    .suggestion = remove the `{$sigil}`
+parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds
+    .suggestion = remove the `{$modifier}`
 
 parse_more_than_one_char = character literal may only contain one codepoint
     .followed_by = this `{$chr}` is followed by the combining {$len ->
@@ -729,8 +726,6 @@ parse_switch_ref_box_order = switch the order of `ref` and `box`
 parse_ternary_operator = Rust has no ternary operator
     .help = use an `if-else` expression instead
 
-parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
-
 parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
     .suggestion = use `!` to perform bitwise not
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 53cce9e2883a9..e276b34ca37af 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2555,20 +2555,13 @@ pub(crate) struct AssocLifetime {
     pub lifetime: Span,
 }
 
-#[derive(Diagnostic)]
-#[diag(parse_tilde_const_lifetime)]
-pub(crate) struct TildeConstLifetime {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(parse_modifier_lifetime)]
 pub(crate) struct ModifierLifetime {
     #[primary_span]
     #[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")]
     pub span: Span,
-    pub sigil: &'static str,
+    pub modifier: &'static str,
 }
 
 #[derive(Diagnostic)]
@@ -2581,15 +2574,6 @@ pub(crate) struct ParenthesizedLifetime {
     pub snippet: String,
 }
 
-#[derive(Diagnostic)]
-#[diag(parse_const_bounds_missing_tilde)]
-pub(crate) struct ConstMissingTilde {
-    #[primary_span]
-    pub span: Span,
-    #[suggestion(code = "~", applicability = "machine-applicable")]
-    pub start: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(parse_underscore_literal_suffix)]
 pub(crate) struct UnderscoreLiteralSuffix {
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 42ab23d62923a..4be2c662d0351 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -86,6 +86,18 @@ fn can_continue_type_after_non_fn_ident(t: &Token) -> bool {
     t == &token::ModSep || t == &token::Lt || t == &token::BinOp(token::Shl)
 }
 
+fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
+    // `Not`, `Tilde` & `Const` are deliberately not part of this list to
+    // contain the number of potential regressions esp. in MBE code.
+    // `Const` would regress `rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs`.
+    // `Not` would regress `dyn!(...)` macro calls in Rust 2015.
+    t.is_path_start()
+        || t.is_lifetime()
+        || t == &TokenKind::Question
+        || t.is_keyword(kw::For)
+        || t == &TokenKind::OpenDelim(Delimiter::Parenthesis)
+}
+
 impl<'a> Parser<'a> {
     /// Parses a type.
     pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
@@ -665,7 +677,8 @@ impl<'a> Parser<'a> {
         self.check_keyword(kw::Dyn)
             && (self.token.uninterpolated_span().at_least_rust_2018()
                 || self.look_ahead(1, |t| {
-                    (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star))
+                    (can_begin_dyn_bound_in_edition_2015(t)
+                        || t.kind == TokenKind::BinOp(token::Star))
                         && !can_continue_type_after_non_fn_ident(t)
                 }))
     }
@@ -758,12 +771,12 @@ impl<'a> Parser<'a> {
 
     /// Can the current token begin a bound?
     fn can_begin_bound(&mut self) -> bool {
-        // This needs to be synchronized with `TokenKind::can_begin_bound`.
         self.check_path()
             || self.check_lifetime()
             || self.check(&token::Not)
             || self.check(&token::Question)
             || self.check(&token::Tilde)
+            || self.check_keyword(kw::Const)
             || self.check_keyword(kw::For)
             || self.check(&token::OpenDelim(Delimiter::Parenthesis))
     }
@@ -812,8 +825,11 @@ impl<'a> Parser<'a> {
     fn error_lt_bound_with_modifiers(&self, modifiers: TraitBoundModifiers) {
         match modifiers.constness {
             BoundConstness::Never => {}
-            BoundConstness::Maybe(span) => {
-                self.dcx().emit_err(errors::TildeConstLifetime { span });
+            BoundConstness::Always(span) | BoundConstness::Maybe(span) => {
+                self.dcx().emit_err(errors::ModifierLifetime {
+                    span,
+                    modifier: modifiers.constness.as_str(),
+                });
             }
         }
 
@@ -822,7 +838,7 @@ impl<'a> Parser<'a> {
             BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => {
                 self.dcx().emit_err(errors::ModifierLifetime {
                     span,
-                    sigil: modifiers.polarity.as_str(),
+                    modifier: modifiers.polarity.as_str(),
                 });
             }
         }
@@ -848,7 +864,7 @@ impl<'a> Parser<'a> {
     /// If no modifiers are present, this does not consume any tokens.
     ///
     /// ```ebnf
-    /// TRAIT_BOUND_MODIFIERS = ["~const"] ["?" | "!"]
+    /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["?" | "!"]
     /// ```
     fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> {
         let constness = if self.eat(&token::Tilde) {
@@ -858,11 +874,8 @@ impl<'a> Parser<'a> {
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
             BoundConstness::Maybe(span)
         } else if self.eat_keyword(kw::Const) {
-            let span = self.prev_token.span;
-            self.sess.gated_spans.gate(sym::const_trait_impl, span);
-            self.dcx().emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() });
-
-            BoundConstness::Maybe(span)
+            self.sess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span);
+            BoundConstness::Always(self.prev_token.span)
         } else {
             BoundConstness::Never
         };
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index a9c0ab557cb33..1923fc1511970 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -449,8 +449,8 @@ impl clean::GenericBound {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
                     hir::TraitBoundModifier::Negative => "!",
-                    // ~const is experimental; do not display those bounds in rustdoc
-                    hir::TraitBoundModifier::MaybeConst => "",
+                    // `const` and `~const` trait bounds are experimental; don't render them.
+                    hir::TraitBoundModifier::Const | hir::TraitBoundModifier::MaybeConst => "",
                 };
                 if f.alternate() {
                     write!(f, "{modifier_str}{ty:#}", ty = ty.print(cx))
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 513e94afe2918..32d7a80863d6d 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -547,6 +547,9 @@ pub(crate) fn from_trait_bound_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...
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index e5ebe1d852861..e6ea4108f4045 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -4,13 +4,13 @@ error[E0635]: unknown feature `const_fn_trait_ref_impls`
 LL | #![feature(const_fn_trait_ref_impls)]
    |            ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:15:15
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
    |               ^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:15:15
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
@@ -18,13 +18,13 @@ LL |     T: ~const Fn<()> + ~const Destruct,
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:22:15
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
    |               ^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:22:15
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
@@ -32,13 +32,13 @@ LL |     T: ~const FnMut<()> + ~const Destruct,
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:29:15
    |
 LL |     T: ~const FnOnce<()>,
    |               ^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:29:15
    |
 LL |     T: ~const FnOnce<()>,
@@ -46,13 +46,13 @@ LL |     T: ~const FnOnce<()>,
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:36:15
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
    |               ^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:36:15
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
@@ -60,13 +60,13 @@ LL |     T: ~const Fn<()> + ~const Destruct,
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:50:15
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
    |               ^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/fn_trait_refs.rs:50:15
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index 4b649bf43ed3d..08147a4afaf37 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,4 +1,4 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/unstable-const-fn-in-libcore.rs:19:39
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
diff --git a/tests/ui/generic-const-items/const-trait-impl.rs b/tests/ui/generic-const-items/const-trait-impl.rs
index 43cdf818c4694..04c3f3eb4340f 100644
--- a/tests/ui/generic-const-items/const-trait-impl.rs
+++ b/tests/ui/generic-const-items/const-trait-impl.rs
@@ -1,14 +1,12 @@
-// known-bug: #110395
-// FIXME check-pass
+// check-pass
 
 // Test that we can call methods from const trait impls inside of generic const items.
 
-#![feature(generic_const_items, const_trait_impl)]
+#![feature(generic_const_items, const_trait_impl, effects)]
 #![allow(incomplete_features)]
 #![crate_type = "lib"]
 
-// FIXME(generic_const_items, effects): Introduce `const` bounds to make this work.
-const CREATE<T: Create>: T = T::create();
+const CREATE<T: const Create>: T = T::create();
 
 pub const K0: i32 = CREATE::<i32>;
 pub const K1: i32 = CREATE; // arg inferred
@@ -23,3 +21,13 @@ impl const Create for i32 {
         4096
     }
 }
+
+trait Mod { // doesn't need to be a `#[const_trait]`
+    const CREATE<T: const Create>: T;
+}
+
+impl Mod for () {
+    const CREATE<T: const Create>: T = T::create();
+}
+
+pub const K2: i32 = <() as Mod>::CREATE::<i32>;
diff --git a/tests/ui/generic-const-items/const-trait-impl.stderr b/tests/ui/generic-const-items/const-trait-impl.stderr
deleted file mode 100644
index cdcd24eceffe5..0000000000000
--- a/tests/ui/generic-const-items/const-trait-impl.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0015]: cannot call non-const fn `<T as Create>::create` in constants
-  --> $DIR/const-trait-impl.rs:11:30
-   |
-LL | const CREATE<T: Create>: T = T::create();
-   |                              ^^^^^^^^^^^
-   |
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
-   = help: add `#![feature(effects)]` to the crate attributes to enable
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index e0513433b8ec1..7fd2ec57b1455 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,4 +1,4 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/normalize-tait-in-const.rs:25:42
    |
 LL | const fn with_positive<F: ~const for<'a> Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs
index 4ae4549ea5896..bd5f6105f51a2 100644
--- a/tests/ui/parser/bounds-type.rs
+++ b/tests/ui/parser/bounds-type.rs
@@ -13,6 +13,7 @@ struct S<
     T: ~const ?Tr, // OK
     T: ~const Tr + 'a, // OK
     T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds
+    T: const 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds
 >;
 
 fn main() {}
diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr
index 005bc1e54bd00..d1210e88d6678 100644
--- a/tests/ui/parser/bounds-type.stderr
+++ b/tests/ui/parser/bounds-type.stderr
@@ -10,5 +10,11 @@ error: `~const` may only modify trait bounds, not lifetime bounds
 LL |     T: ~const 'a,
    |        ^^^^^^
 
-error: aborting due to 2 previous errors
+error: `const` may only modify trait bounds, not lifetime bounds
+  --> $DIR/bounds-type.rs:16:8
+   |
+LL |     T: const 'a,
+   |        ^^^^^
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs b/tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs
new file mode 100644
index 0000000000000..fe062d62e5aa7
--- /dev/null
+++ b/tests/ui/parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs
@@ -0,0 +1,16 @@
+// Check that `?Trait` matches the macro fragment specifier `ty`.
+// Syntactically trait object types can be "bare" (i.e., lack the prefix `dyn`),
+// even in newer editions like Rust 2021.
+// Therefore the arm `?$Trait:path` shouldn't get reached.
+
+// edition: 2021
+// check-pass
+
+macro_rules! check {
+    ($Ty:ty) => {};
+    (?$Trait:path) => { compile_error!("non-ty"); };
+}
+
+check! { ?Trait }
+
+fn main() {}
diff --git a/tests/ui/parser/trait-object-delimiters.rs b/tests/ui/parser/trait-object-delimiters.rs
index e9b13defe0384..240ae3084d68e 100644
--- a/tests/ui/parser/trait-object-delimiters.rs
+++ b/tests/ui/parser/trait-object-delimiters.rs
@@ -8,7 +8,7 @@ fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around t
 fn foo2_no_space(_: &dyn(Drop + AsRef<str>)) {} //~ ERROR incorrect parentheses around trait bounds
 
 fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
-//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
+//~^ ERROR expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{`
 //~| ERROR at least one trait is required for an object type
 
 fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
diff --git a/tests/ui/parser/trait-object-delimiters.stderr b/tests/ui/parser/trait-object-delimiters.stderr
index 519546750938b..2ddb734cee067 100644
--- a/tests/ui/parser/trait-object-delimiters.stderr
+++ b/tests/ui/parser/trait-object-delimiters.stderr
@@ -34,11 +34,11 @@ error: expected parameter name, found `{`
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
    |                 ^ expected parameter name
 
-error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
+error: expected one of `!`, `(`, `)`, `*`, `,`, `?`, `const`, `for`, `~`, lifetime, or path, found `{`
   --> $DIR/trait-object-delimiters.rs:10:17
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
-   |                -^ expected one of 10 possible tokens
+   |                -^ expected one of 11 possible tokens
    |                |
    |                help: missing `,`
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr
index 290ef6e2f5fa0..58ad1849d4fab 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type.stderr
@@ -6,7 +6,7 @@ LL |     type Bar: ~const std::ops::Add;
    |
    = note: this item cannot have `~const` trait bounds
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/assoc-type.rs:17:22
    |
 LL |     type Bar: ~const std::ops::Add;
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs
new file mode 100644
index 0000000000000..3582e5e050c98
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.rs
@@ -0,0 +1,12 @@
+// Regression test for issue #117244.
+#![feature(const_trait_impl, effects)]
+
+trait NonConst {}
+
+const fn perform<T: ~const NonConst>() {}
+//~^ ERROR `~const` can only be applied to `#[const_trait]` traits
+
+fn operate<T: const NonConst>() {}
+//~^ ERROR `const` can only be applied to `#[const_trait]` traits
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr
new file mode 100644
index 0000000000000..08954987d3192
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-bounds-non-const-trait.stderr
@@ -0,0 +1,14 @@
+error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-bounds-non-const-trait.rs:6:28
+   |
+LL | const fn perform<T: ~const NonConst>() {}
+   |                            ^^^^^^^^
+
+error: `const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-bounds-non-const-trait.rs:9:21
+   |
+LL | fn operate<T: const NonConst>() {}
+   |                     ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
index fc9b5557a6496..ace2e7e46c4e8 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-parse-not-item.stderr
@@ -1,4 +1,4 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-parse-not-item.rs:7:32
    |
 LL | const fn test() -> impl ~const Fn() {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
index 73ee0f2151a73..d70b0d66177eb 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method-fail.stderr
@@ -1,4 +1,4 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-trait-method-fail.rs:14:39
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
index 33ae7131b928e..1642de78692b7 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closure-trait-method.stderr
@@ -1,4 +1,4 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closure-trait-method.rs:14:39
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
index 6d61b23e4b7c3..2e448c64d7a40 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-closures.stderr
@@ -1,22 +1,22 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:8:19
    |
 LL |         F: ~const FnOnce() -> u8,
    |                   ^^^^^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:9:19
    |
 LL |         F: ~const FnMut() -> u8,
    |                   ^^^^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:10:19
    |
 LL |         F: ~const Fn() -> u8,
    |                   ^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-closures.rs:23:27
    |
 LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr
index 13350a6d14a42..7529af9293d44 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.precise.stderr
@@ -7,7 +7,7 @@ LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-drop-fail-2.rs:29:26
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr
index 13350a6d14a42..7529af9293d44 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stock.stderr
@@ -7,7 +7,7 @@ LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
    = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
    = note: adding a non-const method body in the future would be a breaking change
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-drop-fail-2.rs:29:26
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
index daaba08d7dde9..f166bdf6cecce 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
@@ -1,10 +1,15 @@
-error: `~const` is not allowed here
-  --> $DIR/const-drop.rs:67:38
+error[E0493]: destructor of `T` cannot be evaluated at compile-time
+  --> $DIR/const-drop.rs:19:32
    |
-LL |     pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);
-   |                                      ^^^^^^
+LL | const fn a<T: ~const Destruct>(_: T) {}
+   |                                ^ the destructor for this type cannot be evaluated in constant functions
+
+error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time
+  --> $DIR/const-drop.rs:24:13
    |
-   = note: this item cannot have `~const` trait bounds
+LL |     let _ = S(&mut c);
+   |             ^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
index 9da84cdb0525b..4836d2b02ce71 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.rs
@@ -4,7 +4,7 @@
 #![feature(const_trait_impl)]
 #![feature(const_mut_refs)]
 #![feature(never_type)]
-// #![cfg_attr(precise, feature(const_precise_live_drops))]
+#![cfg_attr(precise, feature(const_precise_live_drops))]
 
 use std::marker::Destruct;
 
@@ -63,8 +63,7 @@ mod t {
         fn foo() {}
     }
 
-    // FIXME(effects): This should be a `const` bound instead of a `~const` one.
-    pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);
+    pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
 
     impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
         fn drop(&mut self) {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
index daaba08d7dde9..23e368870258e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
@@ -1,10 +1,19 @@
-error: `~const` is not allowed here
-  --> $DIR/const-drop.rs:67:38
+error[E0493]: destructor of `T` cannot be evaluated at compile-time
+  --> $DIR/const-drop.rs:19:32
    |
-LL |     pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);
-   |                                      ^^^^^^
+LL | const fn a<T: ~const Destruct>(_: T) {}
+   |                                ^      - value is dropped here
+   |                                |
+   |                                the destructor for this type cannot be evaluated in constant functions
+
+error[E0493]: destructor of `S<'_>` cannot be evaluated at compile-time
+  --> $DIR/const-drop.rs:24:13
    |
-   = note: this item cannot have `~const` trait bounds
+LL |     let _ = S(&mut c);
+   |             ^^^^^^^^^- value is dropped here
+   |             |
+   |             the destructor for this type cannot be evaluated in constant functions
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0493`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs
new file mode 100644
index 0000000000000..8670667131695
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.rs
@@ -0,0 +1,9 @@
+#![feature(const_trait_impl)]
+// edition: 2021
+
+#[const_trait]
+trait Trait {}
+
+fn main() {
+    let _: &dyn const Trait; //~ ERROR const trait bounds are not allowed in trait object types
+}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr
new file mode 100644
index 0000000000000..8b9ba94d099d5
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds-trait-objects.stderr
@@ -0,0 +1,8 @@
+error: const trait bounds are not allowed in trait object types
+  --> $DIR/const-trait-bounds-trait-objects.rs:8:17
+   |
+LL |     let _: &dyn const Trait;
+   |                 ^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs
new file mode 100644
index 0000000000000..1ebebe632c70a
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-trait-bounds.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+#![feature(const_trait_impl, effects, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let _ = process::<()>([()]);
+    let _ = Struct::<(), 4> { field: [1, 0] };
+}
+
+fn process<T: const Trait>(input: [(); T::make(2)]) -> [(); T::make(2)] {
+    input
+}
+
+struct Struct<T: const Trait, const P: usize>
+where
+    [u32; T::make(P)]:,
+{
+    field: [u32; T::make(P)],
+}
+
+#[const_trait]
+trait Trait {
+    fn make(input: usize) -> usize;
+}
+
+impl const Trait for () {
+    fn make(input: usize) -> usize {
+        input / 2
+    }
+}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
index 61e31fc978643..c6be75a6a2f04 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.rs
@@ -1,6 +1,6 @@
 #![feature(const_trait_impl, effects)]
 
-const fn test() -> impl ~const Fn() { //~ ERROR ~const can only be applied to `#[const_trait]` traits
+const fn test() -> impl ~const Fn() { //~ ERROR `~const` can only be applied to `#[const_trait]` traits
     const move || { //~ ERROR const closures are experimental
         let sl: &[u8] = b"foo";
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
index 658082123140c..fe6b613d1549d 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/ice-112822-expected-type-for-param.stderr
@@ -7,7 +7,7 @@ LL |     const move || {
    = note: see issue #106003 <https://github.com/rust-lang/rust/issues/106003> for more information
    = help: add `#![feature(const_closures)]` to the crate attributes to enable
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/ice-112822-expected-type-for-param.rs:3:32
    |
 LL | const fn test() -> impl ~const Fn() {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr
index 663cdd1fe57bb..12f9355e41d4e 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.gated.stderr
@@ -1,5 +1,5 @@
 error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate.rs:14:1
+  --> $DIR/feature-gate.rs:22:1
    |
 LL | fn main() {}
    | ^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs
index 0b409fbaac9e0..015d90aaf21fa 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.rs
@@ -10,5 +10,13 @@ trait T {}
 impl const T for S {}
 //[stock]~^ ERROR const trait impls are experimental
 
+const fn f<A: ~const T>() {} //[stock]~ ERROR const trait impls are experimental
+fn g<A: const T>() {} //[stock]~ ERROR const trait impls are experimental
+
+macro_rules! discard { ($ty:ty) => {} }
+
+discard! { impl ~const T } //[stock]~ ERROR const trait impls are experimental
+discard! { impl const T } //[stock]~ ERROR const trait impls are experimental
+
 #[rustc_error]
 fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr
index 0e938c1c55d05..c9826aeb1665f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/feature-gate.stock.stderr
@@ -7,6 +7,42 @@ LL | impl const T for S {}
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
+error[E0658]: const trait impls are experimental
+  --> $DIR/feature-gate.rs:13:15
+   |
+LL | const fn f<A: ~const T>() {}
+   |               ^^^^^^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/feature-gate.rs:14:9
+   |
+LL | fn g<A: const T>() {}
+   |         ^^^^^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/feature-gate.rs:18:17
+   |
+LL | discard! { impl ~const T }
+   |                 ^^^^^^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/feature-gate.rs:19:17
+   |
+LL | discard! { impl const T }
+   |                 ^^^^^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
 error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future.
   --> $DIR/feature-gate.rs:8:1
    |
@@ -16,6 +52,6 @@ LL | #[const_trait]
    = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
    = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
 
-error: aborting due to 2 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs
new file mode 100644
index 0000000000000..2304a766aaff5
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-bare-trait-objects-const-trait-bounds.rs
@@ -0,0 +1,20 @@
+// Ensure that we don't consider `const Trait` and `~const Trait` to
+// match the macro fragment specifier `ty` as that would be a breaking
+// change theoretically speaking. Syntactically trait object types can
+// be "bare", i.e., lack the prefix `dyn`.
+// By contrast, `?Trait` *does* match `ty` and therefore an arm like
+// `?$Trait:path` would never be reached.
+// See `parser/macro/mbe-bare-trait-object-maybe-trait-bound.rs`.
+
+// check-pass
+
+macro_rules! check {
+    ($Type:ty) => { compile_error!("ty"); };
+    (const $Trait:path) => {};
+    (~const $Trait:path) => {};
+}
+
+check! { const Trait }
+check! { ~const Trait }
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs
new file mode 100644
index 0000000000000..9105cb6b0438c
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.rs
@@ -0,0 +1,20 @@
+// Demonstrates and records a theoretical regressions / breaking changes caused by the
+// introduction of const trait bounds.
+
+// Setting the edition to 2018 since we don't regress `demo! { dyn const }` in Rust <2018.
+// edition:2018
+
+macro_rules! demo {
+    ($ty:ty) => { compile_error!("ty"); };
+    (impl $c:ident) => {};
+    (dyn $c:ident) => {};
+}
+
+demo! { impl const }
+//~^ ERROR expected identifier, found `<eof>`
+
+demo! { dyn const }
+//~^ ERROR const trait impls are experimental
+//~| ERROR expected identifier, found `<eof>`
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr
new file mode 100644
index 0000000000000..254d31930b366
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-const-trait-bound-theoretical-regression.stderr
@@ -0,0 +1,30 @@
+error: expected identifier, found `<eof>`
+  --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:13:14
+   |
+LL |     ($ty:ty) => { compile_error!("ty"); };
+   |      ------ while parsing argument for this `ty` macro fragment
+...
+LL | demo! { impl const }
+   |              ^^^^^ expected identifier
+
+error: expected identifier, found `<eof>`
+  --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13
+   |
+LL |     ($ty:ty) => { compile_error!("ty"); };
+   |      ------ while parsing argument for this `ty` macro fragment
+...
+LL | demo! { dyn const }
+   |             ^^^^^ expected identifier
+
+error[E0658]: const trait impls are experimental
+  --> $DIR/mbe-const-trait-bound-theoretical-regression.rs:16:13
+   |
+LL | demo! { dyn const }
+   |             ^^^^^
+   |
+   = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
+   = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs
new file mode 100644
index 0000000000000..817e9ee5257d6
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mbe-dyn-const-2015.rs
@@ -0,0 +1,13 @@
+// Ensure that the introduction of const trait bound didn't regress this code in Rust 2015.
+// See also `mbe-const-trait-bound-theoretical-regression.rs`.
+
+// check-pass
+
+macro_rules! check {
+    ($ty:ty) => { compile_error!("ty"); };
+    (dyn $c:ident) => {};
+}
+
+check! { dyn const }
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs
new file mode 100644
index 0000000000000..37e285f2c6590
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs
@@ -0,0 +1,20 @@
+#![feature(const_trait_impl)]
+
+const fn maybe_const_maybe<T: ~const ?Sized>() {}
+//~^ ERROR `~const` and `?` are mutually exclusive
+
+fn const_maybe<T: const ?Sized>() {}
+//~^ ERROR `const` and `?` are mutually exclusive
+
+const fn maybe_const_negative<T: ~const !Trait>() {}
+//~^ ERROR `~const` and `!` are mutually exclusive
+//~| ERROR negative bounds are not supported
+
+fn const_negative<T: const !Trait>() {}
+//~^ ERROR `const` and `!` are mutually exclusive
+//~| ERROR negative bounds are not supported
+
+#[const_trait]
+trait Trait {}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr
new file mode 100644
index 0000000000000..1938f740170b5
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr
@@ -0,0 +1,38 @@
+error: `~const` and `?` are mutually exclusive
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31
+   |
+LL | const fn maybe_const_maybe<T: ~const ?Sized>() {}
+   |                               ^^^^^^^^^^^^^
+
+error: `const` and `?` are mutually exclusive
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:19
+   |
+LL | fn const_maybe<T: const ?Sized>() {}
+   |                   ^^^^^^^^^^^^
+
+error: `~const` and `!` are mutually exclusive
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:34
+   |
+LL | const fn maybe_const_negative<T: ~const !Trait>() {}
+   |                                  ^^^^^^^^^^^^^
+
+error: `const` and `!` are mutually exclusive
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:22
+   |
+LL | fn const_negative<T: const !Trait>() {}
+   |                      ^^^^^^^^^^^^
+
+error: negative bounds are not supported
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41
+   |
+LL | const fn maybe_const_negative<T: ~const !Trait>() {}
+   |                                         ^
+
+error: negative bounds are not supported
+  --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28
+   |
+LL | fn const_negative<T: const !Trait>() {}
+   |                            ^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr
index b2e09d82a905e..ae76cab2f2e66 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/non-const-op-in-closure-in-const.stderr
@@ -1,4 +1,4 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/non-const-op-in-closure-in-const.rs:10:51
    |
 LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
index fd4d7ff347501..eae313ef08748 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.nn.stderr
@@ -10,13 +10,13 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou
 LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:10:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:10:19
    |
 LL | trait Bar: ~const Foo {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
index d2e3a5cec1d9f..be3153d6a0819 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.ny.stderr
@@ -1,10 +1,10 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:10:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-2.rs:10:19
    |
 LL | trait Bar: ~const Foo {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
index 3820d06924342..abdf0feee0384 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-2.rs
@@ -8,8 +8,8 @@ trait Foo {
 
 #[cfg_attr(any(yy, ny), const_trait)]
 trait Bar: ~const Foo {}
-//[ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]`
+//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
+//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
 //[yn,nn]~^^^ ERROR: `~const` is not allowed here
 
 const fn foo<T: Bar>(x: &T) {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
index 199d2199c4ae8..834d6f4dcf382 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.nn.stderr
@@ -10,13 +10,13 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou
 LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-3.rs:12:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-3.rs:12:19
    |
 LL | trait Bar: ~const Foo {}
@@ -24,7 +24,7 @@ LL | trait Bar: ~const Foo {}
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-3.rs:17:24
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
index 46eedc333f148..4fdd2284c4755 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.ny.stderr
@@ -1,10 +1,10 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-3.rs:12:19
    |
 LL | trait Bar: ~const Foo {}
    |                   ^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-3.rs:12:19
    |
 LL | trait Bar: ~const Foo {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
index 3e98e131930af..30131d5849c81 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
@@ -10,12 +10,12 @@ trait Foo {
 
 #[cfg_attr(any(yy, ny), const_trait)]
 trait Bar: ~const Foo {}
-//[ny,nn]~^ ERROR: ~const can only be applied to `#[const_trait]`
-//[ny,nn]~| ERROR: ~const can only be applied to `#[const_trait]`
+//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
+//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]`
 //[yn,nn]~^^^ ERROR: `~const` is not allowed here
 
 const fn foo<T: ~const Bar>(x: &T) {
-    //[yn,nn]~^ ERROR: ~const can only be applied to `#[const_trait]`
+    //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]`
     x.a();
 }
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
index dc08a8997389c..ab7c814eb4985 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yn.stderr
@@ -10,7 +10,7 @@ note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bou
 LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/super-traits-fail-3.rs:17:24
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.rs
deleted file mode 100644
index ed911d965d631..0000000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(const_trait_impl)]
-
-const fn tilde_question<T: ~const ?Sized>() {}
-//~^ ERROR `~const` and `?` are mutually exclusive
-
-fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.stderr
deleted file mode 100644
index 5850ab41c6ba6..0000000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-maybe-trait.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `~const` and `?` are mutually exclusive
-  --> $DIR/tilde-const-maybe-trait.rs:3:28
-   |
-LL | const fn tilde_question<T: ~const ?Sized>() {}
-   |                            ^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs
deleted file mode 100644
index d63381b5f2cc9..0000000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// compile-flags: -Z parse-only
-
-#![feature(const_trait_impl)]
-
-struct S<T: const Tr>;
-//~^ ERROR const bounds must start with `~`
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr
deleted file mode 100644
index 646cdfc78f971..0000000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/without-tilde.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: const bounds must start with `~`
-  --> $DIR/without-tilde.rs:5:13
-   |
-LL | struct S<T: const Tr>;
-   |             -^^^^
-   |             |
-   |             help: add `~`: `~`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index d13cd8f55553d..913d51875cd70 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,16 +1,16 @@
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:34:16
    |
 LL | impl<T: ~const Default> const A for T {
    |                ^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:40:16
    |
 LL | impl<T: ~const Default + ~const Sup> const A for T {
    |                ^^^^^^^
 
-error: ~const can only be applied to `#[const_trait]` traits
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const_trait_impl.rs:46:16
    |
 LL | impl<T: ~const Default + ~const Sub> const A for T {