Remove obsolete divergence related stuff

Replace FnOutput with Ty
Replace FnConverging(ty) with ty
Purge FnDiverging, FunctionRetTy::NoReturn and FunctionRetTy::None
This commit is contained in:
Andrew Cann 2016-07-31 22:33:41 +08:00
parent ee78f37e2a
commit ed02344fbc
73 changed files with 249 additions and 586 deletions

View File

@ -379,7 +379,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
if fn_ty.fn_ret().diverges(self.tcx) {
if fn_ty.fn_ret().0.is_empty(self.tcx) {
self.add_unreachable_node()
} else {
ret

View File

@ -516,7 +516,6 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
output: match output {
Return(ty) => Return(fld.fold_ty(ty)),
DefaultReturn(span) => DefaultReturn(span),
NoReturn(span) => NoReturn(span),
},
variadic: variadic,
}

View File

@ -403,7 +403,6 @@ impl<'a> LoweringContext<'a> {
output: match decl.output {
FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
FunctionRetTy::None(span) => hir::NoReturn(span),
},
variadic: decl.variadic,
})

View File

@ -1286,9 +1286,6 @@ impl fmt::Debug for ImplPolarity {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum FunctionRetTy {
/// Functions with return type `!`that always
/// raise an error or exit (i.e. never return to the caller)
NoReturn(Span),
/// Return type is not specified.
///
/// Functions default to `()` and
@ -1302,7 +1299,6 @@ pub enum FunctionRetTy {
impl FunctionRetTy {
pub fn span(&self) -> Span {
match *self {
NoReturn(span) => span,
DefaultReturn(span) => span,
Return(ref ty) => ty.span,
}

View File

@ -1962,10 +1962,6 @@ impl<'a> State<'a> {
self.maybe_print_comment(ty.span.lo)
}
hir::DefaultReturn(..) => unreachable!(),
hir::NoReturn(span) => {
self.word_nbsp("!")?;
self.maybe_print_comment(span.lo)
}
}
}
@ -2198,7 +2194,6 @@ impl<'a> State<'a> {
self.ibox(indent_unit)?;
self.word_space("->")?;
match decl.output {
hir::NoReturn(_) => self.word_nbsp("!")?,
hir::DefaultReturn(..) => unreachable!(),
hir::Return(ref ty) => self.print_type(&ty)?,
}

View File

@ -1326,7 +1326,6 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
self.rebuild_arg_ty_or_output(&ret_ty, lifetime, anon_nums, region_names)
),
hir::DefaultReturn(span) => hir::DefaultReturn(span),
hir::NoReturn(span) => hir::NoReturn(span)
}
}

View File

@ -607,7 +607,6 @@ impl_trans_normalize!('gcx,
Ty<'gcx>,
&'gcx Substs<'gcx>,
ty::FnSig<'gcx>,
ty::FnOutput<'gcx>,
&'gcx ty::BareFnTy<'gcx>,
ty::ClosureSubsts<'gcx>,
ty::PolyTraitRef<'gcx>

View File

@ -161,10 +161,9 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
let typ = self.infcx.tcx.node_id_to_type(expr.id);
match typ.sty {
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);
}
let from = bare_fn_ty.sig.0.inputs[0];
let to = bare_fn_ty.sig.0.output;
self.check_transmute(expr.span, from, to, expr.id);
}
_ => {
span_bug!(expr.span, "transmute wasn't a bare fn?!");

View File

@ -1112,7 +1112,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprCall(ref f, ref args) => {
let diverges = !self.ir.tcx.is_method_call(expr.id) &&
self.ir.tcx.expr_ty_adjusted(&f).fn_ret().diverges(self.ir.tcx);
self.ir.tcx.expr_ty_adjusted(&f).fn_ret().0.is_empty(self.ir.tcx);
let succ = if diverges {
self.s.exit_ln
} else {
@ -1125,7 +1125,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprMethodCall(_, _, ref args) => {
let method_call = ty::MethodCall::expr(expr.id);
let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
let succ = if method_ty.fn_ret().diverges(self.ir.tcx) {
let succ = if method_ty.fn_ret().0.is_empty(self.ir.tcx) {
self.s.exit_ln
} else {
succ
@ -1454,7 +1454,7 @@ fn check_fn(_v: &Liveness,
}
impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
fn fn_ret(&self, id: NodeId) -> ty::Binder<ty::Ty<'tcx>> {
let fn_ty = self.ir.tcx.node_id_to_type(id);
match fn_ty.sty {
ty::TyClosure(closure_def_id, substs) =>
@ -1477,55 +1477,44 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.ir.tcx.region_maps.call_site_extent(id, body.id),
&self.fn_ret(id));
match fn_ret {
ty::FnConverging(t_ret)
if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() => {
if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
let t_ret_subst = fn_ret.subst(self.ir.tcx, &param_env.free_substs);
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
Reveal::All).enter(|infcx| {
let cause = traits::ObligationCause::dummy();
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
});
let param_env = ParameterEnvironment::for_item(self.ir.tcx, id);
let t_ret_subst = t_ret.subst(self.ir.tcx, &param_env.free_substs);
let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env),
Reveal::All).enter(|infcx| {
let cause = traits::ObligationCause::dummy();
traits::fully_normalize(&infcx, cause, &t_ret_subst).unwrap().is_nil()
});
// for nil return types, it is ok to not return a value expl.
if !is_nil {
let ends_with_stmt = match body.expr {
None if !body.stmts.is_empty() =>
match body.stmts.last().unwrap().node {
hir::StmtSemi(ref e, _) => {
self.ir.tcx.expr_ty(&e) == t_ret
},
_ => false
// for nil return types, it is ok to not return a value expl.
if !is_nil {
let ends_with_stmt = match body.expr {
None if !body.stmts.is_empty() =>
match body.stmts.last().unwrap().node {
hir::StmtSemi(ref e, _) => {
self.ir.tcx.expr_ty(&e) == fn_ret
},
_ => false
_ => false
},
_ => false
};
let mut err = struct_span_err!(self.ir.tcx.sess,
sp,
E0269,
"not all control paths return a value");
if ends_with_stmt {
let last_stmt = body.stmts.last().unwrap();
let original_span = original_sp(self.ir.tcx.sess.codemap(),
last_stmt.span, sp);
let span_semicolon = Span {
lo: original_span.hi - BytePos(1),
hi: original_span.hi,
expn_id: original_span.expn_id
};
let mut err = struct_span_err!(self.ir.tcx.sess,
sp,
E0269,
"not all control paths return a value");
if ends_with_stmt {
let last_stmt = body.stmts.last().unwrap();
let original_span = original_sp(self.ir.tcx.sess.codemap(),
last_stmt.span, sp);
let span_semicolon = Span {
lo: original_span.hi - BytePos(1),
hi: original_span.hi,
expn_id: original_span.expn_id
};
err.span_help(span_semicolon, "consider removing this semicolon:");
}
err.emit();
err.span_help(span_semicolon, "consider removing this semicolon:");
}
err.emit();
}
ty::FnDiverging
if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() => {
span_err!(self.ir.tcx.sess, sp, E0270,
"computation may converge in a function marked as diverging");
}
_ => {}
}
}

View File

@ -923,7 +923,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
let base_cmt = match method_ty {
Some(method_ty) => {
let ref_ty =
self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
}
None => base_cmt
@ -1245,7 +1245,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
// to skip past the binder.
self.tcx().no_late_bound_regions(&method_ty.fn_ret())
.unwrap()
.unwrap() // overloaded ops do not diverge, either
}
}

View File

@ -17,7 +17,7 @@ use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccesso
use rustc_data_structures::control_flow_graph::ControlFlowGraph;
use hir::def_id::DefId;
use ty::subst::Substs;
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
use util::ppaux;
use rustc_back::slice;
use hir::InlineAsm;
@ -74,7 +74,7 @@ pub struct Mir<'tcx> {
pub promoted: IndexVec<Promoted, Mir<'tcx>>,
/// Return type of the function.
pub return_ty: FnOutput<'tcx>,
pub return_ty: Ty<'tcx>,
/// Variables: these are stack slots corresponding to user variables. They may be
/// assigned many times.
@ -107,7 +107,7 @@ impl<'tcx> Mir<'tcx> {
pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
promoted: IndexVec<Promoted, Mir<'tcx>>,
return_ty: FnOutput<'tcx>,
return_ty: Ty<'tcx>,
var_decls: IndexVec<Var, VarDecl<'tcx>>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,

View File

@ -125,7 +125,7 @@ impl<'tcx> Lvalue<'tcx> {
&Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty },
&Lvalue::ReturnPointer =>
LvalueTy::Ty { ty: mir.return_ty.unwrap() },
LvalueTy::Ty { ty: mir.return_ty },
&Lvalue::Projection(ref proj) =>
proj.base.ty(mir, tcx).projection_ty(tcx, &proj.elem),
}

View File

@ -11,7 +11,7 @@
use middle::const_val::ConstVal;
use hir::def_id::DefId;
use ty::subst::Substs;
use ty::{ClosureSubsts, FnOutput, Region, Ty};
use ty::{ClosureSubsts, Region, Ty};
use mir::repr::*;
use rustc_const_math::ConstUsize;
use rustc_data_structures::tuple_slice::TupleSlice;
@ -38,9 +38,7 @@ use syntax_pos::Span;
//
// For the most part, we do not destructure things external to the
// MIR, e.g. types, spans, etc, but simply visit them and stop. This
// avoids duplication with other visitors like `TypeFoldable`. But
// there is one exception: we do destructure the `FnOutput` to reach
// the type within. Just because.
// avoids duplication with other visitors like `TypeFoldable`.
//
// ## Updating
//
@ -192,11 +190,6 @@ macro_rules! make_mir_visitor {
self.super_source_info(source_info);
}
fn visit_fn_output(&mut self,
fn_output: & $($mutability)* FnOutput<'tcx>) {
self.super_fn_output(fn_output);
}
fn visit_ty(&mut self,
ty: & $($mutability)* Ty<'tcx>) {
self.super_ty(ty);
@ -261,7 +254,7 @@ macro_rules! make_mir_visitor {
self.visit_visibility_scope_data(scope);
}
self.visit_fn_output(&$($mutability)* mir.return_ty);
self.visit_ty(&$($mutability)* mir.return_ty);
for var_decl in &$($mutability)* mir.var_decls {
self.visit_var_decl(var_decl);
@ -702,16 +695,6 @@ macro_rules! make_mir_visitor {
self.visit_visibility_scope(scope);
}
fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
match *fn_output {
FnOutput::FnConverging(ref $($mutability)* ty) => {
self.visit_ty(ty);
}
FnOutput::FnDiverging => {
}
}
}
fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
}

View File

@ -269,10 +269,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
return Some(MethodViolationCode::ReferencesSelf);
}
}
if let ty::FnConverging(result_type) = sig.0.output {
if self.contains_illegal_self_type_reference(trait_def_id, result_type) {
return Some(MethodViolationCode::ReferencesSelf);
}
if self.contains_illegal_self_type_reference(trait_def_id, sig.0.output) {
return Some(MethodViolationCode::ReferencesSelf);
}
// We can't monomorphize things like `fn foo<A>(...)`.

View File

@ -1388,7 +1388,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: _,
output: ty::FnConverging(_),
output: _,
variadic: false
})
}) |
@ -1397,7 +1397,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: _,
output: ty::FnConverging(_),
output: _,
variadic: false
})
}) => {

View File

@ -515,7 +515,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
def_id: fn_trait_def_id,
substs: self.mk_substs(trait_substs),
};
ty::Binder((trait_ref, sig.0.output.unwrap_or(self.mk_nil())))
ty::Binder((trait_ref, sig.0.output))
}
}

