Skip to content

correctly lower impl const to bind to host effect param #114545

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

Merged
merged 3 commits into from
Aug 8, 2023
Merged
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: 10 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
@@ -313,6 +313,16 @@ pub enum TraitBoundModifier {
MaybeConstMaybe,
}

impl TraitBoundModifier {
pub fn to_constness(self) -> Const {
match self {
// FIXME(effects) span
Self::MaybeConst => Const::Yes(DUMMY_SP),
_ => Const::No,
}
}
}

/// The AST represents all type param bounds as types.
/// `typeck::collect::compute_bounds` matches these against
/// the "special" built-in traits (see `middle::lang_items`) and
1 change: 1 addition & 0 deletions compiler/rustc_ast_lowering/src/asm.rs
Original file line number Diff line number Diff line change
@@ -207,6 +207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&sym.path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
hir::InlineAsmOperand::SymStatic { path, def_id }
} else {
6 changes: 6 additions & 0 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
@@ -100,6 +100,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ParamMode::Optional,
ParenthesizedGenericArgs::Err,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
));
let receiver = self.lower_expr(receiver);
let args =
@@ -260,6 +261,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
hir::ExprKind::Path(qpath)
}
@@ -307,6 +309,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
)),
self.arena
.alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))),
@@ -1179,6 +1182,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
// Destructure like a tuple struct.
let tuple_struct_pat = hir::PatKind::TupleStruct(
@@ -1198,6 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
// Destructure like a unit struct.
let unit_struct_pat = hir::PatKind::Path(qpath);
@@ -1222,6 +1227,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
&se.path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
let fields_omitted = match &se.rest {
StructRest::Base(e) => {
84 changes: 59 additions & 25 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
@@ -85,6 +85,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()),
generics_def_id_map: Default::default(),
host_param_id: None,
};
lctx.with_hir_id_owner(owner, |lctx| f(lctx));

@@ -139,8 +140,24 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.

if let hir::ItemKind::Impl(impl_) = parent_hir.node().expect_item().kind {
lctx.is_in_trait_impl = impl_.of_trait.is_some();
match parent_hir.node().expect_item().kind {
hir::ItemKind::Impl(impl_) => {
lctx.is_in_trait_impl = impl_.of_trait.is_some();
}
hir::ItemKind::Trait(_, _, generics, _, _) if lctx.tcx.features().effects => {
lctx.host_param_id = generics
.params
.iter()
.find(|param| {
parent_hir
.attrs
.get(param.hir_id.local_id)
.iter()
.any(|attr| attr.has_name(sym::rustc_host))
})
.map(|param| param.def_id);
}
_ => {}
}

match ctxt {
@@ -384,6 +401,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_generics(ast_generics, *constness, id, &itctx, |this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
*constness,
trait_ref,
&ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
)
@@ -414,7 +432,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
polarity,
defaultness,
defaultness_span,
constness: self.lower_constness(*constness),
generics,
of_trait: trait_ref,
self_ty: lowered_ty,
@@ -1358,6 +1375,29 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

// Desugar `~const` bound in generics into an additional `const host: bool` param
// if the effects feature is enabled. This needs to be done before we lower where
// clauses since where clauses need to bind to the DefId of the host param
let host_param_parts = if let Const::Yes(span) = constness && self.tcx.features().effects {
if let Some(param) = generics.params.iter().find(|x| {
x.attrs.iter().any(|x| x.has_name(sym::rustc_host))
}) {
// user has manually specified a `rustc_host` param, in this case, we set
// the param id so that lowering logic can use that. But we don't create
// another host param, so this gives `None`.
self.host_param_id = Some(self.local_def_id(param.id));
None
} else {
let param_node_id = self.next_node_id();
let hir_id = self.next_id();
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
self.host_param_id = Some(def_id);
Some((span, hir_id, def_id))
}
} else {
None
};

let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
predicates.extend(generics.params.iter().filter_map(|param| {
self.lower_generic_bound_predicate(
@@ -1405,22 +1445,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
let impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
predicates.extend(impl_trait_bounds.into_iter());

// Desugar `~const` bound in generics into an additional `const host: bool` param
// if the effects feature is enabled.
if let Const::Yes(span) = constness && self.tcx.features().effects
// Do not add host param if it already has it (manually specified)
&& !params.iter().any(|x| {
self.attrs.get(&x.hir_id.local_id).map_or(false, |attrs| {
attrs.iter().any(|x| x.has_name(sym::rustc_host))
})
})
{
let param_node_id = self.next_node_id();
if let Some((span, hir_id, def_id)) = host_param_parts {
let const_node_id = self.next_node_id();
let def_id = self.create_def(self.local_def_id(parent_node_id), param_node_id, DefPathData::TypeNs(sym::host), span);
let anon_const: LocalDefId = self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);
let anon_const: LocalDefId =
self.create_def(def_id, const_node_id, DefPathData::AnonConst, span);

let hir_id = self.next_id();
let const_id = self.next_id();
let const_expr_id = self.next_id();
let bool_id = self.next_id();
@@ -1430,14 +1459,15 @@ impl<'hir> LoweringContext<'_, 'hir> {

let attr_id = self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();

let attrs = self.arena.alloc_from_iter([
Attribute {
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
let attrs = self.arena.alloc_from_iter([Attribute {
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(
sym::rustc_host,
span,
id: attr_id,
style: AttrStyle::Outer,
},
]);
)))),
span,
id: attr_id,
style: AttrStyle::Outer,
}]);
self.attrs.insert(hir_id.local_id, attrs);

let const_body = self.lower_body(|this| {
@@ -1476,7 +1506,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
}),
)),
)),
default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }),
default: Some(hir::AnonConst {
def_id: anon_const,
hir_id: const_id,
body: const_body,
}),
},
colon_span: None,
pure_wrt_drop: false,
95 changes: 87 additions & 8 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
@@ -142,6 +142,8 @@ struct LoweringContext<'a, 'hir> {
/// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
/// field from the original parameter 'a to the new parameter 'a1.
generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,

host_param_id: Option<LocalDefId>,
}

