Skip to content
Open
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
10 changes: 5 additions & 5 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3687,6 +3687,7 @@ pub struct TyAlias {
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct Impl {
pub generics: Generics,
pub constness: Const,
pub of_trait: Option<Box<TraitImplHeader>>,
pub self_ty: Box<Ty>,
pub items: ThinVec<Box<AssocItem>>,
Expand All @@ -3696,7 +3697,6 @@ pub struct Impl {
pub struct TraitImplHeader {
pub defaultness: Defaultness,
pub safety: Safety,
pub constness: Const,
pub polarity: ImplPolarity,
pub trait_ref: TraitRef,
}
Expand Down Expand Up @@ -4072,9 +4072,9 @@ mod size_asserts {
static_assert_size!(GenericArg, 24);
static_assert_size!(GenericBound, 88);
static_assert_size!(Generics, 40);
static_assert_size!(Impl, 64);
static_assert_size!(Item, 136);
static_assert_size!(ItemKind, 72);
static_assert_size!(Impl, 80);
static_assert_size!(Item, 152);
static_assert_size!(ItemKind, 88);
static_assert_size!(LitKind, 24);
static_assert_size!(Local, 96);
static_assert_size!(MetaItemLit, 40);
Expand All @@ -4085,7 +4085,7 @@ mod size_asserts {
static_assert_size!(PathSegment, 24);
static_assert_size!(Stmt, 32);
static_assert_size!(StmtKind, 16);
static_assert_size!(TraitImplHeader, 80);
static_assert_size!(TraitImplHeader, 72);
static_assert_size!(Ty, 64);
static_assert_size!(TyKind, 40);
// tidy-alphabetical-end
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -928,11 +928,11 @@ macro_rules! common_visitor_and_walkers {
}

impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| {
let Impl { generics, of_trait, self_ty, items } = self;
let Impl { generics, of_trait, self_ty, items, constness: _ } = self;
try_visit!(vis.visit_generics(generics));
if let Some(box of_trait) = of_trait {
let TraitImplHeader { defaultness, safety, constness, polarity, trait_ref } = of_trait;
visit_visitable!($($mut)? vis, defaultness, safety, constness, polarity, trait_ref);
let TraitImplHeader { defaultness, safety, polarity, trait_ref } = of_trait;
visit_visitable!($($mut)? vis, defaultness, safety, polarity, trait_ref);
}
try_visit!(vis.visit_ty(self_ty));
visit_visitable_with!($($mut)? vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() });
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
of_trait,
self_ty: ty,
items: impl_items,
constness,
}) => {
// Lower the "impl header" first. This ordering is important
// for in-band lifetimes! Consider `'a` here:
Expand Down Expand Up @@ -378,11 +379,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
.arena
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));

let constness = self.lower_constness(*constness);

hir::ItemKind::Impl(hir::Impl {
generics,
of_trait,
self_ty: lowered_ty,
items: new_impl_items,
constness,
})
}
ItemKind::Trait(box Trait {
Expand Down Expand Up @@ -970,9 +974,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
trait_impl_header: &TraitImplHeader,
) -> &'hir hir::TraitImplHeader<'hir> {
let TraitImplHeader { constness, safety, polarity, defaultness, ref trait_ref } =
*trait_impl_header;
let constness = self.lower_constness(constness);
let TraitImplHeader { safety, polarity, defaultness, ref trait_ref } = *trait_impl_header;
let safety = self.lower_safety(safety, hir::Safety::Safe);
let polarity = match polarity {
ImplPolarity::Positive => ImplPolarity::Positive,
Expand All @@ -995,7 +997,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
);

self.arena.alloc(hir::TraitImplHeader {
constness,
safety,
polarity,
defaultness,
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ ast_passes_generic_before_constraints = generic arguments must come before the f

ast_passes_generic_default_trailing = generic parameters with a default must be trailing

ast_passes_impl_fn_const =
redundant `const` fn marker in const impl
.parent_constness = this declares all associated functions implicitly const
.label = remove the `const`

ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
.help = remove one of these features

Expand Down
153 changes: 93 additions & 60 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,17 @@ enum SelfSemantic {
No,
}

enum TraitOrTraitImpl {
enum TraitOrImpl {
Trait { span: Span, constness: Const },
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
Impl { constness: Const },
}

impl TraitOrTraitImpl {
impl TraitOrImpl {
fn constness(&self) -> Option<Span> {
match self {
Self::Trait { constness: Const::Yes(span), .. }
| Self::Impl { constness: Const::Yes(span), .. }
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
_ => None,
}
Expand All @@ -69,7 +71,7 @@ struct AstValidator<'a> {
/// The span of the `extern` in an `extern { ... }` block, if any.
extern_mod_span: Option<Span>,

outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
outer_trait_or_trait_impl: Option<TraitOrImpl>,

has_proc_macro_decls: bool,

Expand All @@ -92,28 +94,12 @@ struct AstValidator<'a> {
}

impl<'a> AstValidator<'a> {
fn with_in_trait_impl(
fn with_in_trait_or_impl(
&mut self,
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
in_trait_or_impl: Option<TraitOrImpl>,
f: impl FnOnce(&mut Self),
) {
let old = mem::replace(
&mut self.outer_trait_or_trait_impl,
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
constness,
polarity,
trait_ref_span: trait_ref.path.span,
}),
);
f(self);
self.outer_trait_or_trait_impl = old;
}

fn with_in_trait(&mut self, span: Span, constness: Const, f: impl FnOnce(&mut Self)) {
let old = mem::replace(
&mut self.outer_trait_or_trait_impl,
Some(TraitOrTraitImpl::Trait { span, constness }),
);
let old = mem::replace(&mut self.outer_trait_or_trait_impl, in_trait_or_impl);
f(self);
self.outer_trait_or_trait_impl = old;
}
Expand Down Expand Up @@ -246,14 +232,26 @@ impl<'a> AstValidator<'a> {
}
}

fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
fn check_impl_fn_not_const(&self, constness: Const, parent_constness: Const) {
let Const::Yes(span) = constness else {
return;
};

let Const::Yes(parent_constness) = parent_constness else {
return;
};

self.dcx().emit_err(errors::ImplFnConst { span, parent_constness });
}

fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) {
let Const::Yes(span) = constness else {
return;
};

let const_trait_impl = self.features.const_trait_impl();
let make_impl_const_sugg = if const_trait_impl
&& let TraitOrTraitImpl::TraitImpl {
&& let TraitOrImpl::TraitImpl {
constness: Const::No,
polarity: ImplPolarity::Positive,
trait_ref_span,
Expand All @@ -266,7 +264,7 @@ impl<'a> AstValidator<'a> {
};

let make_trait_const_sugg = if const_trait_impl
&& let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent
&& let TraitOrImpl::Trait { span, constness: ast::Const::No } = parent
{
Some(span.shrink_to_lo())
} else {
Expand All @@ -276,7 +274,7 @@ impl<'a> AstValidator<'a> {
let parent_constness = parent.constness();
self.dcx().emit_err(errors::TraitFnConst {
span,
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
const_context_label: parent_constness,
remove_const_sugg: (
self.sess.source_map().span_extend_while_whitespace(span),
Expand All @@ -292,7 +290,7 @@ impl<'a> AstValidator<'a> {
});
}

fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrTraitImpl) {
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrImpl) {
let Some(const_keyword) = parent.constness() else { return };

let Some(CoroutineKind::Async { span: async_keyword, .. }) = sig.header.coroutine_kind
Expand All @@ -302,7 +300,7 @@ impl<'a> AstValidator<'a> {

self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl {
async_keyword,
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
const_keyword,
});
}
Expand Down Expand Up @@ -1011,14 +1009,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
match &item.kind {
ItemKind::Impl(Impl {
generics,
constness,
of_trait:
Some(box TraitImplHeader {
safety,
polarity,
defaultness: _,
constness,
trait_ref: t,
}),
Some(box TraitImplHeader { safety, polarity, defaultness: _, trait_ref: t }),
self_ty,
items,
}) => {
Expand Down Expand Up @@ -1046,24 +1039,46 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.visit_trait_ref(t);
self.visit_ty(self_ty);

self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
});
self.with_in_trait_or_impl(
Some(TraitOrImpl::TraitImpl {
constness: *constness,
polarity: *polarity,
trait_ref_span: t.path.span,
}),
|this| {
walk_list!(
this,
visit_assoc_item,
items,
AssocCtxt::Impl { of_trait: true }
);
},
);
}
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items }) => {
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness }) => {
self.visit_attrs_vis(&item.attrs, &item.vis);
self.visibility_not_permitted(
&item.vis,
errors::VisibilityNotPermittedNote::IndividualImplItems,
);

self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
this.visit_generics(generics)
});
let disallowed = matches!(constness, ast::Const::No)
.then(|| TildeConstReason::Impl { span: item.span });

self.with_tilde_const(disallowed, |this| this.visit_generics(generics));

self.visit_ty(self_ty);
self.with_in_trait_impl(None, |this| {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
});
self.with_in_trait_or_impl(
Some(TraitOrImpl::Impl { constness: *constness }),
|this| {
walk_list!(
this,
visit_assoc_item,
items,
AssocCtxt::Impl { of_trait: false }
);
},
);
}
ItemKind::Fn(
func @ box Fn {
Expand Down Expand Up @@ -1188,9 +1203,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
});
self.with_in_trait(item.span, constness, |this| {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
});
self.with_in_trait_or_impl(
Some(TraitOrImpl::Trait { span: item.span, constness }),
|this| {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
},
);
}
ItemKind::TraitAlias(box TraitAlias { constness, generics, bounds, .. }) => {
let disallowed = matches!(constness, ast::Const::No)
Expand Down Expand Up @@ -1558,7 +1576,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
&& self
.outer_trait_or_trait_impl
.as_ref()
.and_then(TraitOrTraitImpl::constness)
.and_then(TraitOrImpl::constness)
.is_some();

let disallowed = (!tilde_const_allowed).then(|| match fk {
Expand Down Expand Up @@ -1625,20 +1643,31 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
);
}

if let Some(parent) = &self.outer_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, parent);
self.check_async_fn_in_const_trait_or_impl(sig, parent);
match &self.outer_trait_or_trait_impl {
Some(parent @ (TraitOrImpl::Trait { .. } | TraitOrImpl::TraitImpl { .. })) => {
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, parent);
self.check_async_fn_in_const_trait_or_impl(sig, parent);
}
}
Some(TraitOrImpl::Impl { constness }) => {
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.check_impl_fn_not_const(sig.header.constness, *constness);
}
}
None => {}
}

if let AssocItemKind::Const(ci) = &item.kind {
self.check_item_named(ci.ident, "const");
}

let parent_is_const =
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrImpl::constness).is_some();

match &item.kind {
AssocItemKind::Fn(func)
Expand All @@ -1652,19 +1681,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
AssocItemKind::Type(_) => {
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
Some(TraitOrTraitImpl::Trait { .. }) => {
Some(TraitOrImpl::Trait { .. }) => {
TildeConstReason::TraitAssocTy { span: item.span }
}
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
Some(TraitOrImpl::TraitImpl { .. }) => {
TildeConstReason::TraitImplAssocTy { span: item.span }
}
None => TildeConstReason::InherentAssocTy { span: item.span },
Some(TraitOrImpl::Impl { .. }) | None => {
TildeConstReason::InherentAssocTy { span: item.span }
}
});
self.with_tilde_const(disallowed, |this| {
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
this.with_in_trait_or_impl(None, |this| {
visit::walk_assoc_item(this, item, ctxt)
})
})
}
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
_ => self.with_in_trait_or_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
}
}

Expand Down
Loading
Loading