Skip to content

Require Drop impls to have the same constness on its bounds as the bounds on the struct have #103351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 3 additions & 49 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,20 +251,6 @@ impl<'a> AstValidator<'a> {
}
}

fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
if let Some(ident) = field.ident {
if ident.name == kw::Underscore {
self.visit_vis(&field.vis);
self.visit_ident(ident);
self.visit_ty_common(&field.ty);
self.walk_ty(&field.ty);
walk_list!(self, visit_attribute, &field.attrs);
return;
}
}
self.visit_field_def(field);
}

fn err_handler(&self) -> &rustc_errors::Handler {
&self.session.diagnostic()
}
Expand Down Expand Up @@ -1005,8 +991,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_lifetime(self, lifetime);
}

fn visit_field_def(&mut self, s: &'a FieldDef) {
visit::walk_field_def(self, s)
fn visit_field_def(&mut self, field: &'a FieldDef) {
visit::walk_field_def(self, field)
}

fn visit_item(&mut self, item: &'a Item) {
Expand Down Expand Up @@ -1194,42 +1180,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_mod_file_item_asciionly(item.ident);
}
}
ItemKind::Struct(ref vdata, ref generics) => match vdata {
// Duplicating the `Visitor` logic allows catching all cases
// of `Anonymous(Struct, Union)` outside of a field struct or union.
//
// Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
// encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
// it uses `visit_ty_common`, which doesn't contain that specific check.
VariantData::Struct(ref fields, ..) => {
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
self.with_banned_assoc_ty_bound(|this| {
walk_list!(this, visit_struct_field_def, fields);
});
walk_list!(self, visit_attribute, &item.attrs);
return;
}
_ => {}
},
ItemKind::Union(ref vdata, ref generics) => {
ItemKind::Union(ref vdata, ..) => {
if vdata.fields().is_empty() {
self.err_handler().span_err(item.span, "unions cannot have zero fields");
}
match vdata {
VariantData::Struct(ref fields, ..) => {
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
self.with_banned_assoc_ty_bound(|this| {
walk_list!(this, visit_struct_field_def, fields);
});
walk_list!(self, visit_attribute, &item.attrs);
return;
}
_ => {}
}
}
ItemKind::Const(def, .., None) => {
self.check_defaultness(item.span, def);
Expand Down
8 changes: 1 addition & 7 deletions compiler/rustc_hir_analysis/src/check/dropck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
(ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
// Since struct predicates cannot have ~const, project the impl predicate
// onto one that ignores the constness. This is equivalent to saying that
// we match a `Trait` bound on the struct with a `Trait` or `~const Trait`
// in the impl.
let non_const_a =
ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a };
relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok()
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
(ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,34 +45,55 @@ note: required by a bound in `check`
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`

error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Destruct` is not satisfied
error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
--> $DIR/const-drop-fail.rs:48:47
|
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ----------------------------------------- ^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
| |
| required by a bound introduced by this call
|
note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
--> $DIR/const-drop-fail.rs:48:47
|
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^
note: required by a bound in `ConstDropImplWithBounds`
--> $DIR/const-drop-fail.rs:27:35
|
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
| ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`

error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
--> $DIR/const-drop-fail.rs:48:5
|
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
|
note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
--> $DIR/const-drop-fail.rs:48:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
...
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `ConstDropImplWithBounds<NonTrivialDrop>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `ConstDropImplWithBounds`
--> $DIR/const-drop-fail.rs:27:35
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
--> $DIR/const-drop-fail.rs:29:25
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
| ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`

error[E0367]: `Drop` impl requires `T: ~const A` but the struct it is implemented for does not
--> $DIR/const-drop-fail.rs:55:9
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: 1 redundant requirement hidden
= note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:35:19
LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
| ^^^^^^^^
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`
help: consider borrowing here
note: the implementor must specify the same requirement
--> $DIR/const-drop-fail.rs:53:1
|
LL | &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| +
LL | &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ++++
LL | struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors
error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0367.
For more information about an error, try `rustc --explain E0277`.
12 changes: 11 additions & 1 deletion src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ trait A { fn a() { } }

impl A for NonTrivialDrop {}

struct ConstDropImplWithBounds<T: A>(PhantomData<T>);
struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);

impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
fn drop(&mut self) {
Expand All @@ -47,6 +47,16 @@ check_all! {
//~^ ERROR can't drop
ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
//~^ ERROR the trait bound
//~| ERROR the trait bound
}

struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);

impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
//~^ ERROR `Drop` impl requires `T: ~const A` but the struct it is implemented for does not
fn drop(&mut self) {
T::a();
}
}

fn main() {}
65 changes: 43 additions & 22 deletions src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -45,34 +45,55 @@ note: required by a bound in `check`
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`

error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Destruct` is not satisfied
error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
--> $DIR/const-drop-fail.rs:48:47
|
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ----------------------------------------- ^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
| |
| required by a bound introduced by this call
|
note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
--> $DIR/const-drop-fail.rs:48:47
|
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^
note: required by a bound in `ConstDropImplWithBounds`
--> $DIR/const-drop-fail.rs:27:35
|
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
| ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`

error[E0277]: the trait bound `NonTrivialDrop: ~const A` is not satisfied
--> $DIR/const-drop-fail.rs:48:5
|
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const A` is not implemented for `NonTrivialDrop`
|
note: the trait `A` is implemented for `NonTrivialDrop`, but that implementation is not `const`
--> $DIR/const-drop-fail.rs:48:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
...
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `ConstDropImplWithBounds<NonTrivialDrop>`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `ConstDropImplWithBounds`
--> $DIR/const-drop-fail.rs:27:35
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
--> $DIR/const-drop-fail.rs:29:25
LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
| ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`

error[E0367]: `Drop` impl requires `T: ~const A` but the struct it is implemented for does not
--> $DIR/const-drop-fail.rs:55:9
|
LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
| ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: 1 redundant requirement hidden
= note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:35:19
LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
| ^^^^^^^^
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`
help: consider borrowing here
note: the implementor must specify the same requirement
--> $DIR/const-drop-fail.rs:53:1
|
LL | &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| +
LL | &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ++++
LL | struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 3 previous errors
error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0277, E0367.
For more information about an error, try `rustc --explain E0277`.
2 changes: 1 addition & 1 deletion src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ mod t {
fn foo() {}
}

pub struct ConstDropWithBound<T: SomeTrait>(pub core::marker::PhantomData<T>);
pub struct ConstDropWithBound<T: ~const SomeTrait>(pub core::marker::PhantomData<T>);

impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
fn drop(&mut self) {
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/rfc-2632-const-trait-impl/tilde_const_on_impl_bound.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// check-pass
#![feature(const_trait_impl)]

#[const_trait]
trait Foo {
fn foo(&self) {}
}

struct Bar<T>(T);

impl<T: ~const Foo> Bar<T> {
const fn foo(&self) {
self.0.foo()
}
}

fn main() {}