Skip to content
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

Only allow ~const bounds for traits with #[const_trait] #102647

Merged
merged 2 commits into from
Oct 4, 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
26 changes: 0 additions & 26 deletions compiler/rustc_passes/src/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,32 +191,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
self.tcx.hir()
}

fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
let tcx = self.tcx;
if let hir::ItemKind::Impl(hir::Impl {
constness: hir::Constness::Const,
of_trait: Some(trait_ref),
..
}) = item.kind
&& let Some(def_id) = trait_ref.trait_def_id()
{
let source_map = tcx.sess.source_map();
if !tcx.has_attr(def_id, sym::const_trait) {
tcx.sess
.struct_span_err(
source_map.guess_head_span(item.span),
"const `impl`s must be for traits marked with `#[const_trait]`",
)
.span_note(
source_map.guess_head_span(tcx.def_span(def_id)),
"this trait must be annotated with `#[const_trait]`",
)
.emit();
}
}
intravisit::walk_item(self, item);
}

fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
let kind = Some(hir::ConstContext::Const);
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_trait_selection/src/traits/wf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,32 @@ impl<'tcx> WfPredicates<'tcx> {
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
} else {
if !tcx.has_attr(trait_ref.def_id, rustc_span::sym::const_trait) {
if let Some(item) = self.item &&
let hir::ItemKind::Impl(impl_) = item.kind &&
let Some(trait_) = &impl_.of_trait &&
let Some(def_id) = trait_.trait_def_id() &&
def_id == trait_ref.def_id
{
let trait_name = tcx.item_name(def_id);
let mut err = tcx.sess.struct_span_err(
self.span,
&format!("const `impl` for trait `{trait_name}` which is not marked with `#[const_trait]`"),
);
if def_id.is_local() {
let sp = tcx.def_span(def_id).shrink_to_lo();
err.span_suggestion(sp, &format!("mark `{trait_name}` as const"), "#[const_trait]", rustc_errors::Applicability::MachineApplicable);
}
err.note("marking a trait with `#[const_trait]` ensures all default method bodies are `const`");
err.note("adding a non-const method body in the future would be a breaking change");
err.emit();
} else {
tcx.sess.span_err(
self.span,
"~const can only be applied to `#[const_trait]` traits",
);
}
}
self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
};

Expand Down
2 changes: 1 addition & 1 deletion library/core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ pub trait IntoIterator {

#[rustc_const_unstable(feature = "const_intoiterator_identity", issue = "90603")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ~const Iterator> const IntoIterator for I {
impl<I: Iterator> const IntoIterator for I {
type Item = I::Item;
type IntoIter = I;

Expand Down
1 change: 1 addition & 0 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ impl<T: ?Sized> Unpin for *mut T {}
#[unstable(feature = "const_trait_impl", issue = "67792")]
#[lang = "destruct"]
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
#[const_trait]
pub trait Destruct {}

/// A marker for tuple types.
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/consts/const-fn-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ LL | for i in 0..x {
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | impl<I: ~const Iterator> const IntoIterator for I {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<I: Iterator> const IntoIterator for I {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error[E0658]: mutable references are not allowed in constant functions
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/consts/const-for.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ LL | for _ in 0..5 {}
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | impl<I: ~const Iterator> const IntoIterator for I {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<I: Iterator> const IntoIterator for I {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
Expand Down
1 change: 1 addition & 0 deletions src/test/ui/consts/constifconst-call-in-const-position.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#![feature(const_trait_impl, generic_const_exprs)]

#[const_trait]
pub trait Tr {
fn a() -> usize;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ LL | #![feature(const_trait_impl, generic_const_exprs)]
= note: `#[warn(incomplete_features)]` on by default

error[E0080]: evaluation of `foo::<()>::{constant#0}` failed
--> $DIR/constifconst-call-in-const-position.rs:15:38
--> $DIR/constifconst-call-in-const-position.rs:16:38
|
LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
| ^^^^^^ calling non-const function `<() as Tr>::a`
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/never_type/issue-52443.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ LL | [(); { for _ in 0usize.. {}; 0}];
note: impl defined here, but it is not `const`
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
|
LL | impl<I: ~const Iterator> const IntoIterator for I {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | impl<I: Iterator> const IntoIterator for I {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

error[E0658]: mutable references are not allowed in constants
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@

struct S;

impl PartialEq for S {
#[const_trait]
trait Foo {
fn eq(&self, _: &Self) -> bool;
}

impl Foo for S {
fn eq(&self, _: &S) -> bool {
true
}
}

const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
const fn equals_self<T: ~const Foo>(t: &T) -> bool {
true
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
error[E0277]: can't compare `S` with `S` in const contexts
--> $DIR/call-generic-method-nonconst.rs:18:34
error[E0277]: the trait bound `S: ~const Foo` is not satisfied
--> $DIR/call-generic-method-nonconst.rs:23:34
|
LL | pub const EQ: bool = equals_self(&S);
| ----------- ^^ no implementation for `S == S`
| ----------- ^^ the trait `~const Foo` is not implemented for `S`
| |
| required by a bound introduced by this call
|
= help: the trait `~const PartialEq` is not implemented for `S`
note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const`
--> $DIR/call-generic-method-nonconst.rs:18:34
note: the trait `Foo` is implemented for `S`, but that implementation is not `const`
--> $DIR/call-generic-method-nonconst.rs:23:34
|
LL | pub const EQ: bool = equals_self(&S);
| ^^
note: required by a bound in `equals_self`
--> $DIR/call-generic-method-nonconst.rs:11:25
|
LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
| ^^^^^^^^^^^^^^^^ required by this bound in `equals_self`
help: consider annotating `S` with `#[derive(PartialEq)]`
|
LL | #[derive(PartialEq)]
--> $DIR/call-generic-method-nonconst.rs:16:25
|
LL | const fn equals_self<T: ~const Foo>(t: &T) -> bool {
| ^^^^^^^^^^ required by this bound in `equals_self`

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0277]: can't drop `NonTrivialDrop` in const contexts
--> $DIR/const-drop-fail.rs:43:5
--> $DIR/const-drop-fail.rs:44:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -9,7 +9,7 @@ LL | NonTrivialDrop,
|
= note: the trait bound `NonTrivialDrop: ~const Destruct` is not satisfied
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:34:19
--> $DIR/const-drop-fail.rs:35:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`
Expand All @@ -21,7 +21,7 @@ LL | &mut NonTrivialDrop,
| ++++

error[E0277]: can't drop `NonTrivialDrop` in const contexts
--> $DIR/const-drop-fail.rs:45:5
--> $DIR/const-drop-fail.rs:46:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -30,7 +30,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Destruct` is not implemented for `NonTrivialDrop`
|
note: the trait `Destruct` is implemented for `NonTrivialDrop`, but that implementation is not `const`
--> $DIR/const-drop-fail.rs:45:5
--> $DIR/const-drop-fail.rs:46:5
|
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -40,13 +40,13 @@ note: required because it appears within the type `ConstImplWithDropGlue`
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:34:19
--> $DIR/const-drop-fail.rs:35:19
|
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
--> $DIR/const-drop-fail.rs:47:5
--> $DIR/const-drop-fail.rs:48:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -55,14 +55,14 @@ LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `ConstDropImplWithBounds<NonTrivialDrop>`
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
--> $DIR/const-drop-fail.rs:28:25
--> $DIR/const-drop-fail.rs:29:25
|
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:34:19
--> $DIR/const-drop-fail.rs:35:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`
Expand Down
3 changes: 2 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 @@ -19,7 +19,8 @@ impl const Drop for ConstImplWithDropGlue {
fn drop(&mut self) {}
}

trait A { fn a() { println!("A"); } }
#[const_trait]
trait A { fn a() { } }

impl A for NonTrivialDrop {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0277]: can't drop `NonTrivialDrop` in const contexts
--> $DIR/const-drop-fail.rs:43:5
--> $DIR/const-drop-fail.rs:44:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -9,7 +9,7 @@ LL | NonTrivialDrop,
|
= note: the trait bound `NonTrivialDrop: ~const Destruct` is not satisfied
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:34:19
--> $DIR/const-drop-fail.rs:35:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`
Expand All @@ -21,7 +21,7 @@ LL | &mut NonTrivialDrop,
| ++++

error[E0277]: can't drop `NonTrivialDrop` in const contexts
--> $DIR/const-drop-fail.rs:45:5
--> $DIR/const-drop-fail.rs:46:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -30,7 +30,7 @@ LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Destruct` is not implemented for `NonTrivialDrop`
|
note: the trait `Destruct` is implemented for `NonTrivialDrop`, but that implementation is not `const`
--> $DIR/const-drop-fail.rs:45:5
--> $DIR/const-drop-fail.rs:46:5
|
LL | ConstImplWithDropGlue(NonTrivialDrop),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -40,13 +40,13 @@ note: required because it appears within the type `ConstImplWithDropGlue`
LL | struct ConstImplWithDropGlue(NonTrivialDrop);
| ^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `check`
--> $DIR/const-drop-fail.rs:34:19
--> $DIR/const-drop-fail.rs:35:19
|
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
--> $DIR/const-drop-fail.rs:47:5
--> $DIR/const-drop-fail.rs:48:5
|
LL | const _: () = check($exp);
| ----- required by a bound introduced by this call
Expand All @@ -55,14 +55,14 @@ LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `~const Destruct` is not implemented for `ConstDropImplWithBounds<NonTrivialDrop>`
|
note: required for `ConstDropImplWithBounds<NonTrivialDrop>` to implement `~const Destruct`
--> $DIR/const-drop-fail.rs:28:25
--> $DIR/const-drop-fail.rs:29:25
|
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:34:19
--> $DIR/const-drop-fail.rs:35:19
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^^^^^^^^^^^^^^^ required by this bound in `check`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![feature(const_trait_impl)]

pub trait A {}
//~^ NOTE: this trait must be annotated with `#[const_trait]`
//~^ HELP: mark `A` as const

impl const A for () {}
//~^ ERROR: const `impl`s must be for traits marked with `#[const_trait]`
//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]`

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
error: const `impl`s must be for traits marked with `#[const_trait]`
--> $DIR/const-impl-requires-const-trait.rs:6:1
error: const `impl` for trait `A` which is not marked with `#[const_trait]`
--> $DIR/const-impl-requires-const-trait.rs:6:12
|
LL | pub trait A {}
| - help: mark `A` as const: `#[const_trait]`
...
LL | impl const A for () {}
| ^^^^^^^^^^^^^^^^^^^
|
note: this trait must be annotated with `#[const_trait]`
--> $DIR/const-impl-requires-const-trait.rs:3:1
| ^
|
LL | pub trait A {}
| ^^^^^^^^^^^
= note: marking a trait with `#[const_trait]` ensures all default method bodies are `const`
= note: adding a non-const method body in the future would be a breaking change

error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![feature(const_trait_impl)]

#[const_trait]
trait Tr {}
impl Tr for () {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
--> $DIR/default-method-body-is-const-body-checking.rs:11:15
--> $DIR/default-method-body-is-const-body-checking.rs:12:15
|
LL | foo::<()>();
| ^^ the trait `~const Tr` is not implemented for `()`
|
note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
--> $DIR/default-method-body-is-const-body-checking.rs:11:15
--> $DIR/default-method-body-is-const-body-checking.rs:12:15
|
LL | foo::<()>();
| ^^
note: required by a bound in `foo`
--> $DIR/default-method-body-is-const-body-checking.rs:6:28
--> $DIR/default-method-body-is-const-body-checking.rs:7:28
|
LL | const fn foo<T>() where T: ~const Tr {}
| ^^^^^^^^^ required by this bound in `foo`
Expand Down
Loading