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)]
/// `?Trait`
Maybe,
- /// `?const Trait`
+ /// `~const Trait`
MaybeConst,
- /// `?const ?Trait`
+ /// `~const ?Trait`
//
// This parses but will be rejected during AST validation.
MaybeConstMaybe,
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(
_,
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,
/// 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>`.
/// 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>`
}
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)) {
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);
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 { .. } => {}
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>`
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()
.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.
}
.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));
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;
_ => {}
}
- visit::walk_item(self, item)
+ visit::walk_item(self, item);
}
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
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");
}
_ => {}
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)),
+ }
}
}
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,
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");
/// 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),
/// 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.
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;
/// 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>),
#[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,
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)
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;
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,
/// 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`
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>>;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
pub struct ConstnessAnd<T> {
- pub constness: Constness,
+ pub constness: BoundConstness,
pub value: 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)
}
}
}
}
-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 {
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};
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)
}
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
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,
})
}
}
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;
self.prove_predicates(
Some(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
- constness: hir::Constness::NotConst,
+ constness: ty::BoundConstness::NotConst,
})),
locations,
category,
}
};
+ 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");
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
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;
}
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>,
}
|| 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))
}
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)?
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();
}
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:
/// 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,
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();
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| {
//! 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;
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) => {
// 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 => {
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;
/// 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
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
- const_impls_required: false,
+ is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
intercrate: true,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
- const_impls_required: false,
+ is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
- const_impls_required: false,
+ is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
- const_impls_required: false,
+ is_in_const_context: false,
query_mode,
}
}
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,
}
}
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,
}
}
) -> 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);
}
}
}
// 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 {
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};
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
&self,
trait_ref: &hir::TraitRef<'_>,
span: Span,
- constness: Constness,
+ constness: ty::BoundConstness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
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 {
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,
self.instantiate_poly_trait_ref(
&b.trait_ref,
b.span,
- Constness::NotConst,
+ ty::BoundConstness::ConstIfConst,
param_ty,
bounds,
false,
} = self.instantiate_poly_trait_ref(
&trait_bound.trait_ref,
trait_bound.span,
- Constness::NotConst,
+ ty::BoundConstness::NotConst,
dummy_self,
&mut bounds,
false,
.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!(
//! 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;
/// 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
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,
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,
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()
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
})
.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()
}
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();
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,
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();
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};
// items.
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
- constness: hir::Constness::NotConst,
+ constness: ty::BoundConstness::NotConst,
}) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
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(_)
&item_cx,
hir_trait,
DUMMY_SP,
- hir::Constness::NotConst,
+ ty::BoundConstness::NotConst,
self_ty,
&mut bounds,
true,
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))
// 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
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
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
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
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() {}
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
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 `<`
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 `,`
// 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);
}
trait Foo {
- type Bar: std::ops::Add;
+ type Bar: ~const std::ops::Add;
}
impl const Foo for NonConstAdd {
}
trait Baz {
- type Qux: ?const std::ops::Add;
+ type Qux: std::ops::Add;
}
impl const Baz for NonConstAdd {
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 {
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)
}
}
}
-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)
}
// check-pass
#![feature(const_trait_impl)]
-#![feature(const_trait_bound_opt_out)]
#![feature(const_fn_trait_bound)]
-#![allow(incomplete_features)]
struct S;
}
}
-// 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
}
#![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
}
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
| ^^^^^^^^
--- /dev/null
+// 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() {}
+++ /dev/null
-// 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() {}
}
}
-const fn equals_self<T: PartialEq>(t: &T) -> bool {
+const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
true
}
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
}
}
-const fn equals_self<T: PartialEq>(t: &T) -> bool {
+const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
*t == *t
}
+++ /dev/null
-error: fatal error triggered by #[rustc_error]
- --> $DIR/feature-gate.rs:17:1
- |
-LL | fn main() {}
- | ^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// 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]
+++ /dev/null
-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`.
+++ /dev/null
-#![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() {}
+++ /dev/null
-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
-
+++ /dev/null
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
-
-trait Super {}
-trait T: ?const Super {}
-//~^ ERROR `?const` is not permitted in supertraits
-
-fn main() {}
+++ /dev/null
-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
-
+++ /dev/null
-#![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() {}
+++ /dev/null
-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
-
+++ /dev/null
-// 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 `>`
+++ /dev/null
-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
-
+++ /dev/null
-// 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>,
->;
+++ /dev/null
-#![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() {}
+++ /dev/null
-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
-
+++ /dev/null
-// 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
+++ /dev/null
-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
-
+++ /dev/null
-#![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() {}
+++ /dev/null
-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
-
--- /dev/null
+#![feature(const_trait_impl)]
+
+struct S;
+trait T {}
+
+impl ~const T for S {}
+//~^ ERROR expected a trait, found type
+
+fn main() {}
--- /dev/null
+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
+
#![feature(const_trait_impl)]
-#![feature(const_trait_bound_opt_out)]
-#![allow(incomplete_features)]
#![allow(bare_trait_objects)]
struct S;
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
= 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
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
#![feature(const_trait_impl)]
// For now, this parses since an error does not occur until AST lowering.
-impl ?const T {}
+impl ~const T {}
--- /dev/null
+#![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() {}
--- /dev/null
+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
+
--- /dev/null
+// 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>,
+>;
--- /dev/null
+// compile-flags: -Z parse-only
+
+#![feature(const_trait_impl)]
+
+struct S<T: ~const ~const Tr>;
+//~^ ERROR expected identifier, found `~`
--- /dev/null
+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
+
--- /dev/null
+// compiler-flags: -Z parse-only
+
+#![feature(const_trait_impl)]
+
+struct S<T: const Tr>;
+//~^ ERROR expected one of `!`, `(`, `,`, `=`, `>`, `?`, `for`, `~`, lifetime, or path
--- /dev/null
+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
+
.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 })
}
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)
}
}
type T = typeof(
1);
impl T for .. {
-}
\ No newline at end of file
+}
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)
}
}