diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 5b0dae23807a9..370e5667c1fef 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -119,7 +119,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); - if bcx.tcx().tables.borrow().adjustments.contains_key(&expr.id) { + if adjustment_required(bcx, expr) { // use trans, which may be less efficient but // which will perform the adjustments: let datum = unpack_datum!(bcx, trans(bcx, expr)); @@ -334,6 +334,37 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, } } +fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + expr: &hir::Expr) -> bool { + let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() { + None => { return false; } + Some(adj) => adj + }; + + // Don't skip a conversion from Box to &T, etc. + if bcx.tcx().is_overloaded_autoderef(expr.id, 0) { + return true; + } + + match adjustment { + AdjustReifyFnPointer => { + // FIXME(#19925) once fn item types are + // zero-sized, we'll need to return true here + false + } + AdjustUnsafeFnPointer => { + // purely a type-level thing + false + } + AdjustDerefRef(ref adj) => { + // We are a bit paranoid about adjustments and thus might have a re- + // borrow here which merely derefs and then refs again (it might have + // a different region or mutability, but we don't care here). + !(adj.autoderefs == 1 && adj.autoref.is_some() && adj.unsize.is_none()) + } + } +} + /// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted /// translation of `expr`. fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, diff --git a/src/test/codegen/adjustments.rs b/src/test/codegen/adjustments.rs index b0438f561b935..d9a7acf112908 100644 --- a/src/test/codegen/adjustments.rs +++ b/src/test/codegen/adjustments.rs @@ -26,3 +26,12 @@ pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] { // CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]], { x } } + +// CHECK-LABEL: @no_op_slice_adjustment2 +#[no_mangle] +pub fn no_op_slice_adjustment2(x: &[u8]) -> &[u8] { + // We used to generate an extra alloca and memcpy for the function's return value, so check + // that there's no memcpy (the slice is written to sret_slot element-wise) +// CHECK-NOT: call void @llvm.memcpy. + no_op_slice_adjustment(x) +}