From 02bbef0078a5d6b1e777403ea342c8923314ebb8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 Feb 2015 17:06:19 +0100 Subject: [PATCH 01/10] Replace `exchange_malloc`/`exchange_free` demo with something unrelated to Box. Precursor for landing overloaded-`box`, since that will decouple the `box` syntax from the exchange heap (and in fact will eliminate the use of the two aforementioned lang items). Instead, the new demonstration program shows a definition of the `str_eq` lang item. (We do not have that many procedural lang-items to choose from, which is a good sign for our efforts to decouple the compiler from the runtime!) (This previously used a demo of `panic_bounds_check`, but a `str_eq` demonstration is both easier to code and arguably a more interesting aspect of the language to discuss.) Fix unsafe.md example. --- src/doc/trpl/unsafe.md | 157 +++++++++++++++++++++++++++++++++-------- 1 file changed, 126 insertions(+), 31 deletions(-) diff --git a/src/doc/trpl/unsafe.md b/src/doc/trpl/unsafe.md index 4e14085599b60..21e7acb5f942e 100644 --- a/src/doc/trpl/unsafe.md +++ b/src/doc/trpl/unsafe.md @@ -649,53 +649,148 @@ it exists. The marker is the attribute `#[lang="..."]` and there are various different values of `...`, i.e. various different 'lang items'. -For example, `Box` pointers require two lang items, one for allocation -and one for deallocation. A freestanding program that uses the `Box` -sugar for dynamic allocations via `malloc` and `free`: +For example, there are lang items related to the implementation of +string slices (`&str`); one of these is `str_eq`, which implements the +equivalence relation on two string slices. This is a lang item because +string equivalence is used for more than just the `==` operator; in +particular, it is also used when pattern matching string literals. + +A freestanding program that provides its own definition of the +`str_eq` lang item, with a slightly different semantics than +usual in Rust: ``` -#![feature(lang_items, box_syntax, start, no_std)] +#![feature(lang_items, intrinsics, start, no_std)] #![no_std] -extern crate libc; +// Our str_eq lang item; it normalizes ASCII letters to lowercase. +#[lang="str_eq"] +fn eq_slice(s1: &str, s2: &str) -> bool { + unsafe { + let (p1, s1_len) = str::repr(s1); + let (p2, s2_len) = str::repr(s2); -extern { - fn abort() -> !; -} + if s1_len != s2_len { return false; } + + let mut i = 0; + while i < s1_len { + let b1 = str::at_offset(p1, i); + let b2 = str::at_offset(p2, i); -#[lang = "owned_box"] -pub struct Box(*mut T); + let b1 = lower_if_ascii(b1); + let b2 = lower_if_ascii(b2); -#[lang="exchange_malloc"] -unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { - let p = libc::malloc(size as libc::size_t) as *mut u8; + if b1 != b2 { return false; } - // malloc failed - if p as usize == 0 { - abort(); + i += 1; + } } - p -} -#[lang="exchange_free"] -unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { - libc::free(ptr as *mut libc::c_void) + return true; + + fn lower_if_ascii(b: u8) -> u8 { + if 'A' as u8 <= b && b <= 'Z' as u8 { + b - ('A' as u8) + ('a' as u8) + } else { + b + } + } } #[start] -fn main(argc: isize, argv: *const *const u8) -> isize { - let x = box 1; +fn main(_argc: isize, _argv: *const *const u8) -> isize { + let a = "HELLO\0"; + let b = "World\0"; + unsafe { + let (a_ptr, b_ptr) = (str::as_bytes(a), str::as_bytes(b)); + match (a,b) { + ("hello\0", "world\0") => { + printf::print2p("Whoa; matched \"hello world\" on \"%s, %s\"\n\0", + a_ptr, b_ptr); + } + + ("HELLO\0", "World\0") => { + printf::print2p("obviously match on %s, %s\n\0", a_ptr, b_ptr); + } + + _ => printf::print0("No matches at all???\n\0"), + } + } + return 0; +} - 0 +// To be able to print to standard output from this demonstration +// program, we link with `printf` from the C standard library. Note +// that this requires we null-terminate our strings with "\0". +mod printf { + use super::str; + + #[link(name="c")] + extern { fn printf(f: *const u8, ...); } + + pub unsafe fn print0(s: &str) { + // guard against failure to include '\0' + if str::last_byte(s) != '\0' as u8 { + printf(str::as_bytes("(invalid input str)\n\0")); + } else { + let bytes = str::as_bytes(s); + printf(bytes); + } + } + + pub unsafe fn print2p(s: &str, arg1: *const T, arg2: *const U) { + // guard against failure to include '\0' + if str::last_byte(s) != '\0' as u8 { + printf(str::as_bytes("(invalid input str)\n\0")); + } else { + let bytes = str::as_bytes(s); + printf(bytes, arg1, arg2); + } + } +} + +/// A collection of functions to operate on string slices. +mod str { + /// Extracts the underlying representation of a string slice. + pub unsafe fn repr(s: &str) -> (*const u8, usize) { + extern "rust-intrinsic" { fn transmute(e: T) -> U; } + transmute(s) + } + + /// Extracts the pointer to bytes representing the string slice. + pub fn as_bytes(s: &str) -> *const u8 { + unsafe { repr(s).0 } + } + + /// Returns the last byte in the string slice. + pub fn last_byte(s: &str) -> u8 { + unsafe { + let (bytes, len): (*const u8, usize) = repr(s); + at_offset(bytes, len-1) + } + } + + /// Returns the byte at offset `i` in the byte string. + pub unsafe fn at_offset(p: *const u8, i: usize) -> u8 { + *((p as usize + i) as *const u8) + } } +// Again, these functions and traits are used by the compiler, and are +// normally provided by libstd. (The `Sized` and `Copy` lang_items +// require definitions due to the type-parametric code above.) + #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } +#[lang = "panic"] +pub fn panic(_: &(&'static str, &'static str, u32)) -> ! { panic_fmt() } + +#[lang = "sized"] pub trait Sized: PhantomFn {} +#[lang = "copy"] pub trait Copy: PhantomFn {} +#[lang = "phantom_fn"] pub trait PhantomFn { } ``` -Note the use of `abort`: the `exchange_malloc` lang item is assumed to -return a valid pointer, and so needs to do the check internally. Other features provided by lang items include: @@ -703,8 +798,8 @@ Other features provided by lang items include: `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all marked with lang items; those specific four are `eq`, `ord`, `deref`, and `add` respectively. -- stack unwinding and general failure; the `eh_personality`, `fail` - and `fail_bounds_checks` lang items. +- stack unwinding and general failure; the `eh_personality`, `panic` + `panic_fmt`, and `panic_bounds_check` lang items. - the traits in `std::marker` used to indicate types of various kinds; lang items `send`, `sync` and `copy`. - the marker types and variance indicators found in @@ -712,6 +807,6 @@ Other features provided by lang items include: `contravariant_lifetime`, etc. Lang items are loaded lazily by the compiler; e.g. if one never uses -`Box` then there is no need to define functions for `exchange_malloc` -and `exchange_free`. `rustc` will emit an error when an item is needed -but not found in the current crate or any that it depends on. +array indexing (`a[i]`) then there is no need to define a function for +`panic_bounds_check`. `rustc` will emit an error when an item is +needed but not found in the current crate or any that it depends on. From f2f09a19fdf8f77eecb6e86f127c9994308f4e80 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 6 Mar 2015 15:31:18 +0100 Subject: [PATCH 02/10] Added `Box<_>` type annotations where necessary for overloaded-box. --- src/librustc_trans/save/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 83bb5efb425d2..4311510d6456c 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1531,7 +1531,7 @@ pub fn process_crate(sess: &Session, let mut out_name = cratename.clone(); out_name.push_str(".csv"); root_path.push(&out_name); - let output_file = match File::create(&root_path) { + let output_file: Box<_> = match File::create(&root_path) { Ok(f) => box f, Err(e) => { let disp = root_path.display(); From 7645a2d39ea75d522400a195cd3d987dfeb56418 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sun, 15 Feb 2015 09:52:21 +0100 Subject: [PATCH 03/10] Switched from `box` to `Box::new` where necessary for overloaded-box. See also issue 22405, which tracks going back to `box ` if possible in the future. Precursor for overloaded-`box` and placement-`in`; see Issue 22181. --- src/compiletest/compiletest.rs | 4 ++-- src/librustc/middle/dataflow.rs | 2 +- src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 9 +++++---- src/librustc_driver/pretty.rs | 4 ++-- src/librustc_trans/back/write.rs | 2 +- src/librustdoc/test.rs | 7 ++++--- src/libsyntax/ext/source_util.rs | 2 +- src/libsyntax/parse/mod.rs | 6 +++--- src/libsyntax/print/pprust.rs | 2 +- src/test/auxiliary/custom_derive_plugin.rs | 9 ++++----- 11 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index e32dacd2e6aaa..c9dbd183b9a9e 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -361,9 +361,9 @@ pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn { pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn { let config = (*config).clone(); let testfile = testfile.to_path_buf(); - test::DynMetricFn(box move |mm: &mut test::MetricMap| { + test::DynMetricFn(Box::new(move |mm: &mut test::MetricMap| { runtest::run_metrics(config, &testfile, mm) - }) + })) } fn extract_gdb_version(full_version_line: Option) -> Option { diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index a1ce8d18184e3..fc6bd5120f1b4 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { debug!("Dataflow result for {}:", self.analysis_name); debug!("{}", { let mut v = Vec::new(); - self.pretty_print_to(box &mut v, blk).unwrap(); + self.pretty_print_to(Box::new(&mut v), blk).unwrap(); println!("{}", String::from_utf8(v).unwrap()); "" }); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index dc27a30110950..1386f27bf9110 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -217,7 +217,7 @@ impl<'a> PhaseController<'a> { pub fn basic() -> PhaseController<'a> { PhaseController { stop: Compilation::Continue, - callback: box |_| {}, + callback: Box::new(|_| {}), } } } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4ff3c1f0075e9..27c8b0979c21d 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -378,7 +378,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } if sess.opts.debugging_opts.save_analysis { - control.after_analysis.callback = box |state| { + control.after_analysis.callback = Box::new(|state| { time(state.session.time_passes(), "save analysis", state.expanded_crate.unwrap(), @@ -386,7 +386,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { krate, state.analysis.unwrap(), state.out_dir)); - }; + }); control.make_glob_map = resolve::MakeGlobMap::Yes; } @@ -807,7 +807,8 @@ pub fn monitor(f: F) { cfg = cfg.stack_size(STACK_SIZE); } - match cfg.spawn(move || { stdio::set_stderr(box w); f() }).unwrap().join() { + // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. + match cfg.spawn(move || { stdio::set_stderr(Box::new(w)); f() }).unwrap().join() { Ok(()) => { /* fallthrough */ } Err(value) => { // Thread panicked without emitting a fatal diagnostic @@ -849,7 +850,7 @@ pub fn monitor(f: F) { // Panic so the process returns a failure code, but don't pollute the // output with some unnecessary panic messages, we've already // printed everything that we needed to. - old_io::stdio::set_stderr(box old_io::util::NullWriter); + old_io::stdio::set_stderr(Box::new(old_io::util::NullWriter)); panic!(); } } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index ffb2a05e43749..33a12b4feef58 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -558,7 +558,7 @@ pub fn pretty_print_input(sess: Session, (PpmSource(s), None) => { let out: &mut Write = &mut out; s.call_with_pp_support( - sess, ast_map, &arenas, id, box out, |annotation, out| { + sess, ast_map, &arenas, id, Box::new(out), |annotation, out| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); pprust::print_crate(sess.codemap(), @@ -585,7 +585,7 @@ pub fn pretty_print_input(sess: Session, sess.diagnostic(), src_name.to_string(), &mut rdr, - box out, + Box::new(out), annotation.pp_ann(), is_expanded); for node_id in uii.all_matching_node_ids(ast_map) { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 156cfa6c4b23a..2d11450853603 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -914,7 +914,7 @@ fn run_work_multithreaded(sess: &Session, futures.push(rx); thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || { - let diag_handler = mk_handler(true, box diag_emitter); + let diag_handler = mk_handler(true, Box::new(diag_emitter)); // Must construct cgcx inside the proc because it has non-Send // fields. diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e7312d6548e9f..fd14f4a282e99 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -150,7 +150,8 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, let (tx, rx) = channel(); let w1 = old_io::ChanWriter::new(tx); let w2 = w1.clone(); - let old = old_io::stdio::set_stderr(box w1); + // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. + let old = old_io::stdio::set_stderr(Box::new(w1)); thread::spawn(move || { let mut p = old_io::ChanReader::new(rx); let mut err = match old { @@ -163,11 +164,11 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, }; old_io::util::copy(&mut p, &mut err).unwrap(); }); - let emitter = diagnostic::EmitterWriter::new(box w2, None); + let emitter = diagnostic::EmitterWriter::new(Box::new(w2), None); // Compile the code let codemap = CodeMap::new(); - let diagnostic_handler = diagnostic::mk_handler(true, box emitter); + let diagnostic_handler = diagnostic::mk_handler(true, Box::new(emitter)); let span_diagnostic_handler = diagnostic::mk_span_handler(diagnostic_handler, codemap); diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 62d98be8b8505..7e1eb0692032f 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -128,7 +128,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree } } - box ExpandResult { p: p } + Box::new(ExpandResult { p: p }) } // include_str! : read the given file, insert it as a literal string expr diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index fae305f955174..25664a4a2971c 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -288,7 +288,7 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc) // parsing tt's probably shouldn't require a parser at all. let cfg = Vec::new(); let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap); - let mut p1 = Parser::new(sess, cfg, box srdr); + let mut p1 = Parser::new(sess, cfg, Box::new(srdr)); p1.parse_all_token_trees() } @@ -297,7 +297,7 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess, tts: Vec, cfg: ast::CrateConfig) -> Parser<'a> { let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, None, tts); - let mut p = Parser::new(sess, cfg, box trdr); + let mut p = Parser::new(sess, cfg, Box::new(trdr)); p.check_unknown_macro_variable(); p } @@ -360,7 +360,7 @@ pub mod with_hygiene { use super::lexer::make_reader_with_embedded_idents as make_reader; let cfg = Vec::new(); let srdr = make_reader(&sess.span_diagnostic, filemap); - let mut p1 = Parser::new(sess, cfg, box srdr); + let mut p1 = Parser::new(sess, cfg, Box::new(srdr)); p1.parse_all_token_trees() } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 07303ba51ff70..bdd637f33571b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -187,7 +187,7 @@ pub fn to_string(f: F) -> String where F: FnOnce(&mut State) -> io::Result<()>, { use std::raw::TraitObject; - let mut s = rust_printer(box Vec::new()); + let mut s = rust_printer(Box::new(Vec::new())); f(&mut s).unwrap(); eof(&mut s.s).unwrap(); let wr = unsafe { diff --git a/src/test/auxiliary/custom_derive_plugin.rs b/src/test/auxiliary/custom_derive_plugin.rs index e268896480480..4e23c30d2e2d5 100644 --- a/src/test/auxiliary/custom_derive_plugin.rs +++ b/src/test/auxiliary/custom_derive_plugin.rs @@ -11,7 +11,6 @@ // force-host #![feature(plugin_registrar)] -#![feature(box_syntax)] #![feature(rustc_private)] extern crate syntax; @@ -31,7 +30,7 @@ use rustc::plugin::Registry; pub fn plugin_registrar(reg: &mut Registry) { reg.register_syntax_extension( token::intern("derive_TotalSum"), - Decorator(box expand)); + Decorator(Box::new(expand))); } fn expand(cx: &mut ExtCtxt, @@ -54,7 +53,7 @@ fn expand(cx: &mut ExtCtxt, args: vec![], ret_ty: Literal(Path::new_local("isize")), attributes: vec![], - combine_substructure: combine_substructure(box |cx, span, substr| { + combine_substructure: combine_substructure(Box::new(|cx, span, substr| { let zero = cx.expr_int(span, 0); cs_fold(false, |cx, span, subexpr, field, _| { @@ -63,9 +62,9 @@ fn expand(cx: &mut ExtCtxt, token::str_to_ident("total_sum"), vec![])) }, zero, - box |cx, span, _, _| { cx.span_bug(span, "wtf??"); }, + Box::new(|cx, span, _, _| { cx.span_bug(span, "wtf??"); }), cx, span, substr) - }), + })), }, ], }; From cbf9303717b9dc7f2b8af808a0d4d72e00dea607 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 27 Jan 2015 11:33:38 +0100 Subject: [PATCH 04/10] parser: switch from `box () ` form to `in { }`. Note that `box ` itself remains unchanged. --- src/libsyntax/parse/parser.rs | 71 +++++++++++-------- .../parenthesized-box-expr-message.rs | 2 +- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 39c43ff1e75b4..2700ba268446e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -52,7 +52,7 @@ use ast::{TtDelimited, TtSequence, TtToken}; use ast::{TupleVariantKind, Ty, Ty_, TypeBinding}; use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer}; use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr}; -use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq}; +use ast::{TyRptr, TyTup, TyU32, TyVec}; use ast::{TypeImplItem, TypeTraitItem}; use ast::{UnnamedField, UnsafeBlock}; use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple}; @@ -2785,46 +2785,61 @@ impl<'a> Parser<'a> { ex = ExprAddrOf(m, e); } token::Ident(_, _) => { - if !self.check_keyword(keywords::Box) { + if !self.check_keyword(keywords::Box) && + !self.check_keyword(keywords::In) { return self.parse_dot_or_call_expr(); } let lo = self.span.lo; + let is_in = self.token.is_keyword(keywords::In); self.bump(); + if is_in { + let place = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL); + let blk = self.parse_block(); + hi = blk.span.hi; + ex = ExprBox(Some(place), self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk))); + return self.mk_expr(lo, hi, ex); + } - // Check for a place: `box(PLACE) EXPR`. + // FIXME (22181) Remove `box (PLACE) EXPR` support + // entirely after next release (enabling `(box (EXPR))`) + // + // ...but for now: check for a place: `box(PLACE) EXPR`. if self.eat(&token::OpenDelim(token::Paren)) { - // Support `box() EXPR` as the default. - if !self.eat(&token::CloseDelim(token::Paren)) { - let place = self.parse_expr(); - self.expect(&token::CloseDelim(token::Paren)); - // Give a suggestion to use `box()` when a parenthesised expression is used - if !self.token.can_begin_expr() { - let span = self.span; - let this_token_to_string = self.this_token_to_string(); - self.span_err(span, - &format!("expected expression, found `{}`", - this_token_to_string)); - let box_span = mk_sp(lo, self.last_span.hi); - self.span_help(box_span, - "perhaps you meant `box() (foo)` instead?"); - self.abort_if_errors(); - } - let subexpression = self.parse_prefix_expr(); - hi = subexpression.span.hi; - ex = ExprBox(Some(place), subexpression); - return self.mk_expr(lo, hi, ex); + // SNAP 880fb89 + // Enable this warning after snapshot + // let box_span = mk_sp(lo, self.last_span.hi); + // self.span_warn( + // box_span, + // "deprecated syntax; use the `in` keyword now \ + // (e.g. change `box () ` to \ + // `in () `)"); + // Continue supporting `box() EXPR` (temporarily) + if !self.eat(&token::CloseDelim(token::Paren)) { + let place = self.parse_expr(); + self.expect(&token::CloseDelim(token::Paren)); + if !self.token.can_begin_expr() { + let span = self.span; + let this_token_to_string = self.this_token_to_string(); + self.span_err(span, + &format!("expected expression, found `{}`", + this_token_to_string)); + let box_span = mk_sp(lo, self.last_span.hi); + self.span_help(box_span, + "perhaps you meant `in { }` instead?"); + self.abort_if_errors(); } + let subexpression = self.parse_prefix_expr(); + hi = subexpression.span.hi; + ex = ExprBox(Some(place), subexpression); + return self.mk_expr(lo, hi, ex); + } } - // Otherwise, we use the unique pointer default. let subexpression = self.parse_prefix_expr(); hi = subexpression.span.hi; - // FIXME (pnkfelix): After working out kinks with box - // desugaring, should be `ExprBox(None, subexpression)` - // instead. - ex = self.mk_unary(UnUniq, subexpression); + ex = ExprBox(None, subexpression); } _ => return self.parse_dot_or_call_expr() } diff --git a/src/test/parse-fail/parenthesized-box-expr-message.rs b/src/test/parse-fail/parenthesized-box-expr-message.rs index 05bbaec37af02..88a74ff6c5fd8 100644 --- a/src/test/parse-fail/parenthesized-box-expr-message.rs +++ b/src/test/parse-fail/parenthesized-box-expr-message.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - box(1 + 1) //~ HELP perhaps you meant `box() (foo)` instead? + box(1 + 1) //~ HELP perhaps you meant `in { }` instead? ; //~ ERROR expected expression, found `;` } From 0be597df22edeeb77e979b21a07f5a4ea7106228 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 27 Jan 2015 01:22:12 +0100 Subject: [PATCH 05/10] prototype Placer protocol for unstable overloaded-box and placement-in. --- src/liballoc/boxed.rs | 105 +++++++++++++- src/libcore/ops.rs | 112 +++++++++++++++ src/librustc/middle/expr_use_visitor.rs | 5 + src/libsyntax/ext/expand.rs | 178 ++++++++++++++++++++++++ 4 files changed, 396 insertions(+), 4 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6d865d2bffa8a..239aa21be4060 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -48,14 +48,18 @@ use core::prelude::*; +use heap; + use core::any::Any; use core::cmp::Ordering; use core::default::Default; use core::error::{Error, FromError}; use core::fmt; use core::hash::{self, Hash}; +use core::marker; use core::mem; use core::ops::{Deref, DerefMut}; +use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace}; use core::ptr::Unique; use core::raw::TraitObject; @@ -76,14 +80,108 @@ use core::raw::TraitObject; #[lang = "exchange_heap"] #[unstable(feature = "alloc", reason = "may be renamed; uncertain about custom allocator design")] -pub static HEAP: () = (); +pub const HEAP: ExchangeHeapSingleton = + ExchangeHeapSingleton { _force_singleton: () }; + +/// This the singleton type used solely for `boxed::HEAP`. +pub struct ExchangeHeapSingleton { _force_singleton: () } +impl Copy for ExchangeHeapSingleton { } /// A pointer type for heap allocation. /// /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Box(Unique); +pub struct Box(Unique); + +/// `IntermediateBox` represents uninitialized backing storage for `Box`. +/// +/// FIXME (pnkfelix): Ideally we would just reuse `Box` instead of +/// introducing a separate `IntermediateBox`; but then you hit +/// issues when you e.g. attempt to destructure an instance of `Box`, +/// since it is a lang item and so it gets special handling by the +/// compiler. Easier just to make this parallel type for now. +/// +/// FIXME (pnkfelix): Currently the `box` protocol only supports +/// creating instances of sized types. This IntermediateBox is +/// designed to be forward-compatible with a future protocol that +/// supports creating instances of unsized types; that is why the type +/// parameter has the `?Sized` generalization marker, and is also why +/// this carries an explicit size. However, it probably does not need +/// to carry the explicit alignment; that is just a work-around for +/// the fact that the `align_of` intrinsic currently requires the +/// input type to be Sized (which I do not think is strictly +/// necessary). +#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")] +pub struct IntermediateBox{ + ptr: *mut u8, + size: uint, + align: uint, + marker: marker::PhantomData<*mut T>, +} + +impl Place for IntermediateBox { + fn pointer(&mut self) -> *mut T { self.ptr as *mut T } +} + +unsafe fn finalize(b: IntermediateBox) -> Box { + let p = b.ptr as *mut T; + mem::forget(b); + mem::transmute(p) +} + +fn make_place() -> IntermediateBox { + let size = mem::size_of::(); + let align = mem::align_of::(); + + let p = if size == 0 { + heap::EMPTY as *mut u8 + } else { + let p = unsafe { + heap::allocate(size, align) + }; + if p.is_null() { + panic!("Box make_place allocation failure."); + } + p + }; + + IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData } +} + +impl BoxPlace for IntermediateBox { + fn make_place() -> IntermediateBox { make_place() } +} + +impl InPlace for IntermediateBox { + type Owner = Box; + unsafe fn finalize(self) -> Box { finalize(self) } +} + +impl Boxed for Box { + type Data = T; + type Place = IntermediateBox; + unsafe fn finalize(b: IntermediateBox) -> Box { finalize(b) } +} + +impl Placer for ExchangeHeapSingleton { + type Place = IntermediateBox; + + fn make_place(self) -> IntermediateBox { + make_place() + } +} + +#[unsafe_destructor] +impl Drop for IntermediateBox { + fn drop(&mut self) { + if self.size > 0 { + unsafe { + heap::deallocate(self.ptr, self.size, self.align) + } + } + } +} impl Box { /// Allocates memory on the heap and then moves `x` into it. @@ -171,8 +269,7 @@ impl Clone for Box { /// let y = x.clone(); /// ``` #[inline] - fn clone(&self) -> Box { box {(**self).clone()} } - + fn clone(&self) -> Box { box (HEAP) {(**self).clone()} } /// Copies `source`'s contents into `self` without creating a new allocation. /// /// # Examples diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 077b44f2dd2a7..a38cc35a5c874 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1187,3 +1187,115 @@ impl FnOnce for F self.call_mut(args) } } + +/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions +/// that allocate an intermediate "place" that holds uninitialized +/// state. The desugaring evaluates EXPR, and writes the result at +/// the address returned by the `pointer` method of this trait. +/// +/// A `Place` can be thought of as a special representation for a +/// hypothetical `&uninit` reference (which Rust cannot currently +/// express directly). That is, it represents a pointer to +/// uninitialized storage. +/// +/// The client is responsible for two steps: First, initializing the +/// payload (it can access its address via `pointer`). Second, +/// converting the agent to an instance of the owning pointer, via the +/// appropriate `finalize` method (see the `InPlace`. +/// +/// If evaluating EXPR fails, then the destructor for the +/// implementation of Place to clean up any intermediate state +/// (e.g. deallocate box storage, pop a stack, etc). +pub trait Place { + /// Returns the address where the input value will be written. + /// Note that the data at this address is generally uninitialized, + /// and thus one should use `ptr::write` for initializing it. + fn pointer(&mut self) -> *mut Data; +} + +/// Interface to implementations of `in (PLACE) EXPR`. +/// +/// `in (PLACE) EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let p = PLACE; +/// let mut place = Placer::make_place(p); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// std::ptr::write(raw_place, value); +/// InPlace::finalize(place) +/// } +/// ``` +/// +/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`; +/// if the type of `PLACE` is `P`, then the final type of the whole +/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` +/// traits). +/// +/// Values for types implementing this trait usually are transient +/// intermediate values (e.g. the return value of `Vec::emplace_back`) +/// or `Copy`, since the `make_place` method takes `self` by value. +pub trait Placer { + /// `Place` is the intermedate agent guarding the + /// uninitialized state for `Data`. + type Place: InPlace; + + /// Creates a fresh place from `self`. + fn make_place(self) -> Self::Place; +} + +/// Specialization of `Place` trait supporting `in (PLACE) EXPR`. +pub trait InPlace: Place { + /// `Owner` is the type of the end value of `in (PLACE) EXPR` + /// + /// Note that when `in (PLACE) EXPR` is solely used for + /// side-effecting an existing data-structure, + /// e.g. `Vec::emplace_back`, then `Owner` need not carry any + /// information at all (e.g. it can be the unit type `()` in that + /// case). + type Owner; + + /// Converts self into the final value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// the returned instance of `Owner` and forgetting self. + unsafe fn finalize(self) -> Self::Owner; +} + +/// Core trait for the `box EXPR` form. +/// +/// `box EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let mut place = BoxPlace::make_place(); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// ::std::ptr::write(raw_place, value); +/// Boxed::finalize(place) +/// } +/// ``` +/// +/// The type of `box EXPR` is supplied from its surrounding +/// context; in the above expansion, the result type `T` is used +/// to determine which implementation of `Boxed` to use, and that +/// `` in turn dictates determines which +/// implementation of `BoxPlace` to use, namely: +/// `<::Place as BoxPlace>`. +pub trait Boxed { + /// The kind of data that is stored in this kind of box. + type Data; /* (`Data` unused b/c cannot yet express below bound.) */ + /// The place that will negotiate the storage of the data. + type Place; /* should be bounded by BoxPlace */ + + /// Converts filled place into final owning value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// returned instance of `Self` and forgetting `filled`. + unsafe fn finalize(filled: Self::Place) -> Self; +} + +/// Specialization of `Place` trait supporting `box EXPR`. +pub trait BoxPlace : Place { + /// Creates a globally fresh place. + fn make_place() -> Self; +} diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a1e38a1c8bda7..7dfc44d9bb322 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -605,6 +605,11 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { None => {} } self.consume_expr(&**base); + if place.is_some() { + self.tcx().sess.span_bug( + expr.span, + "box with explicit place remains after expansion"); + } } ast::ExprMac(..) => { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ee2cf9017bbf3..1444e02911dac 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -58,8 +58,21 @@ pub fn expand_type(t: P, fold::noop_fold_ty(t, fld) } +// Given suffix ["b","c","d"], returns path `::std::b::c::d` when +// `fld.cx.use_std`, and `::core::b::c::d` otherwise. +fn mk_core_path(fld: &mut MacroExpander, + span: Span, + suffix: &[&'static str]) -> ast::Path { + let mut idents = vec![fld.cx.ident_of_std("core")]; + for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); } + fld.cx.path_global(span, idents) +} + + pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { + let expr_span = e.span; e.and_then(|ast::Expr {id, node, span}| match node { + // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. ast::ExprMac(mac) => { @@ -84,6 +97,171 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { }) } + // Desugar ExprBox: `in (PLACE) EXPR` + ast::ExprBox(Some(placer), value_expr) => { + // to: + // + // let p = PLACE; + // let mut place = Placer::make_place(p); + // let raw_place = InPlace::pointer(&mut place); + // let value = EXPR; + // unsafe { + // std::ptr::write(raw_place, value); + // InPlace::finalize(place) + // } + + let value_span = value_expr.span; + let placer_span = placer.span; + + let placer_expr = fld.fold_expr(placer); + let value_expr = fld.fold_expr(value_expr); + + let placer_ident = token::gensym_ident("placer"); + let agent_ident = token::gensym_ident("place"); + let value_ident = token::gensym_ident("value"); + let p_ptr_ident = token::gensym_ident("p_ptr"); + + let placer = fld.cx.expr_ident(span, placer_ident); + let agent = fld.cx.expr_ident(span, agent_ident); + let value = fld.cx.expr_ident(span, value_ident); + let p_ptr = fld.cx.expr_ident(span, p_ptr_ident); + + let make_place = ["ops", "Placer", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let ptr_write = ["ptr", "write"]; + let inplace_finalize = ["ops", "InPlace", "finalize"]; + + let make_call = |fld: &mut MacroExpander, p, args| { + let path = mk_core_path(fld, placer_span, p); + let path = fld.cx.expr_path(path); + fld.cx.expr_call(span, path, args) + }; + + let stmt_let = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(placer_span, false, bind, expr) + }; + let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(placer_span, true, bind, expr) + }; + + // let placer = ; + let s1 = stmt_let(fld, placer_ident, placer_expr); + + // let mut place = Placer::make_place(placer); + let s2 = { + let call = make_call(fld, &make_place, vec![placer]); + stmt_let_mut(fld, agent_ident, call) + }; + + // let p_ptr = Place::pointer(&mut place); + let s3 = { + let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())]; + let call = make_call(fld, &place_pointer, args); + stmt_let(fld, p_ptr_ident, call) + }; + + // let value = ; + let s4 = fld.cx.stmt_let(value_span, false, value_ident, value_expr); + + // unsafe { ptr::write(p_ptr, value); InPlace::finalize(place) } + let expr = { + let call_ptr_write = StmtSemi(make_call( + fld, &ptr_write, vec![p_ptr, value]), ast::DUMMY_NODE_ID); + let call_ptr_write = codemap::respan(value_span, call_ptr_write); + + let call = make_call(fld, &inplace_finalize, vec![agent]); + Some(fld.cx.expr_block(P(ast::Block { + stmts: vec![P(call_ptr_write)], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: span, + }))) + }; + + let block = fld.cx.block_all(span, vec![s1, s2, s3, s4], expr); + fld.cx.expr_block(block) + } + + // Desugar ExprBox: `box EXPR` + ast::ExprBox(None, value_expr) => { + // to: + // + // let mut place = BoxPlace::make_place(); + // let raw_place = Place::pointer(&mut place); + // let value = $value; + // unsafe { + // ::std::ptr::write(raw_place, value); + // Boxed::finalize(place) + // } + + let value_span = value_expr.span; + + let value_expr = fld.fold_expr(value_expr); + + let agent_ident = token::gensym_ident("place"); + let value_ident = token::gensym_ident("value"); + let p_ptr_ident = token::gensym_ident("p_ptr"); + + let agent = fld.cx.expr_ident(span, agent_ident); + let value = fld.cx.expr_ident(span, value_ident); + let p_ptr = fld.cx.expr_ident(span, p_ptr_ident); + + let boxplace_make_place = ["ops", "BoxPlace", "make_place"]; + let place_pointer = ["ops", "Place", "pointer"]; + let ptr_write = ["ptr", "write"]; + let boxed_finalize = ["ops", "Boxed", "finalize"]; + + let make_call = |fld: &mut MacroExpander, p, args| { + let path = mk_core_path(fld, expr_span, p); + let path = fld.cx.expr_path(path); + fld.cx.expr_call(span, path, args) + }; + + let stmt_let = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(expr_span, false, bind, expr) + }; + let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| { + fld.cx.stmt_let(expr_span, true, bind, expr) + }; + + // let mut place = BoxPlace::make_place(); + let s1 = { + let call = make_call(fld, &boxplace_make_place, vec![]); + stmt_let_mut(fld, agent_ident, call) + }; + + // let p_ptr = Place::pointer(&mut place); + let s2 = { + let args = vec![fld.cx.expr_mut_addr_of(expr_span, agent.clone())]; + let call = make_call(fld, &place_pointer, args); + stmt_let(fld, p_ptr_ident, call) + }; + + // let value = ; + let s3 = fld.cx.stmt_let(value_span, false, value_ident, value_expr); + + // unsafe { ptr::write(p_ptr, value); Boxed::finalize(place) } + let expr = { + let call_ptr_write = + StmtSemi(make_call(fld, &ptr_write, vec![p_ptr, value]), + ast::DUMMY_NODE_ID); + let call_ptr_write = codemap::respan(value_span, call_ptr_write); + + let call = make_call(fld, &boxed_finalize, vec![agent]); + Some(fld.cx.expr_block(P(ast::Block { + stmts: vec![P(call_ptr_write)], + expr: Some(call), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: span, + }))) + }; + + let block = fld.cx.block_all(span, vec![s1, s2, s3], expr); + fld.cx.expr_block(block) + } + ast::ExprWhile(cond, body, opt_ident) => { let cond = fld.fold_expr(cond); let (body, opt_ident) = expand_loop_block(body, opt_ident, fld); From 467345b7e04d68e9581fad4be881e969a8abf5bb Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 12 Feb 2015 11:30:16 +0100 Subject: [PATCH 06/10] Add feature-gates for desugaring-based `box` and placement-`in`. update test/compile-fail/feature-gate-box-expr.rs to reflect new feature gates. Part of what lands with Issue 22181. --- src/liballoc/lib.rs | 1 + src/libstd/lib.rs | 1 + src/libsyntax/ext/expand.rs | 12 ++++ src/libsyntax/feature_gate.rs | 62 ++++++++++++++++--- .../compile-fail/feature-gate-box-expr.rs | 5 +- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 5c9a42a8a7174..02a83e211c201 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -72,6 +72,7 @@ #![feature(lang_items, unsafe_destructor)] #![feature(box_syntax)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] #![feature(unboxed_closures)] #![feature(unsafe_no_drop_flag)] #![feature(core)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a05d6752073af..62a1f7ee18937 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -116,6 +116,7 @@ #![feature(linkage, thread_local, asm)] #![feature(old_impl_check)] #![feature(optin_builtin_traits)] +#![feature(placement_in_syntax)] #![feature(rand)] #![feature(staged_api)] #![feature(unboxed_closures)] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1444e02911dac..1b26d4d54c94b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -110,6 +110,12 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // InPlace::finalize(place) // } + // Ensure feature-gate is enabled + feature_gate::check_for_placement_in( + fld.cx.ecfg.features, + &fld.cx.parse_sess.span_diagnostic, + expr_span); + let value_span = value_expr.span; let placer_span = placer.span; @@ -195,6 +201,12 @@ pub fn expand_expr(e: P, fld: &mut MacroExpander) -> P { // Boxed::finalize(place) // } + // Ensure feature-gate is enabled + feature_gate::check_for_box_syntax( + fld.cx.ecfg.features, + &fld.cx.parse_sess.span_diagnostic, + expr_span); + let value_span = value_expr.span; let value_expr = fld.fold_expr(value_expr); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c3bac0cf57c75..de156dfeb3839 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -81,6 +81,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("visible_private_types", "1.0.0", Active), ("slicing_syntax", "1.0.0", Accepted), ("box_syntax", "1.0.0", Active), + ("placement_in_syntax", "1.0.0", Active), ("on_unimplemented", "1.0.0", Active), ("simd_ffi", "1.0.0", Active), @@ -324,6 +325,8 @@ pub struct Features { pub allow_trace_macros: bool, pub allow_internal_unstable: bool, pub allow_custom_derive: bool, + pub allow_placement_in: bool, + pub allow_box: bool, pub old_orphan_check: bool, pub simd_ffi: bool, pub unmarked_api: bool, @@ -346,6 +349,8 @@ impl Features { allow_trace_macros: false, allow_internal_unstable: false, allow_custom_derive: false, + allow_placement_in: false, + allow_box: false, old_orphan_check: false, simd_ffi: false, unmarked_api: false, @@ -355,6 +360,26 @@ impl Features { } } +const EXPLAIN_BOX_SYNTAX: &'static str = + "box expression syntax is experimental; you can call `Box::new` instead."; + +const EXPLAIN_PLACEMENT_IN: &'static str = + "placement-in expression syntax is experimental and subject to change."; + +pub fn check_for_box_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_box: true, .. }) = f { + return; + } + emit_feature_err(diag, "box_syntax", span, EXPLAIN_BOX_SYNTAX); +} + +pub fn check_for_placement_in(f: Option<&Features>, diag: &SpanHandler, span: Span) { + if let Some(&Features { allow_placement_in: true, .. }) = f { + return; + } + emit_feature_err(diag, "placement_in_syntax", span, EXPLAIN_PLACEMENT_IN); +} + struct Context<'a> { features: Vec<&'static str>, span_handler: &'a SpanHandler, @@ -363,6 +388,11 @@ struct Context<'a> { } impl<'a> Context<'a> { + fn enable_feature(&mut self, feature: &'static str) { + debug!("enabling feature: {}", feature); + self.features.push(feature); + } + fn gate_feature(&self, feature: &str, span: Span, explain: &str) { let has_feature = self.has_feature(feature); debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature); @@ -482,6 +512,26 @@ impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> { fn visit_attribute(&mut self, attr: &'v ast::Attribute) { self.context.check_attribute(attr); } + + fn visit_expr(&mut self, e: &ast::Expr) { + // Issue 22181: overloaded-`box` and placement-`in` are + // implemented via a desugaring expansion, so their feature + // gates go into MacroVisitor since that works pre-expansion. + // + // Issue 22234: we also check during expansion as well. + // But we keep these checks as a pre-expansion check to catch + // uses in e.g. conditionalized code. + + if let ast::ExprBox(None, _) = e.node { + self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX); + } + + if let ast::ExprBox(Some(_), _) = e.node { + self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN); + } + + visit::walk_expr(self, e); + } } struct PostExpansionVisitor<'a> { @@ -647,12 +697,6 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { fn visit_expr(&mut self, e: &ast::Expr) { match e.node { - ast::ExprBox(..) | ast::ExprUnary(ast::UnOp::UnUniq, _) => { - self.gate_feature("box_syntax", - e.span, - "box expression syntax is experimental; \ - you can call `Box::new` instead."); - } ast::ExprLit(ref lit) => { match lit.node { ast::LitInt(_, ty) => { @@ -754,10 +798,10 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C match KNOWN_FEATURES.iter() .find(|& &(n, _, _)| name == n) { Some(&(name, _, Active)) => { - cx.features.push(name); + cx.enable_feature(name); } Some(&(name, _, Deprecated)) => { - cx.features.push(name); + cx.enable_feature(name); span_handler.span_warn( mi.span, "feature is deprecated and will only be available \ @@ -794,6 +838,8 @@ fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C allow_trace_macros: cx.has_feature("trace_macros"), allow_internal_unstable: cx.has_feature("allow_internal_unstable"), allow_custom_derive: cx.has_feature("custom_derive"), + allow_placement_in: cx.has_feature("placement_in_syntax"), + allow_box: cx.has_feature("box_syntax"), old_orphan_check: cx.has_feature("old_orphan_check"), simd_ffi: cx.has_feature("simd_ffi"), unmarked_api: cx.has_feature("unmarked_api"), diff --git a/src/test/compile-fail/feature-gate-box-expr.rs b/src/test/compile-fail/feature-gate-box-expr.rs index 39f54be456169..3a473526a2a9e 100644 --- a/src/test/compile-fail/feature-gate-box-expr.rs +++ b/src/test/compile-fail/feature-gate-box-expr.rs @@ -17,7 +17,10 @@ fn main() { let x = box () 'c'; //~ ERROR box expression syntax is experimental println!("x: {}", x); - let x = box (HEAP) 'c'; //~ ERROR box expression syntax is experimental + 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); } From 4a7df22097bd1f1850877081b285b1e4818a0617 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 16 Feb 2015 11:45:23 +0100 Subject: [PATCH 07/10] Accommodate error message explosion from box-desugaring in some tests. See discussion on Issue 22231. --- .../check-static-values-constraints.rs | 123 +++++++++++++++++- src/test/compile-fail/dst-rvalue.rs | 12 +- src/test/compile-fail/issue-14084.rs | 7 +- src/test/compile-fail/issue-7364.rs | 17 ++- .../compile-fail/lint-owned-heap-memory.rs | 4 + src/test/compile-fail/occurs-check-2.rs | 19 ++- src/test/compile-fail/occurs-check.rs | 19 ++- .../compile-fail/static-mut-not-constant.rs | 20 ++- 8 files changed, 194 insertions(+), 27 deletions(-) diff --git a/src/test/compile-fail/check-static-values-constraints.rs b/src/test/compile-fail/check-static-values-constraints.rs index 0180bccbca40b..1a6b8a547fc5f 100644 --- a/src/test/compile-fail/check-static-values-constraints.rs +++ b/src/test/compile-fail/check-static-values-constraints.rs @@ -99,7 +99,22 @@ static STATIC10: UnsafeStruct = UnsafeStruct; struct MyOwned; static STATIC11: Box = box MyOwned; -//~^ ERROR allocations are not allowed in statics +//~^ ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR references in statics may only refer to immutable values // The following examples test that mutable structs are just forbidden // to have types with destructors @@ -121,13 +136,77 @@ static mut STATIC14: SafeStruct = SafeStruct { }; static STATIC15: &'static [Box] = &[ - box MyOwned, //~ ERROR allocations are not allowed in statics - box MyOwned, //~ ERROR allocations are not allowed in statics + box MyOwned, + //~^ ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR references in statics may only refer to immutable values + box MyOwned, + //~^ ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR references in statics may only refer to immutable values ]; static STATIC16: (&'static Box, &'static Box) = ( - &box MyOwned, //~ ERROR allocations are not allowed in statics - &box MyOwned, //~ ERROR allocations are not allowed in statics + &box MyOwned, + //~^ ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR references in statics may only refer to immutable values + &box MyOwned, + //~^ ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR references in statics may only refer to immutable values ); static mut STATIC17: SafeEnum = SafeEnum::Variant1; @@ -135,9 +214,39 @@ static mut STATIC17: SafeEnum = SafeEnum::Variant1; static STATIC19: Box = box 3; -//~^ ERROR allocations are not allowed in statics +//~^ ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR references in statics may only refer to immutable values pub fn main() { let y = { static x: Box = box 3; x }; - //~^ ERROR allocations are not allowed in statics + //~^ ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR statics are not allowed to have destructors + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR blocks in statics are limited to items and tail expressions + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR function calls in statics are limited to struct and enum constructors + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR paths in statics may only refer to constants or functions + //~| ERROR references in statics may only refer to immutable values } diff --git a/src/test/compile-fail/dst-rvalue.rs b/src/test/compile-fail/dst-rvalue.rs index 69bda8c1671e7..12a7de9e7d3e9 100644 --- a/src/test/compile-fail/dst-rvalue.rs +++ b/src/test/compile-fail/dst-rvalue.rs @@ -14,11 +14,15 @@ pub fn main() { let _x: Box = box *"hello world"; - //~^ ERROR E0161 - //~^^ ERROR cannot move out of borrowed content + //~^ ERROR E0277 + //~| ERROR the trait `core::marker::Sized` is not implemented for the type `str` + //~| ERROR the trait `core::marker::Sized` is not implemented for the type `str` + //~| ERROR the trait `core::marker::Sized` is not implemented for the type `str` let array: &[isize] = &[1, 2, 3]; let _x: Box<[isize]> = box *array; - //~^ ERROR E0161 - //~^^ ERROR cannot move out of borrowed content + //~^ ERROR E0277 + //~| ERROR the trait `core::marker::Sized` is not implemented for the type `[isize]` + //~| ERROR the trait `core::marker::Sized` is not implemented for the type `[isize]` + //~| ERROR the trait `core::marker::Sized` is not implemented for the type `[isize]` } diff --git a/src/test/compile-fail/issue-14084.rs b/src/test/compile-fail/issue-14084.rs index 92e0dd3ad0e52..225ba6ede5222 100644 --- a/src/test/compile-fail/issue-14084.rs +++ b/src/test/compile-fail/issue-14084.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(box_syntax)] +#![feature(placement_in_syntax)] fn main() { - box ( () ) 0; - //~^ ERROR: only the managed heap and exchange heap are currently supported + let _bx: Box<_> = box ( () ) 0; + //~^ ERROR: the trait `core::ops::Placer<_>` is not implemented for the type `()` + //~| ERROR: the trait `core::ops::Placer<_>` is not implemented for the type `()` } diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 6a36b2f84bfc9..e8191f1a888c8 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -14,9 +14,24 @@ use std::cell::RefCell; // Regression test for issue 7364 static boxed: Box> = box RefCell::new(0); -//~^ ERROR allocations are not allowed in statics +//~^ ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors //~| ERROR the trait `core::marker::Sync` is not implemented for the type //~| ERROR the trait `core::marker::Sync` is not implemented for the type +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions //~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR references in statics may only refer to immutable values fn main() { } diff --git a/src/test/compile-fail/lint-owned-heap-memory.rs b/src/test/compile-fail/lint-owned-heap-memory.rs index 9c68da8beafd6..497df2715fef1 100644 --- a/src/test/compile-fail/lint-owned-heap-memory.rs +++ b/src/test/compile-fail/lint-owned-heap-memory.rs @@ -11,6 +11,7 @@ #![allow(dead_code)] #![forbid(box_pointers)] #![feature(box_syntax)] +#![feature(core)] struct Foo { x: Box //~ ERROR type uses owned @@ -19,4 +20,7 @@ struct Foo { fn main() { let _x : Foo = Foo {x : box 10}; //~^ ERROR type uses owned + //~| ERROR type uses owned + //~| ERROR type uses owned + //~| ERROR type uses owned } diff --git a/src/test/compile-fail/occurs-check-2.rs b/src/test/compile-fail/occurs-check-2.rs index fd2903a85ddb0..37e7dc5374b8e 100644 --- a/src/test/compile-fail/occurs-check-2.rs +++ b/src/test/compile-fail/occurs-check-2.rs @@ -11,12 +11,21 @@ #![feature(box_syntax)] fn main() { - let f; + let f: Box<_>; let g; g = f; f = box g; - //~^ ERROR mismatched types - //~| expected `_` - //~| found `Box<_>` - //~| cyclic type of infinite size + //~^ ERROR the trait `core::ops::Place>` is not implemented for the type + + // (At one time, we produced a nicer error message like below. + // but right now, the desugaring produces the above error instead + // for the cyclic type here; its especially unfortunate because + // printed error leaves out the information necessary for one to + // deduce that the necessary type for the given impls *is* + // cyclic.) + // + // ^ ERROR mismatched types + // | expected `_` + // | found `Box<_>` + // | cyclic type of infinite size } diff --git a/src/test/compile-fail/occurs-check.rs b/src/test/compile-fail/occurs-check.rs index 036fcc1b9d779..0149957b7a11d 100644 --- a/src/test/compile-fail/occurs-check.rs +++ b/src/test/compile-fail/occurs-check.rs @@ -11,10 +11,19 @@ #![feature(box_syntax)] fn main() { - let f; + let f: Box<_>; f = box f; - //~^ ERROR mismatched types - //~| expected `_` - //~| found `Box<_>` - //~| cyclic type of infinite size + //~^ ERROR the trait `core::ops::Place>` is not implemented for the type + + // (At one time, we produced a nicer error message like below. + // but right now, the desugaring produces the above error instead + // for the cyclic type here; its especially unfortunate because + // printed error leaves out the information necessary for one to + // deduce that the necessary type for the given impls *is* + // cyclic.) + // + // ^ ERROR mismatched types + // | expected `_` + // | found `Box<_>` + // | cyclic type of infinite size } diff --git a/src/test/compile-fail/static-mut-not-constant.rs b/src/test/compile-fail/static-mut-not-constant.rs index 08148328edcf3..50a7691886758 100644 --- a/src/test/compile-fail/static-mut-not-constant.rs +++ b/src/test/compile-fail/static-mut-not-constant.rs @@ -11,7 +11,23 @@ #![feature(box_syntax)] static mut a: Box = box 3; -//~^ ERROR allocations are not allowed in statics -//~^^ ERROR mutable statics are not allowed to have owned pointers +//~^ ERROR mutable statics are not allowed to have owned pointers +//~| ERROR statics are not allowed to have destructors +//^| ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors +//~| ERROR statics are not allowed to have destructors +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR blocks in statics are limited to items and tail expressions +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR function calls in statics are limited to struct and enum constructors +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR paths in statics may only refer to constants or functions +//~| ERROR references in statics may only refer to immutable values fn main() {} From 056e58173d56d58b9da9a9c542b927c591d2028f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 16 Feb 2015 11:55:55 +0100 Subject: [PATCH 08/10] Update tests for desugaring box and placement-in. Namely: * Update run-pass/new-box-syntax * Fix doc-embedded test for `alloc::boxed` to reflect new syntax. * Fix test/debuginfo/box.rs to reflect new syntax. Part of what lands with Issue 22181. --- src/liballoc/boxed.rs | 9 +++++---- src/test/debuginfo/box.rs | 7 +++++-- src/test/run-pass/new-box-syntax.rs | 7 ++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 239aa21be4060..bd7d32930cd84 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -63,18 +63,19 @@ use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace}; use core::ptr::Unique; use core::raw::TraitObject; -/// A value that represents the heap. This is the default place that the `box` -/// keyword allocates into when no place is supplied. +/// A value that represents the heap. This is the place that the `box` +/// keyword allocates into. /// /// The following two examples are equivalent: /// /// ```rust /// #![feature(box_syntax)] +/// #![feature(placement_in_syntax)] /// use std::boxed::HEAP; /// /// fn main() { -/// let foo = box(HEAP) 5; -/// let foo = box 5; +/// let foo = in HEAP { 5 }; +/// let foo: Box<_> = box 5; /// } /// ``` #[lang = "exchange_heap"] diff --git a/src/test/debuginfo/box.rs b/src/test/debuginfo/box.rs index 0689a6bc45b68..6b0ac62c3aa66 100644 --- a/src/test/debuginfo/box.rs +++ b/src/test/debuginfo/box.rs @@ -32,11 +32,14 @@ #![allow(unused_variables)] #![feature(box_syntax)] +#![feature(placement_in_syntax)] #![omit_gdb_pretty_printer_section] +use std::boxed::HEAP; + fn main() { - let a = box 1; - let b = box() (2, 3.5f64); + let a: Box<_> = box 1; + let b = in HEAP { (2, 3.5f64) }; zzz(); // #break } diff --git a/src/test/run-pass/new-box-syntax.rs b/src/test/run-pass/new-box-syntax.rs index 3d4847a119a55..95ba1bd574406 100644 --- a/src/test/run-pass/new-box-syntax.rs +++ b/src/test/run-pass/new-box-syntax.rs @@ -13,6 +13,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] +#![feature(placement_in_syntax)] // Tests that the new `box` syntax works with unique pointers. @@ -24,8 +25,8 @@ struct Structure { } pub fn main() { - let x: Box = box(HEAP) 2; + let x: Box = in HEAP { 2 }; let y: Box = box 2; - let b: Box = box()(1 + 2); - let c = box()(3 + 4); + let b: Box = box () (1 + 2); + let c: Box<_> = box () (3 + 4); } From 2d447127a575ee9c06b1bb93acc697396e45f8da Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 Feb 2015 21:03:09 +0100 Subject: [PATCH 09/10] Issue 22450: Address desugaring-box problems in [pretty] run-pass test suite. Precursor for overloaded-`box` and placement-`in`; see Issue 22181. --- src/test/run-pass/alignment-gep-tup-like-1.rs | 5 +++-- src/test/run-pass/close-over-big-then-small-data.rs | 5 +++-- src/test/run-pass/issue-2734.rs | 3 ++- src/test/run-pass/issue-2735.rs | 3 ++- .../issue-7673-cast-generically-implemented-trait.rs | 3 ++- src/test/run-pass/kindck-owned-trait-contains-1.rs | 3 ++- .../regions-close-over-type-parameter-successfully.rs | 3 ++- src/test/run-pass/regions-early-bound-trait-param.rs | 3 ++- 8 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/test/run-pass/alignment-gep-tup-like-1.rs b/src/test/run-pass/alignment-gep-tup-like-1.rs index 72a79e188b3dc..e8125e7f34220 100644 --- a/src/test/run-pass/alignment-gep-tup-like-1.rs +++ b/src/test/run-pass/alignment-gep-tup-like-1.rs @@ -31,10 +31,11 @@ impl Invokable for Invoker { } fn f(a: A, b: u16) -> Box+'static> { - box Invoker { + // FIXME(22450): workaround pretty-printer deficiency via parens. + (box Invoker { a: a, b: b, - } as (Box+'static>) + }) as (Box+'static>) } pub fn main() { diff --git a/src/test/run-pass/close-over-big-then-small-data.rs b/src/test/run-pass/close-over-big-then-small-data.rs index 99fdc34602617..dc8e27b94a75d 100644 --- a/src/test/run-pass/close-over-big-then-small-data.rs +++ b/src/test/run-pass/close-over-big-then-small-data.rs @@ -35,10 +35,11 @@ impl Invokable for Invoker { } fn f(a: A, b: u16) -> Box+'static> { - box Invoker { + // FIXME(22450): workaround pretty-printer deficiency via parens. + (box Invoker { a: a, b: b, - } as (Box+'static>) + }) as (Box+'static>) } pub fn main() { diff --git a/src/test/run-pass/issue-2734.rs b/src/test/run-pass/issue-2734.rs index a7b53db6b0553..eb37b4c684183 100644 --- a/src/test/run-pass/issue-2734.rs +++ b/src/test/run-pass/issue-2734.rs @@ -17,7 +17,8 @@ trait hax { impl hax for A { } fn perform_hax(x: Box) -> Box { - box x as Box + // FIXME(22450): workaround pretty-printer deficiency via parens. + (box x) as Box } fn deadcode() { diff --git a/src/test/run-pass/issue-2735.rs b/src/test/run-pass/issue-2735.rs index 1594b94879cee..7a5878a5901cf 100644 --- a/src/test/run-pass/issue-2735.rs +++ b/src/test/run-pass/issue-2735.rs @@ -17,7 +17,8 @@ trait hax { impl hax for A { } fn perform_hax(x: Box) -> Box { - box x as Box + // FIXME(22450): workaround pretty-printer deficiency via parens. + (box x) as Box } fn deadcode() { diff --git a/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs b/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs index 736860947f23c..2bc69b3c63925 100644 --- a/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs +++ b/src/test/run-pass/issue-7673-cast-generically-implemented-trait.rs @@ -26,4 +26,5 @@ trait A { impl A for T {} fn owned2(a: Box) { a as Box; } -fn owned3(a: Box) { box a as Box; } +// FIXME(22450): workaround pretty-printer deficiency via parens. +fn owned3(a: Box) { (box a) as Box; } diff --git a/src/test/run-pass/kindck-owned-trait-contains-1.rs b/src/test/run-pass/kindck-owned-trait-contains-1.rs index f05ac11d41380..d38454a487c63 100644 --- a/src/test/run-pass/kindck-owned-trait-contains-1.rs +++ b/src/test/run-pass/kindck-owned-trait-contains-1.rs @@ -20,7 +20,8 @@ impl repeat for Box { } fn repeater(v: Box) -> Box+'static> { - box v as Box+'static> // No + // FIXME(22450): workaround pretty-printer deficiency via parens. + (box v) as Box+'static> // No } pub fn main() { diff --git a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs index 3922cb1219c03..9a13d6992177a 100644 --- a/src/test/run-pass/regions-close-over-type-parameter-successfully.rs +++ b/src/test/run-pass/regions-close-over-type-parameter-successfully.rs @@ -23,7 +23,8 @@ impl<'a> SomeTrait for &'a int { } fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box { - box v as Box + // FIXME(22450): workaround pretty-printer deficiency via parens. + (box v) as Box } fn main() { diff --git a/src/test/run-pass/regions-early-bound-trait-param.rs b/src/test/run-pass/regions-early-bound-trait-param.rs index 3f434a4838d42..94e0b76eacca5 100644 --- a/src/test/run-pass/regions-early-bound-trait-param.rs +++ b/src/test/run-pass/regions-early-bound-trait-param.rs @@ -81,7 +81,8 @@ impl<'s> Trait<'s> for (int,int) { } impl<'t> MakerTrait for Box+'static> { - fn mk() -> Box+'static> { box() (4,5) as Box } + // FIXME(22450): workaround pretty-printer deficiency via parens. + fn mk() -> Box+'static> { (box() (4,5)) as Box } } enum List<'l> { From a0e3c715a24db512a96e8d00a35ca1ea24f6fc2f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 17 Feb 2015 21:06:15 +0100 Subject: [PATCH 10/10] Workaround issue 22462 by moving static `value` into its own module. Precursor for overloaded-`box` and placement-`in`; see Issue 22181. --- src/test/run-pass/drop-struct-as-object.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/run-pass/drop-struct-as-object.rs b/src/test/run-pass/drop-struct-as-object.rs index 7a3b6df539f14..9429ffd3d69c8 100644 --- a/src/test/run-pass/drop-struct-as-object.rs +++ b/src/test/run-pass/drop-struct-as-object.rs @@ -14,7 +14,13 @@ #![allow(unknown_features)] #![feature(box_syntax)] -static mut value: uint = 0; +mod s { + // FIXME(22181,22462) workaround hygiene issues between box + // desugaring, macro-hygiene (or lack thereof) and static bindings + // by forcing the static binding `value` into its own module. + + pub static mut value: uint = 0; +} struct Cat { name : uint, @@ -30,7 +36,7 @@ impl Dummy for Cat { impl Drop for Cat { fn drop(&mut self) { - unsafe { value = self.name; } + unsafe { s::value = self.name; } } } @@ -40,6 +46,6 @@ pub fn main() { let nyan: Box = x as Box; } unsafe { - assert_eq!(value, 22); + assert_eq!(s::value, 22); } }