Skip to content

Commit 1999a22

Browse files
committed
Auto merge of #57760 - dlrobertson:varargs1, r=alexreg
Support defining C compatible variadic functions ## Summary Add support for defining C compatible variadic functions in unsafe rust with `extern "C"` according to [RFC 2137]. ## Details ### Parsing When parsing a user defined function that is `unsafe` and `extern "C"` allow variadic signatures and inject a "spoofed" `VaList` in the new functions signature. This allows the user to interact with the variadic arguments via a `VaList` instead of manually using `va_start` and `va_end` (See [RFC 2137] for details). ### Codegen When running codegen for a variadic function, remove the "spoofed" `VaList` from the function signature and inject `va_start` when the arg local references are created for the function and `va_end` on return. ## TODO - [x] Get feedback on injecting `va_start/va_end` in MIR vs codegen - [x] Properly inject `va_end` - It seems like it should be possible to inject `va_end` on the `TerminatorKind::Return`. I just need to figure out how to get the `LocalRef` here. - [x] Properly call Rust defined C variadic functions in Rust - The spoofed `VaList` causes problems here. Related to: #44930 r? @ghost [RFC 2137]: https://github.com/rust-lang/rfcs/blob/master/text/2137-variadic.md
2 parents 190feb6 + f7dd438 commit 1999a22

File tree

78 files changed

