Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rust-lang/rust
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: cab9f8cec89c8fa727b4059a518257c91467a535
Choose a base ref
..
head repository: rust-lang/rust
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 50d96c7981e0e4998e5102e9e940f3fd3c265b80
Choose a head ref
4 changes: 3 additions & 1 deletion compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
@@ -241,8 +241,10 @@ ast_passes_trait_fn_const =
[true] trait impls
*[false] traits
} cannot be const
.const_context_label = this declares all functions implicitly const
.const_context_label = this declares all associated functions implicitly const
.remove_const_sugg = remove the `const`
.make_impl_const_sugg = and declare the impl to be const instead
.make_trait_const_sugg = and declare the trait to be a `#[const_trait]` instead
ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
116 changes: 75 additions & 41 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
@@ -46,20 +46,33 @@ enum DisallowTildeConstContext<'a> {
Item,
}

enum TraitOrImpl<'a> {
Trait { span: Span, constness: Option<Span> },
Impl { trait_: Option<(Const, ImplPolarity, &'a TraitRef)> },
}

impl<'a> TraitOrImpl<'a> {
fn constness(&self) -> Option<Span> {
match self {
Self::Trait { constness: Some(span), .. }
| Self::Impl { trait_: Some((Const::Yes(span), ..)) } => Some(*span),
_ => None,
}
}

fn is_trait_or_trait_impl(&self) -> bool {
matches!(self, Self::Trait { .. } | Self::Impl { trait_: Some(_) })
}
}

struct AstValidator<'a> {
session: &'a Session,
features: &'a Features,

/// The span of the `extern` in an `extern { ... }` block, if any.
extern_mod: Option<&'a Item>,

/// Are we inside a trait impl?
in_trait_impl: bool,

/// Are we inside a const trait defn or impl?
///
/// If so, this is the span of the constness.
in_const_trait_or_impl: Option<Span>,
outer_trait_or_impl: Option<TraitOrImpl<'a>>,

has_proc_macro_decls: bool,

@@ -80,27 +93,24 @@ struct AstValidator<'a> {
impl<'a> AstValidator<'a> {
fn with_in_trait_impl(
&mut self,
is_in: bool,
constness: Option<Const>,
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
f: impl FnOnce(&mut Self),
) {
let old = mem::replace(&mut self.in_trait_impl, is_in);
let old_const = mem::replace(
&mut self.in_const_trait_or_impl,
match constness {
Some(Const::Yes(span)) => Some(span),
_ => None,
},
let old = mem::replace(
&mut self.outer_trait_or_impl,
trait_.map(|trait_| TraitOrImpl::Impl { trait_: Some(trait_) }),
);
f(self);
self.in_trait_impl = old;
self.in_const_trait_or_impl = old_const;
self.outer_trait_or_impl = old;
}

fn with_in_trait(&mut self, is_const: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.in_const_trait_or_impl, is_const);
fn with_in_trait(&mut self, span: Span, constness: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(
&mut self.outer_trait_or_impl,
Some(TraitOrImpl::Trait { span, constness }),
);
f(self);
self.in_const_trait_or_impl = old;
self.outer_trait_or_impl = old;
}

fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
@@ -296,18 +306,42 @@ impl<'a> AstValidator<'a> {
}
}

fn check_trait_fn_not_const(&self, constness: Const) {
fn check_trait_fn_not_const(&self, constness: Const, trait_or_impl: &TraitOrImpl<'a>) {
let Const::Yes(span) = constness else {
return;
};

// FIXME(const_trait_impl): If the trait or impl is not const and feature `const_trait_impl`
// is enabled, provide a structured suggestion to make the trait (impl) const.
let make_impl_const_sugg = if self.features.const_trait_impl
&& let TraitOrImpl::Impl { trait_: Some(trait_) } = trait_or_impl
&& let (Const::No, ImplPolarity::Positive, trait_ref) = trait_
{
Some(trait_ref.path.span.shrink_to_lo())
} else {
None
};

let make_trait_const_sugg = if self.features.const_trait_impl
&& let TraitOrImpl::Trait { span, constness: None } = trait_or_impl
{
Some(span.shrink_to_lo())
} else {
None
};

let parent_constness = trait_or_impl.constness();
self.dcx().emit_err(errors::TraitFnConst {
span,
in_impl: self.in_trait_impl,
const_context_label: self.in_const_trait_or_impl,
remove_const_sugg: self.in_const_trait_or_impl.map(|_| span),
in_impl: matches!(trait_or_impl, TraitOrImpl::Impl { .. }),
const_context_label: parent_constness,
remove_const_sugg: (
self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span),
match parent_constness {
Some(_) => rustc_errors::Applicability::MachineApplicable,
None => rustc_errors::Applicability::MaybeIncorrect,
},
),
make_impl_const_sugg,
make_trait_const_sugg,
});
}

@@ -831,7 +865,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self_ty,
items,
}) => {
self.with_in_trait_impl(true, Some(*constness), |this| {
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
this.visibility_not_permitted(
&item.vis,
errors::VisibilityNotPermittedNote::TraitImpl,
@@ -979,7 +1013,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
ItemKind::Trait(box Trait { is_auto, generics, bounds, items, .. }) => {
let is_const_trait =
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
self.with_in_trait(is_const_trait, |this| {
self.with_in_trait(item.span, is_const_trait, |this| {
if *is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items.
this.deny_generic_params(generics, item.ident.span);
@@ -1356,10 +1390,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}

let tilde_const_allowed = matches!(
fk.header(),
Some(FnHeader { constness: ast::Const::Yes(_), .. })
) || matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)) if self.in_const_trait_or_impl.is_some());
let tilde_const_allowed =
matches!(fk.header(), Some(FnHeader { constness: ast::Const::Yes(_), .. }))
|| matches!(fk.ctxt(), Some(FnCtxt::Assoc(_)))
&& self.outer_trait_or_impl.as_ref().and_then(TraitOrImpl::constness).is_some();

let disallowed = (!tilde_const_allowed).then(|| DisallowTildeConstContext::Fn(fk));
self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
@@ -1370,7 +1404,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_nomangle_item_asciionly(item.ident, item.span);
}

if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
if self.outer_trait_or_impl.as_ref().is_some_and(TraitOrImpl::is_trait_or_trait_impl) {
self.check_defaultness(item.span, item.kind.defaultness());
}

@@ -1418,10 +1452,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
}

if ctxt == AssocCtxt::Trait || self.in_trait_impl {
if let Some(trait_or_impl) = &self.outer_trait_or_impl
&& trait_or_impl.is_trait_or_trait_impl()
{
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_const(sig.header.constness, trait_or_impl);
}
}

@@ -1431,7 +1467,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {

match &item.kind {
AssocItemKind::Fn(box Fn { sig, generics, body, .. })
if self.in_const_trait_or_impl.is_some()
if self.outer_trait_or_impl.as_ref().and_then(TraitOrImpl::constness).is_some()
|| ctxt == AssocCtxt::Trait
|| matches!(sig.header.constness, Const::Yes(_)) =>
{
@@ -1447,8 +1483,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
self.visit_fn(kind, item.span, item.id);
}
_ => self
.with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
}
}
}
@@ -1564,8 +1599,7 @@ pub fn check_crate(
session,
features,
extern_mod: None,
in_trait_impl: false,
in_const_trait_or_impl: None,
outer_trait_or_impl: None,
has_proc_macro_decls: false,
outer_impl_trait: None,
disallow_tilde_const: Some(DisallowTildeConstContext::Item),
18 changes: 15 additions & 3 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Errors emitted by ast_passes.
use rustc_ast::ParamKindOrd;
use rustc_errors::AddToDiagnostic;
use rustc_errors::{AddToDiagnostic, Applicability};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol};

@@ -52,8 +52,20 @@ pub struct TraitFnConst {
pub in_impl: bool,
#[label(ast_passes_const_context_label)]
pub const_context_label: Option<Span>,
#[suggestion(ast_passes_remove_const_sugg, code = "", applicability = "machine-applicable")]
pub remove_const_sugg: Option<Span>,
#[suggestion(ast_passes_remove_const_sugg, code = "")]
pub remove_const_sugg: (Span, Applicability),
#[suggestion(
ast_passes_make_impl_const_sugg,
code = "const ",
applicability = "maybe-incorrect"
)]
pub make_impl_const_sugg: Option<Span>,
#[suggestion(
ast_passes_make_trait_const_sugg,
code = "#[const_trait]\n",
applicability = "maybe-incorrect"
)]
pub make_trait_const_sugg: Option<Span>,
}

