Auto merge of #88328 - fee1-dead:not-quite-const, r=oli-obk
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`
This commit is contained in:
commit
ac50a53359
79 changed files with 501 additions and 545 deletions
|
@ -284,7 +284,7 @@ impl ParenthesizedArgs {
|
||||||
|
|
||||||
pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
|
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.
|
/// Negative bounds should also be handled here.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||||
|
@ -295,10 +295,10 @@ pub enum TraitBoundModifier {
|
||||||
/// `?Trait`
|
/// `?Trait`
|
||||||
Maybe,
|
Maybe,
|
||||||
|
|
||||||
/// `?const Trait`
|
/// `~const Trait`
|
||||||
MaybeConst,
|
MaybeConst,
|
||||||
|
|
||||||
/// `?const ?Trait`
|
/// `~const ?Trait`
|
||||||
//
|
//
|
||||||
// This parses but will be rejected during AST validation.
|
// This parses but will be rejected during AST validation.
|
||||||
MaybeConstMaybe,
|
MaybeConstMaybe,
|
||||||
|
|
|
@ -1414,7 +1414,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
ref ty,
|
ref ty,
|
||||||
TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
|
TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
|
||||||
) => Some(this.lower_poly_trait_ref(ty, itctx.reborrow())),
|
) => 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.
|
// anyways, so treat it like `?Bound` as compilation proceeds.
|
||||||
GenericBound::Trait(
|
GenericBound::Trait(
|
||||||
_,
|
_,
|
||||||
|
|
|
@ -33,24 +33,6 @@ enum SelfSemantic {
|
||||||
No,
|
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> {
|
struct AstValidator<'a> {
|
||||||
session: &'a Session,
|
session: &'a Session,
|
||||||
|
|
||||||
|
@ -60,6 +42,8 @@ struct AstValidator<'a> {
|
||||||
/// Are we inside a trait impl?
|
/// Are we inside a trait impl?
|
||||||
in_trait_impl: bool,
|
in_trait_impl: bool,
|
||||||
|
|
||||||
|
in_const_trait_impl: bool,
|
||||||
|
|
||||||
has_proc_macro_decls: bool,
|
has_proc_macro_decls: bool,
|
||||||
|
|
||||||
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
|
/// 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>`.
|
/// e.g., `impl Iterator<Item = impl Debug>`.
|
||||||
outer_impl_trait: Option<Span>,
|
outer_impl_trait: Option<Span>,
|
||||||
|
|
||||||
/// Keeps track of the `BoundContext` as we recurse.
|
is_tilde_const_allowed: bool,
|
||||||
///
|
|
||||||
/// This is used to forbid `?const Trait` bounds in, e.g.,
|
|
||||||
/// `impl Iterator<Item = Box<dyn ?const Trait>`.
|
|
||||||
bound_context: Option<BoundContext>,
|
|
||||||
|
|
||||||
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
|
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
|
||||||
/// or `Foo::Bar<impl Trait>`
|
/// or `Foo::Bar<impl Trait>`
|
||||||
|
@ -88,10 +68,18 @@ struct AstValidator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> 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 = 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);
|
f(self);
|
||||||
self.in_trait_impl = old;
|
self.in_trait_impl = old;
|
||||||
|
self.in_const_trait_impl = old_const;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
|
||||||
|
@ -100,6 +88,18 @@ impl<'a> AstValidator<'a> {
|
||||||
self.is_impl_trait_banned = old;
|
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)) {
|
fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
|
||||||
let old = mem::replace(&mut self.is_let_allowed, allowed);
|
let old = mem::replace(&mut self.is_let_allowed, allowed);
|
||||||
f(self, old);
|
f(self, old);
|
||||||
|
@ -130,19 +130,13 @@ impl<'a> AstValidator<'a> {
|
||||||
fn with_impl_trait(&mut self, outer: Option<Span>, 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);
|
let old = mem::replace(&mut self.outer_impl_trait, outer);
|
||||||
if outer.is_some() {
|
if outer.is_some() {
|
||||||
self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
|
self.with_banned_tilde_const(f);
|
||||||
} else {
|
} else {
|
||||||
f(self)
|
f(self);
|
||||||
}
|
}
|
||||||
self.outer_impl_trait = old;
|
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) {
|
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
|
||||||
match constraint.kind {
|
match constraint.kind {
|
||||||
AssocTyConstraintKind::Equality { .. } => {}
|
AssocTyConstraintKind::Equality { .. } => {}
|
||||||
|
@ -164,9 +158,7 @@ impl<'a> AstValidator<'a> {
|
||||||
TyKind::ImplTrait(..) => {
|
TyKind::ImplTrait(..) => {
|
||||||
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
|
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
|
||||||
}
|
}
|
||||||
TyKind::TraitObject(..) => {
|
TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
|
||||||
self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
|
|
||||||
}
|
|
||||||
TyKind::Path(ref qself, ref path) => {
|
TyKind::Path(ref qself, ref path) => {
|
||||||
// We allow these:
|
// We allow these:
|
||||||
// - `Option<impl Trait>`
|
// - `Option<impl Trait>`
|
||||||
|
@ -1083,13 +1075,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
unsafety,
|
unsafety,
|
||||||
polarity,
|
polarity,
|
||||||
defaultness: _,
|
defaultness: _,
|
||||||
constness: _,
|
constness,
|
||||||
generics: _,
|
ref generics,
|
||||||
of_trait: Some(ref t),
|
of_trait: Some(ref t),
|
||||||
ref self_ty,
|
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);
|
this.invalid_visibility(&item.vis, None);
|
||||||
if let TyKind::Err = self_ty.kind {
|
if let TyKind::Err = self_ty.kind {
|
||||||
this.err_handler()
|
this.err_handler()
|
||||||
|
@ -1112,7 +1104,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
.emit();
|
.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.
|
return; // Avoid visiting again.
|
||||||
}
|
}
|
||||||
|
@ -1157,13 +1159,24 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
.emit();
|
.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);
|
self.check_defaultness(item.span, def);
|
||||||
|
|
||||||
if body.is_none() {
|
if body.is_none() {
|
||||||
let msg = "free function without a body";
|
let msg = "free function without a body";
|
||||||
self.error_item_without_body(item.span, "function", msg, " { <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, .. }) => {
|
ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => {
|
||||||
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
let old_item = mem::replace(&mut self.extern_mod, Some(item));
|
||||||
|
@ -1206,9 +1219,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.visit_vis(&item.vis);
|
self.visit_vis(&item.vis);
|
||||||
self.visit_ident(item.ident);
|
self.visit_ident(item.ident);
|
||||||
self.visit_generics(generics);
|
self.visit_generics(generics);
|
||||||
self.with_bound_context(BoundContext::TraitBounds, |this| {
|
self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
|
||||||
walk_list!(this, visit_param_bound, bounds);
|
|
||||||
});
|
|
||||||
walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
|
walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
|
||||||
walk_list!(self, visit_attribute, &item.attrs);
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
return;
|
return;
|
||||||
|
@ -1281,7 +1292,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
visit::walk_item(self, item)
|
visit::walk_item(self, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||||
|
@ -1428,15 +1439,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
fn visit_param_bound(&mut self, bound: &'a GenericBound) {
|
fn visit_param_bound(&mut self, bound: &'a GenericBound) {
|
||||||
match bound {
|
match bound {
|
||||||
GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
|
GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
|
||||||
if let Some(ctx) = self.bound_context {
|
if !self.is_tilde_const_allowed {
|
||||||
let msg = format!("`?const` is not permitted in {}", ctx.description());
|
self.err_handler()
|
||||||
self.err_handler().span_err(bound.span(), &msg);
|
.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) => {
|
GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
|
||||||
self.err_handler()
|
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 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.check_item_named(item.ident, "const");
|
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,
|
session,
|
||||||
extern_mod: None,
|
extern_mod: None,
|
||||||
in_trait_impl: false,
|
in_trait_impl: false,
|
||||||
|
in_const_trait_impl: false,
|
||||||
has_proc_macro_decls: false,
|
has_proc_macro_decls: false,
|
||||||
outer_impl_trait: None,
|
outer_impl_trait: None,
|
||||||
bound_context: None,
|
is_tilde_const_allowed: false,
|
||||||
is_impl_trait_banned: false,
|
is_impl_trait_banned: false,
|
||||||
is_assoc_ty_bound_banned: false,
|
is_assoc_ty_bound_banned: false,
|
||||||
is_let_allowed: false,
|
is_let_allowed: false,
|
||||||
|
|
|
@ -656,7 +656,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||||
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
|
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
|
||||||
gate_all!(generators, "yield syntax is experimental");
|
gate_all!(generators, "yield syntax is experimental");
|
||||||
gate_all!(raw_ref_op, "raw address of 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!(const_trait_impl, "const trait impls are experimental");
|
||||||
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
|
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
|
||||||
gate_all!(inline_const, "inline-const is experimental");
|
gate_all!(inline_const, "inline-const is experimental");
|
||||||
|
|
|
@ -515,9 +515,6 @@ declare_features! (
|
||||||
/// Allows `impl const Trait for T` syntax.
|
/// Allows `impl const Trait for T` syntax.
|
||||||
(active, const_trait_impl, "1.42.0", Some(67792), None),
|
(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.
|
/// Allows the use of `no_sanitize` attribute.
|
||||||
(active, no_sanitize, "1.42.0", Some(39699), None),
|
(active, no_sanitize, "1.42.0", Some(39699), None),
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,9 @@ declare_features! (
|
||||||
/// Allows overlapping impls of marker traits.
|
/// Allows overlapping impls of marker traits.
|
||||||
(removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
|
(removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
|
||||||
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
|
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]`.
|
/// Allows `#[no_debug]`.
|
||||||
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
|
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
|
||||||
/// Allows comparing raw pointers during const eval.
|
/// Allows comparing raw pointers during const eval.
|
||||||
|
|
|
@ -17,7 +17,6 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::Constness;
|
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -497,7 +496,7 @@ pub enum ImplSource<'tcx, N> {
|
||||||
/// for some type parameter. The `Vec<N>` represents the
|
/// for some type parameter. The `Vec<N>` represents the
|
||||||
/// obligations incurred from normalizing the where-clause (if
|
/// obligations incurred from normalizing the where-clause (if
|
||||||
/// any).
|
/// any).
|
||||||
Param(Vec<N>, Constness),
|
Param(Vec<N>, ty::BoundConstness),
|
||||||
|
|
||||||
/// Virtual calls through an object.
|
/// Virtual calls through an object.
|
||||||
Object(ImplSourceObjectData<'tcx, N>),
|
Object(ImplSourceObjectData<'tcx, N>),
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl<T> ExpectedFound<T> {
|
||||||
#[derive(Clone, Debug, TypeFoldable)]
|
#[derive(Clone, Debug, TypeFoldable)]
|
||||||
pub enum TypeError<'tcx> {
|
pub enum TypeError<'tcx> {
|
||||||
Mismatch,
|
Mismatch,
|
||||||
ConstnessMismatch(ExpectedFound<hir::Constness>),
|
ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
|
||||||
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
|
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
|
||||||
AbiMismatch(ExpectedFound<abi::Abi>),
|
AbiMismatch(ExpectedFound<abi::Abi>),
|
||||||
Mutability,
|
Mutability,
|
||||||
|
@ -102,7 +102,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> {
|
||||||
CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
|
CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
|
||||||
Mismatch => write!(f, "types differ"),
|
Mismatch => write!(f, "types differ"),
|
||||||
ConstnessMismatch(values) => {
|
ConstnessMismatch(values) => {
|
||||||
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
|
write!(f, "expected {} bound, found {} bound", values.expected, values.found)
|
||||||
}
|
}
|
||||||
UnsafetyMismatch(values) => {
|
UnsafetyMismatch(values) => {
|
||||||
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
|
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
|
||||||
|
|
|
@ -37,7 +37,7 @@ use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
|
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_macros::HashStable;
|
||||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -181,6 +181,25 @@ pub enum Visibility {
|
||||||
Invisible,
|
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(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
Debug,
|
Debug,
|
||||||
|
@ -457,10 +476,6 @@ pub enum PredicateKind<'tcx> {
|
||||||
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
|
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
|
||||||
/// the `Self` type of the trait reference and `A`, `B`, and `C`
|
/// the `Self` type of the trait reference and `A`, `B`, and `C`
|
||||||
/// would be the type parameters.
|
/// 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>),
|
Trait(TraitPredicate<'tcx>),
|
||||||
|
|
||||||
/// `where 'a: 'b`
|
/// `where 'a: 'b`
|
||||||
|
@ -632,10 +647,7 @@ impl<'tcx> Predicate<'tcx> {
|
||||||
pub struct TraitPredicate<'tcx> {
|
pub struct TraitPredicate<'tcx> {
|
||||||
pub trait_ref: TraitRef<'tcx>,
|
pub trait_ref: TraitRef<'tcx>,
|
||||||
|
|
||||||
/// A trait predicate will have `Constness::Const` if it originates
|
pub constness: BoundConstness,
|
||||||
/// from a bound on a `const fn` without the `?const` opt-out (e.g.,
|
|
||||||
/// `const fn foobar<Foo: Bar>() {}`).
|
|
||||||
pub constness: hir::Constness,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
|
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
|
||||||
|
@ -1304,7 +1316,7 @@ impl<'tcx> ParamEnv<'tcx> {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
|
||||||
pub struct ConstnessAnd<T> {
|
pub struct ConstnessAnd<T> {
|
||||||
pub constness: Constness,
|
pub constness: BoundConstness,
|
||||||
pub value: T,
|
pub value: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1312,18 +1324,18 @@ pub struct ConstnessAnd<T> {
|
||||||
// the constness of trait bounds is being propagated correctly.
|
// the constness of trait bounds is being propagated correctly.
|
||||||
pub trait WithConstness: Sized {
|
pub trait WithConstness: Sized {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_constness(self, constness: Constness) -> ConstnessAnd<Self> {
|
fn with_constness(self, constness: BoundConstness) -> ConstnessAnd<Self> {
|
||||||
ConstnessAnd { constness, value: self }
|
ConstnessAnd { constness, value: self }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn with_const(self) -> ConstnessAnd<Self> {
|
fn with_const_if_const(self) -> ConstnessAnd<Self> {
|
||||||
self.with_constness(Constness::Const)
|
self.with_constness(BoundConstness::ConstIfConst)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn without_const(self) -> ConstnessAnd<Self> {
|
fn without_const(self) -> ConstnessAnd<Self> {
|
||||||
self.with_constness(Constness::NotConst)
|
self.with_constness(BoundConstness::NotConst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,12 +200,12 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Relate<'tcx> for ast::Constness {
|
impl<'tcx> Relate<'tcx> for ty::BoundConstness {
|
||||||
fn relate<R: TypeRelation<'tcx>>(
|
fn relate<R: TypeRelation<'tcx>>(
|
||||||
relation: &mut R,
|
relation: &mut R,
|
||||||
a: ast::Constness,
|
a: ty::BoundConstness,
|
||||||
b: ast::Constness,
|
b: ty::BoundConstness,
|
||||||
) -> RelateResult<'tcx, ast::Constness> {
|
) -> RelateResult<'tcx, ty::BoundConstness> {
|
||||||
if a != b {
|
if a != b {
|
||||||
Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
|
Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||||
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
|
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
|
||||||
use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
|
use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
|
||||||
use rustc_data_structures::functor::IdFunctor;
|
use rustc_data_structures::functor::IdFunctor;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_hir::def::Namespace;
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_hir::def_id::CRATE_DEF_INDEX;
|
use rustc_hir::def_id::CRATE_DEF_INDEX;
|
||||||
use rustc_index::vec::{Idx, IndexVec};
|
use rustc_index::vec::{Idx, IndexVec};
|
||||||
|
@ -155,8 +154,8 @@ impl fmt::Debug for ty::ParamConst {
|
||||||
|
|
||||||
impl fmt::Debug for ty::TraitPredicate<'tcx> {
|
impl fmt::Debug for ty::TraitPredicate<'tcx> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if let hir::Constness::Const = self.constness {
|
if let ty::BoundConstness::ConstIfConst = self.constness {
|
||||||
write!(f, "const ")?;
|
write!(f, "~const ")?;
|
||||||
}
|
}
|
||||||
write!(f, "TraitPredicate({:?})", self.trait_ref)
|
write!(f, "TraitPredicate({:?})", self.trait_ref)
|
||||||
}
|
}
|
||||||
|
@ -241,6 +240,7 @@ TrivialTypeFoldableAndLiftImpls! {
|
||||||
crate::traits::Reveal,
|
crate::traits::Reveal,
|
||||||
crate::ty::adjustment::AutoBorrowMutability,
|
crate::ty::adjustment::AutoBorrowMutability,
|
||||||
crate::ty::AdtKind,
|
crate::ty::AdtKind,
|
||||||
|
crate::ty::BoundConstness,
|
||||||
// Including `BoundRegionKind` is a *bit* dubious, but direct
|
// Including `BoundRegionKind` is a *bit* dubious, but direct
|
||||||
// references to bound region appear in `ty::Error`, and aren't
|
// references to bound region appear in `ty::Error`, and aren't
|
||||||
// really meant to be folded. In general, we can only fold a fully
|
// really meant to be folded. In general, we can only fold a fully
|
||||||
|
|
|
@ -878,7 +878,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
|
||||||
pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
|
pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
|
||||||
self.map_bound(|trait_ref| ty::TraitPredicate {
|
self.map_bound(|trait_ref| ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: hir::Constness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_infer::infer::canonical::Canonical;
|
use rustc_infer::infer::canonical::Canonical;
|
||||||
use rustc_infer::traits::query::NoSolution;
|
use rustc_infer::traits::query::NoSolution;
|
||||||
use rustc_middle::mir::ConstraintCategory;
|
use rustc_middle::mir::ConstraintCategory;
|
||||||
|
@ -88,7 +87,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
self.prove_predicates(
|
self.prove_predicates(
|
||||||
Some(ty::PredicateKind::Trait(ty::TraitPredicate {
|
Some(ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: hir::Constness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
})),
|
})),
|
||||||
locations,
|
locations,
|
||||||
category,
|
category,
|
||||||
|
|
|
@ -805,6 +805,8 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut nonconst_call_permission = false;
|
||||||
|
|
||||||
// Attempting to call a trait method?
|
// Attempting to call a trait method?
|
||||||
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
if let Some(trait_id) = tcx.trait_of_item(callee) {
|
||||||
trace!("attempting to call a trait method");
|
trace!("attempting to call a trait method");
|
||||||
|
@ -819,23 +821,54 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
||||||
param_env,
|
param_env,
|
||||||
Binder::dummy(TraitPredicate {
|
Binder::dummy(TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: hir::Constness::Const,
|
constness: ty::BoundConstness::ConstIfConst,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||||
let mut selcx = SelectionContext::new(&infcx);
|
let mut selcx =
|
||||||
selcx.select(&obligation).unwrap()
|
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`
|
match implsrc {
|
||||||
// opt-out, the call is allowed.
|
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
|
||||||
if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
|
debug!(
|
||||||
debug!(
|
"const_trait_impl: provided {:?} via where-clause in {:?}",
|
||||||
"const_trait_impl: provided {:?} via where-clause in {:?}",
|
trait_ref, param_env
|
||||||
trait_ref, param_env
|
);
|
||||||
);
|
return;
|
||||||
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
|
// Resolve a trait method call to its concrete implementation, which may be in a
|
||||||
|
@ -875,34 +908,16 @@ impl Visitor<'tcx> for Checker<'mir, 'tcx> {
|
||||||
let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
|
let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
|
||||||
|
|
||||||
if !tcx.is_const_fn_raw(callee) {
|
if !tcx.is_const_fn_raw(callee) {
|
||||||
let mut permitted = false;
|
if tcx.trait_of_item(callee).is_some() {
|
||||||
|
if tcx.has_attr(callee, sym::default_method_body_is_const) {
|
||||||
let callee_trait = tcx.trait_of_item(callee);
|
// To get to here we must have already found a const impl for the
|
||||||
if let Some(trait_id) = callee_trait {
|
// trait, but for it to still be non-const can be that the impl is
|
||||||
if tcx.has_attr(caller, sym::default_method_body_is_const) {
|
// using default method bodies.
|
||||||
// permit call to non-const fn when caller has default_method_body_is_const..
|
nonconst_call_permission = true;
|
||||||
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 !permitted {
|
if !nonconst_call_permission {
|
||||||
self.check_op(ops::FnCallNonConst);
|
self.check_op(ops::FnCallNonConst);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,12 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
use rustc_span::symbol::{kw, sym};
|
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 {
|
struct BoundModifiers {
|
||||||
/// `?Trait`.
|
/// `?Trait`.
|
||||||
maybe: Option<Span>,
|
maybe: Option<Span>,
|
||||||
|
|
||||||
/// `?const Trait`.
|
/// `~const Trait`.
|
||||||
maybe_const: Option<Span>,
|
maybe_const: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,6 +609,7 @@ impl<'a> Parser<'a> {
|
||||||
|| self.check_lifetime()
|
|| self.check_lifetime()
|
||||||
|| self.check(&token::Not) // Used for error reporting only.
|
|| self.check(&token::Not) // Used for error reporting only.
|
||||||
|| self.check(&token::Question)
|
|| self.check(&token::Question)
|
||||||
|
|| self.check(&token::Tilde)
|
||||||
|| self.check_keyword(kw::For)
|
|| self.check_keyword(kw::For)
|
||||||
|| self.check(&token::OpenDelim(token::Paren))
|
|| self.check(&token::OpenDelim(token::Paren))
|
||||||
}
|
}
|
||||||
|
@ -655,7 +656,7 @@ impl<'a> Parser<'a> {
|
||||||
let inner_lo = self.token.span;
|
let inner_lo = self.token.span;
|
||||||
let is_negative = self.eat(&token::Not);
|
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() {
|
let bound = if self.token.is_lifetime() {
|
||||||
self.error_lt_bound_with_modifiers(modifiers);
|
self.error_lt_bound_with_modifiers(modifiers);
|
||||||
self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
|
self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
|
||||||
|
@ -690,7 +691,7 @@ impl<'a> Parser<'a> {
|
||||||
if let Some(span) = modifiers.maybe_const {
|
if let Some(span) = modifiers.maybe_const {
|
||||||
self.struct_span_err(
|
self.struct_span_err(
|
||||||
span,
|
span,
|
||||||
"`?const` may only modify trait bounds, not lifetime bounds",
|
"`~const` may only modify trait bounds, not lifetime bounds",
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
@ -721,34 +722,27 @@ impl<'a> Parser<'a> {
|
||||||
Ok(())
|
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.
|
/// 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 {
|
fn parse_ty_bound_modifiers(&mut self) -> PResult<'a, BoundModifiers> {
|
||||||
if !self.eat(&token::Question) {
|
let maybe_const = if self.eat(&token::Tilde) {
|
||||||
return BoundModifiers { maybe: None, maybe_const: None };
|
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
|
||||||
|
};
|
||||||
|
|
||||||
// `? ...`
|
let maybe = if self.eat(&token::Question) { Some(self.prev_token.span) } else { None };
|
||||||
let first_question = self.prev_token.span;
|
|
||||||
if !self.eat_keyword(kw::Const) {
|
|
||||||
return BoundModifiers { maybe: Some(first_question), maybe_const: None };
|
|
||||||
}
|
|
||||||
|
|
||||||
// `?const ...`
|
Ok(BoundModifiers { maybe, maybe_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) };
|
|
||||||
}
|
|
||||||
|
|
||||||
// `?const ? ...`
|
|
||||||
let second_question = self.prev_token.span;
|
|
||||||
BoundModifiers { maybe: Some(second_question), maybe_const: Some(maybe_const) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a type bound according to:
|
/// Parses a type bound according to:
|
||||||
|
@ -757,7 +751,7 @@ impl<'a> Parser<'a> {
|
||||||
/// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
|
/// 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(
|
fn parse_generic_ty_bound(
|
||||||
&mut self,
|
&mut self,
|
||||||
lo: Span,
|
lo: Span,
|
||||||
|
|
|
@ -285,7 +285,7 @@ impl AutoTraitFinder<'tcx> {
|
||||||
def_id: trait_did,
|
def_id: trait_did,
|
||||||
substs: infcx.tcx.mk_substs_trait(ty, &[]),
|
substs: infcx.tcx.mk_substs_trait(ty, &[]),
|
||||||
},
|
},
|
||||||
constness: hir::Constness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let computed_preds = param_env.caller_bounds().iter();
|
let computed_preds = param_env.caller_bounds().iter();
|
||||||
|
|
|
@ -778,7 +778,10 @@ pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
|
||||||
let obligation = Obligation::new(
|
let obligation = Obligation::new(
|
||||||
ObligationCause::dummy(),
|
ObligationCause::dummy(),
|
||||||
ty::ParamEnv::reveal_all(),
|
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| {
|
let implsrc = tcx.infer_ctxt().enter(|infcx| {
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
|
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::Constness;
|
|
||||||
use rustc_index::bit_set::GrowableBitSet;
|
use rustc_index::bit_set::GrowableBitSet;
|
||||||
use rustc_infer::infer::InferOk;
|
use rustc_infer::infer::InferOk;
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
||||||
|
@ -75,7 +74,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
ProjectionCandidate(idx) => {
|
ProjectionCandidate(idx) => {
|
||||||
let obligations = self.confirm_projection_candidate(obligation, idx)?;
|
let obligations = self.confirm_projection_candidate(obligation, idx)?;
|
||||||
// FIXME(jschievink): constness
|
// FIXME(jschievink): constness
|
||||||
Ok(ImplSource::Param(obligations, Constness::NotConst))
|
Ok(ImplSource::Param(obligations, ty::BoundConstness::NotConst))
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectCandidate(idx) => {
|
ObjectCandidate(idx) => {
|
||||||
|
@ -113,7 +112,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// This indicates something like `Trait + Send: Send`. In this case, we know that
|
// 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
|
// 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.
|
// 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 => {
|
BuiltinUnsizeCandidate => {
|
||||||
|
|
|
@ -32,7 +32,6 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::ErrorReported;
|
use rustc_errors::ErrorReported;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::Constness;
|
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
|
||||||
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
|
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
|
||||||
|
@ -130,8 +129,8 @@ pub struct SelectionContext<'cx, 'tcx> {
|
||||||
/// and a negative impl
|
/// and a negative impl
|
||||||
allow_negative_impls: bool,
|
allow_negative_impls: bool,
|
||||||
|
|
||||||
/// Do we only want const impls when we have a const trait predicate?
|
/// Are we in a const context that needs `~const` bounds to be const?
|
||||||
const_impls_required: bool,
|
is_in_const_context: bool,
|
||||||
|
|
||||||
/// The mode that trait queries run in, which informs our error handling
|
/// The mode that trait queries run in, which informs our error handling
|
||||||
/// policy. In essence, canonicalized queries need their errors propagated
|
/// policy. In essence, canonicalized queries need their errors propagated
|
||||||
|
@ -224,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
intercrate: false,
|
intercrate: false,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
const_impls_required: false,
|
is_in_const_context: false,
|
||||||
query_mode: TraitQueryMode::Standard,
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
intercrate: true,
|
intercrate: true,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
const_impls_required: false,
|
is_in_const_context: false,
|
||||||
query_mode: TraitQueryMode::Standard,
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,7 +251,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
intercrate: false,
|
intercrate: false,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls,
|
allow_negative_impls,
|
||||||
const_impls_required: false,
|
is_in_const_context: false,
|
||||||
query_mode: TraitQueryMode::Standard,
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +267,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
intercrate: false,
|
intercrate: false,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
allow_negative_impls: false,
|
||||||
const_impls_required: false,
|
is_in_const_context: false,
|
||||||
query_mode,
|
query_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,7 +282,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
intercrate: false,
|
intercrate: false,
|
||||||
intercrate_ambiguity_causes: None,
|
intercrate_ambiguity_causes: None,
|
||||||
allow_negative_impls: false,
|
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,
|
query_mode: TraitQueryMode::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,14 +315,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
self.infcx.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
|
/// Returns `true` if the predicate is considered `const` to
|
||||||
/// this selection context.
|
/// this selection context.
|
||||||
pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
|
pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
|
||||||
match pred.kind().skip_binder() {
|
match pred.kind().skip_binder() {
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate {
|
ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred),
|
||||||
constness: hir::Constness::Const,
|
|
||||||
..
|
|
||||||
}) if self.const_impls_required => true,
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1074,30 +1078,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
// Respect const trait obligations
|
// Respect const trait obligations
|
||||||
if self.const_impls_required {
|
if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
|
||||||
if let hir::Constness::Const = obligation.predicate.skip_binder().constness {
|
if Some(obligation.predicate.skip_binder().trait_ref.def_id)
|
||||||
if Some(obligation.predicate.skip_binder().trait_ref.def_id)
|
!= tcx.lang_items().sized_trait()
|
||||||
!= tcx.lang_items().sized_trait()
|
// const Sized bounds are skipped
|
||||||
// const Sized bounds are skipped
|
{
|
||||||
{
|
match candidate {
|
||||||
match candidate {
|
// const impl
|
||||||
// const impl
|
ImplCandidate(def_id)
|
||||||
ImplCandidate(def_id)
|
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
||||||
if tcx.impl_constness(def_id) == hir::Constness::Const => {}
|
// const param
|
||||||
// const param
|
ParamCandidate(ty::ConstnessAnd {
|
||||||
ParamCandidate(ty::ConstnessAnd {
|
constness: ty::BoundConstness::ConstIfConst,
|
||||||
constness: hir::Constness::Const,
|
..
|
||||||
..
|
}) => {}
|
||||||
}) => {}
|
// auto trait impl
|
||||||
// auto trait impl
|
AutoImplCandidate(..) => {}
|
||||||
AutoImplCandidate(..) => {}
|
// generator, this will raise error in other places
|
||||||
// generator, this will raise error in other places
|
// or ignore error with const_async_blocks feature
|
||||||
// or ignore error with const_async_blocks feature
|
GeneratorCandidate => {}
|
||||||
GeneratorCandidate => {}
|
_ => {
|
||||||
_ => {
|
// reject all other types of candidates
|
||||||
// reject all other types of candidates
|
return Err(Unimplemented);
|
||||||
return Err(Unimplemented);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1495,7 +1497,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// probably best characterized as a "hack", since we might prefer to just do our
|
// 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.
|
// best to *not* create essentially duplicate candidates in the first place.
|
||||||
other.value.bound_vars().len() <= victim.value.bound_vars().len()
|
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.
|
// Drop otherwise equivalent non-const candidates in favor of const candidates.
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -20,7 +20,7 @@ use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
use rustc_hir::intravisit::{walk_generics, Visitor as _};
|
||||||
use rustc_hir::lang_items::LangItem;
|
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::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::GenericParamDefKind;
|
use rustc_middle::ty::GenericParamDefKind;
|
||||||
use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
|
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 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`
|
/// 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
|
/// 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
|
/// matches `assoc_name`. This is a subset of the full set of
|
||||||
|
@ -724,7 +722,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
&self,
|
&self,
|
||||||
trait_ref: &hir::TraitRef<'_>,
|
trait_ref: &hir::TraitRef<'_>,
|
||||||
span: Span,
|
span: Span,
|
||||||
constness: Constness,
|
constness: ty::BoundConstness,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
bounds: &mut Bounds<'tcx>,
|
bounds: &mut Bounds<'tcx>,
|
||||||
speculative: bool,
|
speculative: bool,
|
||||||
|
@ -795,7 +793,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let bound_vars = tcx.late_bound_vars(hir_id);
|
let bound_vars = tcx.late_bound_vars(hir_id);
|
||||||
let poly_trait_ref =
|
let poly_trait_ref =
|
||||||
ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
|
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();
|
let mut dup_bindings = FxHashMap::default();
|
||||||
for binding in assoc_bindings {
|
for binding in assoc_bindings {
|
||||||
|
@ -920,14 +918,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
bounds: &mut Bounds<'tcx>,
|
bounds: &mut Bounds<'tcx>,
|
||||||
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
|
||||||
) {
|
) {
|
||||||
let constness = self.default_constness_for_trait_bounds();
|
|
||||||
for ast_bound in ast_bounds {
|
for ast_bound in ast_bounds {
|
||||||
match *ast_bound {
|
match *ast_bound {
|
||||||
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
|
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
|
||||||
self.instantiate_poly_trait_ref(
|
self.instantiate_poly_trait_ref(
|
||||||
&b.trait_ref,
|
&b.trait_ref,
|
||||||
b.span,
|
b.span,
|
||||||
constness,
|
ty::BoundConstness::NotConst,
|
||||||
param_ty,
|
param_ty,
|
||||||
bounds,
|
bounds,
|
||||||
false,
|
false,
|
||||||
|
@ -937,7 +934,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
self.instantiate_poly_trait_ref(
|
self.instantiate_poly_trait_ref(
|
||||||
&b.trait_ref,
|
&b.trait_ref,
|
||||||
b.span,
|
b.span,
|
||||||
Constness::NotConst,
|
ty::BoundConstness::ConstIfConst,
|
||||||
param_ty,
|
param_ty,
|
||||||
bounds,
|
bounds,
|
||||||
false,
|
false,
|
||||||
|
@ -1251,7 +1248,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
} = self.instantiate_poly_trait_ref(
|
} = self.instantiate_poly_trait_ref(
|
||||||
&trait_bound.trait_ref,
|
&trait_bound.trait_ref,
|
||||||
trait_bound.span,
|
trait_bound.span,
|
||||||
Constness::NotConst,
|
ty::BoundConstness::NotConst,
|
||||||
dummy_self,
|
dummy_self,
|
||||||
&mut bounds,
|
&mut bounds,
|
||||||
false,
|
false,
|
||||||
|
@ -1330,7 +1327,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
|
||||||
|
|
||||||
for (base_trait_ref, span, constness) in regular_traits_refs_spans {
|
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) {
|
for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) {
|
||||||
debug!(
|
debug!(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Bounds are restrictions applied to some types after they've been converted into the
|
//! Bounds are restrictions applied to some types after they've been converted into the
|
||||||
//! `ty` form from the HIR.
|
//! `ty` form from the HIR.
|
||||||
|
|
||||||
use rustc_hir::Constness;
|
|
||||||
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||||
use rustc_span::Span;
|
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
|
/// A list of trait bounds. So if you had `T: Debug` this would be
|
||||||
/// `T: Debug`. Note that the self-type is explicit here.
|
/// `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:
|
/// A list of projection equality bounds. So if you had `T:
|
||||||
/// Iterator<Item = u32>` this would include `<T as
|
/// Iterator<Item = u32>` this would include `<T as
|
||||||
|
|
|
@ -180,10 +180,6 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||||
None
|
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(
|
fn get_type_parameter_bounds(
|
||||||
&self,
|
&self,
|
||||||
_: Span,
|
_: Span,
|
||||||
|
|
|
@ -365,10 +365,6 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
|
||||||
Some(self.item_def_id)
|
Some(self.item_def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_constness_for_trait_bounds(&self) -> hir::Constness {
|
|
||||||
self.node().constness_for_typeck()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_type_parameter_bounds(
|
fn get_type_parameter_bounds(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -664,7 +660,6 @@ impl ItemCtxt<'tcx> {
|
||||||
only_self_bounds: OnlySelfBounds,
|
only_self_bounds: OnlySelfBounds,
|
||||||
assoc_name: Option<Ident>,
|
assoc_name: Option<Ident>,
|
||||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||||
let constness = self.default_constness_for_trait_bounds();
|
|
||||||
let from_ty_params = ast_generics
|
let from_ty_params = ast_generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -677,7 +672,7 @@ impl ItemCtxt<'tcx> {
|
||||||
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
|
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
|
||||||
None => true,
|
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
|
let from_where_clauses = ast_generics
|
||||||
.where_clause
|
.where_clause
|
||||||
|
@ -703,7 +698,7 @@ impl ItemCtxt<'tcx> {
|
||||||
})
|
})
|
||||||
.filter_map(move |b| bt.map(|bt| (bt, b)))
|
.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()
|
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 mut is_default_impl_trait = None;
|
||||||
|
|
||||||
let icx = ItemCtxt::new(tcx, def_id);
|
let icx = ItemCtxt::new(tcx, def_id);
|
||||||
let constness = icx.default_constness_for_trait_bounds();
|
|
||||||
|
|
||||||
const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
|
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 {
|
match bound {
|
||||||
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
|
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
|
||||||
let constness = match modifier {
|
let constness = match modifier {
|
||||||
hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
|
hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
|
||||||
hir::TraitBoundModifier::None => constness,
|
hir::TraitBoundModifier::MaybeConst => {
|
||||||
|
ty::BoundConstness::ConstIfConst
|
||||||
|
}
|
||||||
// We ignore `where T: ?Sized`, it is already part of
|
// We ignore `where T: ?Sized`, it is already part of
|
||||||
// type parameter `T`.
|
// type parameter `T`.
|
||||||
hir::TraitBoundModifier::Maybe => continue,
|
hir::TraitBoundModifier::Maybe => continue,
|
||||||
|
@ -2491,14 +2487,13 @@ fn predicates_from_bound<'tcx>(
|
||||||
astconv: &dyn AstConv<'tcx>,
|
astconv: &dyn AstConv<'tcx>,
|
||||||
param_ty: Ty<'tcx>,
|
param_ty: Ty<'tcx>,
|
||||||
bound: &'tcx hir::GenericBound<'tcx>,
|
bound: &'tcx hir::GenericBound<'tcx>,
|
||||||
constness: hir::Constness,
|
|
||||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
||||||
match *bound {
|
match *bound {
|
||||||
hir::GenericBound::Trait(ref tr, modifier) => {
|
hir::GenericBound::Trait(ref tr, modifier) => {
|
||||||
let constness = match modifier {
|
let constness = match modifier {
|
||||||
hir::TraitBoundModifier::Maybe => return vec![],
|
hir::TraitBoundModifier::Maybe => return vec![],
|
||||||
hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
|
hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
|
||||||
hir::TraitBoundModifier::None => constness,
|
hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut bounds = Bounds::default();
|
let mut bounds = Bounds::default();
|
||||||
|
|
|
@ -68,7 +68,6 @@
|
||||||
use crate::constrained_generic_params as cgp;
|
use crate::constrained_generic_params as cgp;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||||
use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
|
use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
|
||||||
|
@ -368,7 +367,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
|
||||||
// items.
|
// items.
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate {
|
ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: hir::Constness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
}) => {
|
}) => {
|
||||||
if !matches!(
|
if !matches!(
|
||||||
trait_predicate_kind(tcx, predicate),
|
trait_predicate_kind(tcx, predicate),
|
||||||
|
@ -399,7 +398,7 @@ fn trait_predicate_kind<'tcx>(
|
||||||
match predicate.kind().skip_binder() {
|
match predicate.kind().skip_binder() {
|
||||||
ty::PredicateKind::Trait(ty::TraitPredicate {
|
ty::PredicateKind::Trait(ty::TraitPredicate {
|
||||||
trait_ref,
|
trait_ref,
|
||||||
constness: hir::Constness::NotConst,
|
constness: ty::BoundConstness::NotConst,
|
||||||
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
|
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
|
||||||
ty::PredicateKind::Trait(_)
|
ty::PredicateKind::Trait(_)
|
||||||
| ty::PredicateKind::RegionOutlives(_)
|
| ty::PredicateKind::RegionOutlives(_)
|
||||||
|
|
|
@ -548,7 +548,7 @@ pub fn hir_trait_to_predicates<'tcx>(
|
||||||
&item_cx,
|
&item_cx,
|
||||||
hir_trait,
|
hir_trait,
|
||||||
DUMMY_SP,
|
DUMMY_SP,
|
||||||
hir::Constness::NotConst,
|
ty::BoundConstness::NotConst,
|
||||||
self_ty,
|
self_ty,
|
||||||
&mut bounds,
|
&mut bounds,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -387,7 +387,7 @@ impl clean::GenericBound {
|
||||||
let modifier_str = match modifier {
|
let modifier_str = match modifier {
|
||||||
hir::TraitBoundModifier::None => "",
|
hir::TraitBoundModifier::None => "",
|
||||||
hir::TraitBoundModifier::Maybe => "?",
|
hir::TraitBoundModifier::Maybe => "?",
|
||||||
hir::TraitBoundModifier::MaybeConst => "?const",
|
hir::TraitBoundModifier::MaybeConst => "~const",
|
||||||
};
|
};
|
||||||
if f.alternate() {
|
if f.alternate() {
|
||||||
write!(f, "{}{:#}", modifier_str, ty.print(cx))
|
write!(f, "{}{:#}", modifier_str, ty.print(cx))
|
||||||
|
|
|
@ -1,22 +1,13 @@
|
||||||
// issue-49296: Unsafe shenigans in constants can result in missing errors
|
// issue-49296: Unsafe shenigans in constants can result in missing errors
|
||||||
|
|
||||||
#![feature(const_fn_trait_bound)]
|
#![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 {
|
use std::mem::transmute;
|
||||||
#[repr(C)]
|
|
||||||
union Transmute<T: Copy, U: Copy> {
|
|
||||||
from: T,
|
|
||||||
to: U,
|
|
||||||
}
|
|
||||||
|
|
||||||
Transmute { from: t }.to
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn wat(x: u64) -> &'static u64 {
|
const fn wat(x: u64) -> &'static u64 {
|
||||||
unsafe { transmute(&x) }
|
unsafe { transmute(&x) }
|
||||||
}
|
}
|
||||||
|
|
||||||
const X: u64 = *wat(42);
|
const X: u64 = *wat(42);
|
||||||
//~^ ERROR evaluation of constant value failed
|
//~^ ERROR evaluation of constant value failed
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0080]: 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);
|
LL | const X: u64 = *wat(42);
|
||||||
| ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
|
| ^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
|
||||||
|
|
|
@ -4,11 +4,11 @@ error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
|
||||||
LL | type Assoc = OnlySized<<T as Foo>::Item>;
|
LL | type Assoc = OnlySized<<T as Foo>::Item>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: required by a bound in `Foo::Item`
|
note: required by a bound in `OnlySized`
|
||||||
--> $DIR/projection-bound-cycle-generic.rs:11:49
|
--> $DIR/projection-bound-cycle-generic.rs:28:18
|
||||||
|
|
|
|
||||||
LL | type Item: Sized where <Self as Foo>::Item: Sized;
|
LL | struct OnlySized<T> where T: Sized { f: T }
|
||||||
| ^^^^^ required by this bound in `Foo::Item`
|
| ^ required by this bound in `OnlySized`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ error[E0275]: overflow evaluating the requirement `<T as Foo>::Item: Sized`
|
||||||
LL | type Assoc = OnlySized<<T as Foo>::Item>;
|
LL | type Assoc = OnlySized<<T as Foo>::Item>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: required by a bound in `Foo::Item`
|
note: required by a bound in `OnlySized`
|
||||||
--> $DIR/projection-bound-cycle.rs:13:49
|
--> $DIR/projection-bound-cycle.rs:30:18
|
||||||
|
|
|
|
||||||
LL | type Item: Sized where <Self as Foo>::Item: Sized;
|
LL | struct OnlySized<T> where T: Sized { f: T }
|
||||||
| ^^^^^ required by this bound in `Foo::Item`
|
| ^ required by this bound in `OnlySized`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@ struct S<
|
||||||
T: Tr +, // OK
|
T: Tr +, // OK
|
||||||
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
|
T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds
|
||||||
|
|
||||||
T: ?const Tr, // OK
|
T: ~const Tr, // OK
|
||||||
T: ?const ?Tr, // OK
|
T: ~const ?Tr, // OK
|
||||||
T: ?const Tr + 'a, // OK
|
T: ~const Tr + 'a, // OK
|
||||||
T: ?const 'a, //~ ERROR `?const` may only modify trait bounds, not lifetime bounds
|
T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds
|
||||||
>;
|
>;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -4,10 +4,10 @@ error: `?` may only modify trait bounds, not lifetime bounds
|
||||||
LL | T: ?'a,
|
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
|
--> $DIR/bounds-type.rs:15:8
|
||||||
|
|
|
|
||||||
LL | T: ?const 'a,
|
LL | T: ~const 'a,
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -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 foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
|
||||||
|
|
||||||
fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
|
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
|
//~| ERROR at least one trait is required for an object type
|
||||||
|
|
||||||
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
|
fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
|
||||||
|
|
|
@ -22,11 +22,11 @@ error: expected parameter name, found `{`
|
||||||
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
||||||
| ^ expected parameter name
|
| ^ 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
|
--> $DIR/trait-object-delimiters.rs:8:17
|
||||||
|
|
|
|
||||||
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
|
||||||
| -^ expected one of 8 possible tokens
|
| -^ expected one of 9 possible tokens
|
||||||
| |
|
| |
|
||||||
| help: missing `,`
|
| help: missing `,`
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
// FIXME(fee1-dead): this should have a better error message
|
// FIXME(fee1-dead): this should have a better error message
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(const_trait_bound_opt_out)]
|
|
||||||
#![allow(incomplete_features)]
|
|
||||||
|
|
||||||
struct NonConstAdd(i32);
|
struct NonConstAdd(i32);
|
||||||
|
|
||||||
|
@ -14,7 +12,7 @@ impl std::ops::Add for NonConstAdd {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Foo {
|
trait Foo {
|
||||||
type Bar: std::ops::Add;
|
type Bar: ~const std::ops::Add;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const Foo for NonConstAdd {
|
impl const Foo for NonConstAdd {
|
||||||
|
@ -23,7 +21,7 @@ impl const Foo for NonConstAdd {
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Baz {
|
trait Baz {
|
||||||
type Qux: ?const std::ops::Add;
|
type Qux: std::ops::Add;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const Baz for NonConstAdd {
|
impl const Baz for NonConstAdd {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
|
error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
|
||||||
--> $DIR/assoc-type.rs:21:5
|
--> $DIR/assoc-type.rs:19:5
|
||||||
|
|
|
|
||||||
LL | type Bar = NonConstAdd;
|
LL | type Bar = NonConstAdd;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
|
||||||
|
|
|
|
||||||
= help: the trait `Add` is not implemented for `NonConstAdd`
|
= help: the trait `Add` is not implemented for `NonConstAdd`
|
||||||
note: required by a bound in `Foo::Bar`
|
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;
|
LL | type Bar: ~const std::ops::Add;
|
||||||
| ^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
|
| ^^^^^^^^^^^^^^^^^^^^ 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
|
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 {
|
LL | impl const Foo for NonConstAdd where NonConstAdd: Add {
|
||||||
|
|
|
@ -6,7 +6,7 @@ trait MyPartialEq {
|
||||||
fn eq(&self, other: &Self) -> bool;
|
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 {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
PartialEq::eq(self, other)
|
PartialEq::eq(self, other)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,11 @@ impl const PartialEq for S {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn equals_self<T: PartialEq>(t: &T) -> bool {
|
const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
|
||||||
*t == *t
|
*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)
|
equals_self(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
// check-pass
|
// check-pass
|
||||||
|
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(const_trait_bound_opt_out)]
|
|
||||||
#![feature(const_fn_trait_bound)]
|
#![feature(const_fn_trait_bound)]
|
||||||
#![allow(incomplete_features)]
|
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
|
||||||
|
@ -16,9 +14,11 @@ impl const PartialEq for 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.
|
// 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
|
*t == *t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#![feature(const_fn_trait_bound)]
|
#![feature(const_fn_trait_bound)]
|
||||||
#![feature(const_trait_impl)]
|
#![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
|
*t == *t
|
||||||
//~^ ERROR calls in constant functions are limited to constant functions
|
//~^ ERROR calls in constant functions are limited to constant functions
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
|
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
|
LL | *t == *t
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
@ -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() {}
|
|
@ -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() {}
|
|
|
@ -9,7 +9,7 @@ impl PartialEq for S {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn equals_self<T: PartialEq>(t: &T) -> bool {
|
const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ LL | pub const EQ: bool = equals_self(&S);
|
||||||
note: required by a bound in `equals_self`
|
note: required by a bound in `equals_self`
|
||||||
--> $DIR/call-generic-method-nonconst.rs:12:25
|
--> $DIR/call-generic-method-nonconst.rs:12:25
|
||||||
|
|
|
|
||||||
LL | const fn equals_self<T: PartialEq>(t: &T) -> bool {
|
LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
|
||||||
| ^^^^^^^^^ required by this bound in `equals_self`
|
| ^^^^^^^^^^^^^^^^ required by this bound in `equals_self`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ impl const PartialEq for S {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn equals_self<T: PartialEq>(t: &T) -> bool {
|
const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
|
||||||
*t == *t
|
*t == *t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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]
|
|
|
@ -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`.
|
|
|
@ -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() {}
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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() {}
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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() {}
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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 `>`
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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>,
|
|
||||||
>;
|
|
|
@ -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() {}
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
#![feature(const_trait_bound_opt_out)]
|
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![allow(incomplete_features)]
|
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
trait T {}
|
trait T {}
|
||||||
|
|
||||||
impl ?const T for S {}
|
impl ~const T for S {}
|
||||||
//~^ ERROR expected a trait, found type
|
//~^ ERROR expected a trait, found type
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
|
@ -1,7 +1,7 @@
|
||||||
error: expected a trait, found type
|
error: expected a trait, found type
|
||||||
--> $DIR/impl-opt-out-trait.rs:8:6
|
--> $DIR/impl-tilde-const-trait.rs:6:6
|
||||||
|
|
|
|
||||||
LL | impl ?const T for S {}
|
LL | impl ~const T for S {}
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
|
@ -1,6 +1,4 @@
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
#![feature(const_trait_bound_opt_out)]
|
|
||||||
#![allow(incomplete_features)]
|
|
||||||
#![allow(bare_trait_objects)]
|
#![allow(bare_trait_objects)]
|
||||||
|
|
||||||
struct S;
|
struct S;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: inherent impls cannot be `const`
|
error: inherent impls cannot be `const`
|
||||||
--> $DIR/inherent-impl.rs:9:12
|
--> $DIR/inherent-impl.rs:7:12
|
||||||
|
|
|
|
||||||
LL | impl const S {}
|
LL | impl const S {}
|
||||||
| ----- ^ inherent impl for this type
|
| ----- ^ inherent impl for this type
|
||||||
|
@ -9,7 +9,7 @@ LL | impl const S {}
|
||||||
= note: only trait implementations may be annotated with `const`
|
= note: only trait implementations may be annotated with `const`
|
||||||
|
|
||||||
error: inherent impls cannot be `const`
|
error: inherent impls cannot be `const`
|
||||||
--> $DIR/inherent-impl.rs:12:12
|
--> $DIR/inherent-impl.rs:10:12
|
||||||
|
|
|
|
||||||
LL | impl const T {}
|
LL | impl const T {}
|
||||||
| ----- ^ inherent impl for this type
|
| ----- ^ inherent impl for this type
|
||||||
|
|
13
src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
Normal file
13
src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
Normal file
|
@ -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() {}
|
9
src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
Normal file
9
src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
Normal file
|
@ -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`.
|
|
@ -5,4 +5,4 @@
|
||||||
#![feature(const_trait_impl)]
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
// For now, this parses since an error does not occur until AST lowering.
|
// For now, this parses since an error does not occur until AST lowering.
|
||||||
impl ?const T {}
|
impl ~const T {}
|
||||||
|
|
|
@ -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() {}
|
|
@ -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
|
||||||
|
|
|
@ -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>,
|
||||||
|
>;
|
6
src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs
Normal file
6
src/test/ui/rfc-2632-const-trait-impl/tilde-twice.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// compile-flags: -Z parse-only
|
||||||
|
|
||||||
|
#![feature(const_trait_impl)]
|
||||||
|
|
||||||
|
struct S<T: ~const ~const Tr>;
|
||||||
|
//~^ ERROR expected identifier, found `~`
|
8
src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr
Normal file
8
src/test/ui/rfc-2632-const-trait-impl/tilde-twice.stderr
Normal file
|
@ -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
|
||||||
|
|
6
src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
Normal file
6
src/test/ui/rfc-2632-const-trait-impl/without-tilde.rs
Normal file
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -537,10 +537,10 @@ impl Rewrite for ast::GenericBound {
|
||||||
.map(|s| format!("?{}", s)),
|
.map(|s| format!("?{}", s)),
|
||||||
ast::TraitBoundModifier::MaybeConst => poly_trait_ref
|
ast::TraitBoundModifier::MaybeConst => poly_trait_ref
|
||||||
.rewrite(context, shape.offset_left(7)?)
|
.rewrite(context, shape.offset_left(7)?)
|
||||||
.map(|s| format!("?const {}", s)),
|
.map(|s| format!("~const {}", s)),
|
||||||
ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
|
ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
|
||||||
.rewrite(context, shape.offset_left(8)?)
|
.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 })
|
rewrite.map(|s| if has_paren { format!("({})", s) } else { s })
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>>;
|
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 rpit() -> impl ~ const T { S }
|
||||||
|
|
||||||
fn apit(_: impl ?const T) {}
|
|
||||||
|
|
||||||
fn rpit() -> impl ? const T { S }
|
|
||||||
|
|
||||||
pub struct Foo<T: Trait>(T);
|
pub struct Foo<T: Trait>(T);
|
||||||
impl<T: ? const Trait> Foo<T> {
|
impl<T: ~ const Trait> Foo<T> {
|
||||||
fn new(t: T) -> Self {
|
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)
|
Self(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,4 +165,4 @@ impl<T: ? const Trait> Foo<T> {
|
||||||
type T = typeof(
|
type T = typeof(
|
||||||
1);
|
1);
|
||||||
impl T for .. {
|
impl T for .. {
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,35 +145,27 @@ type MyFn = fn(
|
||||||
b: SomeOtherLongComplexType,
|
b: SomeOtherLongComplexType,
|
||||||
) -> Box<Future<Item = AnotherLongType, Error = ALongErrorType>>;
|
) -> 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
|
<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 {
|
fn apit(_: impl ~const T) {}
|
||||||
&S
|
|
||||||
}
|
|
||||||
|
|
||||||
fn i(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
|
fn rpit() -> impl ~const T {
|
||||||
|
|
||||||
fn apit(_: impl ?const T) {}
|
|
||||||
|
|
||||||
fn rpit() -> impl ?const T {
|
|
||||||
S
|
S
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Foo<T: Trait>(T);
|
pub struct Foo<T: Trait>(T);
|
||||||
impl<T: ?const Trait> Foo<T> {
|
impl<T: ~const Trait> Foo<T> {
|
||||||
fn new(t: T) -> Self {
|
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)
|
Self(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue