diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 9bdbcf6ab9071..f03c7dd5b9d59 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -89,6 +89,9 @@ ast_passes_const_and_coroutine = functions cannot be both `const` and `{$corouti .coroutine = `{$coroutine_kind}` because of this .label = {""} +ast_passes_const_auto_trait = auto traits cannot be const + .help = remove the `const` keyword + ast_passes_const_bound_trait_object = const trait bounds are not allowed in trait object types ast_passes_const_without_body = diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 163dbc3350ba2..e57f8da26769b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -820,6 +820,12 @@ impl<'a> AstValidator<'a> { self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name }); } + fn deny_const_auto_traits(&self, constness: Const) { + if let Const::Yes(span) = constness { + self.dcx().emit_err(errors::ConstAutoTrait { span }); + } + } + fn deny_generic_params(&self, generics: &Generics, ident_span: Span) { if !generics.params.is_empty() { self.dcx() @@ -1257,6 +1263,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); if *is_auto == IsAuto::Yes { + // For why we reject `const auto trait`, see rust-lang/rust#149285. + self.deny_const_auto_traits(*constness); // Auto traits cannot have generics, super traits nor contain items. self.deny_generic_params(generics, ident.span); self.deny_super_traits(bounds, ident.span); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 02e6ecfbaee74..c700ae517140c 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -429,6 +429,14 @@ pub(crate) struct AutoTraitItems { pub ident: Span, } +#[derive(Diagnostic)] +#[diag(ast_passes_const_auto_trait)] +#[help] +pub(crate) struct ConstAutoTrait { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_passes_generic_before_constraints)] pub(crate) struct ArgsBeforeConstraint { diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 2cb79a0219f6e..2837b8565f603 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -189,10 +189,11 @@ where } fn consider_auto_trait_candidate( - _ecx: &mut EvalCtxt<'_, D>, + ecx: &mut EvalCtxt<'_, D>, _goal: Goal, ) -> Result, NoSolution> { - unreachable!("auto traits are never const") + ecx.cx().delay_bug("auto traits are never const"); + Err(NoSolution) } fn consider_trait_alias_candidate( diff --git a/tests/ui/traits/const-traits/const-auto-trait.rs b/tests/ui/traits/const-traits/const-auto-trait.rs new file mode 100644 index 0000000000000..d1745a2ec4c72 --- /dev/null +++ b/tests/ui/traits/const-traits/const-auto-trait.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Znext-solver +// See rust-lang/rust#149285 for this test + +#![feature(auto_traits, const_trait_impl)] + +const auto trait Marker {} +//~^ ERROR: auto traits cannot be const + +fn scope() { + fn check() {} + check::<()>(); + //~^ ERROR: the trait bound `(): const Marker` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/const-auto-trait.stderr b/tests/ui/traits/const-traits/const-auto-trait.stderr new file mode 100644 index 0000000000000..094c334fc2897 --- /dev/null +++ b/tests/ui/traits/const-traits/const-auto-trait.stderr @@ -0,0 +1,23 @@ +error: auto traits cannot be const + --> $DIR/const-auto-trait.rs:6:1 + | +LL | const auto trait Marker {} + | ^^^^^ + | + = help: remove the `const` keyword + +error[E0277]: the trait bound `(): const Marker` is not satisfied + --> $DIR/const-auto-trait.rs:11:13 + | +LL | check::<()>(); + | ^^ + | +note: required by a bound in `check` + --> $DIR/const-auto-trait.rs:10:17 + | +LL | fn check() {} + | ^^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/parse-const-unsafe-trait.rs b/tests/ui/traits/const-traits/parse-const-unsafe-trait.rs index 3d62405d9ae20..58a3b5a4cc61f 100644 --- a/tests/ui/traits/const-traits/parse-const-unsafe-trait.rs +++ b/tests/ui/traits/const-traits/parse-const-unsafe-trait.rs @@ -1,5 +1,6 @@ // Test that `const unsafe trait` and `const unsafe auto trait` works. +//@ compile-flags: -Zparse-crate-root-only //@ check-pass #![feature(const_trait_impl)]