trait ResolverAstLoweringExt {
@@ -1267,6 +1269,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: t.span
},
itctx,
ast::Const::No,
);
let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span);
@@ -1277,7 +1280,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}

let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx, None);
self.ty_path(id, t.span, qpath)
}

@@ -1361,10 +1364,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
GenericBound::Trait(
ty,
TraitBoundModifier::None
modifier @ (TraitBoundModifier::None
| TraitBoundModifier::MaybeConst
| TraitBoundModifier::Negative,
) => Some(this.lower_poly_trait_ref(ty, itctx)),
| TraitBoundModifier::Negative),
) => {
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
}
// `~const ?Bound` will cause an error during AST validation
// anyways, so treat it like `?Bound` as compilation proceeds.
GenericBound::Trait(
@@ -2189,7 +2194,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::GenericBound<'hir> {
match tpb {
GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
self.lower_poly_trait_ref(p, itctx),
self.lower_poly_trait_ref(p, itctx, modifier.to_constness()),
self.lower_trait_bound_modifier(*modifier),
),
GenericBound::Outlives(lifetime) => {
@@ -2332,8 +2337,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}

fn lower_trait_ref(&mut self, p: &TraitRef, itctx: &ImplTraitContext) -> hir::TraitRef<'hir> {
let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) {
fn lower_trait_ref(
&mut self,
constness: ast::Const,
p: &TraitRef,
itctx: &ImplTraitContext,
) -> hir::TraitRef<'hir> {
let path = match self.lower_qpath(
p.ref_id,
&None,
&p.path,
ParamMode::Explicit,
itctx,
Some(constness),
) {
hir::QPath::Resolved(None, path) => path,
qpath => panic!("lower_trait_ref: unexpected QPath `{qpath:?}`"),
};
@@ -2345,10 +2362,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
p: &PolyTraitRef,
itctx: &ImplTraitContext,
constness: ast::Const,
) -> hir::PolyTraitRef<'hir> {
let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}

@@ -2702,6 +2720,67 @@ struct GenericArgsCtor<'hir> {
}

impl<'hir> GenericArgsCtor<'hir> {
fn push_constness(&mut self, lcx: &mut LoweringContext<'_, 'hir>, constness: ast::Const) {
if !lcx.tcx.features().effects {
return;
}

// if bound is non-const, don't add host effect param
let ast::Const::Yes(span) = constness else { return };

let span = lcx.lower_span(span);

let id = lcx.next_node_id();
let hir_id = lcx.next_id();
let body = lcx.lower_body(|lcx| {
(
&[],
match constness {
ast::Const::Yes(_) => {
let hir_id = lcx.next_id();
let res =
Res::Def(DefKind::ConstParam, lcx.host_param_id.unwrap().to_def_id());
let expr_kind = hir::ExprKind::Path(hir::QPath::Resolved(
None,
lcx.arena.alloc(hir::Path {
span,
res,
segments: arena_vec![lcx; hir::PathSegment::new(Ident {
name: sym::host,
span,
}, hir_id, res)],
}),
));
lcx.expr(span, expr_kind)
}
ast::Const::No => lcx.expr(
span,
hir::ExprKind::Lit(
lcx.arena.alloc(hir::Lit { span, node: ast::LitKind::Bool(true) }),
),
),
},
)
});

let attr_id = lcx.tcx.sess.parse_sess.attr_id_generator.mk_attr_id();
let attr = lcx.arena.alloc(Attribute {
kind: AttrKind::Normal(P(NormalAttr::from_ident(Ident::new(sym::rustc_host, span)))),
span,
id: attr_id,
style: AttrStyle::Outer,
});
lcx.attrs.insert(hir_id.local_id, std::slice::from_ref(attr));

let def_id =
lcx.create_def(lcx.current_hir_id_owner.def_id, id, DefPathData::AnonConst, span);
lcx.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
self.args.push(hir::GenericArg::Const(hir::ConstArg {
value: hir::AnonConst { def_id, hir_id, body },
span,
}))
}

fn is_empty(&self) -> bool {
self.args.is_empty()
&& self.bindings.is_empty()
3 changes: 3 additions & 0 deletions compiler/rustc_ast_lowering/src/pat.rs
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
break hir::PatKind::TupleStruct(qpath, pats, ddpos);
@@ -54,6 +55,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
break hir::PatKind::Path(qpath);
}
@@ -64,6 +66,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
path,
ParamMode::Optional,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);