View File

@ -234,8 +234,7 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
if let Some(method_ty) = method_type(method_call) {
// Method calls always have all late-bound regions
// fully instantiated.
let fn_ret = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
adjusted_ty = fn_ret.unwrap();
adjusted_ty = tcx.no_late_bound_regions(&method_ty.fn_ret()).unwrap();
}
match adjusted_ty.builtin_deref(true, NoPreference) {
Some(mt) => mt.ty,

View File

@ -172,10 +172,7 @@ impl FlagComputation {
let mut computation = FlagComputation::new();
computation.add_tys(&fn_sig.0.inputs);
if let ty::FnConverging(output) = fn_sig.0.output {
computation.add_ty(output);
}
computation.add_ty(fn_sig.0.output);
self.add_bound_computation(&computation);
}

View File

@ -160,12 +160,6 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized {
sig.super_fold_with(self)
}
fn fold_output(&mut self,
output: &ty::FnOutput<'tcx>)
-> ty::FnOutput<'tcx> {
output.super_fold_with(self)
}
fn fold_bare_fn_ty(&mut self,
fty: &'tcx ty::BareFnTy<'tcx>)
-> &'tcx ty::BareFnTy<'tcx>

View File

@ -55,7 +55,7 @@ use hir::intravisit::Visitor;
pub use self::sty::{Binder, DebruijnIndex};
pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds};
pub use self::sty::{BareFnTy, FnSig, PolyFnSig, FnOutput, PolyFnOutput};
pub use self::sty::{BareFnTy, FnSig, PolyFnSig};
pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, TraitTy};
pub use self::sty::{ClosureSubsts, TypeAndMut};
pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
@ -63,7 +63,6 @@ pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
pub use self::sty::Issue32330;
pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid};
pub use self::sty::BoundRegion::*;
pub use self::sty::FnOutput::*;
pub use self::sty::InferTy::*;
pub use self::sty::Region::*;
pub use self::sty::TypeVariants::*;

View File

@ -256,20 +256,11 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
let inputs = relate_arg_vecs(relation,
&a.inputs,
&b.inputs)?;
let output = relation.relate(&a.output, &b.output)?;
let output = match (a.output, b.output) {
(ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
Ok(ty::FnConverging(relation.relate(&a_ty, &b_ty)?)),
(ty::FnDiverging, ty::FnDiverging) =>
Ok(ty::FnDiverging),
(a, b) =>
Err(TypeError::ConvergenceMismatch(
expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))),
}?;
return Ok(ty::FnSig {inputs: inputs,
output: output,
variadic: a.variadic});
Ok(ty::FnSig {inputs: inputs,
output: output,
variadic: a.variadic})
}
}

View File