#[derive(Diagnostic)]
5 changes: 4 additions & 1 deletion tests/ui/consts/const-fn-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -2,7 +2,10 @@ error[E0379]: functions in trait impls cannot be declared const
--> $DIR/const-fn-mismatch.rs:11:5
|
LL | const fn f() -> u32 {
| ^^^^^ functions in trait impls cannot be const
| ^^^^^-
| |
| functions in trait impls cannot be const
| help: remove the `const`

error: aborting due to 1 previous error

10 changes: 8 additions & 2 deletions tests/ui/consts/const-fn-not-in-trait.stderr
Original file line number Diff line number Diff line change
@@ -2,13 +2,19 @@ error[E0379]: functions in traits cannot be declared const
--> $DIR/const-fn-not-in-trait.rs:5:5
|
LL | const fn f() -> u32;
| ^^^^^ functions in traits cannot be const
| ^^^^^-
| |
| functions in traits cannot be const
| help: remove the `const`

error[E0379]: functions in traits cannot be declared const
--> $DIR/const-fn-not-in-trait.rs:7:5
|
LL | const fn g() -> u32 {
| ^^^^^ functions in traits cannot be const
| ^^^^^-
| |
| functions in traits cannot be const
| help: remove the `const`

error: aborting due to 2 previous errors

5 changes: 4 additions & 1 deletion tests/ui/consts/issue-54954.stderr
Original file line number Diff line number Diff line change
@@ -2,7 +2,10 @@ error[E0379]: functions in traits cannot be declared const
--> $DIR/issue-54954.rs:5:5
|
LL | const fn const_val<T: Sized>() -> usize {
| ^^^^^ functions in traits cannot be const
| ^^^^^-
| |
| functions in traits cannot be const
| help: remove the `const`

error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> $DIR/issue-54954.rs:1:24
15 changes: 12 additions & 3 deletions tests/ui/feature-gates/feature-gate-min_const_fn.stderr
Original file line number Diff line number Diff line change
@@ -2,19 +2,28 @@ error[E0379]: functions in traits cannot be declared const
--> $DIR/feature-gate-min_const_fn.rs:6:5
|
LL | const fn foo() -> u32;
| ^^^^^ functions in traits cannot be const
| ^^^^^-
| |
| functions in traits cannot be const
| help: remove the `const`

error[E0379]: functions in traits cannot be declared const
--> $DIR/feature-gate-min_const_fn.rs:7:5
|
LL | const fn bar() -> u32 { 0 }
| ^^^^^ functions in traits cannot be const
| ^^^^^-
| |
| functions in traits cannot be const
| help: remove the `const`

error[E0379]: functions in trait impls cannot be declared const
--> $DIR/feature-gate-min_const_fn.rs:11:5
|
LL | const fn foo() -> u32 { 0 }
| ^^^^^ functions in trait impls cannot be const
| ^^^^^-
| |
| functions in trait impls cannot be const
| help: remove the `const`

error: aborting due to 3 previous errors

10 changes: 8 additions & 2 deletions tests/ui/mismatched_types/const-fn-in-trait.stderr
Original file line number Diff line number Diff line change
@@ -2,13 +2,19 @@ error[E0379]: functions in traits cannot be declared const
--> $DIR/const-fn-in-trait.rs:3:5
|
LL | const fn g();
| ^^^^^ functions in traits cannot be const
| ^^^^^-
| |
| functions in traits cannot be const
| help: remove the `const`

error[E0379]: functions in trait impls cannot be declared const
--> $DIR/const-fn-in-trait.rs:7:5
|
LL | const fn f() -> u32 { 22 }
| ^^^^^ functions in trait impls cannot be const
| ^^^^^-
| |
| functions in trait impls cannot be const
| help: remove the `const`

error: aborting due to 2 previous errors

Loading