Skip to content

Commit 35e9e09

Browse files
committed
More c-variadic errors as semantic restrictions.
1 parent 3a57a2c commit 35e9e09

File tree

7 files changed

+322
-86
lines changed

7 files changed

+322
-86
lines changed

src/librustc/hir/lowering.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,13 @@ impl<'a> LoweringContext<'a> {
14261426
}
14271427
}
14281428
TyKind::Mac(_) => bug!("`TyKind::Mac` should have been expanded by now"),
1429-
TyKind::CVarArgs => bug!("`TyKind::CVarArgs` should have been handled elsewhere"),
1429+
TyKind::CVarArgs => {
1430+
self.sess.delay_span_bug(
1431+
t.span,
1432+
"`TyKind::CVarArgs` should have been handled elsewhere",
1433+
);
1434+
hir::TyKind::Err
1435+
}
14301436
};
14311437

14321438
hir::Ty {

src/librustc_parse/parser/item.rs

+10-45
Original file line numberDiff line numberDiff line change
@@ -1885,58 +1885,23 @@ impl<'a> Parser<'a> {
18851885

18861886
/// Parses the parameter list of a function, including the `(` and `)` delimiters.
18871887
fn parse_fn_params(&mut self, mut cfg: ParamCfg) -> PResult<'a, Vec<Param>> {
1888-
let sp = self.token.span;
18891888
let is_trait_item = cfg.is_self_allowed;
1890-
let mut c_variadic = false;
18911889
// Parse the arguments, starting out with `self` being possibly allowed...
1892-
let (params, _) = self.parse_paren_comma_seq(|p| {
1893-
let param = p.parse_param_general(&cfg, is_trait_item);
1890+
let (mut params, _) = self.parse_paren_comma_seq(|p| {
1891+
let param = p.parse_param_general(&cfg, is_trait_item).or_else(|mut e| {
1892+
e.emit();
1893+
let lo = p.prev_span;
1894+
// Skip every token until next possible arg or end.
1895+
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
1896+
// Create a placeholder argument for proper arg count (issue #34264).
1897+
Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_span))))
1898+
});
18941899
// ...now that we've parsed the first argument, `self` is no longer allowed.
18951900
cfg.is_self_allowed = false;
1896-
1897-
match param {
1898-
Ok(param) => Ok(
1899-
if let TyKind::CVarArgs = param.ty.kind {
1900-
c_variadic = true;
1901-
if p.token != token::CloseDelim(token::Paren) {
1902-
p.span_err(
1903-
p.token.span,
1904-
"`...` must be the last argument of a C-variadic function",
1905-
);
1906-
// FIXME(eddyb) this should probably still push `CVarArgs`.
1907-
// Maybe AST validation/HIR lowering should emit the above error?
1908-
None
1909-
} else {
1910-
Some(param)
1911-
}
1912-
} else {
1913-
Some(param)
1914-
}
1915-
),
1916-
Err(mut e) => {
1917-
e.emit();
1918-
let lo = p.prev_span;
1919-
// Skip every token until next possible arg or end.
1920-
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
1921-
// Create a placeholder argument for proper arg count (issue #34264).
1922-
let span = lo.to(p.prev_span);
1923-
Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
1924-
}
1925-
}
1901+
param
19261902
})?;
1927-
1928-
let mut params: Vec<_> = params.into_iter().filter_map(|x| x).collect();
1929-
19301903
// Replace duplicated recovered params with `_` pattern to avoid unnecessary errors.
19311904
self.deduplicate_recovered_params_names(&mut params);
1932-
1933-
if c_variadic && params.len() <= 1 {
1934-
self.span_err(
1935-
sp,
1936-
"C-variadic function must be declared with at least one named argument",
1937-
);
1938-
}
1939-
19401905
Ok(params)
19411906
}
19421907

src/librustc_passes/ast_validation.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,26 @@ impl<'a> AstValidator<'a> {
250250
}
251251

