about summary refs log tree commit diff
diff options
context:
space:
mode:
authorben <benlewisj@gmail.com>2019-10-01 17:55:26 +1300
committerben <benlewisj@gmail.com>2019-10-09 05:10:00 +1300
commit2afd277bc3ad53ddb6064b7f2a739583e8b4820a (patch)
treedd7d43db310357a596e14a573a55aea4090c2a55
parentec557aa8180ca08ff749793b3d42383618b96044 (diff)
downloadrust-2afd277bc3ad53ddb6064b7f2a739583e8b4820a.tar.gz
rust-2afd277bc3ad53ddb6064b7f2a739583e8b4820a.zip
Fix calling function pointer const parameters. Also fixes inference of
function pointer const parameters.
-rw-r--r--src/librustc/ty/relate.rs66
-rw-r--r--src/librustc_mir/monomorphize/collector.rs10
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.rs20
-rw-r--r--src/test/ui/const-generics/fn-const-param-call.stderr8
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.rs26
-rw-r--r--src/test/ui/const-generics/fn-const-param-infer.stderr45
6 files changed, 145 insertions, 30 deletions
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 5489c6f5d5a..2d811a83c10 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -8,7 +8,7 @@ use crate::hir::def_id::DefId;
 use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use crate::ty::error::{ExpectedFound, TypeError};
-use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar};
+use crate::mir::interpret::{ConstValue, get_slice_bytes, Scalar, GlobalAlloc};
 use std::rc::Rc;
 use std::iter;
 use rustc_target::spec::abi;
@@ -561,37 +561,47 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
     // implement both `PartialEq` and `Eq`, corresponding to
     // `structural_match` types.
     // FIXME(const_generics): check for `structural_match` synthetic attribute.
-    match (eagerly_eval(a), eagerly_eval(b)) {
+    let new_const_val = match (eagerly_eval(a), eagerly_eval(b)) {
         (ConstValue::Infer(_), _) | (_, ConstValue::Infer(_)) => {
             // The caller should handle these cases!
             bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
         }
         (ConstValue::Param(a_p), ConstValue::Param(b_p)) if a_p.index == b_p.index => {
-            Ok(a)
+            return Ok(a);
         }
         (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => {
-            Ok(a)
+            return Ok(a);
         }
-        (a_val @ ConstValue::Scalar(Scalar::Raw { .. }), b_val @ _)
-            if a.ty == b.ty && a_val == b_val =>
-        {
-            Ok(tcx.mk_const(ty::Const {
-                val: a_val,
-                ty: a.ty,
-            }))
+        (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => {
+            if a_val == b_val {
+                Ok(ConstValue::Scalar(a_val))
+            } else if let ty::FnPtr(_) = a.ty.kind {
+                let alloc_map = tcx.alloc_map.lock();
+                let get_fn_instance = |val: Scalar| {
+                    let ptr = val.to_ptr().unwrap();
+                    if let Some(GlobalAlloc::Function(instance)) = alloc_map.get(ptr.alloc_id) {
+                        instance
+                    } else {
+                        bug!("Allocation for FnPtr isn't a function");
+                    }
+                };
+                let a_instance = get_fn_instance(a_val);
+                let b_instance = get_fn_instance(b_val);
+                if a_instance == b_instance {
+                    Ok(ConstValue::Scalar(a_val))
+                } else {
+                    Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+                }
+            } else {
+                Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
+            }
         }
 
-        // FIXME(const_generics): we should either handle `Scalar::Ptr` or add a comment
-        // saying that we're not handling it intentionally.
-
         (a_val @ ConstValue::Slice { .. }, b_val @ ConstValue::Slice { .. }) => {
             let a_bytes = get_slice_bytes(&tcx, a_val);
             let b_bytes = get_slice_bytes(&tcx, b_val);
             if a_bytes == b_bytes {
-                Ok(tcx.mk_const(ty::Const {
-                    val: a_val,
-                    ty: a.ty,
-                }))
+                Ok(a_val)
             } else {
                 Err(TypeError::ConstMismatch(expected_found(relation, &a, &b)))
             }
@@ -602,16 +612,16 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
         // FIXME(const_generics): this is wrong, as it is a projection
         (ConstValue::Unevaluated(a_def_id, a_substs),
             ConstValue::Unevaluated(b_def_id, b_substs)) if a_def_id == b_def_id => {
-                let substs =
-                    relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
-                Ok(tcx.mk_const(ty::Const {
-                    val: ConstValue::Unevaluated(a_def_id, &substs),
-                    ty: a.ty,
-                }))
-            }
-
-        _ => Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
-    }
+            let substs =
+                relation.relate_with_variance(ty::Variance::Invariant, &a_substs, &b_substs)?;
+            Ok(ConstValue::Unevaluated(a_def_id, &substs))
+        }
+        _ =>  Err(TypeError::ConstMismatch(expected_found(relation, &a, &b))),
+    };
+    new_const_val.map(|val| tcx.mk_const(ty::Const {
+        val,
+        ty: a.ty,
+    }))
 }
 
 impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 3ac837dd330..a0c3ae82bcc 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1265,7 +1265,13 @@ fn collect_const<'tcx>(
 ) {
     debug!("visiting const {:?}", constant);
 
-    match constant.val {
+    let substituted_constant = if let ConstValue::Param(param) = constant.val {
+        param_substs.const_at(param.index as usize)
+    } else {
+        constant
+    };
+
+    match substituted_constant.val {
         ConstValue::Scalar(Scalar::Ptr(ptr)) =>
             collect_miri(tcx, ptr.alloc_id, output),
         ConstValue::Slice { data: alloc, start: _, end: _ } |
@@ -1297,7 +1303,7 @@ fn collect_const<'tcx>(
                     tcx.def_span(def_id), "collection encountered polymorphic constant",
                 ),
             }
-        }
+        },
         _ => {},
     }
 }
diff --git a/src/test/ui/const-generics/fn-const-param-call.rs b/src/test/ui/const-generics/fn-const-param-call.rs
new file mode 100644
index 00000000000..9f64d4bd086
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-call.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+fn function() -> u32 {
+    17
+}
+
+struct Wrapper<const F: fn() -> u32>;
+
+impl<const F: fn() -> u32> Wrapper<{F}> {
+    fn call() -> u32 {
+        F()
+    }
+}
+
+fn main() {
+    assert_eq!(Wrapper::<{function}>::call(), 17);
+}
\ No newline at end of file
diff --git a/src/test/ui/const-generics/fn-const-param-call.stderr b/src/test/ui/const-generics/fn-const-param-call.stderr
new file mode 100644
index 00000000000..88d7700680b
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-call.stderr
@@ -0,0 +1,8 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/fn-const-param-call.rs:3:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/const-generics/fn-const-param-infer.rs b/src/test/ui/const-generics/fn-const-param-infer.rs
new file mode 100644
index 00000000000..ac48ccc26e1
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-infer.rs
@@ -0,0 +1,26 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct Checked<const F: fn(usize) -> bool>;
+
+fn not_one(val: usize) -> bool { val != 1 }
+fn not_two(val: usize) -> bool { val != 2 }
+
+fn generic_arg<T>(val: T) -> bool { true }
+
+fn generic<T>(val: usize) -> bool { val != 1 }
+
+fn main() {
+    let _: Option<Checked<{not_one}>> = None;
+    let _: Checked<{not_one}> = Checked::<{not_one}>;
+    let _: Checked<{not_one}> = Checked::<{not_two}>; //~ mismatched types
+
+    let _ = Checked::<{generic_arg}>;
+    let _ = Checked::<{generic_arg::<usize>}>;
+    let _ = Checked::<{generic_arg::<u32>}>;  //~ mismatched types
+
+    let _ = Checked::<{generic}>; //~ type annotations needed
+    let _ = Checked::<{generic::<u16>}>;
+    let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>;
+    let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; //~ mismatched types
+}
\ No newline at end of file
diff --git a/src/test/ui/const-generics/fn-const-param-infer.stderr b/src/test/ui/const-generics/fn-const-param-infer.stderr
new file mode 100644
index 00000000000..4ef55fd22d4
--- /dev/null
+++ b/src/test/ui/const-generics/fn-const-param-infer.stderr
@@ -0,0 +1,45 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/fn-const-param-infer.rs:1:12
+   |
+LL | #![feature(const_generics)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/fn-const-param-infer.rs:16:33
+   |
+LL |     let _: Checked<{not_one}> = Checked::<{not_two}>;
+   |                                 ^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(1).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(10).0x0) : fn(usize) -> bool`
+   |
+   = note: expected type `Checked<>`
+              found type `Checked<>`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-const-param-infer.rs:20:24
+   |
+LL |     let _ = Checked::<{generic_arg::<u32>}>;
+   |                        ^^^^^^^^^^^^^^^^^^ expected usize, found u32
+   |
+   = note: expected type `fn(usize) -> bool`
+              found type `fn(u32) -> bool {generic_arg::<u32>}`
+
+error[E0282]: type annotations needed
+  --> $DIR/fn-const-param-infer.rs:22:24
+   |
+LL |     let _ = Checked::<{generic}>;
+   |                        ^^^^^^^ cannot infer type for `T`
+
+error[E0308]: mismatched types
+  --> $DIR/fn-const-param-infer.rs:25:40
+   |
+LL |     let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Scalar(AllocId(7).0x0) : fn(usize) -> bool`, found `Scalar(AllocId(20).0x0) : fn(usize) -> bool`
+   |
+   = note: expected type `Checked<>`
+              found type `Checked<>`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0282, E0308.
+For more information about an error, try `rustc --explain E0282`.