Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8117c30

Browse files
committedSep 28, 2018
Auto merge of #49878 - dlrobertson:va_list_pt0, r=eddyb
libcore: Add VaList and variadic arg handling intrinsics ## Summary - Add intrinsics for `va_start`, `va_end`, `va_copy`, and `va_arg`. - Add `core::va_list::VaList` to `libcore`. Part 1 of (at least) 3 for #44930 Comments and critiques are very much welcomed 😄
2 parents 63d51e8 + a7a955a commit 8117c30

File tree

11 files changed

+486
-2
lines changed

11 files changed

+486
-2
lines changed
 

‎src/libcore/ffi.rs

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
111
#![stable(feature = "", since = "1.30.0")]
212

313
#![allow(non_camel_case_types)]
@@ -40,3 +50,204 @@ impl fmt::Debug for c_void {
4050
f.pad("c_void")
4151
}
4252
}
53+
54+
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
55+
not(target_arch = "x86_64"), not(stage0)),
56+
windows))]
57+
#[unstable(feature = "c_variadic",
58+
reason = "the `c_variadic` feature has not been properly tested on \
59+
all supported platforms",
60+
issue = "27745")]
61+
/// Basic implementation of a `va_list`.
62+
extern {
63+
type VaListImpl;
64+
}
65+
66+
67+
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
68+
not(target_arch = "x86_64"), not(stage0)),
69+
windows))]
70+
impl fmt::Debug for VaListImpl {
71+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72+
write!(f, "va_list* {:p}", self)
73+
}
74+
}
75+
76+
#[cfg(all(target_arch = "aarch64", not(windows), not(stage0)))]
77+
#[repr(C)]
78+
#[derive(Debug)]
79+
#[unstable(feature = "c_variadic",
80+
reason = "the `c_variadic` feature has not been properly tested on \
81+
all supported platforms",
82+
issue = "27745")]
83+
/// AArch64 ABI implementation of a `va_list`. See the
84+
/// [Aarch64 Procedure Call Standard] for more details.
85+
///
86+
/// [AArch64 Procedure Call Standard]:
87+
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
88+
struct VaListImpl {
89+
stack: *mut (),
90+
gr_top: *mut (),
91+
vr_top: *mut (),
92+
gr_offs: i32,
93+
vr_offs: i32,
94+
}
95+
96+
#[cfg(all(target_arch = "powerpc", not(windows), not(stage0)))]
97+
#[repr(C)]
98+
#[derive(Debug)]
99+
#[unstable(feature = "c_variadic",
100+
reason = "the `c_variadic` feature has not been properly tested on \
101+
all supported platforms",
102+
issue = "27745")]
103+
/// PowerPC ABI implementation of a `va_list`.
104+
struct VaListImpl {
105+
gpr: u8,
106+
fpr: u8,
107+
reserved: u16,
108+
overflow_arg_area: *mut (),
109+
reg_save_area: *mut (),
110+
}
111+
112+
#[cfg(all(target_arch = "x86_64", not(windows), not(stage0)))]
113+
#[repr(C)]
114+
#[derive(Debug)]
115+
#[unstable(feature = "c_variadic",
116+
reason = "the `c_variadic` feature has not been properly tested on \
117+
all supported platforms",
118+
issue = "27745")]
119+
/// x86_64 ABI implementation of a `va_list`.
120+
struct VaListImpl {
121+
gp_offset: i32,
122+
fp_offset: i32,
123+
overflow_arg_area: *mut (),
124+
reg_save_area: *mut (),
125+
}
126+
127+
/// A wrapper for a `va_list`
128+
#[cfg(not(stage0))]
129+
#[lang = "va_list"]
130+
#[derive(Debug)]
131+
#[unstable(feature = "c_variadic",
132+
reason = "the `c_variadic` feature has not been properly tested on \
133+
all supported platforms",
134+
issue = "27745")]
135+
#[repr(transparent)]
136+
pub struct VaList<'a>(&'a mut VaListImpl);
137+
138+
// The VaArgSafe trait needs to be used in public interfaces, however, the trait
139+
// itself must not be allowed to be used outside this module. Allowing users to
140+
// implement the trait for a new type (thereby allowing the va_arg intrinsic to
141+
// be used on a new type) is likely to cause undefined behavior.
142+
//
143+
// FIXME(dlrobertson): In order to use the VaArgSafe trait in a public interface
144+
// but also ensure it cannot be used elsewhere, the trait needs to be public
145+
// within a private module. Once RFC 2145 has been implemented look into
146+
// improving this.
147+
#[cfg(not(stage0))]
148+
mod sealed_trait {
149+
/// Trait which whitelists the allowed types to be used with [VaList::arg]
150+
///
151+
/// [VaList::va_arg]: struct.VaList.html#method.arg
152+
#[unstable(feature = "c_variadic",
153+
reason = "the `c_variadic` feature has not been properly tested on \
154+
all supported platforms",
155+
issue = "27745")]
156+
pub trait VaArgSafe {}
157+
}
158+
159+
#[cfg(not(stage0))]
160+
macro_rules! impl_va_arg_safe {
161+
($($t:ty),+) => {
162+
$(
163+
#[unstable(feature = "c_variadic",
164+
reason = "the `c_variadic` feature has not been properly tested on \
165+
all supported platforms",
166+
issue = "27745")]
167+
impl sealed_trait::VaArgSafe for $t {}
168+
)+
169+
}
170+
}
171+
172+
#[cfg(not(stage0))]
173+
impl_va_arg_safe!{i8, i16, i32, i64, usize}
174+
#[cfg(not(stage0))]
175+
impl_va_arg_safe!{u8, u16, u32, u64, isize}
176+
#[cfg(not(stage0))]
177+
impl_va_arg_safe!{f64}
178+
179+
#[cfg(not(stage0))]
180+
#[unstable(feature = "c_variadic",
181+
reason = "the `c_variadic` feature has not been properly tested on \
182+
all supported platforms",
183+
issue = "27745")]
184+
impl<T> sealed_trait::VaArgSafe for *mut T {}
185+
#[cfg(not(stage0))]
186+
#[unstable(feature = "c_variadic",
187+
reason = "the `c_variadic` feature has not been properly tested on \
188+
all supported platforms",
189+
issue = "27745")]
190+
impl<T> sealed_trait::VaArgSafe for *const T {}
191+
192+
#[cfg(not(stage0))]
193+
impl<'a> VaList<'a> {
194+
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
195+
not(target_arch = "x86_64")),
196+
windows))]
197+
unsafe fn to_intrinsic_ptr(&mut self) -> *mut i8 {
198+
&mut self.0 as *mut _ as *mut i8
199+
}
200+
201+
#[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
202+
target_arch = "x86_64"),
203+
not(windows)))]
204+
unsafe fn to_intrinsic_ptr(&mut self) -> *mut i8 {
205+
self.0 as *mut _ as *mut i8
206+
}
207+
208+
/// Advance to the next arg.
209+
#[unstable(feature = "c_variadic",
210+
reason = "the `c_variadic` feature has not been properly tested on \
211+
all supported platforms",
212+
issue = "27745")]
213+
pub unsafe fn arg<T: sealed_trait::VaArgSafe>(&mut self) -> T {
214+
va_arg(self.to_intrinsic_ptr())
215+
}
216+
217+
/// Copy the `va_list` at the current location.
218+
#[unstable(feature = "c_variadic",
219+
reason = "the `c_variadic` feature has not been properly tested on \
220+
all supported platforms",
221+
issue = "27745")]
222+
pub unsafe fn copy<F, R>(&mut self, f: F) -> R
223+
where F: for<'copy> FnOnce(VaList<'copy>) -> R {
224+
#[cfg(all(any(target_arch = "aarch64", target_arch = "powerpc",
225+
target_arch = "x86_64"),
226+
not(windows)))]
227+
let ap_inner = &mut ::mem::uninitialized::<VaListImpl>();
228+
#[cfg(any(all(not(target_arch = "aarch64"), not(target_arch = "powerpc"),
229+
not(target_arch = "x86_64")),
230+
windows))]
231+
let ap_inner: &mut VaListImpl = &mut *(1 as *mut VaListImpl);
232+
let mut ap = VaList(ap_inner);
233+
let ap_ptr = ap.to_intrinsic_ptr();
234+
va_copy(ap_ptr, self.to_intrinsic_ptr());
235+
let ret = f(ap);
236+
va_end(ap_ptr);
237+
ret
238+
}
239+
}
240+
241+
#[cfg(not(stage0))]
242+
extern "rust-intrinsic" {
243+
/// Destroy the arglist `ap` after initialization with `va_start` or
244+
/// `va_copy`.
245+
fn va_end(ap: *mut i8);
246+
247+
/// Copy the current location of arglist `src` to the arglist `dst`.
248+
fn va_copy(dst: *mut i8, src: *const i8);
249+
250+
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
251+
/// argument `ap` points to.
252+
fn va_arg<T: sealed_trait::VaArgSafe>(ap: *mut i8) -> T;
253+
}

