pub(super) struct ParamCfg {
/// Is `self` is allowed as the first parameter?
pub is_self_allowed: bool,
- /// Is `...` allowed as the tail of the parameter list?
- pub allow_c_variadic: bool,
/// `is_name_required` decides if, per-parameter,
/// the parameter must have a pattern or just a type.
pub is_name_required: fn(&token::Token) -> bool,
attrs: Vec<Attribute>,
header: FnHeader,
) -> PResult<'a, Option<P<Item>>> {
- let is_c_abi = match header.ext {
- ast::Extern::None => false,
- ast::Extern::Implicit => true,
- ast::Extern::Explicit(abi) => abi.symbol_unescaped == sym::C,
- };
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
is_self_allowed: false,
- // FIXME: Parsing should not depend on ABI or unsafety and
- // the variadic parameter should always be parsed.
- allow_c_variadic: is_c_abi && header.unsafety == Unsafety::Unsafe,
is_name_required: |_| true,
})?;
let (inner_attrs, body) = self.parse_inner_attrs_and_block()?;
self.expect_keyword(kw::Fn)?;
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
is_self_allowed: false,
- allow_c_variadic: true,
is_name_required: |_| true,
})?;
let span = lo.to(self.token.span);
let header = self.parse_fn_front_matter()?;
let (ident, decl, generics) = self.parse_fn_sig(ParamCfg {
is_self_allowed: true,
- allow_c_variadic: false,
is_name_required,
})?;
let sig = FnSig { header, decl };
}
self.eat_incorrect_doc_comment_for_param_type();
- (pat, self.parse_ty_for_param(cfg.allow_c_variadic)?)
+ (pat, self.parse_ty_for_param()?)
} else {
debug!("parse_param_general ident_to_pat");
let parser_snapshot_before_ty = self.clone();
self.eat_incorrect_doc_comment_for_param_type();
- let mut ty = self.parse_ty_for_param(cfg.allow_c_variadic);
+ let mut ty = self.parse_ty_for_param();
if ty.is_ok() && self.token != token::Comma &&
self.token != token::CloseDelim(token::Paren) {
// This wasn't actually a type, but a pattern looking like a type,
/// Parse a type suitable for a function or function pointer parameter.
/// The difference from `parse_ty` is that this version allows `...`
/// (`CVarArgs`) at the top level of the the type.
- pub(super) fn parse_ty_for_param(&mut self, allow_c_variadic: bool) -> PResult<'a, P<Ty>> {
- self.parse_ty_common(true, true, allow_c_variadic)
+ pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
+ self.parse_ty_common(true, true, true)
}
/// Parses a type in restricted contexts where `+` is not permitted.
self.expect_keyword(kw::Fn)?;
let cfg = ParamCfg {
is_self_allowed: false,
- allow_c_variadic: true,
is_name_required: |_| false,
};
let decl = self.parse_fn_decl(cfg, false)?;
.struct_span_err(span, "bounds on associated `type`s in `impl`s have no effect")
.emit();
}
+
+ fn check_c_varadic_type(&self, decl: &FnDecl) {
+ for Param { ty, span, .. } in &decl.inputs {
+ if let TyKind::CVarArgs = ty.kind {
+ self.err_handler()
+ .struct_span_err(
+ *span,
+ "only foreign or `unsafe extern \"C\" functions may be C-variadic",
+ )
+ .emit();
+ }
+ }
+ }
}
enum GenericPosition {
}
}
}
+ // Reject C-varadic type unless the function is `unsafe extern "C"` semantically.
+ match sig.header.ext {
+ Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) |
+ Extern::Implicit if sig.header.unsafety == Unsafety::Unsafe => {}
+ _ => self.check_c_varadic_type(&sig.decl),
+ }
}
ItemKind::ForeignMod(..) => {
self.invalid_visibility(
self.check_defaultness(ti.span, ti.defaultness);
visit::walk_trait_item(self, ti);
}
+
+ fn visit_assoc_item(&mut self, item: &'a AssocItem) {
+ if let AssocItemKind::Method(sig, _) = &item.kind {
+ self.check_c_varadic_type(&sig.decl);
+ }
+ visit::walk_assoc_item(self, item);
+ }
}
pub fn check_crate(session: &Session, krate: &Crate, lints: &mut lint::LintBuffer) -> bool {
+++ /dev/null
-extern "C" fn foo(x: u8, ...);
-//~^ ERROR only foreign functions are allowed to be C-variadic
-//~| ERROR expected one of `->`, `where`, or `{`, found `;`
+++ /dev/null
-error[E0743]: only foreign functions are allowed to be C-variadic
- --> $DIR/invalid-variadic-function.rs:1:26
- |
-LL | extern "C" fn foo(x: u8, ...);
- | ^^^
-
-error: expected one of `->`, `where`, or `{`, found `;`
- --> $DIR/invalid-variadic-function.rs:1:30
- |
-LL | extern "C" fn foo(x: u8, ...);
- | ^ expected one of `->`, `where`, or `{`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0743`.
+++ /dev/null
-fn foo(x: isize, ...) {
- //~^ ERROR: only foreign functions are allowed to be C-variadic
-}
-
-fn main() {}
+++ /dev/null
-error[E0743]: only foreign functions are allowed to be C-variadic
- --> $DIR/variadic-ffi-3.rs:1:18
- |
-LL | fn foo(x: isize, ...) {
- | ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0743`.
+++ /dev/null
-extern "C" fn foo(x: isize, ...) {
- //~^ ERROR: only foreign functions are allowed to be C-variadic
-}
-
-fn main() {}
+++ /dev/null
-error[E0743]: only foreign functions are allowed to be C-variadic
- --> $DIR/variadic-ffi-4.rs:1:29
- |
-LL | extern "C" fn foo(x: isize, ...) {
- | ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0743`.
--- /dev/null
+#![feature(c_variadic)]
+
+fn main() {}
+
+fn f1(x: isize, ...) {}
+//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
+
+extern "C" fn f2(x: isize, ...) {}
+//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
+
+extern fn f3(x: isize, ...) {}
+//~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
+
+struct X;
+
+impl X {
+ fn f4(x: isize, ...) {}
+ //~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
+}
+
+trait T {
+ fn f5(x: isize, ...) {}
+ //~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
+ fn f6(x: isize, ...);
+ //~^ ERROR: only foreign or `unsafe extern "C" functions may be C-variadic
+}
--- /dev/null
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+ --> $DIR/variadic-ffi-semantic-restrictions.rs:5:17
+ |
+LL | fn f1(x: isize, ...) {}
+ | ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+ --> $DIR/variadic-ffi-semantic-restrictions.rs:8:28
+ |
+LL | extern "C" fn f2(x: isize, ...) {}
+ | ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+ --> $DIR/variadic-ffi-semantic-restrictions.rs:11:24
+ |
+LL | extern fn f3(x: isize, ...) {}
+ | ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+ --> $DIR/variadic-ffi-semantic-restrictions.rs:17:21
+ |
+LL | fn f4(x: isize, ...) {}
+ | ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+ --> $DIR/variadic-ffi-semantic-restrictions.rs:22:21
+ |
+LL | fn f5(x: isize, ...) {}
+ | ^^^^
+
+error: only foreign or `unsafe extern "C" functions may be C-variadic
+ --> $DIR/variadic-ffi-semantic-restrictions.rs:24:21
+ |
+LL | fn f6(x: isize, ...);
+ | ^^^^
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn f1(x: isize, ...) {}
+
+#[cfg(FALSE)]
+extern "C" fn f2(x: isize, ...) {}
+
+#[cfg(FALSE)]
+extern fn f3(x: isize, ...) {}
+
+struct X;
+
+#[cfg(FALSE)]
+impl X {
+ fn f4(x: isize, ...) {}
+}
+
+#[cfg(FALSE)]
+trait T {
+ fn f5(x: isize, ...) {}
+ fn f6(x: isize, ...);
+}