252252
fn check_fn_decl(&self, fn_decl: &FnDecl) {
253+
match &*fn_decl.inputs {
254+
[Param { ty, span, .. }] => if let TyKind::CVarArgs = ty.kind {
255+
self.err_handler()
256+
.span_err(
257+
*span,
258+
"C-variadic function must be declared with at least one named argument",
259+
);
260+
},
261+
[ps @ .., _] => for Param { ty, span, .. } in ps {
262+
if let TyKind::CVarArgs = ty.kind {
263+
self.err_handler()
264+
.span_err(
265+
*span,
266+
"`...` must be the last argument of a C-variadic function",
267+
);
268+
}
269+
}
270+
_ => {}
271+
}
272+
253273
fn_decl
254274
.inputs
255275
.iter()
@@ -265,8 +285,7 @@ impl<'a> AstValidator<'a> {
265285
)
266286
.span_label(attr.span, "doc comments are not allowed here")
267287
.emit();
268-
}
269-
else {
288+
} else {
270289
self.err_handler().span_err(attr.span, "allow, cfg, cfg_attr, deny, \
271290
forbid, and warn are the only allowed built-in attributes in function parameters")
272291
});
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error: C-variadic function must be declared with at least one named argument
2-
--> $DIR/variadic-ffi-no-fixed-args.rs:2:11
2+
--> $DIR/variadic-ffi-no-fixed-args.rs:2:12
33
|
44
LL | fn foo(...);
5-
| ^
5+
| ^^^^
66

77
error: aborting due to previous error
88

src/test/ui/parser/variadic-ffi-semantic-restrictions.rs

+62-12
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,75 @@
22

33
fn main() {}
44

5-
fn f1(x: isize, ...) {}
6-
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
5+
fn f1_1(x: isize, ...) {}
6+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
77

8-
extern "C" fn f2(x: isize, ...) {}
9-
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
8+
fn f1_2(...) {}
9+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
10+
//~| ERROR C-variadic function must be declared with at least one named argument
1011

11-
extern fn f3(x: isize, ...) {}
12-
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
12+
extern "C" fn f2_1(x: isize, ...) {}
13+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
14+
15+
extern "C" fn f2_2(...) {}
16+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
17+
//~| ERROR C-variadic function must be declared with at least one named argument
18+
19+
extern "C" fn f2_3(..., x: isize) {}
20+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
21+
//~| ERROR `...` must be the last argument of a C-variadic function
22+
23+
extern fn f3_1(x: isize, ...) {}
24+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
25+
26+
extern fn f3_2(...) {}
27+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
28+
//~| ERROR C-variadic function must be declared with at least one named argument
29+
30+
extern fn f3_3(..., x: isize) {}
31+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
32+
//~| ERROR `...` must be the last argument of a C-variadic function
33+
34+
extern {
35+
fn e_f1(...);
36+
//~^ ERROR C-variadic function must be declared with at least one named argument
37+
fn e_f2(..., x: isize);
38+
//~^ ERROR `...` must be the last argument of a C-variadic function
39+
}
1340

1441
struct X;
1542

1643
impl X {
17-
fn f4(x: isize, ...) {}
18-
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
44+
fn i_f1(x: isize, ...) {}
45+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
46+
fn i_f2(...) {}
47+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
48+
//~| ERROR C-variadic function must be declared with at least one named argument
49+
fn i_f3(..., x: isize, ...) {}
50+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
51+
//~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
52+
//~| ERROR `...` must be the last argument of a C-variadic function
53+
fn i_f4(..., x: isize, ...) {}
54+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
55+
//~| ERROR only foreign or `unsafe extern "C" functions may be C-variadic
56+
//~| ERROR `...` must be the last argument of a C-variadic function
1957
}
2058

2159
trait T {
22-
fn f5(x: isize, ...) {}
23-
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
24-
fn f6(x: isize, ...);
25-
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
60+
fn t_f1(x: isize, ...) {}
61+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
62+
fn t_f2(x: isize, ...);
63+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
64+
fn t_f3(...) {}
65+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
66+
//~| ERROR C-variadic function must be declared with at least one named argument
67+
fn t_f4(...);
68+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
69+
//~| ERROR C-variadic function must be declared with at least one named argument
70+
fn t_f5(..., x: isize) {}
71+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
72+
//~| ERROR `...` must be the last argument of a C-variadic function
73+
fn t_f6(..., x: isize);
74+
//~^ ERROR only foreign or `unsafe extern "C" functions may be C-variadic
75+
//~| ERROR `...` must be the last argument of a C-variadic function
2676
}

0 commit comments

Comments
 (0)