mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-08 13:02:50 +00:00
Auto merge of #34904 - petrochenkov:rustcall, r=nikomatsakis
Properly feature gate all unstable ABIs Fixes https://github.com/rust-lang/rust/issues/34900 [breaking-change] r? @pnkfelix --- Function-visiting machinery for AST/HIR is surprisingly error-prone, it's *very* easy to miss some cases or visit something twice while writing a visitor. This is the true problem behind https://github.com/rust-lang/rust/issues/34900. I'll try to restructure these visitors a bit and send one more PR later.
This commit is contained in:
commit
1225e122fd
@ -223,6 +223,7 @@ trait system to overload operators. Calling functions is no different. We have
|
|||||||
three separate traits to overload with:
|
three separate traits to overload with:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
# #![feature(unboxed_closures)]
|
||||||
# mod foo {
|
# mod foo {
|
||||||
pub trait Fn<Args> : FnMut<Args> {
|
pub trait Fn<Args> : FnMut<Args> {
|
||||||
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
||||||
|
@ -810,6 +810,29 @@ macro_rules! gate_feature_post {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> PostExpansionVisitor<'a> {
|
||||||
|
fn check_abi(&self, abi: Abi, span: Span) {
|
||||||
|
match abi {
|
||||||
|
Abi::RustIntrinsic =>
|
||||||
|
gate_feature_post!(&self, intrinsics, span,
|
||||||
|
"intrinsics are subject to change"),
|
||||||
|
Abi::PlatformIntrinsic => {
|
||||||
|
gate_feature_post!(&self, platform_intrinsics, span,
|
||||||
|
"platform intrinsics are experimental and possibly buggy")
|
||||||
|
},
|
||||||
|
Abi::Vectorcall => {
|
||||||
|
gate_feature_post!(&self, abi_vectorcall, span,
|
||||||
|
"vectorcall is experimental and subject to change")
|
||||||
|
}
|
||||||
|
Abi::RustCall => {
|
||||||
|
gate_feature_post!(&self, unboxed_closures, span,
|
||||||
|
"rust-call ABI is subject to change");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Visitor for PostExpansionVisitor<'a> {
|
impl<'a> Visitor for PostExpansionVisitor<'a> {
|
||||||
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
||||||
if !self.context.cm.span_allows_unstable(attr.span) {
|
if !self.context.cm.span_allows_unstable(attr.span) {
|
||||||
@ -841,21 +864,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
|
|||||||
across platforms, it is recommended to \
|
across platforms, it is recommended to \
|
||||||
use `#[link(name = \"foo\")]` instead")
|
use `#[link(name = \"foo\")]` instead")
|
||||||
}
|
}
|
||||||
match foreign_module.abi {
|
self.check_abi(foreign_module.abi, i.span);
|
||||||
Abi::RustIntrinsic =>
|
|
||||||
gate_feature_post!(&self, intrinsics, i.span,
|
|
||||||
"intrinsics are subject to change"),
|
|
||||||
Abi::PlatformIntrinsic => {
|
|
||||||
gate_feature_post!(&self, platform_intrinsics, i.span,
|
|
||||||
"platform intrinsics are experimental \
|
|
||||||
and possibly buggy")
|
|
||||||
},
|
|
||||||
Abi::Vectorcall => {
|
|
||||||
gate_feature_post!(&self, abi_vectorcall, i.span,
|
|
||||||
"vectorcall is experimental and subject to change")
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::ItemKind::Fn(..) => {
|
ast::ItemKind::Fn(..) => {
|
||||||
@ -938,6 +947,16 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
|
|||||||
visit::walk_foreign_item(self, i)
|
visit::walk_foreign_item(self, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, ty: &ast::Ty) {
|
||||||
|
match ty.node {
|
||||||
|
ast::TyKind::BareFn(ref bare_fn_ty) => {
|
||||||
|
self.check_abi(bare_fn_ty.abi, ty.span);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
visit::walk_ty(self, ty)
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||||
match e.node {
|
match e.node {
|
||||||
ast::ExprKind::Box(_) => {
|
ast::ExprKind::Box(_) => {
|
||||||
@ -1025,23 +1044,10 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match fn_kind {
|
match fn_kind {
|
||||||
FnKind::ItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
|
|
||||||
gate_feature_post!(&self, intrinsics,
|
|
||||||
span,
|
|
||||||
"intrinsics are subject to change")
|
|
||||||
}
|
|
||||||
FnKind::ItemFn(_, _, _, _, abi, _) |
|
FnKind::ItemFn(_, _, _, _, abi, _) |
|
||||||
FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => match abi {
|
FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => {
|
||||||
Abi::RustCall => {
|
self.check_abi(abi, span);
|
||||||
gate_feature_post!(&self, unboxed_closures, span,
|
}
|
||||||
"rust-call ABI is subject to change");
|
|
||||||
},
|
|
||||||
Abi::Vectorcall => {
|
|
||||||
gate_feature_post!(&self, abi_vectorcall, span,
|
|
||||||
"vectorcall is experimental and subject to change");
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
visit::walk_fn(self, fn_kind, fn_decl, block, span);
|
visit::walk_fn(self, fn_kind, fn_decl, block, span);
|
||||||
@ -1054,7 +1060,10 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
|
|||||||
ti.span,
|
ti.span,
|
||||||
"associated constants are experimental")
|
"associated constants are experimental")
|
||||||
}
|
}
|
||||||
ast::TraitItemKind::Method(ref sig, _) => {
|
ast::TraitItemKind::Method(ref sig, ref block) => {
|
||||||
|
if block.is_none() {
|
||||||
|
self.check_abi(sig.abi, ti.span);
|
||||||
|
}
|
||||||
if sig.constness == ast::Constness::Const {
|
if sig.constness == ast::Constness::Const {
|
||||||
gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
|
gate_feature_post!(&self, const_fn, ti.span, "const fn is unstable");
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
extern "rust-call" { fn foo(x: u8, ...); } //~ ERROR E0045
|
extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
// 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 "vectorcall" { //~ ERROR vectorcall is experimental and subject to change
|
|
||||||
fn bar();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "vectorcall" fn baz() { //~ ERROR vectorcall is experimental and subject to change
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
}
|
|
60
src/test/compile-fail/feature-gate-abi.rs
Normal file
60
src/test/compile-fail/feature-gate-abi.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
|
||||||
|
extern "platform-intrinsic" fn f2() {} //~ ERROR platform intrinsics are experimental
|
||||||
|
extern "vectorcall" fn f3() {} //~ ERROR vectorcall is experimental and subject to change
|
||||||
|
extern "rust-call" fn f4() {} //~ ERROR rust-call ABI is subject to change
|
||||||
|
|
||||||
|
// Methods in trait definition
|
||||||
|
trait Tr {
|
||||||
|
extern "rust-intrinsic" fn m1(); //~ ERROR intrinsics are subject to change
|
||||||
|
extern "platform-intrinsic" fn m2(); //~ ERROR platform intrinsics are experimental
|
||||||
|
extern "vectorcall" fn m3(); //~ ERROR vectorcall is experimental and subject to change
|
||||||
|
extern "rust-call" fn m4(); //~ ERROR rust-call ABI is subject to change
|
||||||
|
|
||||||
|
extern "rust-intrinsic" fn dm1() {} //~ ERROR intrinsics are subject to change
|
||||||
|
extern "platform-intrinsic" fn dm2() {} //~ ERROR platform intrinsics are experimental
|
||||||
|
extern "vectorcall" fn dm3() {} //~ ERROR vectorcall is experimental and subject to change
|
||||||
|
extern "rust-call" fn dm4() {} //~ ERROR rust-call ABI is subject to change
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
// Methods in trait impl
|
||||||
|
impl Tr for S {
|
||||||
|
extern "rust-intrinsic" fn m1() {} //~ ERROR intrinsics are subject to change
|
||||||
|
extern "platform-intrinsic" fn m2() {} //~ ERROR platform intrinsics are experimental
|
||||||
|
extern "vectorcall" fn m3() {} //~ ERROR vectorcall is experimental and subject to change
|
||||||
|
extern "rust-call" fn m4() {} //~ ERROR rust-call ABI is subject to change
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods in inherent impl
|
||||||
|
impl S {
|
||||||
|
extern "rust-intrinsic" fn im1() {} //~ ERROR intrinsics are subject to change
|
||||||
|
extern "platform-intrinsic" fn im2() {} //~ ERROR platform intrinsics are experimental
|
||||||
|
extern "vectorcall" fn im3() {} //~ ERROR vectorcall is experimental and subject to change
|
||||||
|
extern "rust-call" fn im4() {} //~ ERROR rust-call ABI is subject to change
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function pointer types
|
||||||
|
type A1 = extern "rust-intrinsic" fn(); //~ ERROR intrinsics are subject to change
|
||||||
|
type A2 = extern "platform-intrinsic" fn(); //~ ERROR platform intrinsics are experimental
|
||||||
|
type A3 = extern "vectorcall" fn(); //~ ERROR vectorcall is experimental and subject to change
|
||||||
|
type A4 = extern "rust-call" fn(); //~ ERROR rust-call ABI is subject to change
|
||||||
|
|
||||||
|
// Foreign modules
|
||||||
|
extern "rust-intrinsic" {} //~ ERROR intrinsics are subject to change
|
||||||
|
extern "platform-intrinsic" {} //~ ERROR platform intrinsics are experimental
|
||||||
|
extern "vectorcall" {} //~ ERROR vectorcall is experimental and subject to change
|
||||||
|
extern "rust-call" {} //~ ERROR rust-call ABI is subject to change
|
||||||
|
|
||||||
|
fn main() {}
|
@ -1,21 +0,0 @@
|
|||||||
// Copyright 2014 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 "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change
|
|
||||||
|
|
||||||
trait Foo {
|
|
||||||
extern "rust-call" fn foo();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Foo for i32 {
|
|
||||||
extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() { }
|
|
Loading…
Reference in New Issue
Block a user