From 2d5d56bb590382dbf2d230036baaf8b230acee01 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 30 Jun 2023 13:53:23 +0000 Subject: [PATCH 1/7] Add feature and attribute definition --- compiler/rustc_feature/src/active.rs | 2 ++ compiler/rustc_feature/src/builtin_attrs.rs | 6 ++++++ compiler/rustc_span/src/symbol.rs | 3 +++ 3 files changed, 11 insertions(+) diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 906c31c9a3def..5185820a7276f 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -391,6 +391,8 @@ declare_features! ( (active, doc_masked, "1.21.0", Some(44027), None), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425), None), + // Uses generic effect parameters for ~const bounds + (active, effects, "CURRENT_RUSTC_VERSION", Some(102090), None), /// Allows `X..Y` patterns. (active, exclusive_range_pattern, "1.11.0", Some(37854), None), /// Allows exhaustive pattern matching on types that contain uninhabited types. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 3c5bff3812a94..36600004404ad 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -723,6 +723,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ and it is only intended to be used in `alloc`." ), + rustc_attr!( + rustc_host, AttributeType::Normal, template!(Word), ErrorFollowing, + "#[rustc_host] annotates const generic parameters as the `host` effect param, \ + and it is only intended for internal use and as a desugaring." + ), + BuiltinAttribute { name: sym::rustc_diagnostic_item, // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c58d85b99f79f..66a627d5aac7c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -656,6 +656,7 @@ symbols! { dyn_trait, e, edition_panic, + effects, eh_catch_typeinfo, eh_personality, emit, @@ -793,6 +794,7 @@ symbols! { hexagon_target_feature, hidden, homogeneous_aggregate, + host, html_favicon_url, html_logo_url, html_no_source, @@ -1284,6 +1286,7 @@ symbols! { rustc_evaluate_where_clauses, rustc_expected_cgu_reuse, rustc_has_incoherent_inherent_impls, + rustc_host, rustc_if_this_changed, rustc_inherit_overflow_checks, rustc_insignificant_dtor, From 1c837cb6f7347b257ea42b8587a7c84bd13c92c9 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 30 Jun 2023 14:01:24 +0000 Subject: [PATCH 2/7] Add effects during lowering for `~const` bounds --- compiler/rustc_ast/src/ast.rs | 9 ++ compiler/rustc_ast_lowering/src/expr.rs | 9 +- compiler/rustc_ast_lowering/src/item.rs | 120 ++++++++++++++++++++++-- 3 files changed, 121 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a398fd80119be..a7198fbf88768 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2652,6 +2652,15 @@ pub struct NormalAttr { pub tokens: Option, } +impl NormalAttr { + pub fn from_ident(ident: Ident) -> Self { + Self { + item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None }, + tokens: None, + } + } +} + #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AttrItem { pub path: Path, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 29972dd76eb0f..dcaaaafedbeac 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -673,14 +673,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_attrs( inner_hir_id, &[Attribute { - kind: AttrKind::Normal(ptr::P(NormalAttr { - item: AttrItem { - path: Path::from_ident(Ident::new(sym::track_caller, span)), - args: AttrArgs::Empty, - tokens: None, - }, - tokens: None, - })), + kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(sym::track_caller, span)))), id: self.tcx.sess.parse_sess.attr_id_generator.mk_attr_id(), style: AttrStyle::Outer, span: unstable_span, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 08ee3761bac2b..5681d365aa1b3 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -3,6 +3,7 @@ use super::ResolverAstLoweringExt; use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; +use hir::definitions::DefPathData; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; @@ -257,10 +258,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let itctx = ImplTraitContext::Universal; - let (generics, decl) = this.lower_generics(generics, id, &itctx, |this| { - let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id) - }); + let (generics, decl) = + this.lower_generics(generics, header.constness, id, &itctx, |this| { + let ret_id = asyncness.opt_return_id(); + this.lower_fn_decl(&decl, id, *fn_sig_span, FnDeclKind::Fn, ret_id) + }); let sig = hir::FnSig { decl, header: this.lower_fn_header(*header), @@ -295,6 +297,7 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, true); let (generics, ty) = self.lower_generics( &generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -316,6 +319,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Enum(enum_definition, generics) => { let (generics, variants) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -329,6 +333,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Struct(struct_def, generics) => { let (generics, struct_def) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), @@ -338,6 +343,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::Union(vdata, generics) => { let (generics, vdata) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), @@ -369,7 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, id, &itctx, |this| { + self.lower_generics(ast_generics, *constness, id, &itctx, |this| { let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( trait_ref, @@ -410,8 +416,18 @@ impl<'hir> LoweringContext<'_, 'hir> { })) } ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => { + // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible + let constness = if let Some(attrs) = attrs { + attrs + .iter() + .find(|x| x.has_name(sym::const_trait)) + .map_or(Const::No, |x| Const::Yes(x.span)) + } else { + Const::No + }; let (generics, (unsafety, items, bounds)) = self.lower_generics( generics, + constness, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -431,6 +447,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::TraitAlias(generics, bounds) => { let (generics, bounds) = self.lower_generics( generics, + Const::No, id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -593,7 +610,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; let (generics, (fn_dec, fn_args)) = - self.lower_generics(generics, i.id, &itctx, |this| { + self.lower_generics(generics, Const::No, i.id, &itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl( @@ -745,6 +762,7 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); let (generics, kind) = self.lower_generics( &generics, + Const::No, i.id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { @@ -843,6 +861,7 @@ impl<'hir> LoweringContext<'_, 'hir> { add_ty_alias_where_clause(&mut generics, *where_clauses, false); self.lower_generics( &generics, + Const::No, i.id, &ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { @@ -1201,9 +1220,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, id, &itctx, |this| { - this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async) - }); + let (generics, decl) = + self.lower_generics(generics, sig.header.constness, id, &itctx, |this| { + this.lower_fn_decl(&sig.decl, id, sig.span, kind, is_async) + }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1275,6 +1295,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_generics( &mut self, generics: &Generics, + constness: Const, parent_node_id: NodeId, itctx: &ImplTraitContext, f: impl FnOnce(&mut Self) -> T, @@ -1372,6 +1393,87 @@ 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(); + 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 hir_id = self.next_id(); + let const_id = self.next_id(); + let const_expr_id = self.next_id(); + let bool_id = self.next_id(); + + self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id))); + self.children.push((anon_const, hir::MaybeOwner::NonOwner(const_id))); + + 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)))), + span, + id: attr_id, + style: AttrStyle::Outer, + }, + ]); + self.attrs.insert(hir_id.local_id, attrs); + + let const_body = self.lower_body(|this| { + ( + &[], + hir::Expr { + hir_id: const_expr_id, + kind: hir::ExprKind::Lit( + this.arena.alloc(hir::Lit { node: LitKind::Bool(true), span }), + ), + span, + }, + ) + }); + + let param = hir::GenericParam { + def_id, + hir_id, + name: hir::ParamName::Plain(Ident { name: sym::host, span }), + span, + kind: hir::GenericParamKind::Const { + ty: self.arena.alloc(self.ty( + span, + hir::TyKind::Path(hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + res: Res::PrimTy(hir::PrimTy::Bool), + span, + segments: self.arena.alloc_from_iter([hir::PathSegment { + ident: Ident { name: sym::bool, span }, + hir_id: bool_id, + res: Res::PrimTy(hir::PrimTy::Bool), + args: None, + infer_args: false, + }]), + }), + )), + )), + default: Some(hir::AnonConst { def_id: anon_const, hir_id: const_id, body: const_body }), + }, + colon_span: None, + pure_wrt_drop: false, + source: hir::GenericParamSource::Generics, + }; + + params.push(param); + } + let lowered_generics = self.arena.alloc(hir::Generics { params: self.arena.alloc_from_iter(params), predicates: self.arena.alloc_from_iter(predicates), From 8eb3e0bf30ac1b9fe27441fcad045ce54304ac37 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 30 Jun 2023 15:21:35 +0000 Subject: [PATCH 3/7] enforce context effects in typeck --- compiler/rustc_hir_typeck/src/callee.rs | 69 +++++++++++++++++++++++-- compiler/rustc_hir_typeck/src/expr.rs | 1 + compiler/rustc_middle/src/ty/context.rs | 10 ++++ compiler/rustc_middle/src/ty/subst.rs | 5 ++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index be908c41c94df..7d6f6ad5e05de 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -6,8 +6,9 @@ use crate::type_error_struct; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, StashKey}; use rustc_hir as hir; -use rustc_hir::def::{self, CtorKind, Namespace, Res}; +use rustc_hir::def::{self, CtorKind, DefKind, Namespace, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::HirId; use rustc_hir_analysis::autoderef::Autoderef; use rustc_infer::{ infer, @@ -376,15 +377,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Expectation<'tcx>, ) -> Ty<'tcx> { let (fn_sig, def_id) = match *callee_ty.kind() { - ty::FnDef(def_id, subst) => { - let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, subst); + ty::FnDef(def_id, substs) => { + self.enforce_context_effects(call_expr.hir_id, call_expr.span, def_id, substs); + let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs); // Unit testing: function items annotated with // `#[rustc_evaluate_where_clauses]` trigger special output // to let us test the trait evaluation system. if self.tcx.has_attr(def_id, sym::rustc_evaluate_where_clauses) { let predicates = self.tcx.predicates_of(def_id); - let predicates = predicates.instantiate(self.tcx, subst); + let predicates = predicates.instantiate(self.tcx, substs); for (predicate, predicate_span) in predicates { let obligation = Obligation::new( self.tcx, @@ -405,6 +407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } (fn_sig, Some(def_id)) } + // FIXME(effects): these arms should error because we can't enforce them ty::FnPtr(sig) => (sig, None), _ => { for arg in arg_exprs { @@ -739,6 +742,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_sig.output() } + #[tracing::instrument(level = "debug", skip(self, span))] + pub(super) fn enforce_context_effects( + &self, + call_expr_hir: HirId, + span: Span, + callee_did: DefId, + callee_substs: SubstsRef<'tcx>, + ) { + let tcx = self.tcx; + + if !tcx.features().effects || tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { + return; + } + + // Compute the constness required by the context. + let context = tcx.hir().enclosing_body_owner(call_expr_hir); + let const_context = tcx.hir().body_const_context(context); + + let kind = tcx.def_kind(context.to_def_id()); + debug_assert_ne!(kind, DefKind::ConstParam); + + if tcx.has_attr(context.to_def_id(), sym::rustc_do_not_const_check) { + trace!("do not const check this context"); + return; + } + + let effect = match const_context { + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_, + Some(hir::ConstContext::ConstFn) => { + let substs = ty::InternalSubsts::identity_for_item(tcx, context); + substs.host_effect_param().expect("ConstContext::Maybe must have host effect param") + } + None => tcx.consts.true_, + }; + + let identity_substs = ty::InternalSubsts::identity_for_item(tcx, callee_did); + + trace!(?effect, ?identity_substs, ?callee_substs); + + // FIXME this should be made more efficient + let host_effect_param_index = identity_substs.iter().position(|x| { + matches!(x.unpack(), ty::GenericArgKind::Const(const_) if matches!(const_.kind(), ty::ConstKind::Param(param) if param.name == sym::host)) + }); + + if let Some(idx) = host_effect_param_index { + let param = callee_substs.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) => { + self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit(); + } + } + } + } + fn confirm_overloaded_call( &self, call_expr: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 52e3779cd41cf..265cacaf6c2fa 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1274,6 +1274,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We could add a "consider `foo::`" suggestion here, but I wasn't able to // trigger this codepath causing `structurally_resolve_type` to emit an error. + self.enforce_context_effects(expr.hir_id, expr.span, method.def_id, method.substs); self.write_method_call(expr.hir_id, method); Ok(method) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 1c610d6891b77..53786fb55821d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -320,6 +320,8 @@ pub struct CommonLifetimes<'tcx> { pub struct CommonConsts<'tcx> { pub unit: Const<'tcx>, + pub true_: Const<'tcx>, + pub false_: Const<'tcx>, } impl<'tcx> CommonTypes<'tcx> { @@ -417,6 +419,14 @@ impl<'tcx> CommonConsts<'tcx> { kind: ty::ConstKind::Value(ty::ValTree::zst()), ty: types.unit, }), + true_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)), + ty: types.bool, + }), + false_: mk_const(ty::ConstData { + kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)), + ty: types.bool, + }), } } } diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 111b1d009b392..4d5f5b8658c88 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -11,6 +11,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; +use rustc_span::sym; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; @@ -451,6 +452,10 @@ impl<'tcx> InternalSubsts<'tcx> { pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> SubstsRef<'tcx> { tcx.mk_substs_from_iter(self.iter().take(generics.count())) } + + pub fn host_effect_param(&'tcx self) -> Option> { + self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host)) + } } impl<'tcx> TypeFoldable> for SubstsRef<'tcx> { From 0b095a60d27921a3af0e9f1ac0d1d15b75dad0ef Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 30 Jun 2023 15:50:48 +0000 Subject: [PATCH 4/7] allow host param to be lowercase --- compiler/rustc_lint/src/nonstandard_style.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 79253cbc8b43c..145de49483519 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -533,6 +533,10 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_generic_param(&mut self, cx: &LateContext<'_>, param: &hir::GenericParam<'_>) { if let GenericParamKind::Const { .. } = param.kind { + // `rustc_host` params are explicitly allowed to be lowercase. + if cx.tcx.has_attr(param.def_id, sym::rustc_host) { + return; + } NonUpperCaseGlobals::check_upper_case(cx, "const parameter", ¶m.name.ident()); } } From 30b21b758a57da86509bb1ebf7a2fe57a98110fa Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 30 Jun 2023 15:50:58 +0000 Subject: [PATCH 5/7] add test --- .../src/collect/generics_of.rs | 8 +++-- .../effects/helloworld.rs | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 2206f640529ca..db446715596e9 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, Symbol}; -use rustc_span::Span; +use rustc_span::{sym, Span}; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; @@ -295,7 +295,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }) } GenericParamKind::Const { default, .. } => { - if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() { + // `rustc_host` effect params are allowed to have defaults. + if !matches!(allow_defaults, Defaults::Allowed) + && default.is_some() + && !tcx.has_attr(param.def_id, sym::rustc_host) + { tcx.sess.span_err( param.span, "defaults for const parameters are only allowed in \ diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs new file mode 100644 index 0000000000000..49457354cc9f4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/helloworld.rs @@ -0,0 +1,29 @@ +// check-pass + +// gate-test-effects +// ^ effects doesn't have a gate so we will trick tidy into thinking this is a gate test + +#![feature(const_trait_impl, effects, rustc_attrs)] + +// ensure we are passing in the correct host effect in always const contexts. + +pub const fn hmm() -> usize { + if host { + 1 + } else { + 0 + } +} + +const _: () = { + let x = hmm(); + assert!(0 == x); +}; + +/* FIXME(effects) +pub const fn uwu(x: [u8; hmm::<()>()]) { + let [] = x; +} +*/ + +fn main() {} From 58c105af04073885703093149c01b0c20d593d6b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 4 Jul 2023 13:49:08 +0000 Subject: [PATCH 6/7] include `host_effect_index` in `Generics` --- compiler/rustc_ast_lowering/src/item.rs | 13 ++++------ .../src/collect/generics_of.rs | 26 +++++++++++++++---- compiler/rustc_hir_typeck/src/callee.rs | 11 +++----- compiler/rustc_middle/src/ty/generics.rs | 3 +++ compiler/rustc_ty_utils/src/assoc.rs | 2 ++ 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5681d365aa1b3..ab68436c0939d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -417,14 +417,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => { // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible - let constness = if let Some(attrs) = attrs { - attrs - .iter() - .find(|x| x.has_name(sym::const_trait)) - .map_or(Const::No, |x| Const::Yes(x.span)) - } else { - Const::No - }; + let constness = attrs + .unwrap_or(&[]) + .iter() + .find(|x| x.has_name(sym::const_trait)) + .map_or(Const::No, |x| Const::Yes(x.span)); let (generics, (unsafety, items, bounds)) = self.lower_generics( generics, constness, diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index db446715596e9..ccc9f808411c3 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -101,6 +101,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, + host_effect_index: None, }; } else { // HACK(eddyb) this provides the correct generics when @@ -226,10 +227,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let has_self = opt_self.is_some(); let mut parent_has_self = false; let mut own_start = has_self as u32; + let mut host_effect_index = None; let parent_count = parent_def_id.map_or(0, |def_id| { let generics = tcx.generics_of(def_id); assert!(!has_self); parent_has_self = generics.has_self; + host_effect_index = generics.host_effect_index; own_start = generics.count() as u32; generics.parent_count + generics.params.len() }); @@ -251,11 +254,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; - let mut i = 0; + let mut i: u32 = 0; let mut next_index = || { let prev = i; i += 1; - prev as u32 + type_start + prev + type_start }; const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ @@ -295,10 +298,12 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }) } GenericParamKind::Const { default, .. } => { - // `rustc_host` effect params are allowed to have defaults. + let is_host_param = tcx.has_attr(param.def_id, sym::rustc_host); + if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() - && !tcx.has_attr(param.def_id, sym::rustc_host) + // `rustc_host` effect params are allowed to have defaults. + && !is_host_param { tcx.sess.span_err( param.span, @@ -307,8 +312,18 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ); } + let index = next_index(); + + if is_host_param { + if let Some(idx) = host_effect_index { + bug!("parent also has host effect param? index: {idx}, def: {def_id:?}"); + } + + host_effect_index = Some(parent_count + index as usize); + } + Some(ty::GenericParamDef { - index: next_index(), + index, name: param.name.ident().name, def_id: param.def_id.to_def_id(), pure_wrt_drop: param.pure_wrt_drop, @@ -360,6 +375,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { param_def_id_to_index, has_self: has_self || parent_has_self, has_late_bound_regions: has_late_bound_regions(tcx, node), + host_effect_index, } } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 7d6f6ad5e05de..d29ba810d6416 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -777,16 +777,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => tcx.consts.true_, }; - let identity_substs = ty::InternalSubsts::identity_for_item(tcx, callee_did); + let generics = tcx.generics_of(callee_did); - trace!(?effect, ?identity_substs, ?callee_substs); + trace!(?effect, ?generics, ?callee_substs); - // FIXME this should be made more efficient - let host_effect_param_index = identity_substs.iter().position(|x| { - matches!(x.unpack(), ty::GenericArgKind::Const(const_) if matches!(const_.kind(), ty::ConstKind::Param(param) if param.name == sym::host)) - }); - - if let Some(idx) = host_effect_param_index { + if let Some(idx) = generics.host_effect_index { let param = callee_substs.const_at(idx); let cause = self.misc(span); match self.at(&cause, self.param_env).eq(infer::DefineOpaqueTypes::No, effect, param) { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 58fd6e1aa272f..ea82e0070b147 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -133,6 +133,9 @@ pub struct Generics { pub has_self: bool, pub has_late_bound_regions: Option, + + // The index of the host effect when substituted. (i.e. might be index to parent substs) + pub host_effect_index: Option, } impl<'tcx> Generics { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index b59458bbf35cc..1adaf5f572ec7 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -337,6 +337,7 @@ fn associated_type_for_impl_trait_in_trait( param_def_id_to_index, has_self: opaque_ty_generics.has_self, has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, + host_effect_index: parent_generics.host_effect_index, } }); @@ -415,6 +416,7 @@ fn associated_type_for_impl_trait_in_impl( param_def_id_to_index, has_self: false, has_late_bound_regions: trait_assoc_generics.has_late_bound_regions, + host_effect_index: parent_generics.host_effect_index, } }); From 25fc6c15869b0bd4241da452ddd2d30b0c16a815 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 4 Jul 2023 14:08:53 +0000 Subject: [PATCH 7/7] add fixme --- compiler/rustc_hir_typeck/src/callee.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d29ba810d6416..ed9fe8fc856ed 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -789,6 +789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicates(obligations); } Err(e) => { + // FIXME(effects): better diagnostic self.err_ctxt().report_mismatched_consts(&cause, effect, param, e).emit(); } }