+1778
-902
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+1778
-902
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# `c_variadic`
2+
3+
The tracking issue for this feature is: [#44930]
4+
5+
[#44930]: https://github.com/rust-lang/rust/issues/44930
6+
7+
------------------------
8+
9+
The `c_variadic` language feature enables C-variadic functions to be
10+
defined in Rust. The may be called both from within Rust and via FFI.
11+
12+
## Examples
13+
14+
```rust
15+
#![feature(c_variadic)]
16+
17+
pub unsafe extern "C" fn add(n: usize, mut args: ...) -> usize {
18+
let mut sum = 0;
19+
for _ in 0..n {
20+
sum += args.arg::<usize>();
21+
}
22+
sum
23+
}
24+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# `c_variadic`
2+
3+
The tracking issue for this feature is: [#44930]
4+
5+
[#44930]: https://github.com/rust-lang/rust/issues/44930
6+
7+
------------------------
8+
9+
The `c_variadic` library feature exposes the `VaList` structure,
10+
Rust's analogue of C's `va_list` type.
11+
12+
## Examples
13+
14+
```rust
15+
#![feature(c_variadic)]
16+
17+
use std::ffi::VaList;
18+
19+
pub unsafe extern "C" fn vadd(n: usize, mut args: VaList) -> usize {
20+
let mut sum = 0;
21+
for _ in 0..n {
22+
sum += args.arg::<usize>();
23+
}
24+
sum
25+
}
26+
```

src/librustc/hir/intravisit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
617617
TyKind::Typeof(ref expression) => {
618618
visitor.visit_anon_const(expression)
619619
}
620+
TyKind::CVarArgs(ref lt) => {
621+
visitor.visit_lifetime(lt)
622+
}
620623
TyKind::Infer | TyKind::Err => {}
621624
}
622625
}

src/librustc/hir/lowering.rs

+25-19
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
7474
pub struct LoweringContext<'a> {
7575
crate_root: Option<&'static str>,
7676

77-
// Used to assign ids to HIR nodes that do not directly correspond to an AST node.
77+
/// Used to assign ids to HIR nodes that do not directly correspond to an AST node.
7878
sess: &'a Session,
7979

8080
cstore: &'a dyn CrateStore,
@@ -107,25 +107,25 @@ pub struct LoweringContext<'a> {
107107
/// written at all (e.g., `&T` or `std::cell::Ref<T>`).
108108
anonymous_lifetime_mode: AnonymousLifetimeMode,
109109

110-
// Used to create lifetime definitions from in-band lifetime usages.
111-
// e.g., `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8`
112-
// When a named lifetime is encountered in a function or impl header and
113-
// has not been defined
114-
// (i.e., it doesn't appear in the in_scope_lifetimes list), it is added
115-
// to this list. The results of this list are then added to the list of
116-
// lifetime definitions in the corresponding impl or function generics.
110+
/// Used to create lifetime definitions from in-band lifetime usages.
111+
/// e.g., `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8`
112+
/// When a named lifetime is encountered in a function or impl header and
113+
/// has not been defined
114+
/// (i.e., it doesn't appear in the in_scope_lifetimes list), it is added
115+
/// to this list. The results of this list are then added to the list of
116+
/// lifetime definitions in the corresponding impl or function generics.
117117
lifetimes_to_define: Vec<(Span, ParamName)>,
118118

119-
// Whether or not in-band lifetimes are being collected. This is used to
120-
// indicate whether or not we're in a place where new lifetimes will result
121-
// in in-band lifetime definitions, such a function or an impl header,
122-
// including implicit lifetimes from `impl_header_lifetime_elision`.
119+
/// Whether or not in-band lifetimes are being collected. This is used to
120+
/// indicate whether or not we're in a place where new lifetimes will result
121+
/// in in-band lifetime definitions, such a function or an impl header,
122+
/// including implicit lifetimes from `impl_header_lifetime_elision`.
123123
is_collecting_in_band_lifetimes: bool,
124124

125-
// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
126-
// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked
127-
// against this list to see if it is already in-scope, or if a definition
128-
// needs to be created for it.
125+
/// Currently in-scope lifetimes defined in impl headers, fn headers, or HRTB.
126+
/// When `is_collectin_in_band_lifetimes` is true, each lifetime is checked
127+
/// against this list to see if it is already in-scope, or if a definition
128+
/// needs to be created for it.
129129
in_scope_lifetimes: Vec<Ident>,
130130

131131
current_module: NodeId,
@@ -954,7 +954,7 @@ impl<'a> LoweringContext<'a> {
954954
let decl = FnDecl {
955955
inputs: vec![],
956956
output,
957-
variadic: false
957+
c_variadic: false
958958
};
959959
let body_id = self.record_body(body_expr, Some(&decl));
960960
self.is_generator = prev_is_generator;
@@ -1345,6 +1345,12 @@ impl<'a> LoweringContext<'a> {
13451345
}
13461346
}
13471347
TyKind::Mac(_) => panic!("TyMac should have been expanded by now."),
1348+
TyKind::CVarArgs => {
1349+
// Create the implicit lifetime of the "spoofed" `VaList`.
1350+
let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
1351+
let lt = self.new_implicit_lifetime(span);
1352+
hir::TyKind::CVarArgs(lt)
1353+
},
13481354
};
13491355

13501356
let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(t.id);
@@ -2112,7 +2118,7 @@ impl<'a> LoweringContext<'a> {
21122118
P(hir::FnDecl {
21132119
inputs,
21142120
output,
2115-
variadic: decl.variadic,
2121+
c_variadic: decl.c_variadic,
21162122
implicit_self: decl.inputs.get(0).map_or(
21172123
hir::ImplicitSelfKind::None,
21182124
|arg| {
@@ -3967,7 +3973,7 @@ impl<'a> LoweringContext<'a> {
39673973
let outer_decl = FnDecl {
39683974
inputs: decl.inputs.clone(),
39693975
output: FunctionRetTy::Default(fn_decl_span),
3970-
variadic: false,
3976+
c_variadic: false,
39713977
};
39723978
// We need to lower the declaration outside the new scope, because we
39733979
// have to conserve the state of being inside a loop condition for the

src/librustc/hir/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,9 @@ pub enum TyKind {
18291829
Infer,
18301830
/// Placeholder for a type that has failed to be defined.
18311831
Err,
1832+
/// Placeholder for C-variadic arguments. We "spoof" the `VaList` created
1833+
/// from the variadic arguments. This type is only valid up to typeck.
1834+
CVarArgs(Lifetime),
18321835
}
18331836

18341837
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -1865,7 +1868,7 @@ pub struct Arg {
18651868
pub struct FnDecl {
18661869
pub inputs: HirVec<Ty>,
18671870
pub output: FunctionRetTy,
1868-
pub variadic: bool,
1871+
pub c_variadic: bool,
18691872
/// Does the function have an implicit self?
18701873
pub implicit_self: ImplicitSelfKind,
18711874
}

src/librustc/hir/print.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,9 @@ impl<'a> State<'a> {
434434
self.s.word("/*ERROR*/")?;
435435
self.pclose()?;
436436
}
437+
hir::TyKind::CVarArgs(_) => {
438+
self.s.word("...")?;
439+
}
437440
}
438441
self.end()
439442
}
@@ -2004,7 +2007,7 @@ impl<'a> State<'a> {
20042007
s.print_type(ty)?;
20052008
s.end()
20062009
})?;
2007-
if decl.variadic {
2010+
if decl.c_variadic {
20082011
self.s.word(", ...")?;
20092012
}
20102013
self.pclose()?;

src/librustc/ich/impls_hir.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -361,13 +361,14 @@ impl_stable_hash_for!(enum hir::TyKind {
361361
TraitObject(trait_refs, lifetime),
362362
Typeof(body_id),
363363
Err,
364-
Infer
364+
Infer,
365+
CVarArgs(lt),
365366
});
366367

367368
impl_stable_hash_for!(struct hir::FnDecl {
368369
inputs,
369370
output,
370-
variadic,
371+
c_variadic,
371372
implicit_self
372373
});
373374

src/librustc/ich/impls_ty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ impl_stable_hash_for!(struct ty::GenSig<'tcx> {
232232

233233
impl_stable_hash_for!(struct ty::FnSig<'tcx> {
234234
inputs_and_output,
235-
variadic,
235+
c_variadic,
236236
unsafety,
237237
abi
238238
});

src/librustc/middle/resolve_lifetime.rs

+21-10
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
764764
});
765765
}
766766
}
767+
hir::TyKind::CVarArgs(ref lt) => {
768+
// Resolve the generated lifetime for the C-variadic arguments.
769+
// The lifetime is generated in AST -> HIR lowering.
770+
if lt.name.is_elided() {
771+
self.resolve_elided_lifetimes(vec![lt])
772+
}
773+
}
767774
_ => intravisit::walk_ty(self, ty),
768775
}
769776
}
@@ -2225,18 +2232,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
22252232
if let hir::TyKind::BareFn(_) = ty.node {
22262233
self.outer_index.shift_in(1);
22272234
}
2228-
if let hir::TyKind::TraitObject(ref bounds, ref lifetime) = ty.node {
2229-
for bound in bounds {
2230-
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
2231-
}
2235+
match ty.node {
2236+
hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
2237+
for bound in bounds {
2238+
self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
2239+
}
22322240

2233-
// Stay on the safe side and don't include the object
2234-
// lifetime default (which may not end up being used).
2235-
if !lifetime.is_elided() {
2236-
self.visit_lifetime(lifetime);
2241+
// Stay on the safe side and don't include the object
2242+
// lifetime default (which may not end up being used).
2243+
if !lifetime.is_elided() {
2244+
self.visit_lifetime(lifetime);
2245+
}
2246+
}
2247+
hir::TyKind::CVarArgs(_) => {}
2248+
_ => {
2249+
intravisit::walk_ty(self, ty);
22372250
}
2238-
} else {
2239-
intravisit::walk_ty(self, ty);
22402251
}
22412252
if let hir::TyKind::BareFn(_) = ty.node {
22422253
self.outer_index.shift_out(1);

src/librustc/traits/select.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1944,7 +1944,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
19441944
if let ty::FnSig {
19451945
unsafety: hir::Unsafety::Normal,
19461946
abi: Abi::Rust,
1947-
variadic: false,
1947+
c_variadic: false,
19481948
..
19491949
} = self_ty.fn_sig(self.tcx()).skip_binder()
19501950
{

src/librustc/ty/context.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2453,7 +2453,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
24532453
self.mk_fn_sig(
24542454
params_iter,
24552455
s.output(),
2456-
s.variadic,
2456+
s.c_variadic,
24572457
hir::Unsafety::Normal,
24582458
abi::Abi::Rust,
24592459
)
@@ -2779,7 +2779,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
27792779
pub fn mk_fn_sig<I>(self,
27802780
inputs: I,
27812781
output: I::Item,
2782-
variadic: bool,
2782+
c_variadic: bool,
27832783
unsafety: hir::Unsafety,
27842784
abi: abi::Abi)
27852785
-> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output
@@ -2788,7 +2788,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
27882788
{
27892789
inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig {
27902790
inputs_and_output: self.intern_type_list(xs),
2791-
variadic, unsafety, abi
2791+
c_variadic, unsafety, abi
27922792
})
27932793
}
27942794

src/librustc/ty/instance.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl<'a, 'tcx> Instance<'tcx> {
6565
sig.map_bound(|sig| tcx.mk_fn_sig(
6666
iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
6767
sig.output(),
68-
sig.variadic,
68+
sig.c_variadic,
6969
sig.unsafety,
7070
sig.abi
7171
))

src/librustc/ty/relate.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
147147
{
148148
let tcx = relation.tcx();
149149

150-
if a.variadic != b.variadic {
150+
if a.c_variadic != b.c_variadic {
151151
return Err(TypeError::VariadicMismatch(
152-
expected_found(relation, &a.variadic, &b.variadic)));
152+
expected_found(relation, &a.c_variadic, &b.c_variadic)));
153153
}
154154
let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
155155
let abi = relation.relate(&a.abi, &b.abi)?;
@@ -171,7 +171,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
171171
});
172172
Ok(ty::FnSig {
173173
inputs_and_output: tcx.mk_type_list(inputs_and_output)?,
174-
variadic: a.variadic,
174+
c_variadic: a.c_variadic,
175175
unsafety,
176176
abi,
177177
})

src/librustc/ty/structural_impls.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> {
396396
tcx.lift(&self.inputs_and_output).map(|x| {
397397
ty::FnSig {
398398
inputs_and_output: x,
399-
variadic: self.variadic,
399+
c_variadic: self.c_variadic,
400400
unsafety: self.unsafety,
401401
abi: self.abi,
402402
}
@@ -832,7 +832,7 @@ BraceStructTypeFoldableImpl! {
832832

833833
BraceStructTypeFoldableImpl! {
834834
impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
835-
inputs_and_output, variadic, unsafety, abi
835+
inputs_and_output, c_variadic, unsafety, abi
836836
}
837837
}
838838

src/librustc/ty/sty.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -977,13 +977,13 @@ impl<'tcx> PolyGenSig<'tcx> {
977977
/// Signature of a function type, which I have arbitrarily
978978
/// decided to use to refer to the input/output types.
979979
///
980-
/// - `inputs` is the list of arguments and their modes.
981-
/// - `output` is the return type.
982-
/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
980+
/// - `inputs`: is the list of arguments and their modes.
981+
/// - `output`: is the return type.
982+
/// - `c_variadic`: indicates whether this is a C-variadic function.
983983
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
984984
pub struct FnSig<'tcx> {
985985
pub inputs_and_output: &'tcx List<Ty<'tcx>>,
986-
pub variadic: bool,
986+
pub c_variadic: bool,
987987
pub unsafety: hir::Unsafety,
988988
pub abi: abi::Abi,
989989
}
@@ -1016,8 +1016,8 @@ impl<'tcx> PolyFnSig<'tcx> {
10161016
pub fn output(&self) -> ty::Binder<Ty<'tcx>> {
10171017
self.map_bound_ref(|fn_sig| fn_sig.output())
10181018
}
1019-
pub fn variadic(&self) -> bool {
1020-
self.skip_binder().variadic
1019+
pub fn c_variadic(&self) -> bool {
1020+
self.skip_binder().c_variadic
10211021
}
10221022
pub fn unsafety(&self) -> hir::Unsafety {
10231023
self.skip_binder().unsafety

0 commit comments

Comments
 (0)