Skip to content

Commit 0d41d0f

Browse files
committed
Move allow_c_varadic logic to ast_validation.
1 parent b499a88 commit 0d41d0f

12 files changed

+119
-63
lines changed

src/librustc_parse/parser/item.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,8 +1727,6 @@ impl<'a> Parser<'a> {
17271727
pub(super) struct ParamCfg {
17281728
/// Is `self` is allowed as the first parameter?
17291729
pub is_self_allowed: bool,
1730-
/// Is `...` allowed as the tail of the parameter list?
1731-
pub allow_c_variadic: bool,
17321730
/// `is_name_required` decides if, per-parameter,
17331731
/// the parameter must have a pattern or just a type.
17341732
pub is_name_required: fn(&token::Token) -> bool,
@@ -1744,16 +1742,8 @@ impl<'a> Parser<'a> {
17441742
attrs: Vec<Attribute>,
17451743
header: FnHeader,
17461744
) -> PResult<'a, Option<P<Item>>> {
1747-
let is_c_abi = match header.ext {
1748-
ast::Extern::None => false,
1749-
ast::Extern::Implicit => true,
1750-
ast::Extern::Explicit(abi) => abi.symbol_unescaped == sym::C,
1751-
};
17521745
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
17531746
is_self_allowed: false,
1754-
// FIXME: Parsing should not depend on ABI or unsafety and
1755-
// the variadic parameter should always be parsed.
1756-
allow_c_variadic: is_c_abi && header.unsafety == Unsafety::Unsafe,
17571747
is_name_required: |_| true,
17581748
})?;
17591749
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -1772,7 +1762,6 @@ impl<'a> Parser<'a> {
17721762
self.expect_keyword(kw::Fn)?;
17731763
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
17741764
is_self_allowed: false,
1775-
allow_c_variadic: true,
17761765
is_name_required: |_| true,
17771766
})?;
17781767
let span = lo.to(self.token.span);
@@ -1797,7 +1786,6 @@ impl<'a> Parser<'a> {
17971786
let header = self.parse_fn_front_matter()?;
17981787
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
17991788
is_self_allowed: true,
1800-
allow_c_variadic: false,
18011789
is_name_required,
18021790
})?;
18031791
let sig = FnSig { header, decl };
@@ -1993,12 +1981,12 @@ impl<'a> Parser<'a> {
19931981
}
19941982

19951983
self.eat_incorrect_doc_comment_for_param_type();
1996-
(pat, self.parse_ty_for_param(cfg.allow_c_variadic)?)
1984+
(pat, self.parse_ty_for_param()?)
19971985
} else {
19981986
debug!("parse_param_general ident_to_pat");
19991987
let parser_snapshot_before_ty = self.clone();
20001988
self.eat_incorrect_doc_comment_for_param_type();
2001-
let mut ty = self.parse_ty_for_param(cfg.allow_c_variadic);
1989+
let mut ty = self.parse_ty_for_param();
20021990
if ty.is_ok() && self.token != token::Comma &&
20031991
self.token != token::CloseDelim(token::Paren) {
20041992
// This wasn't actually a type, but a pattern looking like a type,

src/librustc_parse/parser/ty.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ impl<'a> Parser<'a> {
3333
/// Parse a type suitable for a function or function pointer parameter.
3434
/// The difference from `parse_ty` is that this version allows `...`
3535
/// (`CVarArgs`) at the top level of the the type.
36-
pub(super) fn parse_ty_for_param(&mut self, allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
37-
self.parse_ty_common(true, true, allow_c_variadic)
36+
pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
37+
self.parse_ty_common(true, true, true)
3838
}
3939

4040
/// Parses a type in restricted contexts where `+` is not permitted.
@@ -306,7 +306,6 @@ impl<'a> Parser<'a> {
306306
self.expect_keyword(kw::Fn)?;
307307
let cfg = ParamCfg {
308308
is_self_allowed: false,
309-
allow_c_variadic: true,
310309
is_name_required: |_| false,
311310
};
312311
let decl = self.parse_fn_decl(cfg, false)?;

src/librustc_passes/ast_validation.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,19 @@ impl<'a> AstValidator<'a> {
306306
.struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
307307
.emit();
308308
}
309+
310+
fn check_c_varadic_type(&self, decl: &FnDecl) {
311+
for Param { ty, span, .. } in &decl.inputs {
312+
if let TyKind::CVarArgs = ty.kind {
313+
self.err_handler()
314+
.struct_span_err(
315+
*span,
316+
"only foreign or `unsafe extern \"C\" functions may be C-variadic",
317+
)
318+
.emit();
319+
}
320+
}
321+
}
309322
}
310323

311324
enum GenericPosition {
@@ -554,6 +567,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
554567
}
555568
}
556569
}
570+
// Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
571+
match sig.header.ext {
572+
Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) |
573+
Extern::Implicit if sig.header.unsafety == Unsafety::Unsafe => {}
574+
_ => self.check_c_varadic_type(&sig.decl),
575+
}
557576
}
558577
ItemKind::ForeignMod(..) => {
559578
self.invalid_visibility(
@@ -795,6 +814,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
795814
self.check_defaultness(ti.span, ti.defaultness);
796815
visit::walk_trait_item(self, ti);
797816
}
817+
818+
fn visit_assoc_item(&mut self, item: &'a AssocItem) {
819+
if let AssocItemKind::Method(sig, _) = &item.kind {
820+
self.check_c_varadic_type(&sig.decl);
821+
}
822+
visit::walk_assoc_item(self, item);
823+
}
798824
}
799825

