Auto merge of #35015 - petrochenkov:forearg, r=nikomatsakis
Properly enforce the "patterns aren't allowed in foreign functions" rule
Cases like `arg @ PATTERN` or `mut arg` were missing.
Apply the same rule to function pointer types.
Closes https://github.com/rust-lang/rust/issues/35203
[breaking-change], no breakage in sane code is expected though
r? @nikomatsakis
This is somewhat related to https://github.com/rust-lang/rfcs/pull/1685 (cc @matklad).
The goal is to eventually support full pattern syntax where it makes sense (function body may present) and to support *only* the following forms - `TYPE`, `ident: TYPE`, `_: TYPE` - where patterns don't make sense (function body doesn't present), i.e. in foreign functions and function pointer types.
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index a90b563..d2cf48e 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -55,6 +55,17 @@
err.emit();
}
}
+
+ fn check_decl_no_pat<ReportFn: Fn(Span, bool)>(&self, decl: &FnDecl, report_err: ReportFn) {
+ for arg in &decl.inputs {
+ match arg.pat.node {
+ PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), _, None) |
+ PatKind::Wild => {}
+ PatKind::Ident(..) => report_err(arg.pat.span, true),
+ _ => report_err(arg.pat.span, false),
+ }
+ }
+ }
}
impl<'a> Visitor for AstValidator<'a> {
@@ -82,6 +93,23 @@
visit::walk_expr(self, expr)
}
+ fn visit_ty(&mut self, ty: &Ty) {
+ match ty.node {
+ TyKind::BareFn(ref bfty) => {
+ self.check_decl_no_pat(&bfty.decl, |span, _| {
+ let mut err = struct_span_err!(self.session, span, E0561,
+ "patterns aren't allowed in function pointer types");
+ err.span_note(span, "this is a recent error, see \
+ issue #35203 for more details");
+ err.emit();
+ });
+ }
+ _ => {}
+ }
+
+ visit::walk_ty(self, ty)
+ }
+
fn visit_path(&mut self, path: &Path, id: NodeId) {
if path.global && path.segments.len() > 0 {
let ident = path.segments[0].identifier;
@@ -135,6 +163,25 @@
visit::walk_item(self, item)
}
+ fn visit_foreign_item(&mut self, fi: &ForeignItem) {
+ match fi.node {
+ ForeignItemKind::Fn(ref decl, _) => {
+ self.check_decl_no_pat(decl, |span, is_recent| {
+ let mut err = struct_span_err!(self.session, span, E0130,
+ "patterns aren't allowed in foreign function declarations");
+ if is_recent {
+ err.span_note(span, "this is a recent error, see \
+ issue #35203 for more details");
+ }
+ err.emit();
+ });
+ }
+ ForeignItemKind::Static(..) => {}
+ }
+
+ visit::walk_foreign_item(self, fi)
+ }
+
fn visit_variant_data(&mut self, vdata: &VariantData, _: Ident,
_: &Generics, _: NodeId, span: Span) {
if vdata.fields().is_empty() {
diff --git a/src/librustc_passes/diagnostics.rs b/src/librustc_passes/diagnostics.rs
index a616b95..3e2dd47 100644
--- a/src/librustc_passes/diagnostics.rs
+++ b/src/librustc_passes/diagnostics.rs
@@ -49,6 +49,39 @@
```
"##,
+E0130: r##"
+You declared a pattern as an argument in a foreign function declaration.
+Erroneous code example:
+
+```compile_fail
+extern {
+ fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign
+ // function declarations
+}
+```
+
+Please replace the pattern argument with a regular one. Example:
+
+```
+struct SomeStruct {
+ a: u32,
+ b: u32,
+}
+
+extern {
+ fn foo(s: SomeStruct); // ok!
+}
+```
+
+Or:
+
+```
+extern {
+ fn foo(a: (u32, u32)); // ok!
+}
+```
+"##,
+
E0161: r##"
A value was moved. However, its size was not known at compile time, and only
values of a known size can be moved.
@@ -187,4 +220,5 @@
register_diagnostics! {
E0472, // asm! is unsupported on this target
+ E0561, // patterns aren't allowed in function pointer types
}
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index ec95afe..4486748 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -60,8 +60,6 @@
use astconv::{AstConv, ast_region_to_region, Bounds, PartitionedBounds, partition_bounds};
use lint;
-use hir::def::Def;
-use hir::def_id::DefId;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
use middle::const_val::ConstVal;
@@ -74,7 +72,6 @@
use rustc::ty::util::IntTypeExt;
use rscope::*;
use rustc::dep_graph::DepNode;
-use rustc::hir::map as hir_map;
use util::common::{ErrorReported, MemoizationMap};
use util::nodemap::{NodeMap, FnvHashMap};
use {CrateCtxt, write_ty_to_tcx};
@@ -91,9 +88,9 @@
use syntax::ptr::P;
use syntax_pos::Span;
-use rustc::hir::{self, PatKind};
-use rustc::hir::intravisit;
-use rustc::hir::print as pprust;
+use rustc::hir::{self, intravisit, map as hir_map, print as pprust};
+use rustc::hir::def::Def;
+use rustc::hir::def_id::DefId;
///////////////////////////////////////////////////////////////////////////
// Main entry point
@@ -2144,14 +2141,6 @@
abi: abi::Abi)
-> ty::TypeScheme<'tcx>
{
- for i in &decl.inputs {
- match i.pat.node {
- PatKind::Binding(..) | PatKind::Wild => {}
- _ => span_err!(ccx.tcx.sess, i.pat.span, E0130,
- "patterns aren't allowed in foreign function declarations")
- }
- }
-
let ty_generics = ty_generics_for_fn(ccx, ast_generics, &ty::Generics::empty());
let rb = BindingRscope::new();
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index cd2259a..b655d95 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1800,39 +1800,6 @@
parameter if so.
"##,
-E0130: r##"
-You declared a pattern as an argument in a foreign function declaration.
-Erroneous code example:
-
-```compile_fail
-extern {
- fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign
- // function declarations
-}
-```
-
-Please replace the pattern argument with a regular one. Example:
-
-```
-struct SomeStruct {
- a: u32,
- b: u32,
-}
-
-extern {
- fn foo(s: SomeStruct); // ok!
-}
-```
-
-Or:
-
-```
-extern {
- fn foo(a: (u32, u32)); // ok!
-}
-```
-"##,
-
E0131: r##"
It is not possible to define `main` with type parameters, or even with function
parameters. When `main` is present, it must take no arguments and return `()`.
diff --git a/src/test/compile-fail/no-patterns-in-args.rs b/src/test/compile-fail/no-patterns-in-args.rs
new file mode 100644
index 0000000..3edbdf4
--- /dev/null
+++ b/src/test/compile-fail/no-patterns-in-args.rs
@@ -0,0 +1,30 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern {
+ fn f1(mut arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations
+ //~^ NOTE this is a recent error
+ fn f2(&arg: u8); //~ ERROR patterns aren't allowed in foreign function declarations
+ fn f3(arg @ _: u8); //~ ERROR patterns aren't allowed in foreign function declarations
+ //~^ NOTE this is a recent error
+ fn g1(arg: u8); // OK
+ fn g2(_: u8); // OK
+ // fn g3(u8); // Not yet
+}
+
+type A1 = fn(mut arg: u8); //~ ERROR patterns aren't allowed in function pointer types
+ //~^ NOTE this is a recent error
+type A2 = fn(&arg: u8); //~ ERROR patterns aren't allowed in function pointer types
+ //~^ NOTE this is a recent error
+type B1 = fn(arg: u8); // OK
+type B2 = fn(_: u8); // OK
+type B3 = fn(u8); // OK
+
+fn main() {}