@ -220,18 +220,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoRef<'a> {
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::FnOutput<'a> {
type Lifted = ty::FnOutput<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
ty::FnConverging(ty) => {
tcx.lift(&ty).map(ty::FnConverging)
}
ty::FnDiverging => Some(ty::FnDiverging)
}
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> {
type Lifted = ty::FnSig<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
@ -587,26 +575,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::FnOutput<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ty::FnConverging(ref ty) => ty::FnConverging(ty.fold_with(folder)),
ty::FnDiverging => ty::FnDiverging
}
}
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
folder.fold_output(self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ty::FnConverging(ref ty) => ty.visit_with(visitor),
ty::FnDiverging => false,
}
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::FnSig { inputs: self.inputs.fold_with(folder),

View File

@ -29,7 +29,6 @@ use serialize::{Decodable, Decoder, Encodable, Encoder};
use hir;
use self::FnOutput::*;
use self::InferTy::*;
use self::TypeVariants::*;
@ -477,50 +476,6 @@ pub struct ClosureTy<'tcx> {
pub sig: PolyFnSig<'tcx>,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub enum FnOutput<'tcx> {
FnConverging(Ty<'tcx>),
FnDiverging
}
impl<'tcx> FnOutput<'tcx> {
pub fn diverges(&self, tcx: TyCtxt) -> bool {
match *self {
FnConverging(ref ty) => ty.is_empty(tcx),
FnDiverging => true,
}
}
pub fn unwrap(self) -> Ty<'tcx> {
match self {
ty::FnConverging(t) => t,
ty::FnDiverging => bug!()
}
}
pub fn unwrap_or(self, def: Ty<'tcx>) -> Ty<'tcx> {
match self {
ty::FnConverging(t) => t,
ty::FnDiverging => def
}
}
pub fn maybe_converging(self) -> Option<Ty<'tcx>> {
match self {
ty::FnConverging(t) => Some(t),
ty::FnDiverging => None
}
}
}
pub type PolyFnOutput<'tcx> = Binder<FnOutput<'tcx>>;
impl<'tcx> PolyFnOutput<'tcx> {
pub fn diverges(&self, tcx: TyCtxt) -> bool {
self.0.diverges(tcx)
}
}
/// Signature of a function type, which I have arbitrarily
/// decided to use to refer to the input/output types.
///
@ -530,7 +485,7 @@ impl<'tcx> PolyFnOutput<'tcx> {
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct FnSig<'tcx> {
pub inputs: Vec<Ty<'tcx>>,
pub output: FnOutput<'tcx>,
pub output: Ty<'tcx>,
pub variadic: bool
}
@ -543,7 +498,7 @@ impl<'tcx> PolyFnSig<'tcx> {
pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
self.map_bound_ref(|fn_sig| fn_sig.inputs[index])
}
pub fn output(&self) -> ty::Binder<FnOutput<'tcx>> {
pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
self.map_bound_ref(|fn_sig| fn_sig.output.clone())
}
pub fn variadic(&self) -> bool {
@ -1205,7 +1160,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
self.fn_sig().inputs()
}
pub fn fn_ret(&self) -> Binder<FnOutput<'tcx>> {
pub fn fn_ret(&self) -> Binder<Ty<'tcx>> {
self.fn_sig().output()
}

View File

@ -110,10 +110,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
}
fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
match sig.0.output {
ty::FnConverging(output) => { stack.push(output); }
ty::FnDiverging => { }
}
stack.push(sig.0.output);
push_reversed(stack, &sig.0.inputs);
}

View File

@ -34,7 +34,7 @@ pub fn verbose() -> bool {
fn fn_sig(f: &mut fmt::Formatter,
inputs: &[Ty],
variadic: bool,
output: ty::FnOutput)
output: Ty)
-> fmt::Result {
write!(f, "(")?;
let mut inputs = inputs.iter();
@ -48,18 +48,11 @@ fn fn_sig(f: &mut fmt::Formatter,
}
}
write!(f, ")")?;
match output {
ty::FnConverging(ty) => {
if !ty.is_nil() {
write!(f, " -> {}", ty)?;
}
Ok(())
}
ty::FnDiverging => {
write!(f, " -> !")
}
if !output.is_nil() {
write!(f, " -> {}", output)?;
}
Ok(())
}
/// Namespace of the path given to parameterized to print.
@ -135,7 +128,7 @@ pub fn parameterized<GG>(f: &mut fmt::Formatter,
if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
let projection_ty = projections[0].ty;
if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty {
return fn_sig(f, args, false, ty::FnConverging(projection_ty));
return fn_sig(f, args, false, projection_ty);
}
}

View File

@ -9,7 +9,7 @@
// except according to those terms.
use rustc::ty::{FnOutput, TyCtxt};
use rustc::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::util::nodemap::FnvHashMap;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@ -231,8 +231,7 @@ impl<'tcx> Index<MovePathIndex> for MovePathData<'tcx> {
}
}
struct MovePathDataBuilder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
struct MovePathDataBuilder<'tcx> {
pre_move_paths: Vec<PreMovePath<'tcx>>,
rev_lookup: MovePathLookup<'tcx>,
}
@ -412,7 +411,7 @@ impl<'tcx> MovePathLookup<'tcx> {
}
}
impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> {
impl<'tcx> MovePathDataBuilder<'tcx> {
fn lookup(&mut self, lval: &Lvalue<'tcx>) -> Lookup<MovePathIndex> {
let proj = match *lval {
Lvalue::Var(var_idx) =>
@ -528,7 +527,6 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
// BlockContexts constructed on each iteration. (Moving is more
// straight-forward than mutable borrows in this instance.)
let mut builder = MovePathDataBuilder {
mir: mir,
pre_move_paths: Vec::new(),
rev_lookup: MovePathLookup::new(mir),
};
@ -632,13 +630,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
TerminatorKind::Return => {
let source = Location { block: bb,
index: bb_data.statements.len() };
if let FnOutput::FnConverging(_) = bb_ctxt.builder.mir.return_ty {
debug!("gather_moves Return on_move_out_lval return {:?}", source);
bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
} else {
debug!("gather_moves Return on_move_out_lval \
assuming unreachable return {:?}", source);
}
debug!("gather_moves Return on_move_out_lval return {:?}", source);
bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
}
TerminatorKind::If { ref cond, targets: _ } => {
@ -749,15 +742,15 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
}
}
struct BlockContext<'b, 'a: 'b, 'tcx: 'a> {
struct BlockContext<'b, 'tcx: 'b> {
_tcx: TyCtxt<'b, 'tcx, 'tcx>,
moves: &'b mut Vec<MoveOut>,
builder: MovePathDataBuilder<'a, 'tcx>,
builder: MovePathDataBuilder<'tcx>,
path_map: &'b mut Vec<Vec<MoveOutIndex>>,
loc_map_bb: &'b mut Vec<Vec<MoveOutIndex>>,
}
impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> {
impl<'b, 'tcx: 'b> BlockContext<'b, 'tcx> {
fn on_move_out_lval(&mut self,
stmt_kind: StmtKind,
lval: &Lvalue<'tcx>,

View File

@ -262,7 +262,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: input_args,
output: ty::FnConverging(output_ty),
output: output_ty,
variadic: false,
}),
}))

View File

@ -1110,10 +1110,9 @@ impl LateLintPass for MutableTransmutes {
let typ = cx.tcx.node_id_to_type(expr.id);
match typ.sty {
ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
if let ty::FnConverging(to) = bare_fn.sig.0.output {
let from = bare_fn.sig.0.inputs[0];
return Some((&from.sty, &to.sty));
}
let from = bare_fn.sig.0.inputs[0];
let to = bare_fn.sig.0.output;
return Some((&from.sty, &to.sty));
},
_ => ()
}

View File

