diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 2a268c2da85c..f0434b0294f1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -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 diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index ab55c09465b1..a1e626996800 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -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 { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0954cf03da9a..f06d6fc6e5bd 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -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) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5a0474dbc01d..201094667a1e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -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, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ac7506900467..dd081fafafba 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -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>, + + host_param_id: Option, } 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,57 @@ 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 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() diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2509b7056395..a30f264bc7dc 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -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| { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 441282c05b42..899f92a99582 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -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, ) -> 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, ) -> 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(_))); diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index cc39387c41fc..4ee4ebbb9e44 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -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. diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index e77fb4ea2a2c..e51082e1ec0e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -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; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index e785196c744c..1f3cda35c2ba 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -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 }); + } } } _ => {} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6b76e16825f7..3922dadfdb1b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -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, - pub constness: Constness, pub generics: &'hir Generics<'hir>, /// The trait being implemented, if any. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index a8a94e6a4768..056b68949a2c 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -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, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index b40e31235228..7c03c1794f0f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -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, diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f568b7519519..c65cd25f12c3 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1358,38 +1358,29 @@ fn impl_trait_ref( .of_trait .as_ref() .map(|ast_trait_ref| { - let selfty = tcx.type_of(def_id).instantiate_identity(); - icx.astconv().instantiate_mono_trait_ref( + check_impl_constness( + tcx, + tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref, - selfty, - check_impl_constness(tcx, impl_.constness, ast_trait_ref), - ) + ); + let selfty = tcx.type_of(def_id).instantiate_identity(); + icx.astconv().instantiate_mono_trait_ref(ast_trait_ref, selfty) }) .map(ty::EarlyBinder::bind) } -fn check_impl_constness( - tcx: TyCtxt<'_>, - constness: hir::Constness, - 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, +fn check_impl_constness(tcx: TyCtxt<'_>, is_const: bool, ast_trait_ref: &hir::TraitRef<'_>) { + if is_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: (), + }); + } } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 6e1762c54f21..4842008279a9 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -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 { diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index 6be8d72aed20..61b182b1be78 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -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!(), } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2d8b956771bb..e2aecccb6e9b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -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("!"); } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index c68f2d94f352..ba00954db918 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -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(); } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 1433c67d55dc..6b118ea5a293 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -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) + { tcx.const_param_default(param.def_id) .instantiate(tcx, args.unwrap()) .into() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5eef3e45f327..30f60abe31c8 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -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)) ) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d3fd49150ba2..ed0af6f5eb19 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -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!("!"); diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 25a3d38c1442..3950ac9dd31c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -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 }); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index eae13eb63029..f56b4425b125 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -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 } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs index 3de9d37d4933..10f6c5c064a3 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-drop-fail-2.rs @@ -1,5 +1,5 @@ // known-bug: #110395 -#![feature(const_trait_impl)] +#![feature(const_trait_impl, effects)] #![feature(const_mut_refs)] #![cfg_attr(precise, feature(const_precise_live_drops))]