From bd26307411b336345bb5e5b3af3c2997b37fa65e Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 10 Apr 2015 04:11:21 -0700 Subject: [PATCH 1/3] Use the ecx.call_site() span for generating refs to format_args! internals `format_args!` uses `#[allow_internal_unstable]` to access internal functions and structs that are marked unstable. For this to work, the spans on AST nodes referencing unstable internals must be equal (same lo/hi values) to the `format_args!` call site, so that the stability checker can recognize that the AST node was generated by the macro. --- src/libsyntax/ext/format.rs | 44 +++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 513bbf6c77b..374f6fa5040 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -38,6 +38,10 @@ enum Position { struct Context<'a, 'b:'a> { ecx: &'a mut ExtCtxt<'b>, + /// The macro's call site. References to unstable formatting internals must + /// use this span to pass the stability checker. + macsp: Span, + /// The span of the format string literal. fmtsp: Span, /// Parsed argument expressions and the types that we've found so far for @@ -308,7 +312,7 @@ impl<'a, 'b> Context<'a, 'b> { } fn trans_count(&self, c: parse::Count) -> P { - let sp = self.fmtsp; + let sp = self.macsp; let count = |c, arg| { let mut path = Context::rtpath(self.ecx, "Count"); path.push(self.ecx.ident_of(c)); @@ -346,7 +350,7 @@ impl<'a, 'b> Context<'a, 'b> { /// Translate a `parse::Piece` to a static `rt::Argument` or append /// to the `literal` string. fn trans_piece(&mut self, piece: &parse::Piece) -> Option> { - let sp = self.fmtsp; + let sp = self.macsp; match *piece { parse::String(s) => { self.literal.push_str(s); @@ -442,22 +446,22 @@ impl<'a, 'b> Context<'a, 'b> { piece_ty: P, pieces: Vec>) -> P { - let fmtsp = piece_ty.span; - let ty = ecx.ty_rptr(fmtsp, - ecx.ty(fmtsp, ast::TyVec(piece_ty)), - Some(ecx.lifetime(fmtsp, special_idents::static_lifetime.name)), + let sp = piece_ty.span; + let ty = ecx.ty_rptr(sp, + ecx.ty(sp, ast::TyVec(piece_ty)), + Some(ecx.lifetime(sp, special_idents::static_lifetime.name)), ast::MutImmutable); - let slice = ecx.expr_vec_slice(fmtsp, pieces); + let slice = ecx.expr_vec_slice(sp, pieces); let st = ast::ItemStatic(ty, ast::MutImmutable, slice); let name = ecx.ident_of(name); - let item = ecx.item(fmtsp, name, vec![], st); - let decl = respan(fmtsp, ast::DeclItem(item)); + let item = ecx.item(sp, name, vec![], st); + let decl = respan(sp, ast::DeclItem(item)); // Wrap the declaration in a block so that it forms a single expression. - ecx.expr_block(ecx.block(fmtsp, - vec![P(respan(fmtsp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))], - Some(ecx.expr_ident(fmtsp, name)))) + ecx.expr_block(ecx.block(sp, + vec![P(respan(sp, ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID)))], + Some(ecx.expr_ident(sp, name)))) } /// Actually builds the expression which the iformat! block will be expanded @@ -497,7 +501,7 @@ impl<'a, 'b> Context<'a, 'b> { let name = self.ecx.ident_of(&format!("__arg{}", i)); pats.push(self.ecx.pat_ident(e.span, name)); - locals.push(Context::format_arg(self.ecx, e.span, arg_ty, + locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, self.ecx.expr_ident(e.span, name))); heads.push(self.ecx.expr_addr_of(e.span, e)); } @@ -515,7 +519,7 @@ impl<'a, 'b> Context<'a, 'b> { *name)); pats.push(self.ecx.pat_ident(e.span, lname)); names[*self.name_positions.get(name).unwrap()] = - Some(Context::format_arg(self.ecx, e.span, arg_ty, + Some(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, self.ecx.expr_ident(e.span, lname))); heads.push(self.ecx.expr_addr_of(e.span, e)); } @@ -566,7 +570,7 @@ impl<'a, 'b> Context<'a, 'b> { // Build up the static array which will store our precompiled // nonstandard placeholders, if there are any. let piece_ty = self.ecx.ty_path(self.ecx.path_global( - self.fmtsp, + self.macsp, Context::rtpath(self.ecx, "Argument"))); let fmt = Context::static_array(self.ecx, "__STATIC_FMTARGS", @@ -576,14 +580,14 @@ impl<'a, 'b> Context<'a, 'b> { ("new_v1_formatted", vec![pieces, args_slice, fmt]) }; - self.ecx.expr_call_global(self.fmtsp, vec!( + self.ecx.expr_call_global(self.macsp, vec!( self.ecx.ident_of_std("core"), self.ecx.ident_of("fmt"), self.ecx.ident_of("Arguments"), self.ecx.ident_of(fn_name)), fn_args) } - fn format_arg(ecx: &ExtCtxt, sp: Span, + fn format_arg(ecx: &ExtCtxt, macsp: Span, sp: Span, ty: &ArgumentType, arg: P) -> P { let trait_ = match *ty { @@ -607,7 +611,7 @@ impl<'a, 'b> Context<'a, 'b> { } } Unsigned => { - return ecx.expr_call_global(sp, vec![ + return ecx.expr_call_global(macsp, vec![ ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("ArgumentV1"), @@ -620,7 +624,7 @@ impl<'a, 'b> Context<'a, 'b> { ecx.ident_of("fmt"), ecx.ident_of(trait_), ecx.ident_of("fmt")]); - ecx.expr_call_global(sp, vec![ + ecx.expr_call_global(macsp, vec![ ecx.ident_of_std("core"), ecx.ident_of("fmt"), ecx.ident_of("ArgumentV1"), @@ -650,6 +654,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, names: HashMap>) -> P { let arg_types: Vec<_> = (0..args.len()).map(|_| None).collect(); + let macsp = ecx.call_site(); // Expand the format literal so that efmt.span will have a backtrace. This // is essential for locating a bug when the format literal is generated in // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")). @@ -668,6 +673,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, pieces: Vec::new(), str_pieces: Vec::new(), all_pieces_simple: true, + macsp: macsp, fmtsp: efmt.span, }; let fmt = match expr_to_string(cx.ecx, From 9cdc9e9c614089c294cb19837919fdc0653c2b14 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Wed, 1 Apr 2015 13:36:53 -0700 Subject: [PATCH 2/3] Destabilize format_args! internals. Arguments, Formatters, and the various format traits remain stable. The format_args! macro uses #[allow_internal_unstable] to allow it access to the unstable things in core::fmt. Destabilized things include a "v1" in their name: * core::fmt::rt * core::fmt::rt::v1 (the module and all contents) * core::fmt::ArgumentV1 * core::fmt::ArgumentV1::new * core::fmt::ArgumentV1::from_usize * core::fmt::Arguments::new_v1 * core::fmt::Arguments::new_v1_formatted The unstable message was copied from that of std::io::_print. --- src/libcore/fmt/mod.rs | 18 ++++++++++----- src/libcore/fmt/rt/v1.rs | 47 ++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 67781b73ae2..1c70f9941f7 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -38,7 +38,8 @@ mod num; mod float; mod builders; -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] +#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] #[doc(hidden)] pub mod rt { pub mod v1; @@ -134,7 +135,8 @@ enum Void {} /// compile time it is ensured that the function and the value have the correct /// types, and then this struct is used to canonicalize arguments to one type. #[derive(Copy)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] +#[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] #[doc(hidden)] pub struct ArgumentV1<'a> { value: &'a Void, @@ -154,7 +156,8 @@ impl<'a> ArgumentV1<'a> { } #[doc(hidden)] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> { unsafe { @@ -166,7 +169,8 @@ impl<'a> ArgumentV1<'a> { } #[doc(hidden)] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn from_usize(x: &usize) -> ArgumentV1 { ArgumentV1::new(x, ArgumentV1::show_usize) } @@ -189,7 +193,8 @@ impl<'a> Arguments<'a> { /// When using the format_args!() macro, this function is used to generate the /// Arguments structure. #[doc(hidden)] #[inline] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn new_v1(pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { Arguments { @@ -206,7 +211,8 @@ impl<'a> Arguments<'a> { /// created with `argumentusize`. However, failing to do so doesn't cause /// unsafety, but will ignore invalid . #[doc(hidden)] #[inline] - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] + #[cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] pub fn new_v1_formatted(pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument]) -> Arguments<'a> { diff --git a/src/libcore/fmt/rt/v1.rs b/src/libcore/fmt/rt/v1.rs index d56ec6a74d4..0d851c1e897 100644 --- a/src/libcore/fmt/rt/v1.rs +++ b/src/libcore/fmt/rt/v1.rs @@ -14,68 +14,69 @@ //! These definitions are similar to their `ct` equivalents, but differ in that //! these can be statically allocated and are slightly optimized for the runtime -#![stable(feature = "rust1", since = "1.0.0")] +#![cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] +#![cfg_attr(not(stage0), unstable(feature = "core", reason = "internal to format_args!"))] #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub struct Argument { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub position: Position, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub format: FormatSpec, } #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub struct FormatSpec { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub fill: char, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub align: Alignment, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub flags: u32, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub precision: Count, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub width: Count, } /// Possible alignments that can be requested as part of a formatting directive. #[derive(Copy, Clone, PartialEq)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub enum Alignment { /// Indication that contents should be left-aligned. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Left, /// Indication that contents should be right-aligned. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Right, /// Indication that contents should be center-aligned. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Center, /// No alignment was requested. - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Unknown, } #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub enum Count { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Is(usize), - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Param(usize), - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] NextParam, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Implied, } #[derive(Copy, Clone)] -#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] pub enum Position { - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] Next, - #[stable(feature = "rust1", since = "1.0.0")] + #[cfg_attr(stage0, stable(feature = "rust1", since = "1.0.0"))] At(usize) } From 861556390ea9035396ec37f8eb90570a2a804ec2 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 10 Apr 2015 06:01:04 -0700 Subject: [PATCH 3/3] Remove pretty-expanded from tests that use format_args! Now that the internals of `format_args!` are unstable, tests that use it don't compile after pretty-printing (unless they also declare the necessary feature). --- src/test/run-pass/c-stack-returning-int64.rs | 1 - src/test/run-pass/capturing-logging.rs | 1 - src/test/run-pass/clone-with-exterior.rs | 1 - src/test/run-pass/exponential-notation.rs | 1 - src/test/run-pass/float-nan.rs | 1 - src/test/run-pass/foreign-fn-linkname.rs | 1 - src/test/run-pass/issue-11881.rs | 1 - src/test/run-pass/issue-20676.rs | 1 - src/test/run-pass/item-attributes.rs | 1 - src/test/run-pass/rust-log-filter.rs | 1 - src/test/run-pass/task-comm-7.rs | 1 - src/test/run-pass/task-spawn-move-and-copy.rs | 1 - src/test/run-pass/variadic-ffi.rs | 1 - 13 files changed, 13 deletions(-) diff --git a/src/test/run-pass/c-stack-returning-int64.rs b/src/test/run-pass/c-stack-returning-int64.rs index dcf1b554006..d6b35f5385a 100644 --- a/src/test/run-pass/c-stack-returning-int64.rs +++ b/src/test/run-pass/c-stack-returning-int64.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc, std_misc)] diff --git a/src/test/run-pass/capturing-logging.rs b/src/test/run-pass/capturing-logging.rs index f9b429a935a..6c58194f857 100644 --- a/src/test/run-pass/capturing-logging.rs +++ b/src/test/run-pass/capturing-logging.rs @@ -10,7 +10,6 @@ // exec-env:RUST_LOG=info -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, old_io, rustc_private, std_misc)] diff --git a/src/test/run-pass/clone-with-exterior.rs b/src/test/run-pass/clone-with-exterior.rs index 16efceb9d7e..352733601f2 100644 --- a/src/test/run-pass/clone-with-exterior.rs +++ b/src/test/run-pass/clone-with-exterior.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, std_misc)] diff --git a/src/test/run-pass/exponential-notation.rs b/src/test/run-pass/exponential-notation.rs index 7e947c0be45..4d54bb4ef72 100644 --- a/src/test/run-pass/exponential-notation.rs +++ b/src/test/run-pass/exponential-notation.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(std_misc)] diff --git a/src/test/run-pass/float-nan.rs b/src/test/run-pass/float-nan.rs index b375f122082..298f2a4719d 100644 --- a/src/test/run-pass/float-nan.rs +++ b/src/test/run-pass/float-nan.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(std_misc)] diff --git a/src/test/run-pass/foreign-fn-linkname.rs b/src/test/run-pass/foreign-fn-linkname.rs index 5db83d50b61..a9001a3cdcf 100644 --- a/src/test/run-pass/foreign-fn-linkname.rs +++ b/src/test/run-pass/foreign-fn-linkname.rs @@ -9,7 +9,6 @@ // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(std_misc, libc)] diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs index 35c25b33a97..483ae02d2dc 100644 --- a/src/test/run-pass/issue-11881.rs +++ b/src/test/run-pass/issue-11881.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(rustc_private, old_io)] diff --git a/src/test/run-pass/issue-20676.rs b/src/test/run-pass/issue-20676.rs index df4c3923853..a3016227413 100644 --- a/src/test/run-pass/issue-20676.rs +++ b/src/test/run-pass/issue-20676.rs @@ -12,7 +12,6 @@ // UFCS-style calls to a method in `Trait` where `Self` was bound to a // trait object of type `Trait`. See also `ufcs-trait-object.rs`. -// pretty-expanded FIXME #23616 use std::fmt; diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index c2ed68fc5d4..f1ac96ab63e 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -12,7 +12,6 @@ // for completeness since .rs files linked from .rc files support this // notation to specify their module's attributes -// pretty-expanded FIXME #23616 #![feature(custom_attribute, libc)] #![allow(unused_attribute)] diff --git a/src/test/run-pass/rust-log-filter.rs b/src/test/run-pass/rust-log-filter.rs index 660b1e2036d..3517e4a29b8 100644 --- a/src/test/run-pass/rust-log-filter.rs +++ b/src/test/run-pass/rust-log-filter.rs @@ -10,7 +10,6 @@ // exec-env:RUST_LOG=rust_log_filter/foo -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, std_misc, rustc_private)] diff --git a/src/test/run-pass/task-comm-7.rs b/src/test/run-pass/task-comm-7.rs index b05e36552a2..a5282b1097e 100644 --- a/src/test/run-pass/task-comm-7.rs +++ b/src/test/run-pass/task-comm-7.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(std_misc)] #![allow(dead_assignment)] diff --git a/src/test/run-pass/task-spawn-move-and-copy.rs b/src/test/run-pass/task-spawn-move-and-copy.rs index aa7b61bf112..3f18c0c7464 100644 --- a/src/test/run-pass/task-spawn-move-and-copy.rs +++ b/src/test/run-pass/task-spawn-move-and-copy.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![allow(unknown_features)] #![feature(box_syntax, std_misc)] diff --git a/src/test/run-pass/variadic-ffi.rs b/src/test/run-pass/variadic-ffi.rs index d81dc3afcd7..fd70c0409fb 100644 --- a/src/test/run-pass/variadic-ffi.rs +++ b/src/test/run-pass/variadic-ffi.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 #![feature(libc, std_misc)]