@ -573,16 +573,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
let sig = cx.erase_late_bound_regions(&bare_fn.sig);
match sig.output {
ty::FnDiverging => {}
ty::FnConverging(output) => {
if !output.is_nil() {
let r = self.check_type_for_ffi(cache, output);
match r {
FfiSafe => {}
_ => { return r; }
}
}
if !sig.output.is_nil() {
let r = self.check_type_for_ffi(cache, sig.output);
match r {
FfiSafe => {}
_ => { return r; }
}
}
for arg in sig.inputs {
@ -641,7 +636,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
if let hir::Return(ref ret_hir) = decl.output {
let ret_ty = sig.output.unwrap();
let ret_ty = sig.output;
if !ret_ty.is_nil() {
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
}

View File

@ -540,13 +540,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
'N' => false,
r => bug!("bad variadic: {}", r),
};
let output = match self.peek() {
'z' => {
self.pos += 1;
ty::FnDiverging
}
_ => ty::FnConverging(self.parse_ty())
};
let output = self.parse_ty();
ty::Binder(ty::FnSig {inputs: inputs,
output: output,
variadic: variadic})

View File

@ -383,14 +383,7 @@ fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
} else {
write!(w, "N");
}
match fsig.0.output {
ty::FnConverging(result_type) => {
enc_ty(w, cx, result_type);
}
ty::FnDiverging => {
write!(w, "z");
}
}
enc_ty(w, cx, fsig.0.output);
}
pub fn enc_builtin_bounds(w: &mut Cursor<Vec<u8>>, _cx: &ctxt, bs: &ty::BuiltinBounds) {

View File

@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
ExprKind::Call { ty, fun, args } => {
let diverges = match ty.sty {
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
f.sig.0.output.diverges(this.hir.tcx())
f.sig.0.output.is_empty(this.hir.tcx())
}
_ => false
};

View File

@ -162,7 +162,7 @@ macro_rules! unpack {
pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
fn_id: ast::NodeId,
arguments: A,
return_ty: ty::FnOutput<'gcx>,
return_ty: ty::Ty<'gcx>,
ast_block: &'gcx hir::Block)
-> (Mir<'tcx>, ScopeAuxiliaryVec)
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
@ -255,7 +255,7 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
});
let ty = tcx.expr_ty_adjusted(ast_expr);
builder.finish(vec![], IndexVec::new(), ty::FnConverging(ty))
builder.finish(vec![], IndexVec::new(), ty)
}
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
@ -287,7 +287,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn finish(self,
upvar_decls: Vec<UpvarDecl>,
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
return_ty: ty::FnOutput<'tcx>)
return_ty: ty::Ty<'tcx>)
-> (Mir<'tcx>, ScopeAuxiliaryVec) {
for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
if block.terminator.is_none() {
@ -309,7 +309,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn args_and_body<A>(&mut self,
mut block: BasicBlock,
return_ty: ty::FnOutput<'tcx>,
return_ty: ty::Ty<'tcx>,
arguments: A,
argument_extent: CodeExtent,
ast_block: &'gcx hir::Block)
@ -350,11 +350,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
}
// FIXME(#32959): temporary hack for the issue at hand
let return_is_unit = if let ty::FnConverging(t) = return_ty {
t.is_nil()
} else {
false
};
let return_is_unit = return_ty.is_nil();
// start the first basic block and translate the body
unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block));

View File

@ -12,7 +12,7 @@ use dot;
use rustc::hir::def_id::DefId;
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;
use rustc::ty::{self, TyCtxt};
use rustc::ty::TyCtxt;
use std::fmt::Debug;
use std::io::{self, Write};
use syntax::ast::NodeId;
@ -143,14 +143,7 @@ fn write_graph_label<'a, 'tcx, W: Write>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
write!(w, "{:?}: {}", Lvalue::Arg(Arg::new(i)), escape(&arg.ty))?;
}
write!(w, ") -&gt; ")?;
// fn return type.
match mir.return_ty {
ty::FnOutput::FnConverging(ty) => write!(w, "{}", escape(ty))?,
ty::FnOutput::FnDiverging => write!(w, "!")?,
}
write!(w, ") -&gt; {}", escape(mir.return_ty))?;
write!(w, r#"<br align="left"/>"#)?;
// User variable types (including the user's name in a comment).

View File

@ -97,9 +97,9 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
let (region, mutbl) = match ref_ty {
Some(ty::FnConverging(&ty::TyS {
Some(&ty::TyS {
sty: ty::TyRef(region, mt), ..
})) => (region, mt.mutbl),
}) => (region, mt.mutbl),
_ => span_bug!(expr.span, "autoderef returned bad type")
};
@ -955,10 +955,8 @@ fn overloaded_lvalue<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let tables = cx.tcx.tables.borrow();
let callee = &tables.method_map[&method_call];
let ref_ty = callee.ty.fn_ret();
let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap().unwrap();
// 1~~~~~ 2~~~~~
// (1) callees always have all late-bound regions fully instantiated,
// (2) overloaded methods don't return `!`
let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap();
// callees always have all late-bound regions fully instantiated,
// construct the complete expression `foo()` for the overloaded call,
// which will yield the &T type

View File

@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId;
use rustc::mir::repr::*;
use rustc::mir::mir_map::MirMap;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, TyCtxt};
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv::FnvHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
@ -320,16 +320,10 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
write!(w, "{:?}: {}", Lvalue::Arg(i), arg.ty)?;
}
write!(w, ") -> ")?;
// fn return type.
match mir.return_ty {
ty::FnOutput::FnConverging(ty) => write!(w, "{}", ty),
ty::FnOutput::FnDiverging => write!(w, "!"),
}
write!(w, ") -> {}", mir.return_ty)
} else {
assert!(mir.arg_decls.is_empty());
write!(w, ": {} =", mir.return_ty.unwrap())
write!(w, ": {} =", mir.return_ty)
}
}

View File

@ -25,7 +25,7 @@
use rustc::mir::repr::*;
use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
use rustc::mir::traversal::ReversePostorder;
use rustc::ty::{self, TyCtxt};
use rustc::ty::TyCtxt;
use syntax_pos::Span;
use build::Location;
@ -299,7 +299,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
let span = self.promoted.span;
let new_operand = Operand::Constant(Constant {
span: span,
ty: self.promoted.return_ty.unwrap(),
ty: self.promoted.return_ty,
literal: Literal::Promoted {
index: Promoted::new(self.source.promoted.len())
}
@ -389,7 +389,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>,
parent_scope: None
}).into_iter().collect(),
IndexVec::new(),
ty::FnConverging(ty),
ty,
IndexVec::new(),
IndexVec::new(),
IndexVec::new(),

View File

@ -416,7 +416,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
}
}
let return_ty = mir.return_ty.unwrap();
let return_ty = mir.return_ty;
self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST);
match self.mode {
@ -991,7 +991,7 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
// Statics must be Sync.
if mode == Mode::Static {
let ty = mir.return_ty.unwrap();
let ty = mir.return_ty;
tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();

View File

@ -85,9 +85,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
}
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
if let ty::FnConverging(t) = mir.return_ty {
self.sanitize_type(&"return type", t);
}
self.sanitize_type(&"return type", mir.return_ty);
for var_decl in &mir.var_decls {
self.sanitize_type(var_decl, var_decl.ty);
}
@ -135,14 +133,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
Lvalue::Static(def_id) =>
LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
Lvalue::ReturnPointer => {
if let ty::FnConverging(return_ty) = self.mir.return_ty {
LvalueTy::Ty { ty: return_ty }
} else {
LvalueTy::Ty {
ty: span_mirbug_and_err!(
self, lvalue, "return in diverging function")
}
}
LvalueTy::Ty { ty: self.mir.return_ty }
}
Lvalue::Projection(ref proj) => {
let base_ty = self.sanitize_lvalue(&proj.base);
@ -491,24 +482,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
sig: &ty::FnSig<'tcx>,
destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
let tcx = self.tcx();
match (destination, sig.output) {
(&Some(..), ty::FnDiverging) => {
span_mirbug!(self, term, "call to diverging function {:?} with dest", sig);
}
(&Some((ref dest, _)), ty::FnConverging(ty)) => {
match *destination {
Some((ref dest, _)) => {
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.sub_types(self.last_span, ty, dest_ty) {
if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) {
span_mirbug!(self, term,
"call dest mismatch ({:?} <- {:?}): {:?}",
dest_ty, ty, terr);
dest_ty, sig.output, terr);
}
}
(&None, ty::FnDiverging) => {}
(&None, ty::FnConverging(ref ty)) => {
if !ty.is_empty(tcx) {
},
None => {
if !sig.output.is_empty(tcx) {
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
}
}
},
}
}

View File

@ -440,7 +440,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
let expr_ty = self.tcx.expr_ty(expr);
let def = match expr_ty.sty {
ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
output: ty::FnConverging(ty), ..
output: ty, ..
}), ..}) => ty,
_ => expr_ty
}.ty_adt_def().unwrap();

