diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 6c31d54e081c4..d2c97221bf03e 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -123,7 +123,10 @@ use rustc_data_structures::tiny_list::TinyList; use rustc_macros::HashStable; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; -/// Uniquely identifies a specific constant or static. +/// Uniquely identifies one of the following: +/// - A constant +/// - A static +/// - A const fn where all arguments (if any) are zero-sized types #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable, HashStable)] pub struct GlobalId<'tcx> { /// For a constant or static, the `Instance` of the item itself. diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index e10bb85d52df8..e6ccfe885b5be 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -7,7 +7,7 @@ use syntax::source_map::Span; use rustc_target::spec::abi::Abi; use super::{ - InterpResult, PointerArithmetic, + GlobalId, InterpResult, PointerArithmetic, InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal, }; @@ -293,6 +293,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + // If this function is a const function then as an optimisation we can query this + // evaluation immediately. + // + // For the moment we only do this for functions which take no arguments + // (or all arguments are ZSTs) so that we don't memoize too much. + if self.tcx.is_const_fn_raw(instance.def.def_id()) && + args.iter().all(|a| a.layout.is_zst()) + { + let gid = GlobalId { instance, promoted: None }; + let place = self.const_eval_raw(gid)?; + + let dest = match dest { + Some(dest) => dest, + None => throw_ub!(Unreachable) + }; + + self.copy_op(place.into(), dest)?; + + // No stack frame gets pushed, the main loop will just act as if the + // call completed. + self.goto_block(ret)?; + self.dump_place(*dest); + return Ok(()) + } + // We need MIR for this fn let body = match M::find_fn(self, instance, args, dest, ret)? { Some(body) => body,