about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2023-06-30 15:21:35 +0000
committerDeadbeef <ent3rm4n@gmail.com>2023-07-04 11:47:46 +0000
commit8eb3e0bf30ac1b9fe27441fcad045ce54304ac37 (patch)
treeac6d063363ed8be33171dc257d8a21ecd06769ef
parent1c837cb6f7347b257ea42b8587a7c84bd13c92c9 (diff)
downloadrust-8eb3e0bf30ac1b9fe27441fcad045ce54304ac37.tar.gz
rust-8eb3e0bf30ac1b9fe27441fcad045ce54304ac37.zip
enforce context effects in typeck
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs69
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs1
-rw-r--r--compiler/rustc_middle/src/ty/context.rs10
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs5
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 be908c41c94..7d6f6ad5e05 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 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_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1c610d6891b..53786fb5582 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 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> {