View File

@ -671,7 +671,6 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String {
sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::<Vec<_>>().join(", "));
sig.push(')');
match decl.output {
ast::FunctionRetTy::None(_) => sig.push_str(" -> !"),
ast::FunctionRetTy::Default(_) => {}
ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))),
}

View File

@ -326,10 +326,7 @@ impl FnType {
}
};
let ret_ty = match sig.output {
ty::FnConverging(ret_ty) => ret_ty,
ty::FnDiverging => ccx.tcx().mk_nil()
};
let ret_ty = sig.output;
let mut ret = arg_of(ret_ty, true);
if !type_is_fat_ptr(ccx.tcx(), ret_ty) {
@ -470,7 +467,7 @@ impl FnType {
};
// Fat pointers are returned by-value.
if !self.ret.is_ignore() {
if !type_is_fat_ptr(ccx.tcx(), sig.output.unwrap()) {
if !type_is_fat_ptr(ccx.tcx(), sig.output) {
fixup(&mut self.ret);
}
}

View File

@ -1972,7 +1972,7 @@ pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
let sig = ccx.tcx().normalize_associated_type(&sig);
let result_ty = sig.output.unwrap();
let result_ty = sig.output;
// Get location to store the result. If the user does not care about
// the result, just make a stack slot
@ -2054,7 +2054,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
if !fcx.fn_ty.ret.is_ignore() {
let dest = fcx.get_ret_slot(bcx, "eret_slot");
let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
let repr = adt::represent_type(ccx, sig.output.unwrap());
let repr = adt::represent_type(ccx, sig.output);
let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
let mut arg_idx = 0;
for (i, arg_ty) in sig.inputs.into_iter().enumerate() {

View File

@ -641,10 +641,7 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let opt_llretslot = dest.and_then(|dest| match dest {
expr::SaveIn(dst) => Some(dst),
expr::Ignore => {
let needs_drop = || match output {
ty::FnConverging(ret_ty) => bcx.fcx.type_needs_drop(ret_ty),
ty::FnDiverging => false
};
let needs_drop = || bcx.fcx.type_needs_drop(output);
if fn_ty.ret.is_indirect() || fn_ty.ret.cast.is_some() || needs_drop() {
// Push the out-pointer if we use an out-pointer for this
// return type, otherwise push "undef".
@ -706,16 +703,16 @@ fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
// If the caller doesn't care about the result of this fn call,
// drop the temporary slot we made.
match (dest, opt_llretslot, output) {
(Some(expr::Ignore), Some(llretslot), ty::FnConverging(ret_ty)) => {
match (dest, opt_llretslot) {
(Some(expr::Ignore), Some(llretslot)) => {
// drop the value if it is not being saved.
bcx = glue::drop_ty(bcx, llretslot, ret_ty, debug_loc);
bcx = glue::drop_ty(bcx, llretslot, output, debug_loc);
call_lifetime_end(bcx, llretslot);
}
_ => {}
}
if output == ty::FnDiverging {
if output.is_empty(bcx.tcx()) {
Unreachable(bcx);
}

View File

@ -201,7 +201,11 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
trans_closure_expr(Dest::Ignore(ccx),
&hir::FnDecl {
inputs: P::new(),
output: hir::NoReturn(DUMMY_SP),
output: hir::Return(P(hir::Ty {
id: DUMMY_NODE_ID,
span: DUMMY_SP,
node: hir::Ty_::TyNever,
})),
variadic: false
},
&hir::Block {

View File

@ -558,7 +558,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
abi: Abi::C,
sig: ty::Binder(ty::FnSig {
inputs: vec![tcx.mk_mut_ptr(tcx.types.u8)],
output: ty::FnDiverging,
output: tcx.mk_empty(),
variadic: false
}),
}));
@ -1240,8 +1240,8 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
inlined_vid);
let adt_def = match ctor_ty.sty {
ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
output: ty::FnConverging(ty), ..
}), ..}) => ty,
output, ..
}), ..}) => output,
_ => ctor_ty
}.ty_adt_def().unwrap();
let variant_def_id = if ccx.tcx().map.is_inlined_node_id(inlined_vid) {

View File

@ -279,16 +279,9 @@ impl<'tcx> TypeMap<'tcx> {
}
unique_type_id.push_str(")->");
match sig.output {
ty::FnConverging(ret_ty) => {
let return_type_id = self.get_unique_type_id_of_type(cx, ret_ty);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
unique_type_id.push_str(&return_type_id[..]);
}
ty::FnDiverging => {
unique_type_id.push_str("!");
}
}
let return_type_id = self.get_unique_type_id_of_type(cx, sig.output);
let return_type_id = self.get_unique_type_id_as_string(return_type_id);
unique_type_id.push_str(&return_type_id[..]);
},
ty::TyClosure(_, substs) if substs.upvar_tys.is_empty() => {
push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
@ -596,12 +589,9 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
// return type
signature_metadata.push(match signature.output {
ty::FnConverging(ret_ty) => match ret_ty.sty {
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, ret_ty, span)
},
ty::FnDiverging => diverging_type_metadata(cx)
signature_metadata.push(match signature.output.sty {
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, signature.output, span)
});
// regular arguments
@ -916,17 +906,6 @@ pub fn scope_metadata(fcx: &FunctionContext,
}
}
pub fn diverging_type_metadata(cx: &CrateContext) -> DIType {
unsafe {
llvm::LLVMRustDIBuilderCreateBasicType(
DIB(cx),
"!\0".as_ptr() as *const _,
bytes_to_bits(0),
bytes_to_bits(0),
DW_ATE_unsigned)
}
}
fn basic_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>) -> DIType {

View File

@ -17,8 +17,7 @@ use self::VariableKind::*;
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
use self::namespace::mangled_name_of_item;
use self::type_names::compute_debuginfo_type_name;
use self::metadata::{type_metadata, diverging_type_metadata};
use self::metadata::{file_metadata, TypeMap};
use self::metadata::{type_metadata, file_metadata, TypeMap};
use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
use llvm;
@ -325,12 +324,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
let mut signature = Vec::with_capacity(sig.inputs.len() + 1);
// Return type -- llvm::DIBuilder wants this at index 0
signature.push(match sig.output {
ty::FnConverging(ret_ty) => match ret_ty.sty {
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, ret_ty, syntax_pos::DUMMY_SP)
},
ty::FnDiverging => diverging_type_metadata(cx)
signature.push(match sig.output.sty {
ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, sig.output, syntax_pos::DUMMY_SP)
});
let inputs = if abi == Abi::RustCall {

View File

@ -134,15 +134,9 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
output.push(')');
match sig.output {
ty::FnConverging(result_type) if result_type.is_nil() => {}
ty::FnConverging(result_type) => {
output.push_str(" -> ");
push_debuginfo_type_name(cx, result_type, true, output);
}
ty::FnDiverging => {
output.push_str(" -> !");
}
if !sig.output.is_nil() {
output.push_str(" -> ");
push_debuginfo_type_name(cx, sig.output, true, output);
}
},
ty::TyClosure(..) => {

View File

@ -111,7 +111,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
let fty = FnType::new(ccx, abi, &sig, &[]);
let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
if sig.output == ty::FnDiverging {
if sig.output.is_empty(ccx.tcx()) {
llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
}

View File

@ -803,7 +803,7 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let ix_datum = unpack_datum!(bcx, trans(bcx, idx));
let ref_ty = // invoked methods have LB regions instantiated:
bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
bcx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
let elt_ty = match ref_ty.builtin_deref(true, ty::NoPreference) {
None => {
span_bug!(index_expr.span,
@ -2060,7 +2060,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
};
let ref_ty = // invoked methods have their LB regions instantiated
ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
bcx = Callee::method(bcx, method)

View File

@ -132,7 +132,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
// For `transmute` we can just trans the input expr directly into dest
if name == "transmute" {
let llret_ty = type_of::type_of(ccx, ret_ty.unwrap());
let llret_ty = type_of::type_of(ccx, ret_ty);
match args {
callee::ArgExprs(arg_exprs) => {
assert_eq!(arg_exprs.len(), 1);
@ -315,11 +315,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
return Result::new(bcx, C_nil(ccx));
}
let ret_ty = match ret_ty {
ty::FnConverging(ret_ty) => ret_ty,
ty::FnDiverging => bug!()
};
let llret_ty = type_of::type_of(ccx, ret_ty);
// Get location to store the result. If the user does
@ -1226,7 +1221,7 @@ fn trans_gnu_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
name: &str,
inputs: Vec<Ty<'tcx>>,
output: ty::FnOutput<'tcx>,
output: ty::Ty<'tcx>,
trans: &mut for<'b> FnMut(Block<'b, 'tcx>))
-> ValueRef {
let ccx = fcx.ccx;
@ -1272,11 +1267,11 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: vec![i8p],
output: ty::FnOutput::FnConverging(tcx.mk_nil()),
output: tcx.mk_nil(),
variadic: false,
}),
}));
let output = ty::FnOutput::FnConverging(tcx.types.i32);
let output = tcx.types.i32;
let rust_try = gen_fn(fcx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
ccx.rust_try_fn().set(Some(rust_try));
return rust_try

View File

@ -19,6 +19,7 @@ use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir::traversal;
use common::{self, Block, BlockAndBuilder};
use glue;
use std::iter;
use super::rvalue;
pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
@ -31,7 +32,7 @@ pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
let local_types = mir.arg_decls.iter().map(|a| a.ty)
.chain(mir.var_decls.iter().map(|v| v.ty))
.chain(mir.temp_decls.iter().map(|t| t.ty))
.chain(mir.return_ty.maybe_converging());
.chain(iter::once(mir.return_ty));
for (index, ty) in local_types.enumerate() {
let ty = bcx.monomorphize(&ty);
debug!("local {} has type {:?}", index, ty);

View File

@ -525,7 +525,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// Make a fake operand for store_return
let op = OperandRef {
val: Ref(dst),
ty: sig.output.unwrap()
ty: sig.output,
};
self.store_return(&bcx, ret_dest, fn_ty.ret, op);
}
@ -563,7 +563,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
debug_loc.apply_to_bcx(ret_bcx);
let op = OperandRef {
val: Immediate(invokeret),
ty: sig.output.unwrap()
ty: sig.output,
};
self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
});
@ -574,7 +574,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
if let Some((_, target)) = *destination {
let op = OperandRef {
val: Immediate(llret),
ty: sig.output.unwrap()
ty: sig.output,
};
self.store_return(&bcx, ret_dest, fn_ty.ret, op);
funclet_br(self, bcx, target);

View File

@ -26,6 +26,7 @@ use syntax::parse::token::keywords;
use std::ops::Deref;
use std::rc::Rc;
use std::iter;
use basic_block::BasicBlock;
@ -183,7 +184,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
let locals = mir.temp_decls.iter().enumerate().map(|(i, decl)| {
(mir::Lvalue::Temp(mir::Temp::new(i)), decl.ty)
}).chain(mir.return_ty.maybe_converging().map(|ty| (mir::Lvalue::ReturnPointer, ty)));
}).chain(iter::once((mir::Lvalue::ReturnPointer, mir.return_ty)));
args.into_iter().chain(vars).chain(locals.map(|(lvalue, ty)| {
let ty = bcx.monomorphize(&ty);

View File

@ -233,7 +233,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
let sig = ty::FnSig {
inputs: vec![tcx.mk_mut_ptr(tcx.types.i8)],
output: ty::FnOutput::FnConverging(tcx.mk_nil()),
output: tcx.mk_nil(),
variadic: false,
};
@ -516,15 +516,9 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
output.push(')');
match sig.output {
ty::FnConverging(result_type) if result_type.is_nil() => {}
ty::FnConverging(result_type) => {
output.push_str(" -> ");
push_unique_type_name(tcx, result_type, output);
}
ty::FnDiverging => {
output.push_str(" -> !");
}
if !sig.output.is_nil() {
output.push_str(" -> ");
push_unique_type_name(tcx, sig.output, output);
}
},
ty::TyClosure(def_id, ref closure_substs) => {

View File

@ -1923,11 +1923,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
let output_ty = match decl.output {
hir::Return(ref output) =>
ty::FnConverging(self.convert_ty_with_lifetime_elision(implied_output_region,
&output,
ret_anon_scope)),
hir::DefaultReturn(..) => ty::FnConverging(self.tcx().mk_nil()),
hir::NoReturn(..) => ty::FnDiverging
self.convert_ty_with_lifetime_elision(implied_output_region,
&output,
ret_anon_scope),
hir::DefaultReturn(..) => self.tcx().mk_nil(),
};
(self.tcx().mk_bare_fn(ty::BareFnTy {
@ -2070,11 +2069,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
_ if is_infer && expected_ret_ty.is_some() =>
expected_ret_ty.unwrap(),
_ if is_infer =>
ty::FnConverging(self.ty_infer(None, None, None, decl.output.span())),
self.ty_infer(None, None, None, decl.output.span()),
hir::Return(ref output) =>
ty::FnConverging(self.ast_ty_to_ty(&rb, &output)),
self.ast_ty_to_ty(&rb, &output),
hir::DefaultReturn(..) => bug!(),
hir::NoReturn(..) => ty::FnDiverging
};
debug!("ty_of_closure: input_tys={:?}", input_tys);

View File

@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// set up all the node type bindings.
error_fn_sig = ty::Binder(ty::FnSig {
inputs: self.err_args(arg_exprs.len()),
output: ty::FnConverging(self.tcx.types.err),
output: self.tcx.types.err,
variadic: false
});
@ -345,10 +345,9 @@ impl<'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> for CallResolution<'gcx, 'tc
fcx.demand_eqtype(self.call_expr.span, self_arg_ty, method_arg_ty);
}
let nilty = fcx.tcx.mk_nil();
fcx.demand_eqtype(self.call_expr.span,
method_sig.output.unwrap_or(nilty),
self.fn_sig.output.unwrap_or(nilty));
method_sig.output,
self.fn_sig.output);
fcx.write_overloaded_call_method_map(self.call_expr, method_callee);
}

View File

@ -221,7 +221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let fn_sig = ty::FnSig {
inputs: input_tys,
output: ty::FnConverging(ret_param_ty),
output: ret_param_ty,
variadic: false
};
debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);

View File

@ -31,7 +31,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
n_tps: usize,
abi: Abi,
inputs: Vec<ty::Ty<'tcx>>,
output: ty::FnOutput<'tcx>) {
output: ty::Ty<'tcx>) {
let tcx = ccx.tcx;
let def_id = tcx.map.local_def_id(it.id);
let i_ty = tcx.lookup_item_type(def_id);
@ -104,9 +104,9 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
return;
}
};
(n_tps, inputs, ty::FnConverging(output))
(n_tps, inputs, output)
} else if &name[..] == "abort" || &name[..] == "unreachable" {
(0, Vec::new(), ty::FnConverging(tcx.mk_empty()))
(0, Vec::new(), tcx.mk_empty())
} else {
let (n_tps, inputs, output) = match &name[..] {
"breakpoint" => (0, Vec::new(), tcx.mk_nil()),
@ -291,7 +291,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
abi: Abi::Rust,
sig: ty::Binder(FnSig {
inputs: vec![mut_u8],
output: ty::FnOutput::FnConverging(tcx.mk_nil()),
output: tcx.mk_nil(),
variadic: false,
}),
});
@ -304,7 +304,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
return;
}
};
(n_tps, inputs, ty::FnConverging(output))
(n_tps, inputs, output)
};
equate_intrinsic_type(ccx, it, n_tps, Abi::RustIntrinsic, inputs, output)
}
@ -377,7 +377,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
}
match_intrinsic_type_to_type(ccx, "return value", it.span,
&mut structural_to_nomimal,
&intr.output, sig.output.unwrap());
&intr.output, sig.output);
return
}
None => {
@ -390,7 +390,7 @@ pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
};
equate_intrinsic_type(ccx, it, n_tps, Abi::PlatformIntrinsic,
inputs, ty::FnConverging(output))
inputs, output)
}
// walk the expected type and the actual type in lock step, checking they're

