]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #88328 - fee1-dead:not-quite-const, r=oli-obk
authorbors <bors@rust-lang.org>
Fri, 27 Aug 2021 21:35:08 +0000 (21:35 +0000)
committerbors <bors@rust-lang.org>
Fri, 27 Aug 2021 21:35:08 +0000 (21:35 +0000)
Introduce `~const`

 - [x] Removed `?const` and change uses of `?const`
 - [x] Added `~const` to the AST. It is gated behind const_trait_impl.
 - [x] Validate `~const` in ast_validation.
 - [x] Update UI Tests
 - [x] Add enum `BoundConstness` (With variants `NotConst` and
 `ConstIfConst` allowing future extensions)
 - [x] Adjust trait selection and pre-existing code to use `BoundConstness`.
 - [ ] Optional steps for this PR
      - [x] Fix #88155
      - [x] ~~Do something with constness bounds in chalk~~ Must be done to rust-lang/chalk (just tried to refactor, there are a lot of errors to resolve :( )
      - [ ] Adjust Error messages for `~const` bounds that can't be satisfied.

r? `@oli-obk`

81 files changed:
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/removed.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
compiler/rustc_mir/src/transform/check_consts/check.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/bounds.rs
compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
compiler/rustc_typeck/src/lib.rs
src/librustdoc/html/format.rs
src/test/ui/consts/const-eval/issue-49296.rs
src/test/ui/consts/const-eval/issue-49296.stderr
src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr
src/test/ui/generic-associated-types/projection-bound-cycle.stderr
src/test/ui/parser/bounds-type.rs
src/test/ui/parser/bounds-type.stderr
src/test/ui/parser/trait-object-delimiters.rs
src/test/ui/parser/trait-object-delimiters.stderr
src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
src/test/ui/rfc-2632-const-trait-impl/call-generic-in-impl.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-chain.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-dup-bound.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-pass.rs
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs [deleted file]
src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr [deleted file]
src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.rs
src/test/ui/rfc-2632-const-trait-impl/inherent-impl.stderr
src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/syntax.rs
src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/tilde-const-syntax.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr [new file with mode: 0644]
src/tools/rustfmt/src/types.rs
src/tools/rustfmt/tests/source/type.rs
src/tools/rustfmt/tests/target/type.rs

index 2c2d30d872e2023d38f4a61b054d6bcd59231533..2b86128b3f793b4545426a0257eb8cd39b012b9b 100644 (file)
@@ -284,7 +284,7 @@ pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
 
 pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
 
-/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
+/// A modifier on a bound, e.g., `?Sized` or `~const Trait`.
 ///
 /// Negative bounds should also be handled here.
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
@@ -295,10 +295,10 @@ pub enum TraitBoundModifier {
     /// `?Trait`
     Maybe,
 
-    /// `?const Trait`
+    /// `~const Trait`
     MaybeConst,
 
-    /// `?const ?Trait`
+    /// `~const ?Trait`
     //
     // This parses but will be rejected during AST validation.
     MaybeConstMaybe,
index 7b0188755710bc0825d4cda8d3af5e83f10f14d0..948d74e3bf8ebd307fd25dac4389945aa9b5a198 100644 (file)
@@ -1414,7 +1414,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                                     ref ty,
                                     TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
                                 ) => Some(this.lower_poly_trait_ref(ty, itctx.reborrow())),
-                                // `?const ?Bound` will cause an error during AST validation
+                                // `~const ?Bound` will cause an error during AST validation
                                 // anyways, so treat it like `?Bound` as compilation proceeds.
                                 GenericBound::Trait(
                                     _,
index cff1b70dda9073125b637d5e4f73f17c6d8dac58..c0ea710fdcb4e352debdcac7c97fa3aa3d4ebf8f 100644 (file)
@@ -33,24 +33,6 @@ enum SelfSemantic {
     No,
 }
 
-/// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
-#[derive(Clone, Copy)]
-enum BoundContext {
-    ImplTrait,
-    TraitBounds,
-    TraitObject,
-}
-
-impl BoundContext {
-    fn description(&self) -> &'static str {
-        match self {
-            Self::ImplTrait => "`impl Trait`",
-            Self::TraitBounds => "supertraits",
-            Self::TraitObject => "trait objects",
-        }
-    }
-}
-
 struct AstValidator<'a> {
     session: &'a Session,
 
@@ -60,6 +42,8 @@ struct AstValidator<'a> {
     /// Are we inside a trait impl?
     in_trait_impl: bool,
 
+    in_const_trait_impl: bool,
+
     has_proc_macro_decls: bool,
 
     /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
@@ -67,11 +51,7 @@ struct AstValidator<'a> {
     /// e.g., `impl Iterator<Item = impl Debug>`.
     outer_impl_trait: Option<Span>,
 
-    /// Keeps track of the `BoundContext` as we recurse.
-    ///
-    /// This is used to forbid `?const Trait` bounds in, e.g.,
-    /// `impl Iterator<Item = Box<dyn ?const Trait>`.
-    bound_context: Option<BoundContext>,
+    is_tilde_const_allowed: bool,
 
     /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
     /// or `Foo::Bar<impl Trait>`
@@ -88,10 +68,18 @@ struct AstValidator<'a> {
 }
 
 impl<'a> AstValidator<'a> {
-    fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
+    fn with_in_trait_impl(
+        &mut self,
+        is_in: bool,
+        constness: Option<Const>,
+        f: impl FnOnce(&mut Self),
+    ) {
         let old = mem::replace(&mut self.in_trait_impl, is_in);
+        let old_const =
+            mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
         f(self);
         self.in_trait_impl = old;
+        self.in_const_trait_impl = old_const;
     }
 
     fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
@@ -100,6 +88,18 @@ fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
         self.is_impl_trait_banned = old;
     }
 
+    fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.is_tilde_const_allowed, true);
+        f(self);
+        self.is_tilde_const_allowed = old;
+    }
+
+    fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
+        let old = mem::replace(&mut self.is_tilde_const_allowed, false);
+        f(self);
+        self.is_tilde_const_allowed = old;
+    }
+
     fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
         let old = mem::replace(&mut self.is_let_allowed, allowed);
         f(self, old);
@@ -130,19 +130,13 @@ fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
     fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
         let old = mem::replace(&mut self.outer_impl_trait, outer);
         if outer.is_some() {
-            self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
+            self.with_banned_tilde_const(f);
         } else {
-            f(self)
+            f(self);
         }
         self.outer_impl_trait = old;
     }
 