let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
13 changes: 12 additions & 1 deletion compiler/rustc_ast_lowering/src/path.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
p: &Path,
param_mode: ParamMode,
itctx: &ImplTraitContext,
// constness of the impl/bound if this is a trait path
constness: Option<ast::Const>,
) -> hir::QPath<'hir> {
let qself_position = qself.as_ref().map(|q| q.position);
let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
@@ -73,6 +75,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
parenthesized_generic_args,
itctx,
// if this is the last segment, add constness to the trait path
if i == proj_start - 1 { constness } else { None },
)
},
)),
@@ -119,6 +123,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
ParenthesizedGenericArgs::Err,
itctx,
None,
));
let qpath = hir::QPath::TypeRelative(ty, hir_segment);

@@ -159,6 +164,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode,
ParenthesizedGenericArgs::Err,
&ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
)
})),
span: self.lower_span(p.span),
@@ -172,8 +178,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
param_mode: ParamMode,
parenthesized_generic_args: ParenthesizedGenericArgs,
itctx: &ImplTraitContext,
constness: Option<ast::Const>,
) -> hir::PathSegment<'hir> {
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,);
debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment);
let (mut generic_args, infer_args) = if let Some(generic_args) = segment.args.as_deref() {
match generic_args {
GenericArgs::AngleBracketed(data) => {
@@ -231,6 +238,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
};

if let Some(constness) = constness {
generic_args.push_constness(self, constness);
}

let has_lifetimes =
generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)));

2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
| hir::Node::AnonConst(_)
| hir::Node::ConstBlock(_)
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => hir::Constness::Const,
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.constness,
hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => tcx.generics_of(def_id).host_effect_index.map_or(hir::Constness::NotConst, |_| hir::Constness::Const),
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
// foreign items cannot be evaluated at compile-time.
11 changes: 2 additions & 9 deletions compiler/rustc_const_eval/src/transform/check_consts/mod.rs
Original file line number Diff line number Diff line change
@@ -127,15 +127,8 @@ fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let hir_id = tcx.local_def_id_to_hir_id(local_def_id);

let Some(parent) = tcx.hir().opt_parent_id(hir_id) else { return false };
let parent_def = tcx.hir().get(parent);

if !matches!(
parent_def,
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
..
})
) {

if !tcx.is_const_trait_impl_raw(parent.owner.def_id.to_def_id()) {
return false;
}

7 changes: 5 additions & 2 deletions compiler/rustc_const_eval/src/transform/check_consts/ops.rs
Original file line number Diff line number Diff line change
@@ -145,8 +145,11 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
let implsrc = selcx.select(&obligation);

if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
let span = tcx.def_span(data.impl_def_id);
err.subdiagnostic(errors::NonConstImplNote { span });
// FIXME(effects) revisit this
if !tcx.is_const_trait_impl_raw(data.impl_def_id) {
let span = tcx.def_span(data.impl_def_id);
err.subdiagnostic(errors::NonConstImplNote { span });
}
}
}
_ => {}
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
@@ -3357,7 +3357,6 @@ pub struct Impl<'hir> {
// We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
// decoding as `Span`s cannot be decoded when a `Session` is not available.
pub defaultness_span: Option<Span>,
pub constness: Constness,
pub generics: &'hir Generics<'hir>,

/// The trait being implemented, if any.
1 change: 0 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
@@ -522,7 +522,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
unsafety: _,
defaultness: _,
polarity: _,
constness: _,
defaultness_span: _,
ref generics,
ref of_trait,
12 changes: 5 additions & 7 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
@@ -532,6 +532,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let Err(guar) = ty.error_reported() {
return ty::Const::new_error(tcx, guar, ty).into();
}
// FIXME(effects) see if we should special case effect params here
if !infer_args && has_default {
tcx.const_param_default(param.def_id)
.instantiate(tcx, args.unwrap())
@@ -659,7 +660,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
trait_ref: &hir::TraitRef<'_>,
self_ty: Ty<'tcx>,
constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});

@@ -669,7 +669,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty,
trait_ref.path.segments.last().unwrap(),
true,
constness,
ty::BoundConstness::NotConst,
)
}

@@ -849,6 +849,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'_>,
is_impl: bool,
// FIXME(effects) move all host param things in astconv to hir lowering
constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
let (generic_args, _) = self.create_args_for_ast_trait_ref(
@@ -2712,11 +2713,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
};
let i = hir.get_parent(fn_hir_id).expect_item().expect_impl();

let trait_ref = self.instantiate_mono_trait_ref(
i.of_trait.as_ref()?,
self.ast_ty_to_ty(i.self_ty),
ty::BoundConstness::NotConst,
);
let trait_ref =
self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));

let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
tcx,
70 changes: 46 additions & 24 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
@@ -1359,38 +1359,60 @@ fn impl_trait_ref(
.as_ref()
.map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id).instantiate_identity();
icx.astconv().instantiate_mono_trait_ref(
ast_trait_ref,
selfty,
check_impl_constness(tcx, impl_.constness, ast_trait_ref),
)