View File

@ -372,7 +372,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// expects the types within the function to be consistent.
err_count_on_creation: usize,
ret_ty: ty::FnOutput<'tcx>,
ret_ty: ty::Ty<'tcx>,
ps: RefCell<UnsafetyState>,
@ -676,14 +676,9 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
*fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
fn_sig.output = match fcx.ret_ty {
ty::FnConverging(orig_ret_ty) => {
fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType);
ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty))
}
ty::FnDiverging => ty::FnDiverging
};
fcx.ret_ty = fn_sig.output;
fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType);
fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty);
fn_sig.output = fcx.ret_ty;
{
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
@ -714,10 +709,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
fcx.check_block_with_expected(body, match fcx.ret_ty {
ty::FnConverging(result_type) => ExpectHasType(result_type),
ty::FnDiverging => NoExpectation
});
fcx.check_block_with_expected(body, ExpectHasType(fcx.ret_ty));
fcx
}
@ -1168,7 +1160,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
expected_type: Ty<'tcx>,
id: ast::NodeId) {
ccx.inherited(id).enter(|inh| {
let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
let fcx = FnCtxt::new(&inh, expected_type, expr.id);
fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
// Gather locals in statics (because of block expressions).
@ -1465,7 +1457,7 @@ enum TupleArgumentsFlag {
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
rty: ty::FnOutput<'tcx>,
rty: ty::Ty<'tcx>,
body_id: ast::NodeId)
-> FnCtxt<'a, 'gcx, 'tcx> {
FnCtxt {
@ -2288,7 +2280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// extract method return type, which will be &T;
// all LB regions should have been instantiated during method lookup
let ret_ty = method.ty.fn_ret();
let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap();
// method returns &T, but the type as visible to user is T, so deref
ret_ty.builtin_deref(true, NoPreference).unwrap()
@ -2417,7 +2409,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
args_no_rcvr: &'gcx [P<hir::Expr>],
tuple_arguments: TupleArgumentsFlag,
expected: Expectation<'tcx>)
-> ty::FnOutput<'tcx> {
-> ty::Ty<'tcx> {
if method_fn_ty.references_error() {
let err_inputs = self.err_args(args_no_rcvr.len());
@ -2428,7 +2420,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
false, tuple_arguments);
ty::FnConverging(self.tcx.types.err)
self.tcx.types.err
} else {
match method_fn_ty.sty {
ty::TyFnDef(_, _, ref fty) => {
@ -2688,11 +2680,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn write_call(&self,
call_expr: &hir::Expr,
output: ty::FnOutput<'tcx>) {
self.write_ty_expr(call_expr.id, match output {
ty::FnConverging(output_ty) => output_ty,
ty::FnDiverging => self.next_diverging_ty_var()
});
output: ty::Ty<'tcx>) {
self.write_ty_expr(call_expr.id, output);
}
// AST fragment checking
@ -2815,35 +2804,31 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn expected_types_for_fn_args(&self,
call_span: Span,
expected_ret: Expectation<'tcx>,
formal_ret: ty::FnOutput<'tcx>,
formal_ret: ty::Ty<'tcx>,
formal_args: &[Ty<'tcx>])
-> Vec<Ty<'tcx>> {
let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
if let ty::FnConverging(formal_ret_ty) = formal_ret {
self.commit_regions_if_ok(|| {
// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = TypeOrigin::Misc(call_span);
let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty);
// FIXME(#15760) can't use try! here, FromError doesn't default
// to identity so the resulting type is not constrained.
match ures {
// FIXME(#32730) propagate obligations
Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
Err(e) => return Err(e),
}
self.commit_regions_if_ok(|| {
// Attempt to apply a subtyping relationship between the formal
// return type (likely containing type variables if the function
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = TypeOrigin::Misc(call_span);
let ures = self.sub_types(false, origin, formal_ret, ret_ty);
// FIXME(#15760) can't use try! here, FromError doesn't default
// to identity so the resulting type is not constrained.
match ures {
// FIXME(#32730) propagate obligations
Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
Err(e) => return Err(e),
}
// Record all the argument types, with the substitutions
// produced from the above subtyping unification.
Ok(formal_args.iter().map(|ty| {
self.resolve_type_vars_if_possible(ty)
}).collect())
}).ok()
} else {
None
}
// Record all the argument types, with the substitutions
// produced from the above subtyping unification.
Ok(formal_args.iter().map(|ty| {
self.resolve_type_vars_if_possible(ty)
}).collect())
}).ok()
}).unwrap_or(vec![]);
debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})",
formal_args, formal_ret,
@ -3503,32 +3488,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
hir::ExprBreak(_) => { self.write_empty(id); }
hir::ExprAgain(_) => { self.write_empty(id); }
hir::ExprRet(ref expr_opt) => {
match self.ret_ty {
ty::FnConverging(result_type) => {
if let Some(ref e) = *expr_opt {
self.check_expr_coercable_to_type(&e, result_type);
} else {
let eq_result = self.eq_types(false,
TypeOrigin::Misc(expr.span),
result_type,
tcx.mk_nil())
// FIXME(#32730) propagate obligations
.map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
if eq_result.is_err() {
struct_span_err!(tcx.sess, expr.span, E0069,
"`return;` in a function whose return type is not `()`")
.span_label(expr.span, &format!("return type is not ()"))
.emit();
}
}
}
ty::FnDiverging => {
if let Some(ref e) = *expr_opt {
self.check_expr(&e);
}
struct_span_err!(tcx.sess, expr.span, E0166,
"`return` in a function declared as diverging")
.span_label(expr.span, &format!("diverging function cannot return"))
if let Some(ref e) = *expr_opt {
self.check_expr_coercable_to_type(&e, self.ret_ty);
} else {
let eq_result = self.eq_types(false,
TypeOrigin::Misc(expr.span),
self.ret_ty,
tcx.mk_nil())
// FIXME(#32730) propagate obligations
.map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
if eq_result.is_err() {
struct_span_err!(tcx.sess, expr.span, E0069,
"`return;` in a function whose return type is not `()`")
.span_label(expr.span, &format!("return type is not ()"))
.emit();
}
}

View File

@ -343,7 +343,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// extract return type for method; all late bound regions
// should have been instantiated by now
let ret_ty = method_ty.fn_ret();
Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap())
Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap())
}
None => {
Err(())

View File

@ -311,7 +311,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
let fn_sig_tys: Vec<_> =
fn_sig.inputs.iter()
.cloned()
.chain(Some(fn_sig.output.unwrap_or(self.tcx.types.bool)))
.chain(Some(fn_sig.output))
.collect();
let old_body_id = self.set_body_id(body.id);
@ -708,7 +708,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
None::<hir::Expr>.iter(), true);
// late-bound regions in overloaded method calls are instantiated
let fn_ret = self.tcx.no_late_bound_regions(&method.ty.fn_ret());
fn_ret.unwrap().unwrap()
fn_ret.unwrap()
}
None => self.resolve_node_type(base.id)
};
@ -980,14 +980,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
// Specialized version of constrain_call.
self.type_must_outlive(infer::CallRcvr(deref_expr.span),
self_ty, r_deref_expr);
match fn_sig.output {
ty::FnConverging(return_type) => {
self.type_must_outlive(infer::CallReturn(deref_expr.span),
return_type, r_deref_expr);
return_type
}
ty::FnDiverging => bug!()
}
self.type_must_outlive(infer::CallReturn(deref_expr.span),
fn_sig.output, r_deref_expr);
fn_sig.output
}
None => derefd_ty
};