‎src/librustc/middle/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ language_item_table! {
279279
IndexMutTraitLangItem, "index_mut", index_mut_trait;
280280

281281
UnsafeCellTypeLangItem, "unsafe_cell", unsafe_cell_type;
282+
VaListTypeLangItem, "va_list", va_list;
282283

283284
DerefTraitLangItem, "deref", deref_trait;
284285
DerefMutTraitLangItem, "deref_mut", deref_mut_trait;

‎src/librustc_codegen_llvm/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,11 @@ fn declare_intrinsic(cx: &CodegenCx<'ll, '_>, key: &str) -> Option<&'ll Value> {
768768
ifn!("llvm.assume", fn(i1) -> void);
769769
ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void);
770770

771+
// variadic intrinsics
772+
ifn!("llvm.va_start", fn(i8p) -> void);
773+
ifn!("llvm.va_end", fn(i8p) -> void);
774+
ifn!("llvm.va_copy", fn(i8p, i8p) -> void);
775+
771776
if cx.sess().opts.debuginfo != DebugInfo::None {
772777
ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void);
773778
ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void);

‎src/librustc_codegen_llvm/intrinsic.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ use glue;
2323
use type_::Type;
2424
use type_of::LayoutLlvmExt;
2525
use rustc::ty::{self, Ty};
26-
use rustc::ty::layout::{HasDataLayout, LayoutOf};
26+
use rustc::ty::layout::{self, Primitive, HasDataLayout, LayoutOf};
2727
use rustc::hir;
28-
use syntax::ast;
28+
use syntax::ast::{self, FloatTy};
2929
use syntax::symbol::Symbol;
3030
use builder::Builder;
3131
use value::Value;
@@ -78,6 +78,9 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu
7878
"roundf64" => "llvm.round.f64",
7979
"assume" => "llvm.assume",
8080
"abort" => "llvm.trap",
81+
"va_start" => "llvm.va_start",
82+
"va_copy" => "llvm.va_copy",
83+
"va_end" => "llvm.va_end",
8184
_ => return None
8285
};
8386
Some(cx.get_intrinsic(&llvm_name))
@@ -141,6 +144,26 @@ pub fn codegen_intrinsic_call(
141144
let llfn = cx.get_intrinsic(&("llvm.debugtrap"));
142145
bx.call(llfn, &[], None)
143146
}
147+
"va_arg" => {
148+
match fn_ty.ret.layout.abi {
149+
layout::Abi::Scalar(ref scalar) => {
150+
match scalar.value {
151+
Primitive::Int(..) |
152+
Primitive::Float(FloatTy::F64) |
153+
Primitive::Pointer => {
154+
bx.va_arg(args[0].immediate(), llret_ty)
155+
}
156+
// `va_arg` should never be used with the return type f32.
157+
Primitive::Float(FloatTy::F32) => {
158+
bug!("the va_arg intrinsic does not work with `f32`")
159+
}
160+
}
161+
}
162+
_ => {
163+
bug!("the va_arg intrinsic does not work with non-scalar types")
164+
}
165+
}
166+
}
144167
"size_of" => {
145168
let tp_ty = substs.type_at(0);
146169
C_usize(cx, cx.size_of(tp_ty).bytes())

‎src/librustc_typeck/check/intrinsic.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,18 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
321321
(0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
322322
}
323323

324+
"va_start" | "va_end" => {
325+
(0, vec![tcx.mk_mut_ptr(tcx.types.i8)], tcx.mk_unit())
326+
}
327+
328+
"va_copy" => {
329+
(0, vec![tcx.mk_mut_ptr(tcx.types.i8), tcx.mk_imm_ptr(tcx.types.i8)], tcx.mk_unit())
330+
}
331+
332+
"va_arg" => {
333+
(1, vec![tcx.mk_mut_ptr(tcx.types.i8)], param(0))
334+
}
335+
324336
"nontemporal_store" => {
325337
(1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_unit())
326338
}

‎src/libstd/ffi/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,12 @@ pub use core::ffi::c_void;
176176

177177
mod c_str;
178178
mod os_str;
179+
#[unstable(feature = "c_variadic",
180+
reason = "the `c_variadic` feature has not been properly tested on \
181+
all supported platforms",
182+
issue = "27745")]
183+
#[cfg(any(target_arch = "aarch64", target_arch = "arm", target_arch = "mips",
184+
target_arch = "powerpc", target_arch = "powerpc64", target_arch = "x86",
185+
target_arch = "x86_64"))]
186+
#[cfg(not(stage0))]
187+
pub use core::ffi::*;

