Skip to content

Commit

Permalink
Auto merge of #31710 - eddyb:reify, r=nikomatsakis
Browse files Browse the repository at this point in the history
Distinguish fn item types to allow reification from nothing to fn pointers.

The first commit is a rebase of #26284, except for files that have moved since.

This is a [breaking-change], due to:
* each FFI function has a distinct type, like all other functions currently do
* all generic parameters on functions are recorded in their item types, e.g.:
`size_of::<u8>` & `size_of::<i8>`'s types differ despite their identical signature.
* function items are zero-sized, which will stop transmutes from working on them

The first two cases are handled in most cases with the new coerce-unify logic,
which will combine incompatible function item types into function pointers,
at the outer-most level of if-else chains, match arms and array literals.

The last case is specially handled during type-checking such that transmutes
from a function item type to a pointer or integer type will continue to work for
another release cycle, but are being linted against. To get rid of warnings and
ensure your code will continue to compile, cast to a pointer before transmuting.
  • Loading branch information
bors committed Mar 10, 2016
2 parents 0b9995b + 3855fa9 commit bcda58f
Show file tree
Hide file tree
Showing 109 changed files with 2,056 additions and 2,242 deletions.
9 changes: 8 additions & 1 deletion src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ declare_lint! {
"uses of #[derive] with raw pointers are rarely correct"
}

declare_lint! {
pub TRANSMUTE_FROM_FN_ITEM_TYPES,
Warn,
"transmute from function item type to pointer-sized type erroneously allowed"
}

/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -177,7 +183,8 @@ impl LintPass for HardwiredLints {
INVALID_TYPE_PARAM_DEFAULT,
MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT,
CONST_ERR,
RAW_POINTER_DERIVE
RAW_POINTER_DERIVE,
TRANSMUTE_FROM_FN_ITEM_TYPES
)
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,9 @@ pub fn check_crate(tcx: &TyCtxt, access_levels: &AccessLevels) {
}

*tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();

// Put the lint store back in the session.
mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
}

pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ enum RootUnsafeContext {

fn type_is_unsafe_function(ty: Ty) -> bool {
match ty.sty {
ty::TyBareFn(_, ref f) => f.unsafety == hir::Unsafety::Unsafe,
ty::TyFnDef(_, _, ref f) |
ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe,
_ => false,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
callee, callee_ty);
let call_scope = self.tcx().region_maps.node_extent(call.id);
match callee_ty.sty {
ty::TyBareFn(..) => {
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
self.consume_expr(callee);
}
ty::TyError => { }
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
ty::TySlice(..) |
ty::TyRawPtr(..) |
ty::TyRef(..) |
ty::TyBareFn(..) |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyTrait(..) |
ty::TyStruct(..) |
ty::TyClosure(..) |
Expand Down
14 changes: 7 additions & 7 deletions src/librustc/middle/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
-> UnitResult<'tcx>
{
debug!("mk_eqty({:?} <: {:?})", a, b);
cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
cx.eq_types(a_is_expected, origin, a, b)
}

pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
Expand All @@ -466,7 +466,7 @@ pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
{
debug!("mk_eq_trait_refs({:?} <: {:?})",
a, b);
cx.commit_if_ok(|_| cx.eq_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
cx.eq_trait_refs(a_is_expected, origin, a, b)
}

pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
Expand All @@ -478,7 +478,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
{
debug!("mk_sub_poly_trait_refs({:?} <: {:?})",
a, b);
cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
}

fn expected_found<T>(a_is_expected: bool,
Expand Down Expand Up @@ -1351,18 +1351,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}

pub fn report_mismatched_types(&self,
span: Span,
origin: TypeOrigin,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
err: &TypeError<'tcx>) {
err: TypeError<'tcx>) {
let trace = TypeTrace {
origin: TypeOrigin::Misc(span),
origin: origin,
values: Types(ExpectedFound {
expected: expected,
found: actual
})
};
self.report_and_explain_type_error(trace, err);
self.report_and_explain_type_error(trace, &err);
}

pub fn report_conflicting_default_types(&self,
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/intrinsicck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use dep_graph::DepNode;
use middle::def::Def;
use middle::def_id::DefId;
use middle::subst::{Subst, Substs, EnumeratedItems};
use middle::ty::{TransmuteRestriction, TyCtxt, TyBareFn};
use middle::ty::{TransmuteRestriction, TyCtxt};
use middle::ty::{self, Ty, TypeFoldable};

use std::fmt;
Expand Down Expand Up @@ -53,7 +53,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> {
impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
let intrinsic = match self.tcx.lookup_item_type(def_id).ty.sty {
ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic,
ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic,
_ => return false
};
intrinsic && self.tcx.item_name(def_id).as_str() == "transmute"
Expand Down Expand Up @@ -238,7 +238,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> {
Def::Fn(did) if self.def_id_is_transmute(did) => {
let typ = self.tcx.node_id_to_type(expr.id);
match typ.sty {
TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
if let ty::FnConverging(to) = bare_fn_ty.sig.0.output {
let from = bare_fn_ty.sig.0.inputs[0];
self.check_transmute(expr.span, from, to, expr.id);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/subst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,11 @@ impl<'tcx> Substs<'tcx> {
Substs { types: types, regions: regions }
}

pub fn with_method_from(self,
pub fn with_method_from(&self,
meth_substs: &Substs<'tcx>)
-> Substs<'tcx>
{
let Substs { types, regions } = self;
let Substs { types, regions } = self.clone();
let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
let regions = regions.map(|r| {
r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace))
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/traits/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ fn ty_is_local_constructor<'tcx>(tcx: &TyCtxt<'tcx>,
ty::TyUint(..) |
ty::TyFloat(..) |
ty::TyStr |
ty::TyBareFn(..) |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyArray(..) |
ty::TySlice(..) |
ty::TyRawPtr(..) |
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ pub enum Vtable<'tcx, N> {
#[derive(Clone, PartialEq, Eq)]
pub struct VtableImplData<'tcx, N> {
pub impl_def_id: DefId,
pub substs: subst::Substs<'tcx>,
pub substs: &'tcx subst::Substs<'tcx>,
pub nested: Vec<N>
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ fn confirm_impl_candidate<'cx,'tcx>(
for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
if assoc_ty.name == obligation.predicate.item_name {
return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs),
return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs),
impl_vtable.nested);
}
}
Expand Down
19 changes: 15 additions & 4 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1286,7 +1286,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

// provide an impl, but only for suitable `fn` pointers
ty::TyBareFn(_, &ty::BareFnTy {
ty::TyFnDef(_, _, &ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: _,
output: ty::FnConverging(_),
variadic: false
})
}) |
ty::TyFnPtr(&ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
Expand Down Expand Up @@ -1646,7 +1655,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::TyInt(_) |
ty::TyBool |
ty::TyFloat(_) |
ty::TyBareFn(..) |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyChar => {
// safe for everything
ok_if(Vec::new())
Expand Down Expand Up @@ -1850,7 +1860,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::TyInt(_) |
ty::TyBool |
ty::TyFloat(_) |
ty::TyBareFn(..) |
ty::TyFnDef(..) |
ty::TyFnPtr(_) |
ty::TyStr |
ty::TyError |
ty::TyInfer(ty::IntVar(_)) |
Expand Down Expand Up @@ -2294,7 +2305,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
impl_obligations.append(&mut substs.obligations);

VtableImplData { impl_def_id: impl_def_id,
substs: substs.value,
substs: self.tcx().mk_substs(substs.value),
nested: impl_obligations }
}

Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,10 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx

impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let substs = self.substs.fold_with(folder);
traits::VtableImplData {
impl_def_id: self.impl_def_id,
substs: self.substs.fold_with(folder),
substs: folder.tcx().mk_substs(substs),
nested: self.nested.fold_with(folder),
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/ty/adjustment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ impl<'tcx> ty::TyS<'tcx> {
match *adjustment {
AdjustReifyFnPointer => {
match self.sty {
ty::TyBareFn(Some(_), b) => {
cx.mk_fn(None, b)
ty::TyFnDef(_, _, b) => {
cx.mk_ty(ty::TyFnPtr(b))
}
_ => {
cx.sess.bug(
Expand All @@ -168,7 +168,7 @@ impl<'tcx> ty::TyS<'tcx> {

AdjustUnsafeFnPointer => {
match self.sty {
ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
ty::TyFnPtr(b) => cx.safe_to_unsafe_fn_ty(b),
ref b => {
cx.sess.bug(
&format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl<'tcx> CastTy<'tcx> {
Some(CastTy::Int(IntTy::CEnum)),
ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)),
ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)),
ty::TyBareFn(..) => Some(CastTy::FnPtr),
ty::TyFnPtr(..) => Some(CastTy::FnPtr),
_ => None,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty/contents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl<'tcx> ty::TyS<'tcx> {
// Scalar and unique types are sendable, and durable
ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) |
ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
ty::TyBareFn(..) | ty::TyChar => {
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => {
TC::None
}

Expand Down
38 changes: 12 additions & 26 deletions src/librustc/middle/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ use std::borrow::Borrow;
use std::cell::{Cell, RefCell, Ref};
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
use syntax::parse::token::special_idents;
Expand Down Expand Up @@ -734,8 +733,8 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn print_debug_stats(&self) {
sty_debug_print!(
self,
TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait,
TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);

println!("Substs interner: #{}", self.substs_interner.borrow().len());
println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
Expand Down Expand Up @@ -792,12 +791,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// Create an unsafe fn ty based on a safe fn ty.
pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy {
self.mk_fn_ptr(ty::BareFnTy {
unsafety: hir::Unsafety::Unsafe,
abi: bare_fn.abi,
sig: bare_fn.sig.clone()
});
self.mk_fn(None, unsafe_fn_ty_a)
})
}

pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> {
Expand Down Expand Up @@ -946,26 +944,14 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_ty(TyBool)
}

pub fn mk_fn(&self,
opt_def_id: Option<DefId>,
fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
self.mk_ty(TyBareFn(opt_def_id, fty))
}

pub fn mk_ctor_fn(&self,
def_id: DefId,
input_tys: &[Ty<'tcx>],
output: Ty<'tcx>) -> Ty<'tcx> {
let input_args = input_tys.iter().cloned().collect();
self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: input_args,
output: ty::FnConverging(output),
variadic: false
})
}))
pub fn mk_fn_def(&self, def_id: DefId,
substs: &'tcx Substs<'tcx>,
fty: BareFnTy<'tcx>) -> Ty<'tcx> {
self.mk_ty(TyFnDef(def_id, substs, self.mk_bare_fn(fty)))
}

pub fn mk_fn_ptr(&self, fty: BareFnTy<'tcx>) -> Ty<'tcx> {
self.mk_ty(TyFnPtr(self.mk_bare_fn(fty)))
}

pub fn mk_trait(&self,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/ty/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,8 @@ impl<'tcx> ty::TyS<'tcx> {
ty::TySlice(_) => "slice".to_string(),
ty::TyRawPtr(_) => "*-ptr".to_string(),
ty::TyRef(_, _) => "&-ptr".to_string(),
ty::TyBareFn(Some(_), _) => format!("fn item"),
ty::TyBareFn(None, _) => "fn pointer".to_string(),
ty::TyFnDef(..) => format!("fn item"),
ty::TyFnPtr(_) => "fn pointer".to_string(),
ty::TyTrait(ref inner) => {
format!("trait {}", cx.item_path_str(inner.principal_def_id()))
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty/fast_reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub fn simplify_type(tcx: &TyCtxt,
ty::TyTuple(ref tys) => {
Some(TupleSimplifiedType(tys.len()))
}
ty::TyBareFn(_, ref f) => {
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
}
ty::TyProjection(_) | ty::TyParam(_) => {
Expand Down
7 changes: 6 additions & 1 deletion src/librustc/middle/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,12 @@ impl FlagComputation {
self.add_tys(&ts[..]);
}

&ty::TyBareFn(_, ref f) => {
&ty::TyFnDef(_, substs, ref f) => {
self.add_substs(substs);
self.add_fn_sig(&f.sig);
}

&ty::TyFnPtr(ref f) => {
self.add_fn_sig(&f.sig);
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
ty::TyRawPtr(..) | // ...
ty::TyRef(..) | // OutlivesReference
ty::TyTuple(..) | // ...
ty::TyBareFn(..) | // OutlivesFunction (*)
ty::TyFnDef(..) | // OutlivesFunction (*)
ty::TyFnPtr(_) | // OutlivesFunction (*)
ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*)
ty::TyError => {
// (*) Bare functions and traits are both binders. In the
Expand Down
Loading

0 comments on commit bcda58f

Please sign in to comment.