diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 31131bc889d57..e6b8c537d8451 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1512,7 +1512,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } // FIXME implement variadics in cranelift - sym::va_arg | sym::va_end => { + sym::va_arg => { fx.tcx.dcx().span_fatal( source_info.span, "Defining variadic functions is not yet supported by Cranelift", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 728cd90cf637d..a12116d5b9d39 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -705,10 +705,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc unimplemented!(); } - fn va_end(&mut self, _va_list: RValue<'gcc>) { - // FIXME(antoyo): implement. - } - fn retag_reg(&mut self, _ptr: Self::Value, _info: &RetagInfo) -> Self::Value { unimplemented!() } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 393837375769e..0b03d6862ca84 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1070,10 +1070,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list]); } - fn va_end(&mut self, va_list: &'ll Value) { - self.call_intrinsic("llvm.va_end", &[self.val_ty(va_list)], &[va_list]); - } - fn retag_reg(&mut self, ptr: Self::Value, info: &RetagInfo) -> Self::Value { codegen_retag_inner(self, "__rust_retag_reg", ptr, info) } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 0276e0433cd4e..7fe57fc7adb75 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -525,13 +525,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } fn codegen_return_terminator(&mut self, bx: &mut Bx) { - // Call `va_end` if this is the definition of a C-variadic function. + // Explicitly end the lifetime of the VaList if this function is c-variadic. We explicitly + // start the lifetime when desugaring `...`. Ending the lifetime meaningfully improves + // codegen. if self.fn_abi.c_variadic { // The `VaList` "spoofed" argument is just after all the real arguments. let va_list_arg_idx = self.fn_abi.args.len(); match self.locals[mir::Local::arg(va_list_arg_idx)] { LocalRef::Place(va_list) => { - bx.va_end(va_list.val.llval); + // NOTE: we don't actually call LLVM's va_end here. We know it's a no-op for + // all current targets and hence don't bother + // (as permitted by https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic). // Explicitly end the lifetime of the `va_list`, improves LLVM codegen. bx.lifetime_end(va_list.val.llval, va_list.layout.size); diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index dcd4e722a27a8..47144834b5072 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -52,9 +52,6 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes { /// Trait method used to inject `va_start` on the "spoofed" `VaList` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value); - /// Trait method used to inject `va_end` on the "spoofed" `VaList` before - /// Rust defined C-variadic functions return. - fn va_end(&mut self, val: Self::Value); /// Trait method used to retag a pointer stored within a place. fn retag_mem(&mut self, place: Self::Value, info: &RetagInfo); /// Trait method used to retag a pointer that has been loaded into a register. diff --git a/tests/codegen-llvm/c-variadic-lifetime.rs b/tests/codegen-llvm/c-variadic-lifetime.rs index 302bc621df497..794b98e03914c 100644 --- a/tests/codegen-llvm/c-variadic-lifetime.rs +++ b/tests/codegen-llvm/c-variadic-lifetime.rs @@ -16,6 +16,9 @@ unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 { a + b + c - // CHECK: call void @llvm.va_end.p0(ptr nonnull %args) + // We no longer call the LLVM va_end. + // CHECK-NOT: call void @llvm.va_end + + // But we do still explicitly end the lifetime of the VaList. // CHECK: call void @llvm.lifetime.end.p0({{(i64 [0-9]+, )?}}ptr nonnull %args) } diff --git a/tests/codegen-llvm/c-variadic-va-end.rs b/tests/codegen-llvm/c-variadic-va-end.rs index b0d7371ba01c2..0be1c17257c66 100644 --- a/tests/codegen-llvm/c-variadic-va-end.rs +++ b/tests/codegen-llvm/c-variadic-va-end.rs @@ -11,9 +11,6 @@ unsafe extern "C" { pub unsafe extern "C" fn f(mut args: ...) { // CHECK: call void @llvm.va_start unsafe { g(&raw mut args as *mut u8) } - // We expect one call to the LLVM va_end from our desugaring of `...`. The `Drop` implementation - // should only call the rust va_end intrinsic, which is a no-op. - // - // CHECK: call void @llvm.va_end + // We no longer call the LLVM va_end. // CHECK-NOT: call void @llvm.va_end } diff --git a/tests/codegen-llvm/cffi/c-variadic-opt.rs b/tests/codegen-llvm/cffi/c-variadic-opt.rs index c779b25450fd1..a317b20e975d4 100644 --- a/tests/codegen-llvm/cffi/c-variadic-opt.rs +++ b/tests/codegen-llvm/cffi/c-variadic-opt.rs @@ -15,5 +15,6 @@ extern "C" { pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 { // CHECK: call void @llvm.va_start vprintf(fmt, ap) - // CHECK: call void @llvm.va_end + // We no longer call the LLVM va_end. + // CHECK-NOT: call void @llvm.va_end } diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs index 0fa63b42c2de6..ceef7e72251d9 100644 --- a/tests/codegen-llvm/cffi/c-variadic.rs +++ b/tests/codegen-llvm/cffi/c-variadic.rs @@ -31,7 +31,8 @@ pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { sum += ap.next_arg::(); } sum - // CHECK: call void @llvm.va_end + // We no longer call the LLVM va_end. + // CHECK-NOT: call void @llvm.va_end } // Ensure that we generate the correct `call` signature when calling a Rust