about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-07-05 13:42:00 +0000
committerbors <bors@rust-lang.org>2023-07-05 13:42:00 +0000
commite4cd1610067501fa4d347eba7b18f77137dbbf48 (patch)
tree384a419aa2e8e343ce7fa9262f43cae06239ed6d /compiler
parentdfe0683138de0959b6ab6a039b54d9347f6a6355 (diff)
parent25fc6c15869b0bd4241da452ddd2d30b0c16a815 (diff)
downloadrust-e4cd1610067501fa4d347eba7b18f77137dbbf48.tar.gz
rust-e4cd1610067501fa4d347eba7b18f77137dbbf48.zip
Auto merge of #113210 - fee1-dead-contrib:effects-mvp, r=oli-obk
Effects/keyword generics MVP

This adds `feature(effects)`, which adds `const host: bool` to the generics of const functions, const traits and const impls. This will be used to replace the current logic around const traits.

r? `@oli-obk`
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs9
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs9
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs117
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs30
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs65
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs1
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs10
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs3
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs5
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs2
14 files changed, 240 insertions, 26 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index a398fd80119..a7198fbf887 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<LazyAttrTokenStream>,
 }
 
+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 29972dd76eb..dcaaaafedbe 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 08ee3761bac..ab68436c093 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,15 @@ 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 = 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,
                     id,
                     &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
@@ -431,6 +444,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 +607,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 +759,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 +858,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 +1217,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 +1292,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_generics<T>(
         &mut self,
         generics: &Generics,
+        constness: Const,
         parent_node_id: NodeId,
         itctx: &ImplTraitContext,
         f: impl FnOnce(&mut Self) -> T,
@@ -1372,6 +1390,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),
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 906c31c9a3d..5185820a727 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 3c5bff3812a..36600004404 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_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 2206f640529..ccc9f808411 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::*;
@@ -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,7 +298,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
             })
         }
         GenericParamKind::Const { default, .. } => {
-            if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
+            let is_host_param = tcx.has_attr(param.def_id, sym::rustc_host);
+
+            if !matches!(allow_defaults, Defaults::Allowed)
+                && default.is_some()
+                // `rustc_host` effect params are allowed to have defaults.
+                && !is_host_param
+            {
                 tcx.sess.span_err(
                     param.span,
                     "defaults for const parameters are only allowed in \
@@ -303,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,
@@ -356,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 be908c41c94..ed9fe8fc856 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,60 @@ 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 generics = tcx.generics_of(callee_did);
+
+        trace!(?effect, ?generics, ?callee_substs);
+
+        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) {
+                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();
+                }
+            }
+        }
+    }
+
     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 52e3779cd41..265cacaf6c2 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::<params>`" 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_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 79253cbc8b4..145de494835 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", &param.name.ident());
         }
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e50331bc461..52b6a7a817e 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/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 5eb3289ea3e..452bbf11263 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -135,6 +135,9 @@ pub struct Generics {
 
     pub has_self: bool,
     pub has_late_bound_regions: Option<Span>,
+
+    // The index of the host effect when substituted. (i.e. might be index to parent substs)
+    pub host_effect_index: Option<usize>,
 }
 
 impl<'tcx> Generics {
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 111b1d009b3..4d5f5b8658c 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<ty::Const<'tcx>> {
+        self.consts().rfind(|x| matches!(x.kind(), ty::ConstKind::Param(p) if p.name == sym::host))
+    }
 }
 
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for SubstsRef<'tcx> {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index c58d85b99f7..66a627d5aac 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,
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index b59458bbf35..1adaf5f572e 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,
         }
     });