if let Some(ErrorGuaranteed { .. }) = check_impl_constness(
tcx,
tcx.is_const_trait_impl_raw(def_id.to_def_id()),
&ast_trait_ref,
) {
// we have a const impl, but for a trait without `#[const_trait]`, so
// without the host param. If we continue with the HIR trait ref, we get
// ICEs for generic arg count mismatch. We do a little HIR editing to
// make astconv happy.
let mut path_segments = ast_trait_ref.path.segments.to_vec();
let last_segment = path_segments.len() - 1;
let mut args = path_segments[last_segment].args().clone();
let last_arg = args.args.len() - 1;
assert!(matches!(args.args[last_arg], hir::GenericArg::Const(anon_const) if tcx.has_attr(anon_const.value.def_id, sym::rustc_host)));
args.args = &args.args[..args.args.len() - 1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe assert that you are actually removing the host param, and not something else that snuck in

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This turns out to be a bit more complicated and I didn't want to look inside bodies, so I just added the attr to all automatically generated bodies and asserted that the attr exists instead.

path_segments[last_segment].args = Some(&args);
let path = hir::Path {
span: ast_trait_ref.path.span,
res: ast_trait_ref.path.res,
segments: &path_segments,
};
let trait_ref = hir::TraitRef { path: &path, hir_ref_id: ast_trait_ref.hir_ref_id };
icx.astconv().instantiate_mono_trait_ref(&trait_ref, selfty)
} else {
icx.astconv().instantiate_mono_trait_ref(&ast_trait_ref, selfty)
}
})
.map(ty::EarlyBinder::bind)
}

fn check_impl_constness(
tcx: TyCtxt<'_>,
constness: hir::Constness,
is_const: bool,
ast_trait_ref: &hir::TraitRef<'_>,
) -> ty::BoundConstness {
match constness {
hir::Constness::Const => {
if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
let trait_name = tcx.item_name(trait_def_id).to_string();
tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
trait_ref_span: ast_trait_ref.path.span,
trait_name,
local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
marking: (),
adding: (),
});
ty::BoundConstness::NotConst
} else {
ty::BoundConstness::ConstIfConst
}
},
hir::Constness::NotConst => ty::BoundConstness::NotConst,
) -> Option<ErrorGuaranteed> {
if !is_const {
return None;
}

let trait_def_id = ast_trait_ref.trait_def_id()?;
if tcx.has_attr(trait_def_id, sym::const_trait) {
return None;
}

let trait_name = tcx.item_name(trait_def_id).to_string();
Some(tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
trait_ref_span: ast_trait_ref.path.span,
trait_name,
local_trait_span:
trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
marking: (),
adding: (),
}))
}

fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity {
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/generics_of.rs
Original file line number Diff line number Diff line change
@@ -320,7 +320,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
bug!("parent also has host effect param? index: {idx}, def: {def_id:?}");
}

host_effect_index = Some(parent_count + index as usize);
host_effect_index = Some(index as usize);
}

Some(ty::GenericParamDef {
Original file line number Diff line number Diff line change
@@ -578,6 +578,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
MissingTypesOrConsts { .. } => {
self.suggest_adding_type_and_const_args(err);
}
ExcessTypesOrConsts { .. } => {
// this can happen with `~const T` where T isn't a const_trait.
}
_ => unreachable!(),
}
}
5 changes: 0 additions & 5 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
@@ -626,7 +626,6 @@ impl<'a> State<'a> {
unsafety,
polarity,
defaultness,
constness,
defaultness_span: _,
generics,
ref of_trait,
@@ -643,10 +642,6 @@ impl<'a> State<'a> {
self.space();
}

if constness == hir::Constness::Const {
self.word_nbsp("const");
}

if let hir::ImplPolarity::Negative(_) = polarity {
self.word("!");
}
37 changes: 20 additions & 17 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
@@ -767,9 +767,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let tcx = self.tcx;

if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
return;
}
// fast-reject if callee doesn't have the host effect param (non-const)
let generics = tcx.generics_of(callee_did);
let Some(host_effect_index) = generics.host_effect_index else { return };

// if the callee does have the param, we need to equate the param to some const
// value no matter whether the effects feature is enabled in the local crate,
// because inference will fail if we don't.
let mut host_always_on =
!tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you;

// Compute the constness required by the context.
let context = tcx.hir().enclosing_body_owner(call_expr_hir);
@@ -780,10 +786,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) {
trace!("do not const check this context");
return;
host_always_on = true;
}