800826
pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {

src/test/ui/invalid/invalid-variadic-function.rs

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/test/ui/invalid/invalid-variadic-function.stderr

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/test/ui/parser/variadic-ffi-3.rs

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/test/ui/parser/variadic-ffi-3.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/test/ui/parser/variadic-ffi-4.rs

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/test/ui/parser/variadic-ffi-4.stderr

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![feature(c_variadic)]
2+
3+
fn main() {}
4+
5+
fn f1(x: isize, ...) {}
6+
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
7+
8+
extern "C" fn f2(x: isize, ...) {}
9+
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
10+
11+
extern fn f3(x: isize, ...) {}
12+
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
13+
14+
struct X;
15+
16+
impl X {
17+
fn f4(x: isize, ...) {}
18+
//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
19+
}
20+
21+
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
26+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
error: only foreign or `unsafe extern "C" functions may be C-variadic
2+
--> $DIR/variadic-ffi-semantic-restrictions.rs:5:17
3+
|
4+
LL | fn f1(x: isize, ...) {}
5+
| ^^^^
6+
7+
error: only foreign or `unsafe extern "C" functions may be C-variadic
8+
--> $DIR/variadic-ffi-semantic-restrictions.rs:8:28
9+
|
10+
LL | extern "C" fn f2(x: isize, ...) {}
11+
| ^^^^
12+
13+
error: only foreign or `unsafe extern "C" functions may be C-variadic
14+
--> $DIR/variadic-ffi-semantic-restrictions.rs:11:24
15+
|
16+
LL | extern fn f3(x: isize, ...) {}
17+
| ^^^^
18+
19+
error: only foreign or `unsafe extern "C" functions may be C-variadic
20+
--> $DIR/variadic-ffi-semantic-restrictions.rs:17:21
21+
|
22+
LL | fn f4(x: isize, ...) {}
23+
| ^^^^
24+
25+
error: only foreign or `unsafe extern "C" functions may be C-variadic
26+
--> $DIR/variadic-ffi-semantic-restrictions.rs:22:21
27+
|
28+
LL | fn f5(x: isize, ...) {}
29+
| ^^^^
30+
31+
error: only foreign or `unsafe extern "C" functions may be C-variadic
32+
--> $DIR/variadic-ffi-semantic-restrictions.rs:24:21
33+
|
34+
LL | fn f6(x: isize, ...);
35+
| ^^^^
36+
37+
error: aborting due to 6 previous errors
38+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// check-pass
2+
3+
fn main() {}
4+
5+
#[cfg(FALSE)]
6+
fn f1(x: isize, ...) {}
7+
8+
#[cfg(FALSE)]
9+
extern "C" fn f2(x: isize, ...) {}
10+
11+
#[cfg(FALSE)]
12+
extern fn f3(x: isize, ...) {}
13+
14+
struct X;
15+
16+
#[cfg(FALSE)]
17+
impl X {
18+
fn f4(x: isize, ...) {}
19+
}
20+
21+
#[cfg(FALSE)]
22+
trait T {
23+
fn f5(x: isize, ...) {}
24+
fn f6(x: isize, ...);
25+
}

0 commit comments

Comments
 (0)