-    fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
-        let old = self.bound_context.replace(ctx);
-        f(self);
-        self.bound_context = old;
-    }
-
     fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
         match constraint.kind {
             AssocTyConstraintKind::Equality { .. } => {}
@@ -164,9 +158,7 @@ fn walk_ty(&mut self, t: &'a Ty) {
             TyKind::ImplTrait(..) => {
                 self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
             }
-            TyKind::TraitObject(..) => {
-                self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
-            }
+            TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
             TyKind::Path(ref qself, ref path) => {
                 // We allow these:
                 //  - `Option<impl Trait>`
@@ -1083,13 +1075,13 @@ fn visit_item(&mut self, item: &'a Item) {
                 unsafety,
                 polarity,
                 defaultness: _,
-                constness: _,
-                generics: _,
+                constness,
+                ref generics,
                 of_trait: Some(ref t),
                 ref self_ty,
-                items: _,
+                ref items,
             }) => {
-                self.with_in_trait_impl(true, |this| {
+                self.with_in_trait_impl(true, Some(constness), |this| {
                     this.invalid_visibility(&item.vis, None);
                     if let TyKind::Err = self_ty.kind {
                         this.err_handler()
@@ -1112,7 +1104,17 @@ fn visit_item(&mut self, item: &'a Item) {
                         .emit();
                     }
 
-                    visit::walk_item(this, item);
+                    this.visit_vis(&item.vis);
+                    this.visit_ident(item.ident);
+                    if let Const::Yes(_) = constness {
+                        this.with_tilde_const_allowed(|this| this.visit_generics(generics));
+                    } else {
+                        this.visit_generics(generics);
+                    }
+                    this.visit_trait_ref(t);
+                    this.visit_ty(self_ty);
+
+                    walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
                 });
                 return; // Avoid visiting again.
             }
@@ -1157,13 +1159,24 @@ fn visit_item(&mut self, item: &'a Item) {
                         .emit();
                 }
             }
-            ItemKind::Fn(box FnKind(def, _, _, ref body)) => {
+            ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => {
                 self.check_defaultness(item.span, def);
 
                 if body.is_none() {
                     let msg = "free function without a body";
                     self.error_item_without_body(item.span, "function", msg, " { <body> }");
                 }
+                self.visit_vis(&item.vis);
+                self.visit_ident(item.ident);
+                if let Const::Yes(_) = sig.header.constness {
+                    self.with_tilde_const_allowed(|this| this.visit_generics(generics));
+                } else {
+                    self.visit_generics(generics);
+                }
+                let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+                self.visit_fn(kind, item.span, item.id);
+                walk_list!(self, visit_attribute, &item.attrs);
+                return; // Avoid visiting again.
             }
             ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => {
                 let old_item = mem::replace(&mut self.extern_mod, Some(item));
@@ -1206,9 +1219,7 @@ fn visit_item(&mut self, item: &'a Item) {
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
                 self.visit_generics(generics);
-                self.with_bound_context(BoundContext::TraitBounds, |this| {
-                    walk_list!(this, visit_param_bound, bounds);
-                });
+                self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
                 walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
@@ -1281,7 +1292,7 @@ fn visit_item(&mut self, item: &'a Item) {
             _ => {}
         }
 
-        visit::walk_item(self, item)
+        visit::walk_item(self, item);
     }
 
     fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
@@ -1428,15 +1439,17 @@ fn visit_generic_param(&mut self, param: &'a GenericParam) {
     fn visit_param_bound(&mut self, bound: &'a GenericBound) {
         match bound {
             GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
-                if let Some(ctx) = self.bound_context {
-                    let msg = format!("`?const` is not permitted in {}", ctx.description());
-                    self.err_handler().span_err(bound.span(), &msg);
+                if !self.is_tilde_const_allowed {
+                    self.err_handler()
+                        .struct_span_err(bound.span(), "`~const` is not allowed here")
+                        .note("only allowed on bounds on traits' associated types, const fns, const impls and its associated functions")
+                        .emit();
                 }
             }
 
             GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
                 self.err_handler()
-                    .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
+                    .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
             }
 
             _ => {}
@@ -1589,7 +1602,32 @@ fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
             self.check_item_named(item.ident, "const");
         }
 
-        self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
+        match item.kind {
+            AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty))
+                if ctxt == AssocCtxt::Trait =>
+            {
+                self.visit_vis(&item.vis);
+                self.visit_ident(item.ident);
+                walk_list!(self, visit_attribute, &item.attrs);
+                self.with_tilde_const_allowed(|this| {
+                    this.visit_generics(generics);
+                    walk_list!(this, visit_param_bound, bounds);
+                });
+                walk_list!(self, visit_ty, ty);
+            }
+            AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
+                if self.in_const_trait_impl =>
+            {
+                self.visit_vis(&item.vis);
+                self.visit_ident(item.ident);
+                self.with_tilde_const_allowed(|this| this.visit_generics(generics));
+                let kind =
+                    FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
+                self.visit_fn(kind, item.span, item.id);
+            }
+            _ => self
+                .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
+        }
     }
 }
 
@@ -1683,9 +1721,10 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) ->
         session,
         extern_mod: None,
         in_trait_impl: false,
+        in_const_trait_impl: false,
         has_proc_macro_decls: false,
         outer_impl_trait: None,
-        bound_context: None,
+        is_tilde_const_allowed: false,
         is_impl_trait_banned: false,
         is_assoc_ty_bound_banned: false,
         is_let_allowed: false,
index 0be26b6f8e9de8d8eb11f86558269f2c87cbaff3..557271e32adb492d57908229c00febc6e5be6f2f 100644 (file)
@@ -656,7 +656,6 @@ macro_rules! gate_all {
     gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
     gate_all!(generators, "yield syntax is experimental");
     gate_all!(raw_ref_op, "raw address of syntax is experimental");
-    gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
     gate_all!(const_trait_impl, "const trait impls are experimental");
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
index 4f4baf2877df71d75a0555f3c1d6d671878f8e94..5ae106353da616286d889110fcc6d61a0e5a7c43 100644 (file)
@@ -515,9 +515,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows `impl const Trait for T` syntax.
     (active, const_trait_impl, "1.42.0", Some(67792), None),
 
-    /// Allows `T: ?const Trait` syntax in bounds.
-    (incomplete, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
-
     /// Allows the use of `no_sanitize` attribute.
     (active, no_sanitize, "1.42.0", Some(39699), None),
 
index 5cadbd9e5cf7198bf87c908d4de5e2dff56818fa..a8aa3c606c6c0d249dfe4024f41e3dfe74f0f15b 100644 (file)
@@ -123,6 +123,9 @@ macro_rules! declare_features {
     /// Allows overlapping impls of marker traits.
     (removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
      Some("removed in favor of `#![feature(marker_trait_attr)]`")),
+    /// Allows `T: ?const Trait` syntax in bounds.
+    (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
+     Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
     /// Allows `#[no_debug]`.
     (removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
     /// Allows comparing raw pointers during const eval.
index 457e80c1663ac413660e65d5db0ed0b7a720dd48..676cb7fe41d979c2525208ee60294654b92fa94f 100644 (file)
@@ -17,7 +17,6 @@
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::Constness;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
 use smallvec::SmallVec;
@@ -497,7 +496,7 @@ pub enum ImplSource<'tcx, N> {
     /// for some type parameter. The `Vec<N>` represents the
     /// obligations incurred from normalizing the where-clause (if
     /// any).
-    Param(Vec<N>, Constness),
+    Param(Vec<N>, ty::BoundConstness),
 
     /// Virtual calls through an object.
     Object(ImplSourceObjectData<'tcx, N>),
index ecbe9ca417593fc0c1acdb71548532cafcad015c..796ca650bdd77f55bd1f7c6df12175c39a300904 100644 (file)
@@ -33,7 +33,7 @@ pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
 #[derive(Clone, Debug, TypeFoldable)]
 pub enum TypeError<'tcx> {
     Mismatch,
-    ConstnessMismatch(ExpectedFound<hir::Constness>),
+    ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
     UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
@@ -102,7 +102,7 @@ fn report_maybe_different(
             CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
             Mismatch => write!(f, "types differ"),
             ConstnessMismatch(values) => {
-                write!(f, "expected {} fn, found {} fn", values.expected, values.found)
+                write!(f, "expected {} bound, found {} bound", values.expected, values.found)
             }
             UnsafetyMismatch(values) => {
                 write!(f, "expected {} fn, found {} fn", values.expected, values.found)
index 8f814a84b4959ff0102c87968099eddede56b344..8aa27d4ca53e3fe21c3c0ff6c5273bc1927c839b 100644 (file)
@@ -37,7 +37,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
-use rustc_hir::{Constness, Node};
+use rustc_hir::Node;
 use rustc_macros::HashStable;
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
@@ -181,6 +181,25 @@ pub enum Visibility {
     Invisible,
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
+pub enum BoundConstness {
+    /// `T: Trait`
+    NotConst,
+    /// `T: ~const Trait`
+    ///
+    /// Requires resolving to const only when we are in a const context.
+    ConstIfConst,
+}
+
+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`"),
+        }
+    }
+}
+
 #[derive(
     Clone,
     Debug,
@@ -457,10 +476,6 @@ pub enum PredicateKind<'tcx> {
     /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
     /// would be the type parameters.
-    ///
-    /// A trait predicate will have `Constness::Const` if it originates
-    /// from a bound on a `const fn` without the `?const` opt-out (e.g.,
-    /// `const fn foobar<Foo: Bar>() {}`).
     Trait(TraitPredicate<'tcx>),
 
     /// `where 'a: 'b`
@@ -632,10 +647,7 @@ pub fn subst_supertrait(
 pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>,
 
-    /// A trait predicate will have `Constness::Const` if it originates
-    /// from a bound on a `const fn` without the `?const` opt-out (e.g.,
-    /// `const fn foobar<Foo: Bar>() {}`).
-    pub constness: hir::Constness,
+    pub constness: BoundConstness,
 }
 
 pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
@@ -1304,7 +1316,7 @@ pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
 pub struct ConstnessAnd<T> {
-    pub constness: Constness,
+    pub constness: BoundConstness,
     pub value: T,
 }
 
@@ -1312,18 +1324,18 @@ pub struct ConstnessAnd<T> {
 // the constness of trait bounds is being propagated correctly.
 pub trait WithConstness: Sized {
     #[inline]
-    fn with_constness(self, constness: Constness) -> ConstnessAnd<Self> {
+    fn with_constness(self, constness: BoundConstness) -> ConstnessAnd<Self> {
         ConstnessAnd { constness, value: self }
     }
 
     #[inline]
-    fn with_const(self) -> ConstnessAnd<Self> {
-        self.with_constness(Constness::Const)
+    fn with_const_if_const(self) -> ConstnessAnd<Self> {
+        self.with_constness(BoundConstness::ConstIfConst)
     }
 
     #[inline]
     fn without_const(self) -> ConstnessAnd<Self> {
-        self.with_constness(Constness::NotConst)
+        self.with_constness(BoundConstness::NotConst)
     }
 }
 
index 4a2c8349fdc684270918203c738c5fb130b1e335..44981f171d50a2a9b53aec7de2474d4d90795b78 100644 (file)
@@ -200,12 +200,12 @@ fn relate<R: TypeRelation<'tcx>>(
     }
 }
 
-impl<'tcx> Relate<'tcx> for ast::Constness {
+impl<'tcx> Relate<'tcx> for ty::BoundConstness {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: ast::Constness,
-        b: ast::Constness,
-    ) -> RelateResult<'tcx, ast::Constness> {
+        a: ty::BoundConstness,
+        b: ty::BoundConstness,
+    ) -> RelateResult<'tcx, ty::BoundConstness> {
         if a != b {
             Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
         } else {
index 2ab25c839704ddbb56e1b2ddd5322251536a0ff0..89ad99d9f0794f6d9f7805a4d7c96bd86dbdf7c5 100644 (file)
@@ -8,7 +8,6 @@
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
-use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
 use rustc_index::vec::{Idx, IndexVec};
@@ -155,8 +154,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl fmt::Debug for ty::TraitPredicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let hir::Constness::Const = self.constness {
-            write!(f, "const ")?;
+        if let ty::BoundConstness::ConstIfConst = self.constness {
+            write!(f, "~const ")?;
         }
         write!(f, "TraitPredicate({:?})", self.trait_ref)
     }
@@ -241,6 +240,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     crate::traits::Reveal,
     crate::ty::adjustment::AutoBorrowMutability,
     crate::ty::AdtKind,
+    crate::ty::BoundConstness,
     // Including `BoundRegionKind` is a *bit* dubious, but direct
     // references to bound region appear in `ty::Error`, and aren't
     // really meant to be folded. In general, we can only fold a fully
index 8b893b779c0a2d47a44974c399c1af59435c1734..65dd61b63295cf2eef68df4c1a982057a952eb93 100644 (file)
@@ -878,7 +878,7 @@ pub fn def_id(&self) -> DefId {
     pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
         self.map_bound(|trait_ref| ty::TraitPredicate {
             trait_ref,
-            constness: hir::Constness::NotConst,
+            constness: ty::BoundConstness::NotConst,
         })
     }
 }
index 9fafcfafe67cdba8ba3b20619ffcfd1dd6361fc7..b501716a899752b41db2117da612e6ada703ff34 100644 (file)
@@ -1,6 +1,5 @@
 use std::fmt;
 
-use rustc_hir as hir;
 use rustc_infer::infer::canonical::Canonical;
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::mir::ConstraintCategory;
@@ -88,7 +87,7 @@ pub(super) fn prove_trait_ref(
         self.prove_predicates(
             Some(ty::PredicateKind::Trait(ty::TraitPredicate {
                 trait_ref,
-                constness: hir::Constness::NotConst,
+                constness: ty::BoundConstness::NotConst,
             })),
             locations,
             category,
index 0361ddc915d4cd67abb4ccf3327630b2a60ab686..2b748062cdf2319d3476a176fcd647e00f293f60 100644 (file)
@@ -805,6 +805,8 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     }
                 };
 
+                let mut nonconst_call_permission = false;
+
                 // Attempting to call a trait method?
                 if let Some(trait_id) = tcx.trait_of_item(callee) {
                     trace!("attempting to call a trait method");
@@ -819,23 +821,54 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                         param_env,
                         Binder::dummy(TraitPredicate {
                             trait_ref,
-                            constness: hir::Constness::Const,
+                            constness: ty::BoundConstness::ConstIfConst,
                         }),
                     );
 
                     let implsrc = tcx.infer_ctxt().enter(|infcx| {
-                        let mut selcx = SelectionContext::new(&infcx);
-                        selcx.select(&obligation).unwrap()
+                        let mut selcx =
+                            SelectionContext::with_constness(&infcx, hir::Constness::Const);
+                        selcx.select(&obligation)
                     });
 
-                    // If the method is provided via a where-clause that does not use the `?const`
-                    // opt-out, the call is allowed.
-                    if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
-                        debug!(
-                            "const_trait_impl: provided {:?} via where-clause in {:?}",
-                            trait_ref, param_env
-                        );
-                        return;
+                    match implsrc {
+                        Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
+                            debug!(
+                                "const_trait_impl: provided {:?} via where-clause in {:?}",
+                                trait_ref, param_env
+                            );
+                            return;
+                        }
+                        Ok(Some(ImplSource::UserDefined(data))) => {
+                            let callee_name = tcx.item_name(callee);
+                            if let Some(&did) = tcx
+                                .associated_item_def_ids(data.impl_def_id)
+                                .iter()
+                                .find(|did| tcx.item_name(**did) == callee_name)
+                            {
+                                callee = did;
+                            }
+                        }
+                        _ => {
+                            if !tcx.is_const_fn_raw(callee) {
+                                // At this point, it is only legal when the caller is marked with
+                                // #[default_method_body_is_const], and the callee is in the same
+                                // trait.
+                                let callee_trait = tcx.trait_of_item(callee);
+                                if callee_trait.is_some() {
+                                    if tcx.has_attr(caller, sym::default_method_body_is_const) {
+                                        if tcx.trait_of_item(caller) == callee_trait {
+                                            nonconst_call_permission = true;
+                                        }
+                                    }
+                                }
+
+                                if !nonconst_call_permission {
+                                    self.check_op(ops::FnCallNonConst);
+                                    return;
+                                }
+                            }
+                        }
                     }
 
                     // Resolve a trait method call to its concrete implementation, which may be in a
@@ -875,34 +908,16 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
 
                 if !tcx.is_const_fn_raw(callee) {
-                    let mut permitted = false;
-
-                    let callee_trait = tcx.trait_of_item(callee);
-                    if let Some(trait_id) = callee_trait {
-                        if tcx.has_attr(caller, sym::default_method_body_is_const) {
-                            // permit call to non-const fn when caller has default_method_body_is_const..
-                            if tcx.trait_of_item(caller) == callee_trait {
-                                // ..and caller and callee are in the same trait.
-                                permitted = true;
-                            }
-                        }
-                        if !permitted {
-                            // if trait's impls are all const, permit the call.
-                            let mut const_impls = true;
-                            tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| {
-                                if const_impls {
-                                    if let hir::Constness::NotConst = tcx.impl_constness(imp) {
-                                        const_impls = false;
-                                    }
-                                }
-                            });
-                            if const_impls {
-                                permitted = true;
-                            }
+                    if tcx.trait_of_item(callee).is_some() {
+                        if tcx.has_attr(callee, sym::default_method_body_is_const) {
+                            // To get to here we must have already found a const impl for the
+                            // trait, but for it to still be non-const can be that the impl is
+                            // using default method bodies.
+                            nonconst_call_permission = true;
                         }
                     }
 
-                    if !permitted {
+                    if !nonconst_call_permission {
                         self.check_op(ops::FnCallNonConst);
                         return;
                     }
index 1fbf01b1b97d55ad5b3e300a2f1498d2fd7c3791..299fc916ac97fa7802b2f6a6865877dc8a0744e7 100644 (file)
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym};
 
-/// Any `?` or `?const` modifiers that appear at the start of a bound.
+/// Any `?` or `~const` modifiers that appear at the start of a bound.
 struct BoundModifiers {
     /// `?Trait`.
     maybe: Option<Span>,
 
-    /// `?const Trait`.
+    /// `~const Trait`.
     maybe_const: Option<Span>,
 }
 
@@ -609,6 +609,7 @@ fn can_begin_bound(&mut self) -> bool {
         || self.check_lifetime()
         || self.check(&token::Not) // Used for error reporting only.
         || self.check(&token::Question)
+        || self.check(&token::Tilde)
         || self.check_keyword(kw::For)
         || self.check(&token::OpenDelim(token::Paren))
     }
@@ -655,7 +656,7 @@ fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
         let inner_lo = self.token.span;
         let is_negative = self.eat(&token::Not);
 
-        let modifiers = self.parse_ty_bound_modifiers();
+        let modifiers = self.parse_ty_bound_modifiers()?;
         let bound = if self.token.is_lifetime() {
             self.error_lt_bound_with_modifiers(modifiers);
             self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
@@ -690,7 +691,7 @@ fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) {
         if let Some(span) = modifiers.maybe_const {
             self.struct_span_err(
                 span,
-                "`?const` may only modify trait bounds, not lifetime bounds",
+                "`~const` may only modify trait bounds, not lifetime bounds",
             )
             .emit();
         }
@@ -721,34 +722,27 @@ fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()
         Ok(())
     }
 
-    /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
+    /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `~const Trait`.
     ///
     /// If no modifiers are present, this does not consume any tokens.
     ///
     /// ```
-    /// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
+    /// TY_BOUND_MODIFIERS = ["~const"] ["?"]
     /// ```
-    fn parse_ty_bound_modifiers(&mut self) -> BoundModifiers {
-        if !self.eat(&token::Question) {
-            return BoundModifiers { maybe: None, maybe_const: None };
-        }
-
-        // `? ...`
-        let first_question = self.prev_token.span;
-        if !self.eat_keyword(kw::Const) {
-            return BoundModifiers { maybe: Some(first_question), maybe_const: None };
-        }
+    fn parse_ty_bound_modifiers(&mut self) -> PResult<'a, BoundModifiers> {
+        let maybe_const = if self.eat(&token::Tilde) {
+            let tilde = self.prev_token.span;
+            self.expect_keyword(kw::Const)?;
+            let span = tilde.to(self.prev_token.span);
+            self.sess.gated_spans.gate(sym::const_trait_impl, span);
+            Some(span)
+        } else {
+            None
+        };
 
-        // `?const ...`
-        let maybe_const = first_question.to(self.prev_token.span);
-        self.sess.gated_spans.gate(sym::const_trait_bound_opt_out, maybe_const);
-        if !self.eat(&token::Question) {
-            return BoundModifiers { maybe: None, maybe_const: Some(maybe_const) };
-        }
+        let maybe = if self.eat(&token::Question) { Some(self.prev_token.span) } else { None };
 
-        // `?const ? ...`
-        let second_question = self.prev_token.span;
-        BoundModifiers { maybe: Some(second_question), maybe_const: Some(maybe_const) }
+        Ok(BoundModifiers { maybe, maybe_const })
     }
 
     /// Parses a type bound according to:
@@ -757,7 +751,7 @@ fn parse_ty_bound_modifiers(&mut self) -> BoundModifiers {
     /// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
     /// ```
     ///
-    /// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
+    /// For example, this grammar accepts `~const ?for<'a: 'b> m::Trait<'a>`.
     fn parse_generic_ty_bound(
         &mut self,
         lo: Span,
index 282502cfa0d3d8d73f2ed0ccc7871a6a84092387..622c9edc4345035b2af384334f8109d424489ac8 100644 (file)
@@ -285,7 +285,7 @@ fn evaluate_predicates(
                 def_id: trait_did,
                 substs: infcx.tcx.mk_substs_trait(ty, &[]),
             },
-            constness: hir::Constness::NotConst,
+            constness: ty::BoundConstness::NotConst,
         }));
 
         let computed_preds = param_env.caller_bounds().iter();
index 554b2950263ec38f3e24eb812ad300672d0d9fe3..17a4184c3c9ef92d734ce676477ad4e747a3340a 100644 (file)
@@ -778,7 +778,10 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
     let obligation = Obligation::new(
         ObligationCause::dummy(),
         ty::ParamEnv::reveal_all(),
-        ty::Binder::dummy(ty::TraitPredicate { trait_ref, constness: hir::Constness::NotConst }),
+        ty::Binder::dummy(ty::TraitPredicate {
+            trait_ref,
+            constness: ty::BoundConstness::NotConst,
+        }),
     );
 
     let implsrc = tcx.infer_ctxt().enter(|infcx| {
index c571a1d628427f6af88f025a94195d1c39b1c8f2..6fae8173985be82c233b0ce04dcac77e09b7e55c 100644 (file)
@@ -8,7 +8,6 @@
 //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::Constness;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
@@ -75,7 +74,7 @@ pub(super) fn confirm_candidate(
             ProjectionCandidate(idx) => {
                 let obligations = self.confirm_projection_candidate(obligation, idx)?;
                 // FIXME(jschievink): constness
-                Ok(ImplSource::Param(obligations, Constness::NotConst))
+                Ok(ImplSource::Param(obligations, ty::BoundConstness::NotConst))
             }
 
             ObjectCandidate(idx) => {
@@ -113,7 +112,7 @@ pub(super) fn confirm_candidate(
                 // This indicates something like `Trait + Send: Send`. In this case, we know that
                 // this holds because that's what the object type is telling us, and there's really
                 // no additional obligations to prove and no types in particular to unify, etc.
-                Ok(ImplSource::Param(Vec::new(), Constness::NotConst))
+                Ok(ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst))
             }
 
             BuiltinUnsizeCandidate => {
index 1580562a92f38ac6fa5b78f763beb16140a75103..6cf1dabad8592316b4b99928035b290b4ffe3c17 100644 (file)
@@ -32,7 +32,6 @@
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::Constness;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::abstract_const::NotConstEvaluatable;
@@ -130,8 +129,8 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// and a negative impl
     allow_negative_impls: bool,
 
-    /// Do we only want const impls when we have a const trait predicate?
-    const_impls_required: bool,
+    /// Are we in a const context that needs `~const` bounds to be const?
+    is_in_const_context: bool,
 
     /// The mode that trait queries run in, which informs our error handling
     /// policy. In essence, canonicalized queries need their errors propagated
@@ -224,7 +223,7 @@ pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
-            const_impls_required: false,
+            is_in_const_context: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -236,7 +235,7 @@ pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tc
             intercrate: true,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
-            const_impls_required: false,
+            is_in_const_context: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -252,7 +251,7 @@ pub fn with_negative(
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls,
-            const_impls_required: false,
+            is_in_const_context: false,
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -268,7 +267,7 @@ pub fn with_query_mode(
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
-            const_impls_required: false,
+            is_in_const_context: false,
             query_mode,
         }
     }
@@ -283,7 +282,7 @@ pub fn with_constness(
             intercrate: false,
             intercrate_ambiguity_causes: None,
             allow_negative_impls: false,
-            const_impls_required: matches!(constness, hir::Constness::Const),
+            is_in_const_context: matches!(constness, hir::Constness::Const),
             query_mode: TraitQueryMode::Standard,
         }
     }
@@ -316,14 +315,19 @@ pub fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
+    /// Returns `true` if the trait predicate is considerd `const` to this selection context.
+    pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
+        match pred.constness {
+            ty::BoundConstness::ConstIfConst if self.is_in_const_context => true,
+            _ => false,
+        }
+    }
+
     /// Returns `true` if the predicate is considered `const` to
     /// this selection context.
     pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
         match pred.kind().skip_binder() {
-            ty::PredicateKind::Trait(ty::TraitPredicate {
-                constness: hir::Constness::Const,
-                ..
-            }) if self.const_impls_required => true,
+            ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred),
             _ => false,
         }
     }
@@ -1074,30 +1078,28 @@ fn filter_impls(
     ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
         let tcx = self.tcx();
         // Respect const trait obligations
-        if self.const_impls_required {
-            if let hir::Constness::Const = obligation.predicate.skip_binder().constness {
-                if Some(obligation.predicate.skip_binder().trait_ref.def_id)
-                    != tcx.lang_items().sized_trait()
-                // const Sized bounds are skipped
-                {
-                    match candidate {
-                        // const impl
-                        ImplCandidate(def_id)
-                            if tcx.impl_constness(def_id) == hir::Constness::Const => {}
-                        // const param
-                        ParamCandidate(ty::ConstnessAnd {
-                            constness: hir::Constness::Const,
-                            ..
-                        }) => {}
-                        // auto trait impl
-                        AutoImplCandidate(..) => {}
-                        // generator, this will raise error in other places
-                        // or ignore error with const_async_blocks feature
-                        GeneratorCandidate => {}
-                        _ => {
-                            // reject all other types of candidates
-                            return Err(Unimplemented);
-                        }
+        if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+            if Some(obligation.predicate.skip_binder().trait_ref.def_id)
+                != tcx.lang_items().sized_trait()
+            // const Sized bounds are skipped
+            {
+                match candidate {
+                    // const impl
+                    ImplCandidate(def_id)
+                        if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+                    // const param
+                    ParamCandidate(ty::ConstnessAnd {
+                        constness: ty::BoundConstness::ConstIfConst,
+                        ..
+                    }) => {}
+                    // auto trait impl
+                    AutoImplCandidate(..) => {}
+                    // generator, this will raise error in other places
+                    // or ignore error with const_async_blocks feature
+                    GeneratorCandidate => {}
+                    _ => {
+                        // reject all other types of candidates
+                        return Err(Unimplemented);
                     }
                 }
             }
@@ -1495,7 +1497,9 @@ fn candidate_should_be_dropped_in_favor_of(
                     // probably best characterized as a "hack", since we might prefer to just do our
                     // best to *not* create essentially duplicate candidates in the first place.
                     other.value.bound_vars().len() <= victim.value.bound_vars().len()
-                } else if other.value == victim.value && victim.constness == Constness::NotConst {
+                } else if other.value == victim.value
+                    && victim.constness == ty::BoundConstness::NotConst
+                {
                     // Drop otherwise equivalent non-const candidates in favor of const candidates.
                     true
                 } else {
index d916ff7db3d51af667b793f99bd1b52b08f9b2bf..059e0cadd190cf649cf092fe4a291e48e6ebca11 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{walk_generics, Visitor as _};
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{Constness, GenericArg, GenericArgs};
+use rustc_hir::{GenericArg, GenericArgs};
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
@@ -47,8 +47,6 @@ pub trait AstConv<'tcx> {
 
     fn item_def_id(&self) -> Option<DefId>;
 
-    fn default_constness_for_trait_bounds(&self) -> Constness;
-
     /// Returns predicates in scope of the form `X: Foo<T>`, where `X`
     /// is a type parameter `X` with the given id `def_id` and T
     /// matches `assoc_name`. This is a subset of the full set of
@@ -724,7 +722,7 @@ pub fn instantiate_poly_trait_ref(
         &self,
         trait_ref: &hir::TraitRef<'_>,
         span: Span,
-        constness: Constness,
+        constness: ty::BoundConstness,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
         speculative: bool,
@@ -795,7 +793,7 @@ pub fn instantiate_lang_item_trait_ref(
         let bound_vars = tcx.late_bound_vars(hir_id);
         let poly_trait_ref =
             ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
-        bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst));
+        bounds.trait_bounds.push((poly_trait_ref, span, ty::BoundConstness::NotConst));
 
         let mut dup_bindings = FxHashMap::default();
         for binding in assoc_bindings {
@@ -920,14 +918,13 @@ fn add_bounds(
         bounds: &mut Bounds<'tcx>,
         bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
     ) {
-        let constness = self.default_constness_for_trait_bounds();
         for ast_bound in ast_bounds {
             match *ast_bound {
                 hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
                     self.instantiate_poly_trait_ref(
                         &b.trait_ref,
                         b.span,
-                        constness,
+                        ty::BoundConstness::NotConst,
                         param_ty,
                         bounds,
                         false,
@@ -937,7 +934,7 @@ fn add_bounds(
                     self.instantiate_poly_trait_ref(
                         &b.trait_ref,
                         b.span,
-                        Constness::NotConst,
+                        ty::BoundConstness::ConstIfConst,
                         param_ty,
                         bounds,
                         false,
@@ -1251,7 +1248,7 @@ fn conv_object_ty_poly_trait_ref(
             } = self.instantiate_poly_trait_ref(
                 &trait_bound.trait_ref,
                 trait_bound.span,
-                Constness::NotConst,
+                ty::BoundConstness::NotConst,
                 dummy_self,
                 &mut bounds,
                 false,
@@ -1330,7 +1327,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
             .filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
         for (base_trait_ref, span, constness) in regular_traits_refs_spans {
-            assert_eq!(constness, Constness::NotConst);
+            assert_eq!(constness, ty::BoundConstness::NotConst);
 
             for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) {
                 debug!(
index 5d2006407226304530509df458aa6819b374beb8..24474e163b9daf23586c3d24e2efb063f652c596 100644 (file)
@@ -1,7 +1,6 @@
 //! Bounds are restrictions applied to some types after they've been converted into the
 //! `ty` form from the HIR.
 
-use rustc_hir::Constness;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::Span;
 
@@ -30,7 +29,7 @@ pub struct Bounds<'tcx> {
 
     /// A list of trait bounds. So if you had `T: Debug` this would be
     /// `T: Debug`. Note that the self-type is explicit here.
-    pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,
+    pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
 
     /// A list of projection equality bounds. So if you had `T:
     /// Iterator<Item = u32>` this would include `<T as
index 16f3de58078ac1c4c747221652990eb68d103dd7..9c70d2cb365b2714ff563cca9402aa7ff2c7b44d 100644 (file)
@@ -180,10 +180,6 @@ fn item_def_id(&self) -> Option<DefId> {
         None
     }
 
-    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
-        self.tcx.hir().get(self.body_id).constness_for_typeck()
-    }
-
     fn get_type_parameter_bounds(
         &self,
         _: Span,
index 75f9405e082ca3c5a6a3b7de96a786743025d9b4..b514176ad529d439556c1645bd0ac56d754d76e3 100644 (file)
@@ -365,10 +365,6 @@ fn item_def_id(&self) -> Option<DefId> {
         Some(self.item_def_id)
     }
 
-    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
-        self.node().constness_for_typeck()
-    }
-
     fn get_type_parameter_bounds(
         &self,
         span: Span,
@@ -664,7 +660,6 @@ fn type_parameter_bounds_in_generics(
         only_self_bounds: OnlySelfBounds,
         assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
-        let constness = self.default_constness_for_trait_bounds();
         let from_ty_params = ast_generics
             .params
             .iter()
@@ -677,7 +672,7 @@ fn type_parameter_bounds_in_generics(
                 Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
                 None => true,
             })
-            .flat_map(|b| predicates_from_bound(self, ty, b, constness));
+            .flat_map(|b| predicates_from_bound(self, ty, b));
 
         let from_where_clauses = ast_generics
             .where_clause
@@ -703,7 +698,7 @@ fn type_parameter_bounds_in_generics(
                     })
                     .filter_map(move |b| bt.map(|bt| (bt, b)))
             })
-            .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness));
+            .flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
 
         from_ty_params.chain(from_where_clauses).collect()
     }
@@ -2031,7 +2026,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     let mut is_default_impl_trait = None;
 
     let icx = ItemCtxt::new(tcx, def_id);
-    let constness = icx.default_constness_for_trait_bounds();
 
     const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
 
@@ -2227,8 +2221,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                     match bound {
                         hir::GenericBound::Trait(poly_trait_ref, modifier) => {
                             let constness = match modifier {
-                                hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
-                                hir::TraitBoundModifier::None => constness,
+                                hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
+                                hir::TraitBoundModifier::MaybeConst => {
+                                    ty::BoundConstness::ConstIfConst
+                                }
                                 // We ignore `where T: ?Sized`, it is already part of
                                 // type parameter `T`.
                                 hir::TraitBoundModifier::Maybe => continue,
@@ -2491,14 +2487,13 @@ fn predicates_from_bound<'tcx>(
     astconv: &dyn AstConv<'tcx>,
     param_ty: Ty<'tcx>,
     bound: &'tcx hir::GenericBound<'tcx>,
-    constness: hir::Constness,
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     match *bound {
         hir::GenericBound::Trait(ref tr, modifier) => {
             let constness = match modifier {
                 hir::TraitBoundModifier::Maybe => return vec![],
-                hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
-                hir::TraitBoundModifier::None => constness,
+                hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
+                hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
             };
 
             let mut bounds = Bounds::default();
index d3e4be128a8df54a7b1c93b20da1cb82530b833c..8ecd6034ad6951c1d7dd8a5908eb896c92169e2e 100644 (file)
@@ -68,7 +68,6 @@
 use crate::constrained_generic_params as cgp;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
@@ -368,7 +367,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
         // items.
         ty::PredicateKind::Trait(ty::TraitPredicate {
             trait_ref,
-            constness: hir::Constness::NotConst,
+            constness: ty::BoundConstness::NotConst,
         }) => {
             if !matches!(
                 trait_predicate_kind(tcx, predicate),
@@ -399,7 +398,7 @@ fn trait_predicate_kind<'tcx>(
     match predicate.kind().skip_binder() {
         ty::PredicateKind::Trait(ty::TraitPredicate {
             trait_ref,
-            constness: hir::Constness::NotConst,
+            constness: ty::BoundConstness::NotConst,
         }) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
         ty::PredicateKind::Trait(_)
         | ty::PredicateKind::RegionOutlives(_)
index 638a46fec36f4ac4afd1b27a2d466a3fab7f6026..749f681e92ed174750f70420ff063b70ccb10a41 100644 (file)
@@ -548,7 +548,7 @@ pub fn hir_trait_to_predicates<'tcx>(
         &item_cx,
         hir_trait,
         DUMMY_SP,
-        hir::Constness::NotConst,
+        ty::BoundConstness::NotConst,
         self_ty,
         &mut bounds,
         true,
index eb7c12d13c339029bacf8566c62837f88dae3071..54be830bf42e7404231de5e62b66a8235d148acf 100644 (file)
@@ -387,7 +387,7 @@ impl clean::GenericBound {
                 let modifier_str = match modifier {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
-                    hir::TraitBoundModifier::MaybeConst => "?const",
+                    hir::TraitBoundModifier::MaybeConst => "~const",
                 };
                 if f.alternate() {
                     write!(f, "{}{:#}", modifier_str, ty.print(cx))
index bb8113e53f9c19f917d1e5fd4cd694860d02a899..80f6bbec2a181f04d6146376b12e96c246ee72a8 100644 (file)
@@ -1,22 +1,13 @@
 // issue-49296: Unsafe shenigans in constants can result in missing errors
 
 #![feature(const_fn_trait_bound)]
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
 
-const unsafe fn transmute<T: ?const Copy, U: ?const Copy>(t: T) -> U {
-    #[repr(C)]
-    union Transmute<T: Copy, U: Copy> {
-        from: T,
-        to: U,
-    }
-
-    Transmute { from: t }.to
-}
+use std::mem::transmute;
 
 const fn wat(x: u64) -> &'static u64 {
     unsafe { transmute(&x) }
 }
+
 const X: u64 = *wat(42);
 //~^ ERROR evaluation of constant value failed
 
index 28fdcb7c486371ddb1cdfaf37b0dd789b54733be..bc3074b10bee6f326c048121d07b093515e63e46 100644 (file)
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/issue-49296.rs:20:16
+  --> $DIR/issue-49296.rs:11:16
    |
 LL | const X: u64 = *wat(42);
    |                ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
index 5e7e72ca562dd62067f807634203787c995bd355..2b57c439fe9a026057815233558d1cf5512e6a1e 100644 (file)
@@ -4,11 +4,11 @@ error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
 LL |     type Assoc = OnlySized<<T as Foo>::Item>;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: required by a bound in `Foo::Item`
-  --> $DIR/projection-bound-cycle-generic.rs:11:49
+note: required by a bound in `OnlySized`
+  --> $DIR/projection-bound-cycle-generic.rs:28:18
    |
-LL |     type Item: Sized where <Self as Foo>::Item: Sized;
-   |                                                 ^^^^^ required by this bound in `Foo::Item`
+LL | struct OnlySized<T> where T: Sized { f: T }
+   |                  ^ required by this bound in `OnlySized`
 
 error: aborting due to previous error
 
index 1153bf53ba43ed187298df8f28c756c1da6a633a..d9d0bf4274bd72c2f35ed75ea9053881260c36fb 100644 (file)
@@ -4,11 +4,11 @@ error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
 LL |     type Assoc = OnlySized<<T as Foo>::Item>;
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: required by a bound in `Foo::Item`
-  --> $DIR/projection-bound-cycle.rs:13:49
+note: required by a bound in `OnlySized`
+  --> $DIR/projection-bound-cycle.rs:30:18
    |
-LL |     type Item: Sized where <Self as Foo>::Item: Sized;
-   |                                                 ^^^^^ required by this bound in `Foo::Item`
+LL | struct OnlySized<T> where T: Sized { f: T }
+   |                  ^ required by this bound in `OnlySized`
 
 error: aborting due to previous error
 
index 7a187a0518af9d7f404c031d1c3be8f25dbf175f..4ae4549ea58966346c2d0d6994ae0a8d0407d8c1 100644 (file)
@@ -9,10 +9,10 @@ struct S<
     T: Tr +, // OK
     T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
 
-    T: ?const Tr, // OK
-    T: ?const ?Tr, // OK
-    T: ?const Tr + 'a, // OK
-    T: ?const 'a, //~ ERROR `?const` may only modify trait bounds, not lifetime bounds
+    T: ~const Tr, // OK
+    T: ~const ?Tr, // OK
+    T: ~const Tr + 'a, // OK
+    T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds
 >;
 
 fn main() {}
index 9a1f2ed398240f48f8da6b140af1848eee8b5fea..005bc1e54bd00421358c18ea1f832e595df62041 100644 (file)
@@ -4,10 +4,10 @@ error: `?` may only modify trait bounds, not lifetime bounds
 LL |     T: ?'a,
    |        ^
 
-error: `?const` may only modify trait bounds, not lifetime bounds
+error: `~const` may only modify trait bounds, not lifetime bounds
   --> $DIR/bounds-type.rs:15:8
    |
-LL |     T: ?const 'a,
+LL |     T: ~const 'a,
    |        ^^^^^^
 
 error: aborting due to 2 previous errors
index 650ab57226187a4c497221e76b5d27874e87cc23..b5258eebb90adf774132336d9078bc3226aa48c8 100644 (file)
@@ -6,7 +6,7 @@ fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
 fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces 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 `!`, `(`, `)`, `,`, `?`, `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 `<`
index 1ae0205615cb11f952c6618d8d545df23cf96020..ee638d8a4f5ecf20c214d76f1dcfcb2687e1fb2c 100644 (file)
@@ -22,11 +22,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 `!`, `(`, `)`, `,`, `?`, `for`, `~`, lifetime, or path, found `{`
   --> $DIR/trait-object-delimiters.rs:8:17
    |
 LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
-   |                -^ expected one of 8 possible tokens
+   |                -^ expected one of 9 possible tokens
    |                |
    |                help: missing `,`
 
index 1dbd000afd73ebf0debdf5058268f79e35c7d310..228b5ed71e80a833142ecd43054b0cc42fd936bb 100644 (file)
@@ -1,7 +1,5 @@
 // FIXME(fee1-dead): this should have a better error message
 #![feature(const_trait_impl)]
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
 
 struct NonConstAdd(i32);
 
@@ -14,7 +12,7 @@ fn add(self, rhs: Self) -> Self {
 }
 
 trait Foo {
-    type Bar: std::ops::Add;
+    type Bar: ~const std::ops::Add;
 }
 
 impl const Foo for NonConstAdd {
@@ -23,7 +21,7 @@ impl const Foo for NonConstAdd {
 }
 
 trait Baz {
-    type Qux: ?const std::ops::Add;
+    type Qux: std::ops::Add;
 }
 
 impl const Baz for NonConstAdd {
index ada29ba3f8b4e0a1743fd1bb6da995d14a296ed5..b894092205e433448fc0c812770e9fbace38583b 100644 (file)
@@ -1,15 +1,15 @@
 error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
-  --> $DIR/assoc-type.rs:21:5
+  --> $DIR/assoc-type.rs:19:5
    |
 LL |     type Bar = NonConstAdd;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
    |
    = help: the trait `Add` is not implemented for `NonConstAdd`
 note: required by a bound in `Foo::Bar`
-  --> $DIR/assoc-type.rs:17:15
+  --> $DIR/assoc-type.rs:15:15
    |
-LL |     type Bar: std::ops::Add;
-   |               ^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
+LL |     type Bar: ~const std::ops::Add;
+   |               ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
 help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
    |
 LL | impl const Foo for NonConstAdd where NonConstAdd: Add {
index 536c1d737402346f87f5209e4bf0be7f11e5c01f..4b706a190e65e5985a7a3e3048ff0c1fa90e9426 100644 (file)
@@ -6,7 +6,7 @@ trait MyPartialEq {
     fn eq(&self, other: &Self) -> bool;
 }
 
-impl<T: PartialEq> const MyPartialEq for T {
+impl<T: ~const PartialEq> const MyPartialEq for T {
     fn eq(&self, other: &Self) -> bool {
         PartialEq::eq(self, other)
     }
index f3391aa63468cf91580aec8019bdd5bcb5e7a73e..adf8d4f9ea565a208c3d92cd57416df8eb54b968 100644 (file)
@@ -16,11 +16,11 @@ fn ne(&self, other: &S) -> bool {
     }
 }
 
-const fn equals_self<T: PartialEq>(t: &T) -> bool {
+const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
     *t == *t
 }
 
-const fn equals_self_wrapper<T: PartialEq>(t: &T) -> bool {
+const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
     equals_self(t)
 }
 
index 00a3c7f51fe90df88eeedf1b1aa9cbc2654d83db..7185376b440c8fdf10e7b029f7f94f2a4ac1acba 100644 (file)
@@ -1,9 +1,7 @@
 // check-pass
 
 #![feature(const_trait_impl)]
-#![feature(const_trait_bound_opt_out)]
 #![feature(const_fn_trait_bound)]
-#![allow(incomplete_features)]
 
 struct S;
 
@@ -16,9 +14,11 @@ fn ne(&self, other: &S) -> bool {
     }
 }
 
-// This duplicate bound should not result in ambiguities. It should be equivalent to a single const
+// This duplicate bound should not result in ambiguities. It should be equivalent to a single ~const
 // bound.
-const fn equals_self<T: PartialEq + ?const PartialEq>(t: &T) -> bool {
+// const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
+// FIXME(fee1-dead)^ why should the order matter here?
+const fn equals_self<T: ~const PartialEq + PartialEq>(t: &T) -> bool {
     *t == *t
 }
 
index dc4d5561d47459b2b44de68aa58b3a326efe22ed..e96249ff2fd5a4710f2c9b68166e438e136dc9f0 100644 (file)
@@ -1,9 +1,7 @@
 #![feature(const_fn_trait_bound)]
 #![feature(const_trait_impl)]
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
 
-pub const fn equals_self<T: ?const PartialEq>(t: &T) -> bool {
+pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
     *t == *t
     //~^ ERROR calls in constant functions are limited to constant functions
 }
index 4b2fc56aaa78a944791f288eeb42035c050ff00e..818c582869631f9bc70f22b5be7077b0d34955a7 100644 (file)
@@ -1,5 +1,5 @@
 error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/call-generic-method-fail.rs:7:5
+  --> $DIR/call-generic-method-fail.rs:5:5
    |
 LL |     *t == *t
    |     ^^^^^^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-bound.rs
new file mode 100644 (file)
index 0000000..585b659
--- /dev/null
@@ -0,0 +1,19 @@
+// check-pass
+
+#![feature(const_fn_trait_bound)]
+
+struct S;
+
+impl PartialEq for S {
+    fn eq(&self, _: &S) -> bool {
+        true
+    }
+}
+
+const fn equals_self<T: PartialEq>(t: &T) -> bool {
+    true
+}
+
+pub const EQ: bool = equals_self(&S);
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst-opt-out.rs
deleted file mode 100644 (file)
index 1fc2c4f..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// check-pass
-
-#![feature(const_fn_trait_bound)]
-#![feature(const_trait_impl)]
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
-
-struct S;
-
-impl PartialEq for S {
-    fn eq(&self, _: &S) -> bool {
-        true
-    }
-}
-
-const fn equals_self<T: ?const PartialEq>(t: &T) -> bool {
-    true
-}
-
-pub const EQ: bool = equals_self(&S);
-
-// Calling `equals_self` with a type that only has a non-const impl is fine, because we opted out.
-
-fn main() {}
index 8343974f8c7e756358600e41d278e2cd72249c35..6881db0aa02c3cec75158117a2e856de518efd82 100644 (file)
@@ -9,7 +9,7 @@ fn eq(&self, _: &S) -> bool {
     }
 }
 
-const fn equals_self<T: PartialEq>(t: &T) -> bool {
+const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
     true
 }
 
index 7cc54e0129a53e374e3db164eaa2e9fdfe5ca90d..9b9bda7c90ec7d313aab8b9096411c4c5d6acc2f 100644 (file)
@@ -8,8 +8,8 @@ LL | pub const EQ: bool = equals_self(&S);
 note: required by a bound in `equals_self`
   --> $DIR/call-generic-method-nonconst.rs:12:25
    |
-LL | const fn equals_self<T: PartialEq>(t: &T) -> bool {
-   |                         ^^^^^^^^^ required by this bound in `equals_self`
+LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
+   |                         ^^^^^^^^^^^^^^^^ required by this bound in `equals_self`
 
 error: aborting due to previous error
 
index aee88d6053eee2cee24404f497867fe66abe009e..aa9bd4d824e1704aba419008433985d59c7f7727 100644 (file)
@@ -16,7 +16,7 @@ fn ne(&self, other: &S) -> bool {
     }
 }
 
-const fn equals_self<T: PartialEq>(t: &T) -> bool {
+const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
     *t == *t
 }
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr
deleted file mode 100644 (file)
index 5804145..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/feature-gate.rs:17:1
-   |
-LL | fn main() {}
-   | ^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs
deleted file mode 100644 (file)
index 4452ad7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// revisions: stock gated
-// gate-test-const_trait_bound_opt_out
-
-#![cfg_attr(gated, feature(const_trait_bound_opt_out))]
-#![allow(incomplete_features)]
-#![feature(rustc_attrs)]
-#![feature(const_fn_trait_bound)]
-
-trait T {
-    const CONST: i32;
-}
-
-const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
-//[stock]~^ ERROR `?const` on trait bounds is experimental
-
-#[rustc_error]
-fn main() {} //[gated]~ ERROR fatal error triggered by #[rustc_error]
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr
deleted file mode 100644 (file)
index 8ae8b88..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: `?const` on trait bounds is experimental
-  --> $DIR/feature-gate.rs:13:29
-   |
-LL | const fn get_assoc_const<S: ?const T>() -> i32 { <S as T>::CONST }
-   |                             ^^^^^^
-   |
-   = note: see issue #67794 <https://github.com/rust-lang/rust/issues/67794> for more information
-   = help: add `#![feature(const_trait_bound_opt_out)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.rs
deleted file mode 100644 (file)
index f5561a9..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#![feature(const_trait_bound_opt_out)]
-#![feature(associated_type_bounds)]
-#![allow(incomplete_features)]
-
-trait T {}
-struct S;
-impl T for S {}
-
-fn rpit() -> impl ?const T { S }
-//~^ ERROR `?const` is not permitted in `impl Trait`
-
-fn apit(_: impl ?const T) {}
-//~^ ERROR `?const` is not permitted in `impl Trait`
-
-fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
-//~^ ERROR `?const` is not permitted in `impl Trait`
-
-fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
-//~^ ERROR `?const` is not permitted in `impl Trait`
-
-fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-impl-trait.stderr
deleted file mode 100644 (file)
index 06cd00a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-error: `?const` is not permitted in `impl Trait`
-  --> $DIR/in-impl-trait.rs:9:19
-   |
-LL | fn rpit() -> impl ?const T { S }
-   |                   ^^^^^^^^
-
-error: `?const` is not permitted in `impl Trait`
-  --> $DIR/in-impl-trait.rs:12:17
-   |
-LL | fn apit(_: impl ?const T) {}
-   |                 ^^^^^^^^
-
-error: `?const` is not permitted in `impl Trait`
-  --> $DIR/in-impl-trait.rs:15:50
-   |
-LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ?const T> { Some(S) }
-   |                                                  ^^^^^^^^
-
-error: `?const` is not permitted in `impl Trait`
-  --> $DIR/in-impl-trait.rs:18:48
-   |
-LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ?const T>) {}
-   |                                                ^^^^^^^^
-
-error: aborting due to 4 previous errors
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.rs
deleted file mode 100644 (file)
index fc9ed5b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
-
-trait Super {}
-trait T: ?const Super {}
-//~^ ERROR `?const` is not permitted in supertraits
-
-fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-bounds.stderr
deleted file mode 100644 (file)
index a0d8f95..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `?const` is not permitted in supertraits
-  --> $DIR/in-trait-bounds.rs:5:10
-   |
-LL | trait T: ?const Super {}
-   |          ^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.rs
deleted file mode 100644 (file)
index b3d1f48..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#![feature(const_trait_bound_opt_out)]
-#![allow(bare_trait_objects)]
-#![allow(incomplete_features)]
-
-struct S;
-trait T {}
-impl T for S {}
-
-// An inherent impl for the trait object `?const T`.
-impl ?const T {}
-//~^ ERROR `?const` is not permitted in trait objects
-
-fn trait_object() -> &'static dyn ?const T { &S }
-//~^ ERROR `?const` is not permitted in trait objects
-
-fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
-//~^ ERROR `?const` is not permitted in trait objects
-
-fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/in-trait-object.stderr
deleted file mode 100644 (file)
index 331fe04..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: `?const` is not permitted in trait objects
-  --> $DIR/in-trait-object.rs:10:6
-   |
-LL | impl ?const T {}
-   |      ^^^^^^^^
-
-error: `?const` is not permitted in trait objects
-  --> $DIR/in-trait-object.rs:13:35
-   |
-LL | fn trait_object() -> &'static dyn ?const T { &S }
-   |                                   ^^^^^^^^
-
-error: `?const` is not permitted in trait objects
-  --> $DIR/in-trait-object.rs:16:61
-   |
-LL | fn trait_object_in_apit(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
-   |                                                             ^^^^^^^^
-
-error: aborting due to 3 previous errors
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.rs
deleted file mode 100644 (file)
index 01e941a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// compile-flags: -Z parse-only
-
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
-
-struct S<T: ?const ?const Tr>;
-//~^ ERROR expected identifier, found keyword `const`
-//~| ERROR expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/opt-out-twice.stderr
deleted file mode 100644 (file)
index f7924b3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: expected identifier, found keyword `const`
-  --> $DIR/opt-out-twice.rs:6:21
-   |
-LL | struct S<T: ?const ?const Tr>;
-   |                     ^^^^^ expected identifier, found keyword
-
-error: expected one of `(`, `+`, `,`, `::`, `<`, `=`, or `>`, found `Tr`
-  --> $DIR/opt-out-twice.rs:6:27
-   |
-LL | struct S<T: ?const ?const Tr>;
-   |                           ^^ expected one of 7 possible tokens
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs
deleted file mode 100644 (file)
index a0d9610..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// compile-flags: -Z parse-only
-// check-pass
-
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
-
-struct S<
-    T: ?const ?for<'a> Tr<'a> + 'static + ?const std::ops::Add,
-    T: ?const ?for<'a: 'b> m::Trait<'a>,
->;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.rs
deleted file mode 100644 (file)
index c2c8689..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
-
-struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
-//~^ ERROR `?const` and `?` are mutually exclusive
-
-fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/with-maybe-sized.stderr
deleted file mode 100644 (file)
index e8e9d6c..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `?const` and `?` are mutually exclusive
-  --> $DIR/with-maybe-sized.rs:4:13
-   |
-LL | struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
-   |             ^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.rs
deleted file mode 100644 (file)
index b904a2e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// compile-flags: -Z parse-only
-
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
-
-struct S<T: const Tr>;
-//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/without-question-mark.stderr
deleted file mode 100644 (file)
index 0dbca95..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, lifetime, or path, found keyword `const`
-  --> $DIR/without-question-mark.rs:6:13
-   |
-LL | struct S<T: const Tr>;
-   |             ^^^^^ expected one of 9 possible tokens
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.rs
deleted file mode 100644 (file)
index 98d3a22..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(const_trait_bound_opt_out)]
-#![feature(const_trait_impl)]
-#![allow(incomplete_features)]
-
-struct S;
-trait T {}
-
-impl ?const T for S {}
-//~^ ERROR expected a trait, found type
-
-fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-opt-out-trait.stderr
deleted file mode 100644 (file)
index 8f923ef..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: expected a trait, found type
-  --> $DIR/impl-opt-out-trait.rs:8:6
-   |
-LL | impl ?const T for S {}
-   |      ^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs b/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.rs
new file mode 100644 (file)
index 0000000..05b2646
--- /dev/null
@@ -0,0 +1,9 @@
+#![feature(const_trait_impl)]
+
+struct S;
+trait T {}
+
+impl ~const T for S {}
+//~^ ERROR expected a trait, found type
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr b/src/test/ui/rfc-2632-const-trait-impl/impl-tilde-const-trait.stderr
new file mode 100644 (file)
index 0000000..0a91719
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected a trait, found type
+  --> $DIR/impl-tilde-const-trait.rs:6:6
+   |
+LL | impl ~const T for S {}
+   |      ^^^^^^^^
+
+error: aborting due to previous error
+
index 04123a532bd9faaf386bab563e5a96e022b1bd87..afd0d137bb4aadf8565a12443527e43e2ba5a760 100644 (file)
@@ -1,6 +1,4 @@
 #![feature(const_trait_impl)]
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
 #![allow(bare_trait_objects)]
 
 struct S;
index 834f6a409f5b69bcbf8c1410a51f6c365880c05f..8c55627031d1edfbaeb6636e237c39f5d5223897 100644 (file)
@@ -1,5 +1,5 @@
 error: inherent impls cannot be `const`
-  --> $DIR/inherent-impl.rs:9:12
+  --> $DIR/inherent-impl.rs:7:12
    |
 LL | impl const S {}
    |      ----- ^ inherent impl for this type
@@ -9,7 +9,7 @@ LL | impl const S {}
    = note: only trait implementations may be annotated with `const`
 
 error: inherent impls cannot be `const`
-  --> $DIR/inherent-impl.rs:12:12
+  --> $DIR/inherent-impl.rs:10:12
    |
 LL | impl const T {}
    |      ----- ^ inherent impl for this type
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
new file mode 100644 (file)
index 0000000..157005b
--- /dev/null
@@ -0,0 +1,13 @@
+#![feature(const_fn_trait_bound)]
+#![feature(const_trait_impl)]
+
+pub trait A {
+    fn assoc() -> bool;
+}
+
+pub const fn foo<T: A>() -> bool {
+    T::assoc()
+    //~^ ERROR calls in constant functions are limited
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr b/src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
new file mode 100644 (file)
index 0000000..931baac
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-88155.rs:9:5
+   |
+LL |     T::assoc()
+   |     ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
index 82a1275bffaedf89ee825a02233a49d1985306f9..7ac2458e3992850d051422629f17de153eca752f 100644 (file)
@@ -5,4 +5,4 @@
 #![feature(const_trait_impl)]
 
 // For now, this parses since an error does not occur until AST lowering.
-impl ?const T {}
+impl ~const T {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.rs
new file mode 100644 (file)
index 0000000..b4302f3
--- /dev/null
@@ -0,0 +1,29 @@
+#![feature(const_trait_impl)]
+#![feature(associated_type_bounds)]
+
+trait T {}
+struct S;
+impl T for S {}
+
+fn rpit() -> impl ~const T { S }
+//~^ ERROR `~const` is not allowed
+
+fn apit(_: impl ~const T) {}
+//~^ ERROR `~const` is not allowed
+
+fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
+//~^ ERROR `~const` is not allowed
+
+fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
+//~^ ERROR `~const` is not allowed
+
+fn generic<P: ~const T>() {}
+//~^ ERROR `~const` is not allowed
+
+fn where_clause<P>() where P: ~const T {}
+//~^ ERROR `~const` is not allowed
+
+struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
+//~^ ERROR `~const` and `?` are mutually exclusive
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
new file mode 100644 (file)
index 0000000..b026099
--- /dev/null
@@ -0,0 +1,56 @@
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-invalid-places.rs:8:19
+   |
+LL | fn rpit() -> impl ~const T { S }
+   |                   ^^^^^^^^
+   |
+   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-invalid-places.rs:11:17
+   |
+LL | fn apit(_: impl ~const T) {}
+   |                 ^^^^^^^^
+   |
+   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-invalid-places.rs:14:50
+   |
+LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
+   |                                                  ^^^^^^^^
+   |
+   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-invalid-places.rs:17:48
+   |
+LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
+   |                                                ^^^^^^^^
+   |
+   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-invalid-places.rs:20:15
+   |
+LL | fn generic<P: ~const T>() {}
+   |               ^^^^^^^^
+   |
+   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+
+error: `~const` is not allowed here
+  --> $DIR/tilde-const-invalid-places.rs:23:31
+   |
+LL | fn where_clause<P>() where P: ~const T {}
+   |                               ^^^^^^^^
+   |
+   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+
+error: `~const` and `?` are mutually exclusive
+  --> $DIR/tilde-const-invalid-places.rs:26:25
+   |
+LL | struct TildeQuestion<T: ~const ?Sized>(std::marker::PhantomData<T>);
+   |                         ^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-syntax.rs
new file mode 100644 (file)
index 0000000..9b3c2cf
--- /dev/null
@@ -0,0 +1,9 @@
+// compile-flags: -Z parse-only
+// check-pass
+
+#![feature(const_trait_impl)]
+
+struct S<
+    T: ~const ?for<'a> Tr<'a> + 'static + ~const std::ops::Add,
+    T: ~const ?for<'a: 'b> m::Trait<'a>,
+>;
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs b/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs
new file mode 100644 (file)
index 0000000..06e4ede
--- /dev/null
@@ -0,0 +1,6 @@
+// compile-flags: -Z parse-only
+
+#![feature(const_trait_impl)]
+
+struct S<T: ~const ~const Tr>;
+//~^ ERROR expected identifier, found `~`
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr
new file mode 100644 (file)
index 0000000..928d23e
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected identifier, found `~`
+  --> $DIR/tilde-twice.rs:5:20
+   |
+LL | struct S<T: ~const ~const Tr>;
+   |                    ^ expected identifier
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
new file mode 100644 (file)
index 0000000..96ba393
--- /dev/null
@@ -0,0 +1,6 @@
+// compiler-flags: -Z parse-only
+
+#![feature(const_trait_impl)]
+
+struct S<T: const Tr>;
+//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path
diff --git a/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr b/src/test/ui/rfc-2632-const-trait-impl/without-tilde.stderr
new file mode 100644 (file)
index 0000000..b6b77ac
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path, found keyword `const`
+  --> $DIR/without-tilde.rs:5:13
+   |
+LL | struct S<T: const Tr>;
+   |             ^^^^^ expected one of 10 possible tokens
+
+error: aborting due to previous error
+
index c6f89c310650c93306adca00625e6e117f70bfcc..640d127e8609818052a0024ad2aa8f604b215066 100644 (file)
@@ -537,10 +537,10 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
                         .map(|s| format!("?{}", s)),
                     ast::TraitBoundModifier::MaybeConst => poly_trait_ref
                         .rewrite(context, shape.offset_left(7)?)
-                        .map(|s| format!("?const {}", s)),
+                        .map(|s| format!("~const {}", s)),
                     ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
                         .rewrite(context, shape.offset_left(8)?)
-                        .map(|s| format!("?const ?{}", s)),
+                        .map(|s| format!("~const ?{}", s)),
                 };
                 rewrite.map(|s| if has_paren { format!("({})", s) } else { s })
             }
index 57f31dc901e77d0dcb02a69b24405574bc351d4a..61ef73a3cab1c6dbe80399e0f4fc5c0f77ae6685 100644 (file)
@@ -140,29 +140,23 @@ fn foo(a: SomeLongComplexType, b: SomeOtherLongComplexType) -> Box<Future<Item =
 
 type MyFn = fn(a: SomeLongComplexType, b: SomeOtherLongComplexType,) -> Box<Future<Item = AnotherLongType, Error = ALongErrorType>>;
 
-// Const opt-out
+// Const bound
 
-trait T: ?   const  Super {}
+trait T: ~   const  Super {}
 
-const fn maybe_const<S: ?   const    T>() -> i32 { <S as T>::CONST }
+const fn not_quite_const<S: ~  const    T>() -> i32 { <S as T>::CONST }
 
-struct S<T:?  const   ?  Sized>(std::marker::PhantomData<T>);
+struct S<T:~  const   ?  Sized>(std::marker::PhantomData<T>);
 
-impl ?    const T {}
+impl ~    const T {}
 
-fn trait_object() -> &'static dyn ?  const T { &S }
+fn apit(_: impl ~   const T) {}
 
-fn i(_: impl IntoIterator<Item = Box<dyn ?    const    T>>) {}
-
-fn apit(_: impl ?const T) {}
-
-fn rpit() -> impl ?  const T { S }
+fn rpit() -> impl ~  const T { S }
 
 pub struct Foo<T: Trait>(T);
-impl<T:   ?  const Trait> Foo<T> {
+impl<T:   ~  const Trait> Foo<T> {
     fn new(t: T) -> Self {
-        // not calling methods on `t`, so we opt out of requiring
-        // `<T as Trait>` to have const methods via `?const`
         Self(t)
     }
 }
@@ -171,4 +165,4 @@ fn new(t: T) -> Self {
 type T = typeof(
 1);
 impl T for  .. {
-}
\ No newline at end of file
+}
index e7761251688a9f31e86b6860171a7482203ca4e4..38cf909c2587a52c0b4b452df0cf6a79400d8270 100644 (file)
@@ -145,35 +145,27 @@ fn foo(
     b: SomeOtherLongComplexType,
 ) -> Box<Future<Item = AnotherLongType, Error = ALongErrorType>>;
 
-// Const opt-out
+// Const bound
 
-trait T: ?const Super {}
+trait T: ~const Super {}
 
-const fn maybe_const<S: ?const T>() -> i32 {
+const fn not_quite_const<S: ~const T>() -> i32 {
     <S as T>::CONST
 }
 
-struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
+struct S<T: ~const ?Sized>(std::marker::PhantomData<T>);
 
-impl ?const T {}
+impl ~const T {}
 
-fn trait_object() -> &'static dyn ?const T {
-    &S
-}
-
-fn i(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
-
-fn apit(_: impl ?const T) {}
+fn apit(_: impl ~const T) {}
 
-fn rpit() -> impl ?const T {
+fn rpit() -> impl ~const T {
     S
 }
 
 pub struct Foo<T: Trait>(T);
-impl<T: ?const Trait> Foo<T> {
+impl<T: ~const Trait> Foo<T> {
     fn new(t: T) -> Self {
-        // not calling methods on `t`, so we opt out of requiring
-        // `<T as Trait>` to have const methods via `?const`
         Self(t)
     }
 }