let effect = match const_context {
_ if host_always_on => tcx.consts.true_,
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
Some(hir::ConstContext::ConstFn) => {
let args = ty::GenericArgs::identity_for_item(tcx, context);
@@ -792,21 +799,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None => tcx.consts.true_,
};

let generics = tcx.generics_of(callee_did);

trace!(?effect, ?generics, ?callee_args);

if let Some(idx) = generics.host_effect_index {
let param = callee_args.const_at(idx);
let cause = self.misc(span);
match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
Ok(infer::InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
Err(e) => {
// FIXME(effects): better diagnostic
self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
}
let param = callee_args.const_at(host_effect_index);
let cause = self.misc(span);
match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) {
Ok(infer::InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
Err(e) => {
// FIXME(effects): better diagnostic
self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit();
}
}
}
5 changes: 4 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
@@ -1349,7 +1349,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
GenericParamDefKind::Const { has_default } => {
if !infer_args && has_default {
if !infer_args
&& has_default
&& !tcx.has_attr(param.def_id, sym::rustc_host)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work for desugared params?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

desugared params get this attribute as well: link

{
tcx.const_param_default(param.def_id)
.instantiate(tcx, args.unwrap())
.into()
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
@@ -1963,9 +1963,9 @@ impl<'tcx> TyCtxt<'tcx> {
matches!(
node,
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
..
})
}) if generics.params.iter().any(|p| self.has_attr(p.def_id, sym::rustc_host))
)
}

5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
@@ -2841,6 +2841,11 @@ define_print_and_forward_display! {

ty::TraitPredicate<'tcx> {
p!(print(self.trait_ref.self_ty()), ": ");
if let Some(idx) = cx.tcx().generics_of(self.trait_ref.def_id).host_effect_index {
if self.trait_ref.args.const_at(idx) != cx.tcx().consts.true_ {
p!("~const ");
}
}
// FIXME(effects) print `~const` here
if let ty::ImplPolarity::Negative = self.polarity {
p!("!");
10 changes: 2 additions & 8 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
@@ -732,13 +732,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
hir::ItemKind::Impl(hir::Impl {
of_trait: Some(ref t),
self_ty,
items,
constness,
..
}) => {
hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
let features = self.tcx.features();
if features.staged_api {
let attrs = self.tcx.hir().attrs(item.hir_id());
@@ -769,7 +763,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
// needs to have an error emitted.
if features.const_trait_impl
&& *constness == hir::Constness::Const
&& self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
&& const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
{
self.tcx.sess.emit_err(errors::TraitImplConstStable { span: item.span });
21 changes: 0 additions & 21 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
@@ -3102,27 +3102,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) -> UnsatisfiedConst {
let unsatisfied_const = UnsatisfiedConst(false);
// FIXME(effects)
/* if trait_predicate.is_const_if_const() {
let non_const_predicate = trait_ref.without_const();
let non_const_obligation = Obligation {
cause: obligation.cause.clone(),
param_env: obligation.param_env,
predicate: non_const_predicate.to_predicate(self.tcx),
recursion_depth: obligation.recursion_depth,
};
if self.predicate_may_hold(&non_const_obligation) {
unsatisfied_const = UnsatisfiedConst(true);
err.span_note(
span,
format!(
"the trait `{}` is implemented for `{}`, \
but that implementation is not `const`",
non_const_predicate.print_modifiers_and_trait_path(),
trait_ref.skip_binder().self_ty(),
),
);
}
} */
unsatisfied_const
}

2 changes: 1 addition & 1 deletion tests/ui/const-generics/const_trait_fn-issue-88433.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// build-pass

#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]

#[const_trait]
trait Func<T> {
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
error: const `impl` for trait `Add` which is not marked with `#[const_trait]`
--> $DIR/unify-op-with-fn-call.rs:10:12
error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/unify-op-with-fn-call.rs:18:29
|
LL | impl const std::ops::Add for Foo {
| ^^^^^^^^^^^^^
LL | struct Evaluatable<const N: Foo>;
| ^^^
|
help: add `#[derive(ConstParamTy)]` to the struct
|
LL + #[derive(ConstParamTy)]
LL | struct Foo(u8);
|

error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/unify-op-with-fn-call.rs:20:17
|
LL | fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
| ^^^
|
help: add `#[derive(ConstParamTy)]` to the struct
|
LL + #[derive(ConstParamTy)]
LL | struct Foo(u8);
|

error[E0741]: `Foo` must implement `ConstParamTy` to be used as the type of a const generic parameter
--> $DIR/unify-op-with-fn-call.rs:24:17
|
LL | fn bar<const N: Foo>() {}
| ^^^
|
help: add `#[derive(ConstParamTy)]` to the struct
|
LL + #[derive(ConstParamTy)]
LL | struct Foo(u8);
|
= 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
error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0741`.
33 changes: 21 additions & 12 deletions tests/ui/consts/const-try.stderr
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
--> $DIR/const-try.rs:15:12
error[E0015]: `?` cannot determine the branch of `TryMe` in constant functions
--> $DIR/const-try.rs:33:5
|
LL | impl const FromResidual<Error> for TryMe {
| ^^^^^^^^^^^^^^^^^^^
LL | TryMe?;
| ^^^^^^
|
= 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: const `impl` for trait `Try` which is not marked with `#[const_trait]`
--> $DIR/const-try.rs:21:12
note: impl defined here, but it is not `const`
--> $DIR/const-try.rs:21:1
|
LL | impl const Try for TryMe {
| ^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error[E0015]: `?` cannot convert from residual of `TryMe` in constant functions
--> $DIR/const-try.rs:33:5
|
= 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
LL | TryMe?;
| ^^^^^^
|
note: impl defined here, but it is not `const`
--> $DIR/const-try.rs:15:1
|
LL | impl const FromResidual<Error> for TryMe {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
2 changes: 1 addition & 1 deletion tests/ui/consts/rustc-impl-const-stability.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

#![crate_type = "lib"]
#![feature(staged_api)]
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]
#![stable(feature = "foo", since = "1.0.0")]

#[stable(feature = "potato", since = "1.27.0")]
12 changes: 11 additions & 1 deletion tests/ui/consts/rustc-impl-const-stability.stderr
Original file line number Diff line number Diff line change
@@ -7,5 +7,15 @@ LL | impl const Default for Data {
= 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
error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates
--> $DIR/rustc-impl-const-stability.rs:15:6
|
LL | impl const Default for Data {
| ^^^^^ unconstrained const parameter
|
= note: expressions using a const parameter must map each value to a distinct output value
= note: proving the result of expressions other than the parameter are unique is not supported

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0207`.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]

#[const_trait]
pub trait MyTrait {
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]
#![feature(staged_api)]
#![stable(feature = "rust1", since = "1.0.0")]

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

#[const_trait]
pub trait Plus {
@@ -23,7 +23,7 @@ pub const fn add_i32(a: i32, b: i32) -> i32 {

pub const fn add_u32(a: u32, b: u32) -> u32 {
a.plus(b)
//~^ ERROR cannot call
//~^ ERROR the trait bound
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0015]: cannot call non-const fn `<u32 as Plus>::plus` in constant functions
error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
--> $DIR/call-const-trait-method-fail.rs:25:7
|
LL | a.plus(b)
| ^^^^^^^
| ^^^^ the trait `Plus` is not implemented for `u32`
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: the trait `Plus` is implemented for `u32`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0277`.
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
error: const `impl` for trait `Add` which is not marked with `#[const_trait]`
--> $DIR/call-const-trait-method-pass.rs:7:12
error[E0015]: cannot call non-const fn `<i32 as Plus>::plus` in constant functions
--> $DIR/call-const-trait-method-pass.rs:36:7
|
LL | impl const std::ops::Add for Int {
| ^^^^^^^^^^^^^
LL | a.plus(b)
| ^^^^^^^
|
= 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
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/call-const-trait-method-pass.rs:15:12
error[E0015]: cannot call non-const operator in constants
--> $DIR/call-const-trait-method-pass.rs:39:22
|
LL | const ADD_INT: Int = Int(1i32) + Int(2i32);
| ^^^^^^^^^^^^^^^^^^^^^
|
LL | impl const PartialEq for Int {
| ^^^^^^^^^
note: impl defined here, but it is not `const`
--> $DIR/call-const-trait-method-pass.rs:7:1
|
= 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
LL | impl const std::ops::Add for Int {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constants are limited to constant functions, tuple structs and tuple variants

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/call-generic-method-chain.rs:9:12
|
LL | impl const PartialEq for S {
| ^^^^^^^^^
|
= 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: ~const can only be applied to `#[const_trait]` traits
--> $DIR/call-generic-method-chain.rs:18:32
|
@@ -19,5 +10,5 @@ error: ~const can only be applied to `#[const_trait]` traits
LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
| ^^^^^^^^^

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/call-generic-method-dup-bound.rs:7:12
|
LL | impl const PartialEq for S {
| ^^^^^^^^^
|
= 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: ~const can only be applied to `#[const_trait]` traits
--> $DIR/call-generic-method-dup-bound.rs:18:44
|
@@ -19,5 +10,5 @@ error: ~const can only be applied to `#[const_trait]` traits
LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
| ^^^^^^^^^

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/call-generic-method-pass.rs:9:12
|
LL | impl const PartialEq for S {
| ^^^^^^^^^
|
= 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: ~const can only be applied to `#[const_trait]` traits
--> $DIR/call-generic-method-pass.rs:18:32
|
LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
| ^^^^^^^^^

error: aborting due to 2 previous errors
error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
error: const `impl` for trait `Add` which is not marked with `#[const_trait]`
--> $DIR/const-and-non-const-impl.rs:7:12
error[E0117]: only traits defined in the current crate can be implemented for primitive types
--> $DIR/const-and-non-const-impl.rs:7:1
|
LL | impl const std::ops::Add for i32 {
| ^^^^^^^^^^^^^
| ^^^^^^^^^^^-------------^^^^^---
| | | |
| | | `i32` is not defined in the current crate
| | `i32` is not defined in the current crate
| impl doesn't use only types from inside the current crate
|
= 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
= note: define and implement a trait or new type instead

error: const `impl` for trait `Add` which is not marked with `#[const_trait]`
--> $DIR/const-and-non-const-impl.rs:23:12
error[E0119]: conflicting implementations of trait `Add` for type `Int`
--> $DIR/const-and-non-const-impl.rs:23:1
|
LL | impl std::ops::Add for Int {
| -------------------------- first implementation here
...
LL | impl const std::ops::Add for Int {
| ^^^^^^^^^^^^^
|
= 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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Int`

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0117, E0119.
For more information about an error, try `rustc --explain E0117`.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]

struct S;
#[const_trait]
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]

#[const_trait]
trait ConstDefaultFn: Sized {
@@ -22,7 +22,7 @@ impl const ConstDefaultFn for ConstImpl {

const fn test() {
NonConstImpl.a();
//~^ ERROR cannot call
//~^ ERROR the trait bound
ConstImpl.a();
}

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
--> $DIR/const-default-method-bodies.rs:24:18
|
LL | NonConstImpl.a();
| ^^^
| ^ the trait `ConstDefaultFn` is not implemented for `NonConstImpl`
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: the trait `ConstDefaultFn` is implemented for `NonConstImpl`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0277`.
7 changes: 5 additions & 2 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,10 @@ trait A { fn a() { } }

impl A for NonTrivialDrop {}

const fn check<T: ~const Destruct>(_: T) {}


/* FIXME(effects)
struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
@@ -26,11 +30,10 @@ impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
}
}
const fn check<T: ~const Destruct>(_: T) {}

const _: () = check::<ConstDropImplWithBounds<NonTrivialDrop>>(
ConstDropImplWithBounds(PhantomData)
);
*/

struct ConstDropImplWithNonConstBounds<T: A>(PhantomData<T>);

23 changes: 3 additions & 20 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.stderr
Original file line number Diff line number Diff line change
@@ -1,28 +1,11 @@
error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions
--> $DIR/const-drop-fail-2.rs:25:9
|
LL | T::a();
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error[E0493]: destructor of `T` cannot be evaluated at compile-time
--> $DIR/const-drop-fail-2.rs:29:36
--> $DIR/const-drop-fail-2.rs:21:36
|
LL | const fn check<T: ~const Destruct>(_: T) {}
| ^ - value is dropped here
| |
| the destructor for this type cannot be evaluated in constant functions

error[E0015]: cannot call non-const fn `<T as A>::a` in constant functions
--> $DIR/const-drop-fail-2.rs:39:9
|
LL | T::a();
| ^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to 3 previous errors
error: aborting due to previous error

Some errors have detailed explanations: E0015, E0493.
For more information about an error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0493`.
13 changes: 2 additions & 11 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.precise.stderr
Original file line number Diff line number Diff line change
@@ -14,15 +14,6 @@ LL | let _ = S(&mut c);
| |
| the destructor for this type cannot be evaluated in constant functions

error[E0015]: cannot call non-const fn `<T as SomeTrait>::foo` in constant functions
--> $DIR/const-drop.rs:70:13
|
LL | T::foo();
| ^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0015, E0493.
For more information about an error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0493`.
13 changes: 2 additions & 11 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop.stock.stderr
Original file line number Diff line number Diff line change
@@ -14,15 +14,6 @@ LL | let _ = S(&mut c);
| |
| the destructor for this type cannot be evaluated in constant functions

error[E0015]: cannot call non-const fn `<T as SomeTrait>::foo` in constant functions
--> $DIR/const-drop.rs:70:13
|
LL | T::foo();
| ^^^^^^^^
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to 3 previous errors
error: aborting due to 2 previous errors

Some errors have detailed explanations: E0015, E0493.
For more information about an error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0493`.
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#![feature(const_trait_impl)]
// known-bug: #110395

#![feature(const_trait_impl, effects)]

pub trait A {}
//~^ HELP: mark `A` as const
// FIXME ~^ HELP: mark `A` as const

impl const A for () {}
//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]`
// FIXME ~^ 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,5 +1,5 @@
error: const `impl` for trait `A` which is not marked with `#[const_trait]`
--> $DIR/const-impl-requires-const-trait.rs:6:12
--> $DIR/const-impl-requires-const-trait.rs:8:12
|
LL | pub trait A {}
| - help: mark `A` as const: `#[const_trait]`
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#[derive_const(Default)] //~ ERROR use of unstable library feature
//~^ ERROR not marked with `#[const_trait]`
pub struct S;

fn main() {}
Original file line number Diff line number Diff line change
@@ -6,16 +6,6 @@ LL | #[derive_const(Default)]
|
= help: add `#![feature(derive_const)]` to the crate attributes to enable

error: const `impl` for trait `Default` which is not marked with `#[const_trait]`
--> $DIR/derive-const-gate.rs:1:16
|
LL | #[derive_const(Default)]
| ^^^^^^^
|
= 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
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// known-bug: #110395
#![feature(derive_const)]
#![feature(derive_const, effects)]

pub struct A;

Original file line number Diff line number Diff line change
@@ -10,44 +10,6 @@ error[E0635]: unknown feature `const_default_impls`
LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const)]
| ^^^^^^^^^^^^^^^^^^^

error: const `impl` for trait `Default` which is not marked with `#[const_trait]`
--> $DIR/derive-const-use.rs:6:12
|
LL | impl const Default for 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: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/derive-const-use.rs:10:12
|
LL | impl const PartialEq for 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: const `impl` for trait `Default` which is not marked with `#[const_trait]`
--> $DIR/derive-const-use.rs:14:16
|
LL | #[derive_const(Default, PartialEq)]
| ^^^^^^^
|
= 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
= note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)

error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/derive-const-use.rs:14:25
|
LL | #[derive_const(Default, PartialEq)]
| ^^^^^^^^^
|
= 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
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 6 previous errors
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0635`.
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
--> $DIR/derive-const-with-params.rs:6:16
|
LL | #[derive_const(PartialEq)]
| ^^^^^^^^^
|
= 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
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)

error: ~const can only be applied to `#[const_trait]` traits
--> $DIR/derive-const-with-params.rs:6:16
|
@@ -16,5 +6,5 @@ LL | #[derive_const(PartialEq)]
|
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 2 previous errors
error: aborting due to previous error

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
--> $DIR/cross-crate.rs:17:14
|
LL | NonConst.func();
| ^^^^^^
| ^^^^ the trait `cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
|
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
= help: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0015`.
For more information about this error, try `rustc --explain E0277`.
4 changes: 2 additions & 2 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/cross-crate.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// revisions: stock gated stocknc gatednc
// [gated] check-pass
#![cfg_attr(any(gated, gatednc), feature(const_trait_impl))]
#![cfg_attr(any(gated, gatednc), feature(const_trait_impl, effects))]

// aux-build: cross-crate.rs
extern crate cross_crate;
@@ -16,7 +16,7 @@ const fn const_context() {
#[cfg(any(stocknc, gatednc))]
NonConst.func();
//[stocknc]~^ ERROR: cannot call
//[gatednc]~^^ ERROR: cannot call
//[gatednc]~^^ ERROR: the trait bound
Const.func();
//[stock]~^ ERROR: cannot call
//[stocknc]~^^ ERROR: cannot call
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0277]: the trait bound `(): Tr` is not satisfied
error[E0277]: the trait bound `(): ~const Tr` is not satisfied
--> $DIR/default-method-body-is-const-same-trait-ck.rs:8:12
|
LL | ().a()
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// check-pass
#![feature(const_trait_impl, rustc_attrs)]
#![feature(const_trait_impl, rustc_attrs, effects)]

#[const_trait]
trait Foo {
6 changes: 2 additions & 4 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

// ensure we are passing in the correct host effect in always const contexts.

pub const fn hmm</* T, */ #[rustc_host] const host: bool = true>() -> usize {
pub const fn hmm<T, #[rustc_host] const host: bool = true>() -> usize {
if host {
1
} else {
@@ -16,14 +16,12 @@ pub const fn hmm</* T, */ #[rustc_host] const host: bool = true>() -> usize {
}

const _: () = {
let x = hmm();
let x = hmm::<()>();
assert!(0 == x);
};

/* FIXME(effects)
pub const fn uwu(x: [u8; hmm::<()>()]) {
let [] = x;
}
*/

fn main() {}
17 changes: 11 additions & 6 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/generic-bound.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
error: const `impl` for trait `Add` which is not marked with `#[const_trait]`
--> $DIR/generic-bound.rs:16:15
error[E0015]: cannot call non-const operator in constant functions
--> $DIR/generic-bound.rs:25:5
|
LL | impl<T> const std::ops::Add for S<T> {
| ^^^^^^^^^^^^^
LL | arg + arg
| ^^^^^^^^^
|
note: impl defined here, but it is not `const`
--> $DIR/generic-bound.rs:16:1
|
= 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
LL | impl<T> const std::ops::Add for S<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to previous error

For more information about this error, try `rustc --explain E0015`.
2 changes: 1 addition & 1 deletion tests/ui/rfcs/rfc-2632-const-trait-impl/hir-const-check.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Regression test for #69615.

#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]

#[const_trait]
pub trait MyTrait {
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Tests that specializing trait impls must be at least as const as the default impl.

#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]
#![feature(min_specialization)]

#[const_trait]
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(const_trait_impl, min_specialization, rustc_attrs)]
#![feature(const_trait_impl, effects, min_specialization, rustc_attrs)]

#[rustc_specialization_trait]
#[const_trait]
2 changes: 1 addition & 1 deletion tests/ui/rfcs/rfc-2632-const-trait-impl/staged-api.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// revisions: stable unstable

#![cfg_attr(unstable, feature(unstable))] // The feature from the ./auxiliary/staged-api.rs file.
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]
#![feature(staged_api)]
#![stable(feature = "rust1", since = "1.0.0")]

Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
error: const `impl` for trait `Try` which is not marked with `#[const_trait]`
--> $DIR/trait-default-body-stability.rs:18:12
error[E0015]: `?` cannot determine the branch of `T` in constant functions
--> $DIR/trait-default-body-stability.rs:44:9
|
LL | impl const Try for T {
| ^^^
LL | T?
| ^^
|
note: impl defined here, but it is not `const`
--> $DIR/trait-default-body-stability.rs:18:1
|
= 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
LL | impl const Try for T {
| ^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
--> $DIR/trait-default-body-stability.rs:33:12
error[E0015]: `?` cannot convert from residual of `T` in constant functions
--> $DIR/trait-default-body-stability.rs:44:9
|
LL | impl const FromResidual for T {
| ^^^^^^^^^^^^
LL | T?
| ^^
|
note: impl defined here, but it is not `const`
--> $DIR/trait-default-body-stability.rs:33:1
|
= 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
LL | impl const FromResidual for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: calls in constant functions are limited to constant functions, tuple structs and tuple variants

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0015`.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// known-bug: #110395
// FIXME run-pass

#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]

#[const_trait]
trait Bar {
2 changes: 1 addition & 1 deletion tests/ui/stability-attribute/missing-const-stability.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![feature(staged_api)]
#![feature(const_trait_impl)]
#![feature(const_trait_impl, effects)]
#![stable(feature = "stable", since = "1.0.0")]

#[stable(feature = "stable", since = "1.0.0")]