@@ -9,7 +9,7 @@ use syntax::codemap::{DUMMY_SP, Span};
99use syntax:: { ast, attr} ;
1010
1111use error:: { EvalError , EvalResult } ;
12- use eval_context:: { EvalContext , IntegerExt , StackPopCleanup , monomorphize_field_ty} ;
12+ use eval_context:: { EvalContext , IntegerExt , StackPopCleanup , monomorphize_field_ty, is_inhabited } ;
1313use lvalue:: { Lvalue , LvalueExtra } ;
1414use memory:: Pointer ;
1515use value:: PrimVal ;
@@ -155,7 +155,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
155155
156156 DropAndReplace { .. } => unimplemented ! ( ) ,
157157 Resume => unimplemented ! ( ) ,
158- Unreachable => unimplemented ! ( ) ,
158+ Unreachable => return Err ( EvalError :: Unreachable ) ,
159159 }
160160
161161 Ok ( ( ) )
@@ -200,7 +200,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
200200 Abi :: RustIntrinsic => {
201201 let ty = fn_ty. sig . 0 . output ( ) ;
202202 let layout = self . type_layout ( ty) ?;
203- let ( ret, target) = destination. unwrap ( ) ;
203+ let ( ret, target) = match destination {
204+ Some ( dest) if is_inhabited ( self . tcx , ty) => dest,
205+ _ => return Err ( EvalError :: Unreachable ) ,
206+ } ;
204207 self . call_intrinsic ( def_id, substs, arg_operands, ret, ty, layout, target) ?;
205208 Ok ( ( ) )
206209 }
@@ -229,6 +232,33 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
229232 ( def_id, substs, Vec :: new ( ) )
230233 } ;
231234
235+ // FIXME(eddyb) Detect ADT constructors more efficiently.
236+ if let Some ( adt_def) = fn_ty. sig . skip_binder ( ) . output ( ) . ty_adt_def ( ) {
237+ if let Some ( v) = adt_def. variants . iter ( ) . find ( |v| resolved_def_id == v. did ) {
238+ let ( lvalue, target) = destination. expect ( "tuple struct constructors can't diverge" ) ;
239+ let dest_ty = self . tcx . item_type ( adt_def. did ) ;
240+ let dest_layout = self . type_layout ( dest_ty) ?;
241+ match * dest_layout {
242+ Layout :: Univariant { ref variant, .. } => {
243+ assert_eq ! ( v. disr_val. to_u128_unchecked( ) , 0 ) ;
244+ let offsets = variant. offsets . iter ( ) . map ( |s| s. bytes ( ) ) ;
245+
246+ // FIXME: don't allocate for single or dual field structs
247+ let dest = self . force_allocation ( lvalue) ?. to_ptr ( ) ;
248+
249+ for ( offset, ( value, value_ty) ) in offsets. into_iter ( ) . zip ( args) {
250+ let field_dest = dest. offset ( offset) ;
251+ self . write_value_to_ptr ( value, field_dest, value_ty) ?;
252+ }
253+ } ,
254+ // FIXME: enum variant constructors
255+ _ => bug ! ( "bad layout for tuple struct constructor: {:?}" , dest_layout) ,
256+ }
257+ self . goto_block ( target) ;
258+ return Ok ( ( ) ) ;
259+ }
260+ }
261+
232262 let mir = self . load_mir ( resolved_def_id) ?;
233263 let ( return_lvalue, return_to_block) = match destination {
234264 Some ( ( lvalue, block) ) => ( lvalue, StackPopCleanup :: Goto ( block) ) ,
0 commit comments