‎src/libstd/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@
245245
#![feature(array_error_internals)]
246246
#![feature(asm)]
247247
#![feature(box_syntax)]
248+
#![feature(c_variadic)]
248249
#![feature(cfg_target_has_atomic)]
249250
#![feature(cfg_target_thread_local)]
250251
#![feature(cfg_target_vendor)]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-include ../tools.mk
2+
3+
all:
4+
$(RUSTC) checkrust.rs
5+
$(CC) test.c $(call STATICLIB,checkrust) $(call OUT_EXE,test) $(EXTRACFLAGS)
6+
$(call RUN,test)
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "staticlib"]
12+
#![feature(c_variadic)]
13+
use std::ffi::VaList;
14+
use std::slice;
15+
use std::ffi::CStr;
16+
17+
#[repr(C)]
18+
#[derive(Clone, Copy, Debug)]
19+
pub enum AnswerType {
20+
Double,
21+
Long,
22+
Int,
23+
Byte,
24+
CStr,
25+
Skip,
26+
}
27+
28+
#[repr(C)]
29+
pub union AnswerData {
30+
pub double: f64,
31+
pub long: i64,
32+
pub int: i32,
33+
pub byte: i8,
34+
pub cstr: *const i8,
35+
pub skip_ty: AnswerType,
36+
}
37+
38+
#[repr(C)]
39+
pub struct Answer {
40+
tag: AnswerType,
41+
data: AnswerData,
42+
}
43+
44+
#[no_mangle]
45+
pub unsafe fn compare_answers(answers: &[Answer], mut ap: VaList) -> usize {
46+
for (i, answer) in answers.iter().enumerate() {
47+
match answer {
48+
Answer { tag: AnswerType::Double, data: AnswerData { double: d } } => {
49+
let tmp = ap.arg::<f64>();
50+
if d.floor() != tmp.floor() {
51+
println!("Double: {} != {}", d, tmp);
52+
return i + 1;
53+
}
54+
}
55+
Answer { tag: AnswerType::Long, data: AnswerData { long: l } } => {
56+
let tmp = ap.arg::<i64>();
57+
if *l != tmp {
58+
println!("Long: {} != {}", l, tmp);
59+
return i + 1;
60+
}
61+
}
62+
Answer { tag: AnswerType::Int, data: AnswerData { int: n } } => {
63+
let tmp = ap.arg::<i32>();
64+
if *n != tmp {
65+
println!("Int: {} != {}", n, tmp);
66+
return i + 1;
67+
}
68+
}
69+
Answer { tag: AnswerType::Byte, data: AnswerData { byte: b } } => {
70+
let tmp = ap.arg::<i8>();
71+
if *b != tmp {
72+
println!("Byte: {} != {}", b, tmp);
73+
return i + 1;
74+
}
75+
}
76+
Answer { tag: AnswerType::CStr, data: AnswerData { cstr: c0 } } => {
77+
let c1 = ap.arg::<*const i8>();
78+
let cstr0 = CStr::from_ptr(*c0);
79+
let cstr1 = CStr::from_ptr(c1);
80+
if cstr0 != cstr1 {
81+
println!("C String: {:?} != {:?}", cstr0, cstr1);
82+
return i + 1;
83+
}
84+
}
85+
_ => {
86+
println!("Unknown type!");
87+
return i + 1;
88+
}
89+
}
90+
}
91+
return 0;
92+
}
93+
94+
#[no_mangle]
95+
pub unsafe extern "C" fn check_rust(argc: usize, answers: *const Answer, ap: VaList) -> usize {
96+
let slice = slice::from_raw_parts(answers, argc);
97+
compare_answers(slice, ap)
98+
}
99+
100+
#[no_mangle]
101+
pub unsafe extern "C" fn check_rust_copy(argc: usize, answers: *const Answer,
102+
mut ap: VaList) -> usize {
103+
let slice = slice::from_raw_parts(answers, argc);
104+
let mut skip_n = 0;
105+
for (i, answer) in slice.iter().enumerate() {
106+
match answer {
107+
Answer { tag: AnswerType::Skip, data: AnswerData { skip_ty } } => {
108+
match skip_ty {
109+
AnswerType::Double => { ap.arg::<f64>(); }
110+
AnswerType::Long => { ap.arg::<i64>(); }
111+
AnswerType::Int => { ap.arg::<i32>(); }
112+
AnswerType::Byte => { ap.arg::<i8>(); }
113+
AnswerType::CStr => { ap.arg::<*const i8>(); }
114+
_ => { return i; }
115+
};
116+
}
117+
_ => {
118+
skip_n = i;
119+
break;
120+
}
121+
}
122+
}
123+
124+
ap.copy(|ap| {
125+
compare_answers(&slice[skip_n..], ap)
126+
})
127+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#include <stdarg.h>
12+
#include <assert.h>
13+
#include <stdint.h>
14+
#include <stdlib.h>
15+
16+
typedef enum {
17+
TAG_DOUBLE,
18+
TAG_LONG,
19+
TAG_INT,
20+
TAG_BYTE,
21+
TAG_CSTR,
22+
TAG_SKIP,
23+
} tag;
24+
25+
typedef struct {
26+
tag answer_type;
27+
union {
28+
double double_precision;
29+
int64_t num_long;
30+
int32_t num_int;
31+
int8_t byte;
32+
char* cstr;
33+
tag skip_ty;
34+
} answer_data;
35+
} answer;
36+
37+
#define MK_DOUBLE(n) \
38+
{ TAG_DOUBLE, { .double_precision = n } }
39+
#define MK_LONG(n) \
40+
{ TAG_LONG, { .num_long = n } }
41+
#define MK_INT(n) \
42+
{ TAG_INT, { .num_int = n } }
43+
#define MK_BYTE(b) \
44+
{ TAG_BYTE, { .byte = b } }
45+
#define MK_CSTR(s) \
46+
{ TAG_CSTR, { .cstr = s } }
47+
#define MK_SKIP(ty) \
48+
{ TAG_SKIP, { .skip_ty = TAG_ ## ty } }
49+
50+
extern size_t check_rust(size_t argc, const answer* answers, va_list ap);
51+
extern size_t check_rust_copy(size_t argc, const answer* answers, va_list ap);
52+
53+
size_t test_check_rust(size_t argc, const answer* answers, ...) {
54+
size_t ret = 0;
55+
va_list ap;
56+
va_start(ap, answers);
57+
ret = check_rust(argc, answers, ap);
58+
va_end(ap);
59+
return ret;
60+
}
61+
62+
size_t test_check_rust_copy(size_t argc, const answer* answers, ...) {
63+
size_t ret = 0;
64+
va_list ap;
65+
va_start(ap, answers);
66+
ret = check_rust_copy(argc, answers, ap);
67+
va_end(ap);
68+
return ret;
69+
}
70+
71+
int main(int argc, char* argv[]) {
72+
answer answers0[] = {MK_DOUBLE(3.14), MK_BYTE('a'), MK_DOUBLE(6.28),
73+
MK_INT(42), MK_LONG(12l), MK_CSTR("Hello, World!")};
74+
assert(test_check_rust(4, answers0, 3.14, 'a', 6.28, 42, 12l,
75+
"Hello, World!") == 0);
76+
77+
answer answers1[] = { MK_SKIP(DOUBLE), MK_SKIP(INT), MK_SKIP(BYTE),
78+
MK_SKIP(CSTR), MK_CSTR("Correctly skipped and copied list") };
79+
assert(test_check_rust_copy(5, answers1, 6.28, 16, 'A', "Skip Me!",
80+
"Correctly skipped and copied list") == 0);
81+
return 0;
82+
}

‎src/tools/tidy/src/pal.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ const EXCEPTION_PATHS: &[&str] = &[
7878
"src/libcore/tests",
7979
"src/liballoc/tests/lib.rs",
8080

81+
// The `VaList` implementation must have platform specific code.
82+
// The Windows implementation of a `va_list` is always a character
83+
// pointer regardless of the target architecture. As a result,
84+
// we must use `#[cfg(windows)]` to conditionally compile the
85+
// correct `VaList` structure for windows.
86+
"src/libcore/ffi.rs",
87+
8188
// non-std crates
8289
"src/test",
8390
"src/tools",

0 commit comments

Comments
 (0)
Please sign in to comment.