Auto merge of #27215 - pnkfelix:fsk-placer-take-5-just-in, r=nikomatsakis
Macro desugaring of `in PLACE { BLOCK }` into "simpler" expressions following the in-development "Placer" protocol.
Includes Placer API that one can override to integrate support for `in` into one's own type. (See [RFC 809].)
[RFC 809]: https://github.com/rust-lang/rfcs/blob/master/text/0809-box-and-in-for-stdlib.md
Part of #22181
Replaced PR #26180.
Turns on the `in PLACE { BLOCK }` syntax, while leaving in support for the old `box (PLACE) EXPR` syntax (since we need to support that at least until we have a snapshot with support for `in PLACE { BLOCK }`.
(Note that we are not 100% committed to the `in PLACE { BLOCK }` syntax. In particular I still want to play around with some other alternatives. Still, I want to get the fundamental framework for the protocol landed so we can play with implementing it for non `Box` types.)
----
Also, this PR leaves out support for desugaring-based `box EXPR`. We will hopefully land that in the future, but for the short term there are type-inference issues injected by that change that we want to resolve separately.
This commit is contained in:
commit
9413a926fc
28 changed files with 899 additions and 47 deletions
|
|
@ -8,15 +8,18 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
use std::boxed::HEAP;
|
||||
// Check that `box EXPR` is feature-gated.
|
||||
//
|
||||
// See also feature-gate-placement-expr.rs
|
||||
//
|
||||
// (Note that the two tests are separated since the checks appear to
|
||||
// be performed at distinct phases, with an abort_if_errors call
|
||||
// separating them.)
|
||||
|
||||
fn main() {
|
||||
let x = box 'c'; //~ ERROR box expression syntax is experimental
|
||||
println!("x: {}", x);
|
||||
|
||||
let x = box () 'c'; //~ ERROR box expression syntax is experimental
|
||||
println!("x: {}", x);
|
||||
|
||||
let x = box (HEAP) 'c'; //~ ERROR box expression syntax is experimental
|
||||
println!("x: {}", x);
|
||||
}
|
||||
|
|
|
|||
27
src/test/compile-fail/feature-gate-placement-expr.rs
Normal file
27
src/test/compile-fail/feature-gate-placement-expr.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// Check that `in PLACE { EXPR }` is feature-gated.
|
||||
//
|
||||
// See also feature-gate-box-expr.rs
|
||||
//
|
||||
// (Note that the two tests are separated since the checks appear to
|
||||
// be performed at distinct phases, with an abort_if_errors call
|
||||
// separating them.)
|
||||
|
||||
fn main() {
|
||||
use std::boxed::HEAP;
|
||||
|
||||
let x = box (HEAP) 'c'; //~ ERROR placement-in expression syntax is experimental
|
||||
println!("x: {}", x);
|
||||
|
||||
let x = in HEAP { 'c' }; //~ ERROR placement-in expression syntax is experimental
|
||||
println!("x: {}", x);
|
||||
}
|
||||
14
src/test/compile-fail/feature-gate-pushpop-unsafe.rs
Normal file
14
src/test/compile-fail/feature-gate-pushpop-unsafe.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
fn main() {
|
||||
let c = push_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
|
||||
let c = pop_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
|
||||
}
|
||||
|
|
@ -9,8 +9,10 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![feature(box_syntax)]
|
||||
#![feature(placement_in_syntax)]
|
||||
|
||||
fn main() {
|
||||
box ( () ) 0;
|
||||
//~^ ERROR: only the exchange heap is currently supported
|
||||
//~^ ERROR: the trait `core::ops::Placer<_>` is not implemented
|
||||
//~| ERROR: the trait `core::ops::Placer<_>` is not implemented
|
||||
}
|
||||
|
|
|
|||
74
src/test/compile-fail/pushpop-unsafe-rejects.rs
Normal file
74
src/test/compile-fail/pushpop-unsafe-rejects.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// Basic sanity check for `push_unsafe!(EXPR)` and
|
||||
// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
|
||||
// positive number of pushes in the stack, or if we are within a
|
||||
// normal `unsafe` block, but otherwise cannot.
|
||||
|
||||
#![feature(pushpop_unsafe)]
|
||||
|
||||
static mut X: i32 = 0;
|
||||
|
||||
unsafe fn f() { X += 1; return; }
|
||||
fn g() { unsafe { X += 1_000; } return; }
|
||||
|
||||
fn main() {
|
||||
push_unsafe!( {
|
||||
f(); pop_unsafe!({
|
||||
f() //~ ERROR: call to unsafe function
|
||||
})
|
||||
} );
|
||||
|
||||
push_unsafe!({
|
||||
f();
|
||||
pop_unsafe!({
|
||||
g();
|
||||
f(); //~ ERROR: call to unsafe function
|
||||
})
|
||||
} );
|
||||
|
||||
push_unsafe!({
|
||||
g(); pop_unsafe!({
|
||||
unsafe {
|
||||
f();
|
||||
}
|
||||
f(); //~ ERROR: call to unsafe function
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
// Note: For implementation simplicity the compiler just
|
||||
// ICE's if you underflow the push_unsafe stack.
|
||||
//
|
||||
// Thus all of the following cases cause an ICE.
|
||||
//
|
||||
// (The "ERROR" notes are from an earlier version
|
||||
// that used saturated arithmetic rather than checked
|
||||
// arithmetic.)
|
||||
|
||||
// pop_unsafe!{ g() };
|
||||
//
|
||||
// push_unsafe!({
|
||||
// pop_unsafe!(pop_unsafe!{ g() })
|
||||
// });
|
||||
//
|
||||
// push_unsafe!({
|
||||
// g();
|
||||
// pop_unsafe!(pop_unsafe!({
|
||||
// f() // ERROR: call to unsafe function
|
||||
// }))
|
||||
// });
|
||||
//
|
||||
// pop_unsafe!({
|
||||
// f(); // ERROR: call to unsafe function
|
||||
// })
|
||||
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
fn main() {
|
||||
box (1 + 1)
|
||||
//~^ HELP try using `box()` instead:
|
||||
//~| SUGGESTION box() (1 + 1)
|
||||
//~^ HELP try using `box ()` instead:
|
||||
//~| SUGGESTION box () (1 + 1)
|
||||
; //~ ERROR expected expression, found `;`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use std::mem::{self, transmute};
|
|||
mod rusti {
|
||||
extern "rust-intrinsic" {
|
||||
pub fn init<T>() -> T;
|
||||
pub fn move_val_init<T>(dst: &mut T, src: T);
|
||||
pub fn move_val_init<T>(dst: *mut T, src: T);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,13 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
#![allow(warnings)]
|
||||
#![allow(dead_code, unused_variables)]
|
||||
#![feature(box_syntax, box_heap)]
|
||||
#![feature(placement_in_syntax)]
|
||||
|
||||
// during check-pretty, the expanded code needs to opt into these
|
||||
// features
|
||||
#![feature(placement_new_protocol, core_intrinsics)]
|
||||
|
||||
// Tests that the new `box` syntax works with unique pointers.
|
||||
|
||||
|
|
@ -30,4 +35,9 @@ pub fn main() {
|
|||
let y: Box<isize> = box 2;
|
||||
let b: Box<isize> = box()(1 + 2);
|
||||
let c = box()(3 + 4);
|
||||
|
||||
let s: Box<Structure> = box Structure {
|
||||
x: 3,
|
||||
y: 4,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
37
src/test/run-pass/placement-in-syntax.rs
Normal file
37
src/test/run-pass/placement-in-syntax.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
#![allow(dead_code, unused_variables)]
|
||||
#![feature(box_heap)]
|
||||
#![feature(placement_in_syntax)]
|
||||
|
||||
// Tests that the new `in` syntax works with unique pointers.
|
||||
//
|
||||
// Compare with new-box-syntax.rs
|
||||
|
||||
use std::boxed::{Box, HEAP};
|
||||
|
||||
struct Structure {
|
||||
x: isize,
|
||||
y: isize,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let x: Box<isize> = in HEAP { 2 };
|
||||
let b: Box<isize> = in HEAP { 1 + 2 };
|
||||
let c = in HEAP { 3 + 4 };
|
||||
|
||||
let s: Box<Structure> = in HEAP {
|
||||
Structure {
|
||||
x: 3,
|
||||
y: 4,
|
||||
}
|
||||
};
|
||||
}
|
||||
56
src/test/run-pass/pushpop-unsafe-okay.rs
Normal file
56
src/test/run-pass/pushpop-unsafe-okay.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// Basic sanity check for `push_unsafe!(EXPR)` and
|
||||
// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
|
||||
// positive number of pushes in the stack, or if we are within a
|
||||
// normal `unsafe` block, but otherwise cannot.
|
||||
|
||||
// ignore-pretty because the `push_unsafe!` and `pop_unsafe!` macros
|
||||
// are not integrated with the pretty-printer.
|
||||
|
||||
#![feature(pushpop_unsafe)]
|
||||
|
||||
static mut X: i32 = 0;
|
||||
|
||||
unsafe fn f() { X += 1; return; }
|
||||
fn g() { unsafe { X += 1_000; } return; }
|
||||
|
||||
fn check_reset_x(x: i32) -> bool {
|
||||
#![allow(unused_parens)] // dont you judge my style choices!
|
||||
unsafe {
|
||||
let ret = (x == X);
|
||||
X = 0;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// double-check test infrastructure
|
||||
assert!(check_reset_x(0));
|
||||
unsafe { f(); }
|
||||
assert!(check_reset_x(1));
|
||||
assert!(check_reset_x(0));
|
||||
{ g(); }
|
||||
assert!(check_reset_x(1000));
|
||||
assert!(check_reset_x(0));
|
||||
unsafe { f(); g(); g(); }
|
||||
assert!(check_reset_x(2001));
|
||||
|
||||
push_unsafe!( { f(); pop_unsafe!( g() ) } );
|
||||
assert!(check_reset_x(1_001));
|
||||
push_unsafe!( { g(); pop_unsafe!( unsafe { f(); f(); } ) } );
|
||||
assert!(check_reset_x(1_002));
|
||||
|
||||
unsafe { push_unsafe!( { f(); pop_unsafe!( { f(); f(); } ) } ); }
|
||||
assert!(check_reset_x(3));
|
||||
push_unsafe!( { f(); push_unsafe!( { pop_unsafe!( { f(); f(); f(); } ) } ); } );
|
||||
assert!(check_reset_x(4));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue