about summary refs log tree commit diff
path: root/src/librustc/ty
diff options
context:
space:
mode:
authorTyler Mandry <tmandry@gmail.com>2019-10-11 15:09:42 -0700
committerGitHub <noreply@github.com>2019-10-11 15:09:42 -0700
commitea0d155f2d0fa8328c93ee7ca52f96ccd764ccf0 (patch)
tree69408fb9053a57ce42a8e5babf752d448ed05143 /src/librustc/ty
parent215b09194f2ca1c19b1b5b4f5de4044671d6ad9a (diff)
parent8569dd1db985509cd235fafdd962aa52ced68e35 (diff)
downloadrust-ea0d155f2d0fa8328c93ee7ca52f96ccd764ccf0.tar.gz
rust-ea0d155f2d0fa8328c93ee7ca52f96ccd764ccf0.zip
Rollup merge of #64986 - skinny121:fn-ptr-const-generics, r=varkor
Function pointers as const generic arguments

Makes function pointers as const generic arguments usable.

Fixes #62395

r? @varkor
Diffstat (limited to 'src/librustc/ty')
-rw-r--r--src/librustc/ty/print/pretty.rs218
-rw-r--r--src/librustc/ty/relate.rs58
2 files changed, 137 insertions, 139 deletions
diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs
index 07c63a92b39..c4967f8d66d 100644
--- a/src/librustc/ty/print/pretty.rs
+++ b/src/librustc/ty/print/pretty.rs
@@ -863,125 +863,121 @@ pub trait PrettyPrinter<'tcx>:
         }
 
         let u8 = self.tcx().types.u8;
-        if let ty::FnDef(did, substs) = ct.ty.kind {
-            p!(print_value_path(did, substs));
-            return Ok(self);
-        }
-        if let ConstValue::Unevaluated(did, substs) = ct.val {
-            match self.tcx().def_kind(did) {
-                | Some(DefKind::Static)
-                | Some(DefKind::Const)
-                | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
-                _ => if did.is_local() {
-                    let span = self.tcx().def_span(did);
-                    if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
-                        p!(write("{}", snip))
+
+        match (ct.val, &ct.ty.kind) {
+            (_,  ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
+            (ConstValue::Unevaluated(did, substs), _) => {
+                match self.tcx().def_kind(did) {
+                    | Some(DefKind::Static)
+                    | Some(DefKind::Const)
+                    | Some(DefKind::AssocConst) => p!(print_value_path(did, substs)),
+                    _ => if did.is_local() {
+                        let span = self.tcx().def_span(did);
+                        if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
+                            p!(write("{}", snip))
+                        } else {
+                            p!(write("_: "), print(ct.ty))
+                        }
                     } else {
                         p!(write("_: "), print(ct.ty))
-                    }
+                    },
+                }
+            },
+            (ConstValue::Infer(..), _) =>  p!(write("_: "), print(ct.ty)),
+            (ConstValue::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
+            (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) =>
+                p!(write("{}", if data == 0 { "false" } else { "true" })),
+            (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) =>
+                p!(write("{}f32", Single::from_bits(data))),
+            (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) =>
+                p!(write("{}f64", Double::from_bits(data))),
+            (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => {
+                let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
+                let max = truncate(u128::max_value(), bit_size);
+
+                if data == max {
+                    p!(write("std::{}::MAX", ui))
                 } else {
-                    p!(write("_: "), print(ct.ty))
-                },
-            }
-            return Ok(self);
-        }
-        if let ConstValue::Infer(..) = ct.val {
-            p!(write("_: "), print(ct.ty));
-            return Ok(self);
-        }
-        if let ConstValue::Param(ParamConst { name, .. }) = ct.val {
-            p!(write("{}", name));
-            return Ok(self);
-        }
-        if let ConstValue::Scalar(Scalar::Raw { data, .. }) = ct.val {
-            match ct.ty.kind {
-                ty::Bool => {
-                    p!(write("{}", if data == 0 { "false" } else { "true" }));
-                    return Ok(self);
-                },
-                ty::Float(ast::FloatTy::F32) => {
-                    p!(write("{}f32", Single::from_bits(data)));
-                    return Ok(self);
-                },
-                ty::Float(ast::FloatTy::F64) => {
-                    p!(write("{}f64", Double::from_bits(data)));
-                    return Ok(self);
-                },
-                ty::Uint(ui) => {
-                    let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(ui)).size();
-                    let max = truncate(u128::max_value(), bit_size);
+                    p!(write("{}{}", data, ui))
+                };
+            },
+            (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => {
+                let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i))
+                    .size().bits() as u128;
+                let min = 1u128 << (bit_size - 1);
+                let max = min - 1;
+
+                let ty = self.tcx().lift(&ct.ty).unwrap();
+                let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
+                    .unwrap()
+                    .size;
+                match data {
+                    d if d == min => p!(write("std::{}::MIN", i)),
+                    d if d == max => p!(write("std::{}::MAX", i)),
+                    _ => p!(write("{}{}", sign_extend(data, size) as i128, i))
+                }
+            },
+            (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) =>
+                p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())),
+            (ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")),
+            (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => {
+                let instance = {
+                    let alloc_map = self.tcx().alloc_map.lock();
+                    alloc_map.unwrap_fn(ptr.alloc_id)
+                };
+                p!(print_value_path(instance.def_id(), instance.substs));
+            },
+            _ => {
+                let printed = if let ty::Ref(_, ref_ty, _) = ct.ty.kind {
+                    let byte_str = match (ct.val, &ref_ty.kind) {
+                        (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
+                            let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
+                            Some(self.tcx()
+                                .alloc_map.lock()
+                                .unwrap_memory(ptr.alloc_id)
+                                .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
+                        },
+                        (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
+                            // The `inspect` here is okay since we checked the bounds, and there are
+                            // no relocations (we have an active slice reference here). We don't use
+                            // this result to affect interpreter execution.
+                            Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
+                        },
+                        _ => None,
+                    };
 
-                    if data == max {
-                        p!(write("std::{}::MAX", ui))
+                    if let Some(byte_str) = byte_str {
+                        p!(write("b\""));
+                        for &c in byte_str {
+                            for e in std::ascii::escape_default(c) {
+                                self.write_char(e as char)?;
+                            }
+                        }
+                        p!(write("\""));
+                        true
+                    } else if let (ConstValue::Slice { data, start, end }, ty::Str) =
+                        (ct.val, &ref_ty.kind)
+                    {
+                        // The `inspect` here is okay since we checked the bounds, and there are no
+                        // relocations (we have an active `str` reference here). We don't use this
+                        // result to affect interpreter execution.
+                        let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
+                        let s = ::std::str::from_utf8(slice)
+                            .expect("non utf8 str from miri");
+                        p!(write("{:?}", s));
+                        true
                     } else {
-                        p!(write("{}{}", data, ui))
-                    };
-                    return Ok(self);
-                },
-                ty::Int(i) =>{
-                    let bit_size = Integer::from_attr(&self.tcx(), SignedInt(i))
-                        .size().bits() as u128;
-                    let min = 1u128 << (bit_size - 1);
-                    let max = min - 1;
-
-                    let ty = self.tcx().lift(&ct.ty).unwrap();
-                    let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty))
-                        .unwrap()
-                        .size;
-                    match data {
-                        d if d == min => p!(write("std::{}::MIN", i)),
-                        d if d == max => p!(write("std::{}::MAX", i)),
-                        _ => p!(write("{}{}", sign_extend(data, size) as i128, i))
-                    }
-                    return Ok(self);
-                },
-                ty::Char => {
-                    p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap()));
-                    return Ok(self);
-                }
-                _ => {},
-            }
-        }
-        if let ty::Ref(_, ref_ty, _) = ct.ty.kind {
-            let byte_str = match (ct.val, &ref_ty.kind) {
-                (ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
-                    let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
-                    Some(self.tcx()
-                        .alloc_map.lock()
-                        .unwrap_memory(ptr.alloc_id)
-                        .get_bytes(&self.tcx(), ptr, Size::from_bytes(n)).unwrap())
-                },
-                (ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
-                    // The `inspect` here is okay since we checked the bounds, and there are no
-                    // relocations (we have an active slice reference here). We don't use this
-                    // result to affect interpreter execution.
-                    Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
-                },
-                (ConstValue::Slice { data, start, end }, ty::Str) => {
-                    // The `inspect` here is okay since we checked the bounds, and there are no
-                    // relocations (we have an active `str` reference here). We don't use this
-                    // result to affect interpreter execution.
-                    let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
-                    let s = ::std::str::from_utf8(slice)
-                        .expect("non utf8 str from miri");
-                    p!(write("{:?}", s));
-                    return Ok(self);
-                },
-                _ => None,
-            };
-            if let Some(byte_str) = byte_str {
-                p!(write("b\""));
-                for &c in byte_str {
-                    for e in std::ascii::escape_default(c) {
-                        self.write_char(e as char)?;
+                        false
                     }
+                } else {
+                    false
+                };
+                if !printed {
+                    // fallback
+                    p!(write("{:?} : ", ct.val), print(ct.ty))
                 }
-                p!(write("\""));
-                return Ok(self);
             }
-        }
-        p!(write("{:?} : ", ct.val), print(ct.ty));
-
+        };
         Ok(self)
     }
 }
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 5489c6f5d5a..41f34703622 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};
 use std::rc::Rc;
 use std::iter;
 use rustc_target::spec::abi;
@@ -561,37 +561,39 @@ 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 a_instance = alloc_map.unwrap_fn(a_val.to_ptr().unwrap().alloc_id);
+                let b_instance = alloc_map.unwrap_fn(b_val.to_ptr().unwrap().alloc_id);
+                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 +604,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>> {