View File

@ -51,7 +51,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let id = self.id;
let span = self.span;
self.inherited.enter(|inh| {
let fcx = FnCtxt::new(&inh, ty::FnDiverging, id);
let fcx = FnCtxt::new(&inh, inh.ccx.tcx.mk_empty(), id);
let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
ccx: fcx.ccx,
code: code
@ -394,15 +394,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
}
implied_bounds.extend(sig.inputs);
match sig.output {
ty::FnConverging(output) => {
fcx.register_wf_obligation(output, span, self.code.clone());
fcx.register_wf_obligation(sig.output, span, self.code.clone());
// FIXME(#25759) return types should not be implied bounds
implied_bounds.push(output);
}
ty::FnDiverging => { }
}
// FIXME(#25759) return types should not be implied bounds
implied_bounds.push(sig.output);
self.check_where_clauses(fcx, span, predicates);
}

View File

@ -971,7 +971,7 @@ fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
abi: abi::Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: inputs,
output: ty::FnConverging(scheme.ty),
output: scheme.ty,
variadic: false
})
}))
@ -2155,11 +2155,9 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
let output = match decl.output {
hir::Return(ref ty) =>
ty::FnConverging(AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty)),
AstConv::ast_ty_to_ty(&ccx.icx(ast_generics), &rb, &ty),
hir::DefaultReturn(..) =>
ty::FnConverging(ccx.tcx.mk_nil()),
hir::NoReturn(..) =>
ty::FnDiverging
ccx.tcx.mk_nil(),
};
// feature gate SIMD types in FFI, since I (huonw) am not sure the
@ -2180,7 +2178,7 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
check(&input.ty, ty)
}
if let hir::Return(ref ty) = decl.output {
check(&ty, output.unwrap())
check(&ty, output)
}
}

