]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #52089 - eddyb:issue-51907, r=nagisa
authorbors <bors@rust-lang.org>
Thu, 12 Jul 2018 01:20:19 +0000 (01:20 +0000)
committerbors <bors@rust-lang.org>
Thu, 12 Jul 2018 01:20:19 +0000 (01:20 +0000)
rustc_codegen_llvm: replace the first argument early in FnType::new_vtable.

Fixes #51907 by removing the vtable pointer before the `ArgType` is even created.
This allows any ABI to support trait object method calls, regardless of how it passes `*dyn Trait`.

r? @nikomatsakis

1  2 
src/librustc_codegen_llvm/abi.rs

index a4fb0378e57a3cae99398546cd2458db873c9b45,b96e9b4300f0b624e8815e5aa1dd5e32cddb9d76..dbada85098b41b92bbf8cb614acb6a777b02d913
@@@ -261,9 -261,12 +261,12 @@@ pub trait FnTypeExt<'a, 'tcx> 
      fn new_vtable(cx: &CodegenCx<'a, 'tcx>,
                    sig: ty::FnSig<'tcx>,
                    extra_args: &[Ty<'tcx>]) -> Self;
-     fn unadjusted(cx: &CodegenCx<'a, 'tcx>,
-                   sig: ty::FnSig<'tcx>,
-                   extra_args: &[Ty<'tcx>]) -> Self;
+     fn new_internal(
+         cx: &CodegenCx<'a, 'tcx>,
+         sig: ty::FnSig<'tcx>,
+         extra_args: &[Ty<'tcx>],
+         mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+     ) -> Self;
      fn adjust_for_abi(&mut self,
                        cx: &CodegenCx<'a, 'tcx>,
                        abi: Abi);
@@@ -285,40 -288,40 +288,40 @@@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for 
      fn new(cx: &CodegenCx<'a, 'tcx>,
                 sig: ty::FnSig<'tcx>,
                 extra_args: &[Ty<'tcx>]) -> Self {
-         let mut fn_ty = FnType::unadjusted(cx, sig, extra_args);
-         fn_ty.adjust_for_abi(cx, sig.abi);
-         fn_ty
+         FnType::new_internal(cx, sig, extra_args, |ty, _| {
+             ArgType::new(cx.layout_of(ty))
+         })
      }
  
      fn new_vtable(cx: &CodegenCx<'a, 'tcx>,
                        sig: ty::FnSig<'tcx>,
                        extra_args: &[Ty<'tcx>]) -> Self {
-         let mut fn_ty = FnType::unadjusted(cx, sig, extra_args);
-         // Don't pass the vtable, it's not an argument of the virtual fn.
-         {
-             let self_arg = &mut fn_ty.args[0];
-             match self_arg.mode {
-                 PassMode::Pair(data_ptr, _) => {
-                     self_arg.mode = PassMode::Direct(data_ptr);
-                 }
-                 _ => bug!("FnType::new_vtable: non-pair self {:?}", self_arg)
+         FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
+             let mut layout = cx.layout_of(ty);
+             // Don't pass the vtable, it's not an argument of the virtual fn.
+             // Instead, pass just the (thin pointer) first field of `*dyn Trait`.
+             if arg_idx == Some(0) {
+                 // FIXME(eddyb) `layout.field(cx, 0)` is not enough because e.g.
+                 // `Box<dyn Trait>` has a few newtype wrappers around the raw
+                 // pointer, so we'd have to "dig down" to find `*dyn Trait`.
+                 let pointee = layout.ty.builtin_deref(true)
+                     .unwrap_or_else(|| {
+                         bug!("FnType::new_vtable: non-pointer self {:?}", layout)
+                     }).ty;
+                 let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee);
+                 layout = cx.layout_of(fat_ptr_ty).field(cx, 0);
              }
-             let pointee = self_arg.layout.ty.builtin_deref(true)
-                 .unwrap_or_else(|| {
-                     bug!("FnType::new_vtable: non-pointer self {:?}", self_arg)
-                 }).ty;
-             let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee);
-             self_arg.layout = cx.layout_of(fat_ptr_ty).field(cx, 0);
-         }
-         fn_ty.adjust_for_abi(cx, sig.abi);
-         fn_ty
+             ArgType::new(layout)
+         })
      }
  
-     fn unadjusted(cx: &CodegenCx<'a, 'tcx>,
-                       sig: ty::FnSig<'tcx>,
-                       extra_args: &[Ty<'tcx>]) -> Self {
-         debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args);
+     fn new_internal(
+         cx: &CodegenCx<'a, 'tcx>,
+         sig: ty::FnSig<'tcx>,
+         extra_args: &[Ty<'tcx>],
+         mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+     ) -> Self {
+         debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
  
          use self::Abi::*;
          let conv = match cx.sess().target.target.adjust_abi(sig.abi) {
              }
          };
  
-         let arg_of = |ty: Ty<'tcx>, is_return: bool| {
-             let mut arg = ArgType::new(cx.layout_of(ty));
+         let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
+             let is_return = arg_idx.is_none();
+             let mut arg = mk_arg_type(ty, arg_idx);
              if arg.layout.is_zst() {
                  // For some forsaken reason, x86_64-pc-windows-gnu
                  // doesn't ignore zero-sized struct arguments.
              arg
          };
  
-         FnType {
-             ret: arg_of(sig.output(), true),
-             args: inputs.iter().chain(extra_args.iter()).map(|ty| {
-                 arg_of(ty, false)
+         let mut fn_ty = FnType {
+             ret: arg_of(sig.output(), None),
+             args: inputs.iter().chain(extra_args).enumerate().map(|(i, ty)| {
+                 arg_of(ty, Some(i))
              }).collect(),
              variadic: sig.variadic,
              conv,
-         }
+         };
+         fn_ty.adjust_for_abi(cx, sig.abi);
+         fn_ty
      }
  
      fn adjust_for_abi(&mut self,
                  PassMode::Ignore => continue,
                  PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
                  PassMode::Pair(..) => {
 -                    llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0));
 -                    llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1));
 +                    llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
 +                    llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
                      continue;
                  }
                  PassMode::Cast(cast) => cast.llvm_type(cx),
                  layout::Int(..) if !scalar.is_bool() => {
                      let range = scalar.valid_range_exclusive(bx.cx);
                      if range.start != range.end {
 -                        // FIXME(nox): This causes very weird type errors about
 -                        // SHL operators in constants in stage 2 with LLVM 3.9.
 -                        if unsafe { llvm::LLVMRustVersionMajor() >= 4 } {
 -                            bx.range_metadata(callsite, range);
 -                        }
 +                        bx.range_metadata(callsite, range);
                      }
                  }
                  _ => {}