Skip to content

parse const trait Trait #143879

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3637,6 +3637,7 @@ impl Default for FnHeader {

#[derive(Clone, Encodable, Decodable, Debug)]
pub struct Trait {
pub constness: Const,
pub safety: Safety,
pub is_auto: IsAuto,
pub ident: Ident,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,8 @@ macro_rules! common_visitor_and_walkers {
try_visit!(vis.visit_ty(self_ty));
visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() })
}
ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => {
ItemKind::Trait(box Trait { constness, safety, is_auto: _, ident, generics, bounds, items }) => {
try_visit!(visit_constness(vis, constness));
try_visit!(visit_safety(vis, safety));
try_visit!(vis.visit_ident(ident));
try_visit!(vis.visit_generics(generics));
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
items: new_impl_items,
}))
}
ItemKind::Trait(box Trait { is_auto, safety, ident, generics, bounds, items }) => {
ItemKind::Trait(box Trait {
constness,
is_auto,
safety,
ident,
generics,
bounds,
items,
}) => {
let constness = self.lower_constness(*constness);
let ident = self.lower_ident(*ident);
let (generics, (safety, items, bounds)) = self.lower_generics(
generics,
Expand All @@ -435,7 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
(safety, items, bounds)
},
);
hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items)
hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items)
}
ItemKind::TraitAlias(ident, generics, bounds) => {
let ident = self.lower_ident(*ident);
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,10 @@ ast_passes_static_without_body =
ast_passes_tilde_const_disallowed = `[const]` is not allowed here
.closure = closures cannot have `[const]` trait bounds
.function = this function is not `const`, so it cannot have `[const]` trait bounds
.trait = this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds
.trait = this trait is not `const`, so it cannot have `[const]` trait bounds
.trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds
.impl = inherent impls cannot have `[const]` trait bounds
.trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds
.trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds
.trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds
.inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds
.object = trait objects cannot have `[const]` trait bounds
Expand Down
38 changes: 23 additions & 15 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ enum SelfSemantic {
}

enum TraitOrTraitImpl {
Trait { span: Span, constness_span: Option<Span> },
Trait { span: Span, constness: Const },
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
}

impl TraitOrTraitImpl {
fn constness(&self) -> Option<Span> {
match self {
Self::Trait { constness_span: Some(span), .. }
Self::Trait { constness: Const::Yes(span), .. }
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
_ => None,
}
Expand Down Expand Up @@ -110,15 +110,10 @@ impl<'a> AstValidator<'a> {
self.outer_trait_or_trait_impl = old;
}

fn with_in_trait(
&mut self,
span: Span,
constness_span: Option<Span>,
f: impl FnOnce(&mut Self),
) {
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_span }),
Some(TraitOrTraitImpl::Trait { span, constness }),
);
f(self);
self.outer_trait_or_trait_impl = old;
Expand Down Expand Up @@ -273,7 +268,7 @@ impl<'a> AstValidator<'a> {
};

let make_trait_const_sugg = if const_trait_impl
&& let TraitOrTraitImpl::Trait { span, constness_span: None } = parent
&& let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent
{
Some(span.shrink_to_lo())
} else {
Expand Down Expand Up @@ -1131,10 +1126,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
visit::walk_item(self, item)
}
ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => {
ItemKind::Trait(box Trait {
constness,
is_auto,
generics,
ident,
bounds,
items,
..
}) => {
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
let is_const_trait =
// FIXME(const_trait_impl) remove this
let alt_const_trait_span =
attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span);
let constness = match (*constness, alt_const_trait_span) {
(Const::Yes(span), _) | (Const::No, Some(span)) => Const::Yes(span),
(Const::No, None) => Const::No,
};
if *is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items.
self.deny_generic_params(generics, ident.span);
Expand All @@ -1145,13 +1153,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {

// Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound
// context for the supertraits.
let disallowed =
is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span });
let disallowed = matches!(constness, ast::Const::No)
.then(|| TildeConstReason::Trait { span: item.span });
self.with_tilde_const(disallowed, |this| {
this.visit_generics(generics);
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
});
self.with_in_trait(item.span, is_const_trait, |this| {
self.with_in_trait(item.span, constness, |this| {
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
});
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ pub(crate) struct ConstBoundTraitObject {
}

// FIXME(const_trait_impl): Consider making the note/reason the message of the diagnostic.
// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here).
// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` here).
#[derive(Diagnostic)]
#[diag(ast_passes_tilde_const_disallowed)]
pub(crate) struct TildeConstDisallowed {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ impl<'a> State<'a> {
self.bclose(item.span, empty, cb);
}
ast::ItemKind::Trait(box ast::Trait {
constness,
safety,
is_auto,
ident,
Expand All @@ -366,6 +367,7 @@ impl<'a> State<'a> {
}) => {
let (cb, ib) = self.head("");
self.print_visibility(&item.vis);
self.print_constness(*constness);
self.print_safety(*safety);
self.print_is_auto(*is_auto);
self.word_nbsp("trait");
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
}

// FIXME(const_trait_impl): remove this
// Const traits

pub(crate) struct ConstTraitParser;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub fn rustc_allow_const_fn_unstable(
/// world into two functions: those that are safe to expose on stable (and hence may not use
/// unstable features, not even recursively), and those that are not.
pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// A default body in a `#[const_trait]` is const-stable when the trait is const-stable.
// A default body in a `const trait` is const-stable when the trait is const-stable.
if tcx.is_const_default_method(def_id) {
return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id));
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
if let ty::InstanceKind::Item(def) = instance.def {
// Execution might have wandered off into other crates, so we cannot do a stability-
// sensitive check here. But we can at least rule out functions that are not const at
// all. That said, we have to allow calling functions inside a trait marked with
// #[const_trait]. These *are* const-checked!
// all. That said, we have to allow calling functions inside a `const trait`. These
// *are* const-checked!
if !ecx.tcx.is_const_fn(def) || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) {
// We certainly do *not* want to actually call the fn
// though, so be sure we return here.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),

// RFC 2632
// FIXME(const_trait_impl) remove this
gated!(
const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl,
"`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \
Expand Down
19 changes: 14 additions & 5 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4157,15 +4157,16 @@ impl<'hir> Item<'hir> {

expect_trait,
(
Constness,
IsAuto,
Safety,
Ident,
&'hir Generics<'hir>,
GenericBounds<'hir>,
&'hir [TraitItemId]
),
ItemKind::Trait(is_auto, safety, ident, generics, bounds, items),
(*is_auto, *safety, *ident, generics, bounds, items);
ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items),
(*constness, *is_auto, *safety, *ident, generics, bounds, items);

expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds);
Expand Down Expand Up @@ -4335,7 +4336,15 @@ pub enum ItemKind<'hir> {
/// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
Union(Ident, &'hir Generics<'hir>, VariantData<'hir>),
/// A trait definition.
Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemId]),
Trait(
Constness,
IsAuto,
Safety,
Ident,
&'hir Generics<'hir>,
GenericBounds<'hir>,
&'hir [TraitItemId],
),
/// A trait alias.
TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>),

Expand Down Expand Up @@ -4379,7 +4388,7 @@ impl ItemKind<'_> {
| ItemKind::Enum(ident, ..)
| ItemKind::Struct(ident, ..)
| ItemKind::Union(ident, ..)
| ItemKind::Trait(_, _, ident, ..)
| ItemKind::Trait(_, _, _, ident, ..)
| ItemKind::TraitAlias(ident, ..) => Some(ident),

ItemKind::Use(_, UseKind::Glob | UseKind::ListStem)
Expand All @@ -4397,7 +4406,7 @@ impl ItemKind<'_> {
| ItemKind::Enum(_, generics, _)
| ItemKind::Struct(_, generics, _)
| ItemKind::Union(_, generics, _)
| ItemKind::Trait(_, _, _, generics, _, _)
| ItemKind::Trait(_, _, _, _, generics, _, _)
| ItemKind::TraitAlias(_, generics, _)
| ItemKind::Impl(Impl { generics, .. }) => generics,
_ => return None,
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_variant_data(struct_definition));
}
ItemKind::Trait(_is_auto, _safety, ident, ref generics, bounds, trait_item_refs) => {
ItemKind::Trait(
_constness,
_is_auto,
_safety,
ident,
ref generics,
bounds,
trait_item_refs,
) => {
try_visit!(visitor.visit_ident(ident));
try_visit!(visitor.visit_generics(generics));
walk_list!(visitor, visit_param_bound, bounds);
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s
hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found
hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `#[const_trait]` traits
hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `const` traits
.label = can't be applied to `{$trait_name}`
.note = `{$trait_name}` can't be used with `{$modifier}` because it isn't annotated with `#[const_trait]`
.suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations
.note = `{$trait_name}` can't be used with `{$modifier}` because it isn't `const`
.suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations
hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not `const`
.label = this trait is not `const`
.suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations
.note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
.suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations
.note = marking a trait with `const` ensures all default method bodies are `const`
.adding = adding a non-const method body in the future would be a breaking change
hir_analysis_const_param_ty_impl_on_non_adt =
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -844,15 +844,20 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
let item = tcx.hir_expect_item(def_id);

let (is_alias, is_auto, safety) = match item.kind {
hir::ItemKind::Trait(is_auto, safety, ..) => (false, is_auto == hir::IsAuto::Yes, safety),
hir::ItemKind::TraitAlias(..) => (true, false, hir::Safety::Safe),
let (constness, is_alias, is_auto, safety) = match item.kind {
hir::ItemKind::Trait(constness, is_auto, safety, ..) => {
(constness, false, is_auto == hir::IsAuto::Yes, safety)
}
hir::ItemKind::TraitAlias(..) => (hir::Constness::NotConst, true, false, hir::Safety::Safe),
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
};

let attrs = tcx.get_all_attrs(def_id);
// Only regular traits can be const.
let constness = if !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) {
// FIXME(const_trait_impl): remove this
let constness = if constness == hir::Constness::Const
|| !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_))
{
hir::Constness::Const
} else {
hir::Constness::NotConst
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
.map(|t| ty::Binder::dummy(t.instantiate_identity()));
}
}
ItemKind::Trait(_, _, _, _, self_bounds, ..)
ItemKind::Trait(_, _, _, _, _, self_bounds, ..)
| ItemKind::TraitAlias(_, _, self_bounds) => {
is_trait = Some((self_bounds, item.span));
}
Expand Down Expand Up @@ -1006,7 +1006,7 @@ pub(super) fn const_conditions<'tcx>(
Node::Item(item) => match item.kind {
hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
hir::ItemKind::Fn { generics, .. } => (generics, None, false),
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => {
hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => {
(generics, Some((item.owner_id.def_id, supertraits)), false)
}
_ => bug!("const_conditions called on wrong item: {def_id:?}"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
| hir::ItemKind::Enum(_, generics, _)
| hir::ItemKind::Struct(_, generics, _)
| hir::ItemKind::Union(_, generics, _)
| hir::ItemKind::Trait(_, _, _, generics, ..)
| hir::ItemKind::Trait(_, _, _, _, generics, ..)
| hir::ItemKind::TraitAlias(_, generics, ..)
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters.
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ pub(crate) struct ConstImplForNonConstTrait {
pub trait_name: String,
#[suggestion(
applicability = "machine-applicable",
// FIXME(const_trait_impl) fix this suggestion
code = "#[const_trait] ",
style = "verbose"
)]
Expand All @@ -548,6 +549,7 @@ pub(crate) struct ConstBoundForNonConstTrait {
pub suggestion_pre: &'static str,
#[suggestion(
applicability = "machine-applicable",
// FIXME(const_trait_impl) fix this suggestion
code = "#[const_trait] ",
style = "verbose"
)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
self.suggest_adding_type_and_const_args(err);
}
ExcessTypesOrConsts { .. } => {
// this can happen with `[const] T` where T isn't a const_trait.
// this can happen with `[const] T` where T isn't a `const trait`.
}
_ => unreachable!(),
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
};

let (trait_generics, trait_bounds) = match parent_trait.kind {
hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits),
hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits),
hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits),
_ => unreachable!(),
};
Expand Down
Loading
Loading