View File

@ -238,7 +238,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
abi: Abi::Rust,
sig: ty::Binder(ty::FnSig {
inputs: Vec::new(),
output: ty::FnConverging(tcx.mk_nil()),
output: tcx.mk_nil(),
variadic: false
})
}));
@ -294,7 +294,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
tcx.types.isize,
tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
),
output: ty::FnConverging(tcx.types.isize),
output: tcx.types.isize,
variadic: false,
}),
}));

View File

@ -490,9 +490,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
for &input in &sig.0.inputs {
self.add_constraints_from_ty(generics, input, contra);
}
if let ty::FnConverging(result_type) = sig.0.output {
self.add_constraints_from_ty(generics, result_type, variance);
}
self.add_constraints_from_ty(generics, sig.0.output, variance);
}
/// Adds constraints appropriate for a region appearing in a

View File

@ -1176,15 +1176,6 @@ impl Clean<FnDecl> for hir::FnDecl {
}
}
impl<'tcx> Clean<Type> for ty::FnOutput<'tcx> {
fn clean(&self, cx: &DocContext) -> Type {
match *self {
ty::FnConverging(ty) => ty.clean(cx),
ty::FnDiverging => Bottom
}
}
}
impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
fn clean(&self, cx: &DocContext) -> FnDecl {
let (did, sig) = *self;
@ -1254,7 +1245,6 @@ impl Clean<Argument> for hir::Arg {
pub enum FunctionRetTy {
Return(Type),
DefaultReturn,
NoReturn
}
impl Clean<FunctionRetTy> for hir::FunctionRetTy {
@ -1262,7 +1252,6 @@ impl Clean<FunctionRetTy> for hir::FunctionRetTy {
match *self {
hir::Return(ref typ) => Return(typ.clean(cx)),
hir::DefaultReturn(..) => DefaultReturn,
hir::NoReturn(..) => NoReturn
}
}
}

View File

@ -634,7 +634,6 @@ impl fmt::Display for clean::FunctionRetTy {
clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
clean::DefaultReturn => Ok(()),
clean::NoReturn => write!(f, " -&gt; !")
}
}
}

View File

@ -1567,9 +1567,6 @@ impl fmt::Debug for ImplPolarity {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum FunctionRetTy {
/// Functions with return type `!`that always
/// raise an error or exit (i.e. never return to the caller)
None(Span),
/// Return type is not specified.
///
/// Functions default to `()` and
@ -1583,7 +1580,6 @@ pub enum FunctionRetTy {
impl FunctionRetTy {
pub fn span(&self) -> Span {
match *self {
FunctionRetTy::None(span) => span,
FunctionRetTy::Default(span) => span,
FunctionRetTy::Ty(ref ty) => ty.span,
}

View File

@ -638,7 +638,6 @@ pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
output: match output {
FunctionRetTy::Ty(ty) => FunctionRetTy::Ty(fld.fold_ty(ty)),
FunctionRetTy::Default(span) => FunctionRetTy::Default(span),
FunctionRetTy::None(span) => FunctionRetTy::None(span),
},
variadic: variadic
})

View File

@ -2696,10 +2696,6 @@ impl<'a> State<'a> {
self.maybe_print_comment(ty.span.lo)
}
ast::FunctionRetTy::Default(..) => unreachable!(),
ast::FunctionRetTy::None(span) => {
try!(self.word_nbsp("!"));
self.maybe_print_comment(span.lo)
}
}
}
@ -2955,8 +2951,6 @@ impl<'a> State<'a> {
try!(self.ibox(INDENT_UNIT));
try!(self.word_space("->"));
match decl.output {
ast::FunctionRetTy::None(_) =>
try!(self.word_nbsp("!")),
ast::FunctionRetTy::Default(..) => unreachable!(),
ast::FunctionRetTy::Ty(ref ty) =>
try!(self.print_type(&ty))

View File

@ -1,16 +0,0 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// pretty-expanded FIXME #23616
enum v {}
pub fn main() {
let y: v = unsafe { ::std::mem::uninitialized() };
}