From 8347450ee61dea57633351aa61586b3c6ee25ed8 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Fri, 14 Nov 2014 14:26:13 +0800 Subject: [PATCH 01/25] libstd: improve os::args() doc --- src/libstd/os.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 1402d3a355905..3bc2e5756ad23 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -1083,6 +1083,10 @@ extern "system" { /// Returns the arguments which this program was started with (normally passed /// via the command line). /// +/// The first element is traditionally the path to the executable, but it can be +/// set to arbitrary text, and it may not even exist, so this property should not +// be relied upon for security purposes. +/// /// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD. /// See `String::from_utf8_lossy` for details. /// # Example From 0f11eb547914f32dfcd04b1190a231d76876435a Mon Sep 17 00:00:00 2001 From: Dan Luu Date: Fri, 14 Nov 2014 22:16:25 -0600 Subject: [PATCH 02/25] Guide: add a pointer to play.rust-lang.org and explain how to run the code examples. --- src/doc/guide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/guide.md b/src/doc/guide.md index 473c30ab1c44e..8a82df97a5722 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -159,6 +159,8 @@ $ ./main # or main.exe on Windows Hello, world! ``` +You can also run these examples on [play.rust-lang.org](http://play.rust-lang.org/) by clicking on the arrow that appears in the upper right of the example when you mouse over the code. + Success! Let's go over what just happened in detail. ```{rust} From 2aa241d76f5168dc554583d2347e6c74e9a7d3bc Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Tue, 18 Nov 2014 15:14:34 +0100 Subject: [PATCH 03/25] Reference: Add missing third dot of range --- src/doc/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 171c39a4cbc39..62c80fff7e320 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3441,7 +3441,7 @@ use to avoid conflicts is simply to name variants with upper-case letters, and local variables with lower-case letters. Multiple match patterns may be joined with the `|` operator. A range of values -may be specified with `..`. For example: +may be specified with `...`. For example: ``` # let x = 2i; From 33f8a82c02fa73ba57ac7422e4342839c0228913 Mon Sep 17 00:00:00 2001 From: jxv Date: Tue, 18 Nov 2014 09:24:11 -0800 Subject: [PATCH 04/25] librustrt: check for mips+linux config in stack_overflow --- src/librustrt/stack_overflow.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustrt/stack_overflow.rs b/src/librustrt/stack_overflow.rs index d01b4a3a4b34c..10a3efbca1001 100644 --- a/src/librustrt/stack_overflow.rs +++ b/src/librustrt/stack_overflow.rs @@ -283,6 +283,7 @@ mod imp { #[cfg(any(all(target_os = "linux", target_arch = "x86"), // may not match all(target_os = "linux", target_arch = "x86_64"), all(target_os = "linux", target_arch = "arm"), // may not match + all(target_os = "linux", target_arch = "mips"), // may not match target_os = "android"))] // may not match mod signal { use libc; From 0e6d97aab2dac7cb35afa70436a82d30280921a3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 12 Nov 2014 11:33:28 -0500 Subject: [PATCH 05/25] New guide: error handling --- configure | 1 + mk/docs.mk | 2 +- src/doc/guide-error-handling.md | 2 ++ src/doc/index.md | 1 + src/doc/po4a.conf | 1 + 5 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 src/doc/guide-error-handling.md diff --git a/configure b/configure index 7790025301401..35bba159208f8 100755 --- a/configure +++ b/configure @@ -1031,6 +1031,7 @@ do make_dir $h/test/doc-guide-tasks make_dir $h/test/doc-guide-plugin make_dir $h/test/doc-guide-crates + make_dir $h/test/doc-guide-error-handling make_dir $h/test/doc-rust done diff --git a/mk/docs.mk b/mk/docs.mk index bc1e9ccf2ead5..48eb9e81c20a4 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -27,7 +27,7 @@ ###################################################################### DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \ guide-tasks guide-container guide-pointers guide-testing \ - guide-plugin guide-crates complement-bugreport \ + guide-plugin guide-crates complement-bugreport guide-error-handling \ complement-lang-faq complement-design-faq complement-project-faq \ rustdoc guide-unsafe guide-strings reference diff --git a/src/doc/guide-error-handling.md b/src/doc/guide-error-handling.md new file mode 100644 index 0000000000000..c175298bd3a55 --- /dev/null +++ b/src/doc/guide-error-handling.md @@ -0,0 +1,2 @@ +% Error Handling in Rust + diff --git a/src/doc/index.md b/src/doc/index.md index 8d54550a9f988..7d4d48e80a383 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -59,6 +59,7 @@ a guide that can help you out: * [References and Lifetimes](guide-lifetimes.html) * [Crates and modules](guide-crates.html) * [Tasks and Communication](guide-tasks.html) +* [Error Handling](guide-error-handling.html) * [Foreign Function Interface](guide-ffi.html) * [Writing Unsafe and Low-Level Code](guide-unsafe.html) * [Macros](guide-macros.html) diff --git a/src/doc/po4a.conf b/src/doc/po4a.conf index c0406d104fcf1..4fbb3c210165a 100644 --- a/src/doc/po4a.conf +++ b/src/doc/po4a.conf @@ -20,6 +20,7 @@ [type: text] src/doc/guide-testing.md $lang:doc/l10n/$lang/guide-testing.md [type: text] src/doc/guide-unsafe.md $lang:doc/l10n/$lang/guide-unsafe.md [type: text] src/doc/guide-crates.md $lang:doc/l10n/$lang/guide-crates.md +[type: text] src/doc/guide-error-handling.md $lang:doc/l10n/$lang/guide-error-handling.md [type: text] src/doc/guide.md $lang:doc/l10n/$lang/guide.md [type: text] src/doc/index.md $lang:doc/l10n/$lang/index.md [type: text] src/doc/intro.md $lang:doc/l10n/$lang/intro.md From bde225e2fafc7f593cfa5a9e1e6c750264682b71 Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Tue, 18 Nov 2014 17:39:16 +0100 Subject: [PATCH 06/25] Feature gate non-ASCII lifetime identifiers Fixes #19069. --- src/librustc/lint/builtin.rs | 2 +- src/librustc/lint/context.rs | 4 ++-- src/librustc/lint/mod.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc_back/svh.rs | 6 +++--- src/libsyntax/ast_map/mod.rs | 2 +- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/feature_gate.rs | 4 ++-- src/libsyntax/visit.rs | 26 ++++++++++++++++++------- src/test/compile-fail/utf8_idents.rs | 24 +++++++++++++++++++++++ 10 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 src/test/compile-fail/utf8_idents.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index df014eb1206aa..9ab45ff0f7abc 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -992,7 +992,7 @@ impl LintPass for NonSnakeCase { self.check_snake_case(cx, "trait method", t.ident, t.span); } - fn check_lifetime_decl(&mut self, cx: &Context, t: &ast::LifetimeDef) { + fn check_lifetime_def(&mut self, cx: &Context, t: &ast::LifetimeDef) { self.check_snake_case(cx, "lifetime", t.lifetime.name.ident(), t.lifetime.span); } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e9b235a2fe34b..52d1c72de68c1 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -725,8 +725,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { run_lints!(self, check_lifetime_ref, lt); } - fn visit_lifetime_decl(&mut self, lt: &ast::LifetimeDef) { - run_lints!(self, check_lifetime_decl, lt); + fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) { + run_lints!(self, check_lifetime_def, lt); } fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 315462235bebd..d6b83752cc50c 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -155,7 +155,7 @@ pub trait LintPass { fn check_variant_post(&mut self, _: &Context, _: &ast::Variant, _: &ast::Generics) { } fn check_opt_lifetime_ref(&mut self, _: &Context, _: Span, _: &Option) { } fn check_lifetime_ref(&mut self, _: &Context, _: &ast::Lifetime) { } - fn check_lifetime_decl(&mut self, _: &Context, _: &ast::LifetimeDef) { } + fn check_lifetime_def(&mut self, _: &Context, _: &ast::LifetimeDef) { } fn check_explicit_self(&mut self, _: &Context, _: &ast::ExplicitSelf) { } fn check_mac(&mut self, _: &Context, _: &ast::Mac) { } fn check_path(&mut self, _: &Context, _: &ast::Path, _: ast::NodeId) { } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a1257caf47ffa..3fc92a8419424 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -226,7 +226,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { self.with(LateScope(&trait_ref.bound_lifetimes, self.scope), |this| { this.check_lifetime_defs(&trait_ref.bound_lifetimes); for lifetime in trait_ref.bound_lifetimes.iter() { - this.visit_lifetime_decl(lifetime); + this.visit_lifetime_def(lifetime); } this.visit_trait_ref(&trait_ref.trait_ref) }) diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index c7a7888c1cd60..2cca63bd65d94 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -181,7 +181,7 @@ mod svh_visitor { SawStructDef(token::InternedString), SawLifetimeRef(token::InternedString), - SawLifetimeDecl(token::InternedString), + SawLifetimeDef(token::InternedString), SawMod, SawViewItem, @@ -414,8 +414,8 @@ mod svh_visitor { SawLifetimeRef(content(l.name)).hash(self.st); } - fn visit_lifetime_decl(&mut self, l: &LifetimeDef) { - SawLifetimeDecl(content(l.lifetime.name)).hash(self.st); + fn visit_lifetime_def(&mut self, l: &LifetimeDef) { + SawLifetimeDef(content(l.lifetime.name)).hash(self.st); } // We do recursively walk the bodies of functions/methods diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index b116c84552e6a..472331bc9e15d 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -866,7 +866,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { self.insert(lifetime.id, NodeLifetime(lifetime)); } - fn visit_lifetime_decl(&mut self, def: &'ast LifetimeDef) { + fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) { self.visit_lifetime_ref(&def.lifetime); } } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 30cdecbc85199..043e79bffd9e9 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -535,7 +535,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { self.operation.visit_id(lifetime.id); } - fn visit_lifetime_decl(&mut self, def: &'v LifetimeDef) { + fn visit_lifetime_def(&mut self, def: &'v LifetimeDef) { self.visit_lifetime_ref(&def.lifetime); } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index ebdcf27893402..460a94a8d5aaa 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -141,8 +141,8 @@ impl<'a> Context<'a> { } impl<'a, 'v> Visitor<'v> for Context<'a> { - fn visit_ident(&mut self, sp: Span, id: ast::Ident) { - if !token::get_ident(id).get().is_ascii() { + fn visit_name(&mut self, sp: Span, name: ast::Name) { + if !token::get_name(name).get().is_ascii() { self.gate_feature("non_ascii_idents", sp, "non-ascii idents are not fully supported."); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index efe1e18eda928..e98cc3b9c7190 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -55,8 +55,11 @@ pub enum FnKind<'a> { /// new default implementation gets introduced.) pub trait Visitor<'v> { - fn visit_ident(&mut self, _sp: Span, _ident: Ident) { - /*! Visit the idents */ + fn visit_name(&mut self, _span: Span, _name: Name) { + // Nothing to do. + } + fn visit_ident(&mut self, span: Span, ident: Ident) { + self.visit_name(span, ident.name); } fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } fn visit_view_item(&mut self, i: &'v ViewItem) { walk_view_item(self, i) } @@ -102,11 +105,11 @@ pub trait Visitor<'v> { None => () } } - fn visit_lifetime_ref(&mut self, _lifetime: &'v Lifetime) { - /*! Visits a reference to a lifetime */ + fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) { + self.visit_name(lifetime.span, lifetime.name) } - fn visit_lifetime_decl(&mut self, _lifetime: &'v LifetimeDef) { - /*! Visits a declaration of a lifetime */ + fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) { + walk_lifetime_def(self, lifetime) } fn visit_explicit_self(&mut self, es: &'v ExplicitSelf) { walk_explicit_self(self, es) @@ -207,6 +210,14 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { walk_expr_opt(visitor, &local.init); } +pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, + lifetime_def: &'v LifetimeDef) { + visitor.visit_lifetime_ref(&lifetime_def.lifetime); + for bound in lifetime_def.bounds.iter() { + visitor.visit_lifetime_ref(bound); + } +} + pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) { match explicit_self.node { @@ -424,7 +435,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { pub fn walk_lifetime_decls_helper<'v, V: Visitor<'v>>(visitor: &mut V, lifetimes: &'v Vec) { for l in lifetimes.iter() { - visitor.visit_lifetime_decl(l); + visitor.visit_lifetime_def(l); } } @@ -555,6 +566,7 @@ pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { for type_parameter in generics.ty_params.iter() { + visitor.visit_ident(type_parameter.span, type_parameter.ident); walk_ty_param_bounds_helper(visitor, &type_parameter.bounds); match type_parameter.default { Some(ref ty) => visitor.visit_ty(&**ty), diff --git a/src/test/compile-fail/utf8_idents.rs b/src/test/compile-fail/utf8_idents.rs new file mode 100644 index 0000000000000..0c3c11ccd07b3 --- /dev/null +++ b/src/test/compile-fail/utf8_idents.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// ignore-lexer-test FIXME #15679 + +fn foo< + 'β, //~ ERROR non-ascii idents are not fully supported. + γ //~ ERROR non-ascii idents are not fully supported. +>() {} + +struct X { + δ: uint //~ ERROR non-ascii idents are not fully supported. +} + +pub fn main() { + let α = 0.00001f64; //~ ERROR non-ascii idents are not fully supported. +} From ad61ff4b817f8581ea4c12f897f5e6baafe27952 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Tue, 18 Nov 2014 14:02:40 -0800 Subject: [PATCH 07/25] deriving: error out when used on a non-type Besides being more helpful, this gives us the flexibility to later define a meaning for something like #[deriving(...)] mod bar { ... } --- src/libsyntax/ext/deriving/generic/mod.rs | 7 ++-- src/test/compile-fail/deriving-non-type.rs | 40 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/deriving-non-type.rs diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index dccc12e406bdc..eec3805721a85 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -335,7 +335,7 @@ pub fn combine_substructure<'a>(f: CombineSubstructureFunc<'a>) impl<'a> TraitDef<'a> { pub fn expand(&self, cx: &mut ExtCtxt, - _mitem: &ast::MetaItem, + mitem: &ast::MetaItem, item: &ast::Item, push: |P|) { let newitem = match item.node { @@ -351,7 +351,10 @@ impl<'a> TraitDef<'a> { item.ident, generics) } - _ => return + _ => { + cx.span_err(mitem.span, "`deriving` may only be applied to structs and enums"); + return; + } }; // Keep the lint attributes of the previous item to control how the // generated implementations are linted diff --git a/src/test/compile-fail/deriving-non-type.rs b/src/test/compile-fail/deriving-non-type.rs new file mode 100644 index 0000000000000..8226bba42b0e1 --- /dev/null +++ b/src/test/compile-fail/deriving-non-type.rs @@ -0,0 +1,40 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +struct S; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +trait T { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +impl S { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +impl T for S { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +static s: uint = 0u; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +const c: uint = 0u; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +mod m { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +extern "C" { } + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +type A = uint; + +#[deriving(PartialEq)] //~ ERROR: `deriving` may only be applied to structs and enums +fn main() { } From 16b9f67bf3bed2313eb53a3d37e5d4def1d88838 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 12 Nov 2014 13:43:06 -0500 Subject: [PATCH 08/25] Error handling guide --- src/doc/guide-error-handling.md | 225 ++++++++++++++++++++++++++++++++ src/libcore/result.rs | 46 ------- 2 files changed, 225 insertions(+), 46 deletions(-) diff --git a/src/doc/guide-error-handling.md b/src/doc/guide-error-handling.md index c175298bd3a55..427ca4ba1a163 100644 --- a/src/doc/guide-error-handling.md +++ b/src/doc/guide-error-handling.md @@ -1,2 +1,227 @@ % Error Handling in Rust +> The best-laid plans of mice and men +> Often go awry +> +> "Tae a Moose", Robert Burns + +Sometimes, things just go wrong. It's important to have a plan for when the +inevitable happens. Rust has rich support for handling errors that may (let's +be honest: will) occur in your programs. + +There are two main kinds of errors that can occur in your programs: failures, +and panics. Let's talk about the difference between the two, and then discuss +how to handle each. Then, we'll discuss upgrading failures to panics. + +# Failure vs. Panic + +Rust uses two terms to differentiate between two forms of error: failure, and +panic. A **failure** is an error that can be recovered from in some way. A +**panic** is an error that cannot be recovered from. + +What do we mean by 'recover'? Well, in most cases, the possibility of an error +is expected. For example, consider the `from_str` function: + +```{rust,ignore} +from_str("5"); +``` + +This function takes a string argument and converts it into another type. But +because it's a string, you can't be sure that the conversion actually works. +For example, what should this convert to? + +```{rust,ignore} +from_str("hello5world"); +``` + +This won't work. So we know that this function will only work properly for some +inputs. It's expected behavior. We call this kind of error 'failure.' + +On the other hand, sometimes, there are errors that are unexpected, or which +we cannot recover from. A classic example is an `assert!`: + +```{rust,ignore} +assert!(x == 5); +``` + +We use `assert!` to declare that something is true. If it's not true, something +is very wrong. Wrong enough that we can't continue with things in the current +state. Another example is using the `unreachable!()` macro + +```{rust,ignore} +enum Event { + NewRelease, +} + +fn probability(_: &Event) -> f64 { + // real implementation would be more complex, of course + 0.95 +} + +fn descriptive_probability(event: Event) -> &'static str { + match probability(&event) { + 1.00 => "certain", + 0.00 => "impossible", + 0.00 ... 0.25 => "very unlikely", + 0.25 ... 0.50 => "unlikely", + 0.50 ... 0.75 => "likely", + 0.75 ... 1.00 => "very likely", + } +} + +fn main() { + std::io::println(descriptive_probability(NewRelease)); +} +``` + +This will give us an error: + +```{notrust,ignore} +error: non-exhaustive patterns: `_` not covered [E0004] +``` + +While we know that we've covered all possible cases, Rust can't tell. It +doesn't know that probability is between 0.0 and 1.0. So we add another case: + +```rust +enum Event { + NewRelease, +} + +fn probability(_: &Event) -> f64 { + // real implementation would be more complex, of course + 0.95 +} + +fn descriptive_probability(event: Event) -> &'static str { + match probability(&event) { + 1.00 => "certain", + 0.00 => "impossible", + 0.00 ... 0.25 => "very unlikely", + 0.25 ... 0.50 => "unlikely", + 0.50 ... 0.75 => "likely", + 0.75 ... 1.00 => "very likely", + _ => unreachable!() + } +} + +fn main() { + std::io::println(descriptive_probability(NewRelease)); +} +``` + +We shouldn't ever hit the `_` case, so we use the `unreachable!()` macro to +indicate this. `unreachable!()` gives a different kind of error than `Result`. +Rust calls these sorts of errors 'panics.' + +# Handling errors with `Option` and `Result` + +The simplest way to indicate that a function may fail is to use the `Option` +type. Remember our `from_str()` example? Here's its type signature: + +```{rust,ignore} +pub fn from_str(s: &str) -> Option +``` + +`from_str()` returns an `Option`. If the conversion succeeds, it will return +`Some(value)`, and if it fails, it will return `None`. + +This is appropriate for the simplest of cases, but doesn't give us a lot of +information in the failure case. What if we wanted to know _why_ the conversion +failed? For this, we can use the `Result` type. It looks like this: + +```rust +enum Result { + Ok(T), + Err(E) +} +``` + +This enum is provided by Rust itself, so you don't need to define it to use it +in your code. The `Ok(T)` variant represents a success, and the `Err(E)` variant +represents a failure. Returning a `Result` instead of an `Option` is recommended +for all but the most trivial of situations. + +Here's an example of using `Result`: + +```rust +#[deriving(Show)] +enum Version { Version1, Version2 } + +#[deriving(Show)] +enum ParseError { InvalidHeaderLength, InvalidVersion } + + +fn parse_version(header: &[u8]) -> Result { + if header.len() < 1 { + return Err(InvalidHeaderLength); + } + match header[0] { + 1 => Ok(Version1), + 2 => Ok(Version2), + _ => Err(InvalidVersion) + } +} + +let version = parse_version(&[1, 2, 3, 4]); +match version { + Ok(v) => { + println!("working with version: {}", v); + } + Err(e) => { + println!("error parsing header: {}", e); + } +} +``` + +This function makes use of an enum, `ParseError`, to enumerate the various +errors that can occur. + +# Non-recoverable errors with `panic!` + +In the case of an error that is unexpected and not recoverable, the `panic!` +macro will induce a panic. This will crash the current task, and give an error: + +```{rust,ignore} +panic!("boom"); +``` + +gives + +```{notrust,ignore} +task '
' panicked at 'boom', hello.rs:2 +``` + +when you run it. + +Because these kinds of situations are relatively rare, use panics sparingly. + +# Upgrading failures to panics + +In certain circumstances, even though a function may fail, we may want to treat +it as a panic instead. For example, `io::stdin().read_line()` returns an +`IoResult`, a form of `Result`, when there is an error reading the +line. This allows us to handle and possibly recover from this sort of error. + +If we don't want to handle this error, and would rather just abort the program, +we can use the `unwrap()` method: + +```{rust,ignore} +io::stdin().read_line().unwrap(); +``` + +`unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give +me the value, and if something goes wrong, just crash." This is less reliable +than matching the error and attempting to recover, but is also significantly +shorter. Sometimes, just crashing is appropriate. + +There's another way of doing this that's a bit nicer than `unwrap()`: + +```{rust,ignore} +let input = io::stdin().read_line() + .ok() + .expect("Failed to read line"); +``` +`ok()` converts the `IoResult` into an `Option`, and `expect()` does the same +thing as `unwrap()`, but takes a message. This message is passed along to the +underlying `panic!`, providing a better error message if the code errors. diff --git a/src/libcore/result.rs b/src/libcore/result.rs index e88b6b2cf03d8..e2f739457970f 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -227,52 +227,6 @@ //! ``` //! //! `try!` is imported by the prelude, and is available everywhere. -//! -//! # `Result` and `Option` -//! -//! The `Result` and [`Option`](../option/index.html) types are -//! similar and complementary: they are often employed to indicate a -//! lack of a return value; and they are trivially converted between -//! each other, so `Result`s are often handled by first converting to -//! `Option` with the [`ok`](type.Result.html#method.ok) and -//! [`err`](type.Result.html#method.ok) methods. -//! -//! Whereas `Option` only indicates the lack of a value, `Result` is -//! specifically for error reporting, and carries with it an error -//! value. Sometimes `Option` is used for indicating errors, but this -//! is only for simple cases and is generally discouraged. Even when -//! there is no useful error value to return, prefer `Result`. -//! -//! Converting to an `Option` with `ok()` to handle an error: -//! -//! ``` -//! use std::io::Timer; -//! let mut t = Timer::new().ok().expect("failed to create timer!"); -//! ``` -//! -//! # `Result` vs. `panic!` -//! -//! `Result` is for recoverable errors; `panic!` is for unrecoverable -//! errors. Callers should always be able to avoid panics if they -//! take the proper precautions, for example, calling `is_some()` -//! on an `Option` type before calling `unwrap`. -//! -//! The suitability of `panic!` as an error handling mechanism is -//! limited by Rust's lack of any way to "catch" and resume execution -//! from a thrown exception. Therefore using panics for error -//! handling requires encapsulating code that may panic in a task. -//! Calling the `panic!` macro, or invoking `panic!` indirectly should be -//! avoided as an error reporting strategy. Panics is only for -//! unrecoverable errors and a panicking task is typically the sign of -//! a bug. -//! -//! A module that instead returns `Results` is alerting the caller -//! that failure is possible, and providing precise control over how -//! it is handled. -//! -//! Furthermore, panics may not be recoverable at all, depending on -//! the context. The caller of `panic!` should assume that execution -//! will not resume after the panic, that a panic is catastrophic. #![stable] From 5b5638f6863803477d56e200d6a9a208015838c1 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 10:17:40 +1100 Subject: [PATCH 09/25] Switch to an independent enum for `Lit*` subtokens. --- src/grammar/verify.rs | 50 +++++++++++++++-------------- src/librustdoc/html/highlight.rs | 7 ++-- src/libsyntax/ast.rs | 2 +- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/ext/quote.rs | 37 ++++++++++----------- src/libsyntax/parse/lexer/mod.rs | 41 +++++++++++------------ src/libsyntax/parse/parser.rs | 28 ++++++++-------- src/libsyntax/parse/token.rs | 42 ++++++++++-------------- src/libsyntax/print/pprust.rs | 24 +++++++------- 9 files changed, 115 insertions(+), 118 deletions(-) diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 159a62f011072..84a288ef042d0 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -61,7 +61,7 @@ fn parse_token_list(file: &str) -> HashMap { "SHL" => token::BinOp(token::Shl), "LBRACE" => token::OpenDelim(token::Brace), "RARROW" => token::Rarrow, - "LIT_STR" => token::LitStr(Name(0)), + "LIT_STR" => token::Literal(token::Str_(Name(0))), "DOTDOT" => token::DotDot, "MOD_SEP" => token::ModSep, "DOTDOTDOT" => token::DotDotDot, @@ -71,7 +71,7 @@ fn parse_token_list(file: &str) -> HashMap { "ANDAND" => token::AndAnd, "AT" => token::At, "LBRACKET" => token::OpenDelim(token::Bracket), - "LIT_STR_RAW" => token::LitStrRaw(Name(0), 0), + "LIT_STR_RAW" => token::Literal(token::StrRaw(Name(0), 0)), "RPAREN" => token::CloseDelim(token::Paren), "SLASH" => token::BinOp(token::Slash), "COMMA" => token::Comma, @@ -80,8 +80,8 @@ fn parse_token_list(file: &str) -> HashMap { "TILDE" => token::Tilde, "IDENT" => token::Id(), "PLUS" => token::BinOp(token::Plus), - "LIT_CHAR" => token::LitChar(Name(0)), - "LIT_BYTE" => token::LitByte(Name(0)), + "LIT_CHAR" => token::Literal(token::Char(Name(0))), + "LIT_BYTE" => token::Literal(token::Byte(Name(0))), "EQ" => token::Eq, "RBRACKET" => token::CloseDelim(token::Bracket), "COMMENT" => token::Comment, @@ -95,9 +95,9 @@ fn parse_token_list(file: &str) -> HashMap { "BINOP" => token::BinOp(token::Plus), "POUND" => token::Pound, "OROR" => token::OrOr, - "LIT_INTEGER" => token::LitInteger(Name(0)), + "LIT_INTEGER" => token::Literal(token::Integer(Name(0))), "BINOPEQ" => token::BinOpEq(token::Plus), - "LIT_FLOAT" => token::LitFloat(Name(0)), + "LIT_FLOAT" => token::Literal(token::Float(Name(0))), "WHITESPACE" => token::Whitespace, "UNDERSCORE" => token::Underscore, "MINUS" => token::BinOp(token::Minus), @@ -107,8 +107,8 @@ fn parse_token_list(file: &str) -> HashMap { "OR" => token::BinOp(token::Or), "GT" => token::Gt, "LE" => token::Le, - "LIT_BINARY" => token::LitBinary(Name(0)), - "LIT_BINARY_RAW" => token::LitBinaryRaw(Name(0), 0), + "LIT_BINARY" => token::Literal(token::Binary(Name(0))), + "LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0)), _ => continue, }; @@ -189,15 +189,17 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAndSpan { token::BinOp(..) => token::BinOp(str_to_binop(content)), token::BinOpEq(..) => token::BinOpEq(str_to_binop(content.slice_to( content.len() - 1))), - token::LitStr(..) => token::LitStr(fix(content)), - token::LitStrRaw(..) => token::LitStrRaw(fix(content), count(content)), - token::LitChar(..) => token::LitChar(fixchar(content)), - token::LitByte(..) => token::LitByte(fixchar(content)), + token::Literal(token::Str_(..)) => token::Literal(token::Str_(fix(content))), + token::Literal(token::StrRaw(..)) => token::Literal(token::StrRaw(fix(content), + count(content))), + token::Literal(token::Char(..)) => token::Literal(token::Char(fixchar(content))), + token::Literal(token::Byte(..)) => token::Literal(token::Byte(fixchar(content))), token::DocComment(..) => token::DocComment(nm), - token::LitInteger(..) => token::LitInteger(nm), - token::LitFloat(..) => token::LitFloat(nm), - token::LitBinary(..) => token::LitBinary(nm), - token::LitBinaryRaw(..) => token::LitBinaryRaw(fix(content), count(content)), + token::Literal(token::Integer(..)) => token::Literal(token::Integer(nm)), + token::Literal(token::Float(..)) => token::Literal(token::Float(nm)), + token::Literal(token::Binary(..)) => token::Literal(token::Binary(nm)), + token::Literal(token::BinaryRaw(..)) => token::Literal(token::BinaryRaw(fix(content), + count(content))), token::Ident(..) => token::Ident(ast::Ident { name: nm, ctxt: 0 }, token::ModName), token::Lifetime(..) => token::Lifetime(ast::Ident { name: nm, ctxt: 0 }), @@ -284,14 +286,14 @@ fn main() { ) matches!( - LitByte(..), - LitChar(..), - LitInteger(..), - LitFloat(..), - LitStr(..), - LitStrRaw(..), - LitBinary(..), - LitBinaryRaw(..), + token::Literal(token::Byte(..)), + token::Literal(token::Char(..)), + token::Literal(token::Integer(..)), + token::Literal(token::Float(..)), + token::Literal(token::Str_(..)), + token::Literal(token::StrRaw(..)), + token::Literal(token::Binary(..)), + token::Literal(token::BinaryRaw(..)), Ident(..), Lifetime(..), Interpolated(..), diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index d445da9d1340d..527ef553d99e5 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -129,11 +129,12 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, } // text literals - token::LitByte(..) | token::LitBinary(..) | token::LitBinaryRaw(..) | - token::LitChar(..) | token::LitStr(..) | token::LitStrRaw(..) => "string", + token::Literal(token::Byte(..)) | token::Literal(token::Char(..)) | + token::Literal(token::Binary(..)) | token::Literal(token::BinaryRaw(..)) | + token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => "string", // number literals - token::LitInteger(..) | token::LitFloat(..) => "number", + token::Literal(token::Integer(..)) | token::Literal(token::Float(..)) => "number", // keywords are also included in the identifier set token::Ident(ident, _is_mod_sep) => { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 15e14902727f5..2158bdb416c7e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -838,7 +838,7 @@ impl TokenTree { tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::LitStr(name))], + TtToken(sp, token::Literal(token::Str_(name)))], close_span: sp, })) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index d077fbd7bf00f..b928fc778e8bc 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -87,7 +87,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, }, [ast::TtToken(_, token::Ident(ref code, _)), ast::TtToken(_, token::Comma), - ast::TtToken(_, token::LitStrRaw(description, _))] => { + ast::TtToken(_, token::Literal(token::StrRaw(description, _)))] => { (code, Some(description)) } _ => unreachable!() diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index ec69175707746..ec51ce00605fd 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -542,6 +542,13 @@ fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P { #[allow(non_upper_case_globals)] fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { + macro_rules! mk_lit { + ($name: expr, $($args: expr),*) => {{ + let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]); + + cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner]) + }} + } match *tok { token::BinOp(binop) => { return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop))); @@ -560,38 +567,32 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { vec![mk_delim(cx, sp, delim)]); } - token::LitByte(i) => { + token::Literal(token::Byte(i)) => { let e_byte = mk_name(cx, sp, i.ident()); - - return cx.expr_call(sp, mk_token_path(cx, sp, "LitByte"), vec!(e_byte)); + return mk_lit!("Byte", e_byte); } - token::LitChar(i) => { + token::Literal(token::Char(i)) => { let e_char = mk_name(cx, sp, i.ident()); - - return cx.expr_call(sp, mk_token_path(cx, sp, "LitChar"), vec!(e_char)); + return mk_lit!("Char", e_char); } - token::LitInteger(i) => { + token::Literal(token::Integer(i)) => { let e_int = mk_name(cx, sp, i.ident()); - return cx.expr_call(sp, mk_token_path(cx, sp, "LitInteger"), vec!(e_int)); + return mk_lit!("Integer", e_int); } - token::LitFloat(fident) => { + token::Literal(token::Float(fident)) => { let e_fident = mk_name(cx, sp, fident.ident()); - return cx.expr_call(sp, mk_token_path(cx, sp, "LitFloat"), vec!(e_fident)); + return mk_lit!("Float", e_fident); } - token::LitStr(ident) => { - return cx.expr_call(sp, - mk_token_path(cx, sp, "LitStr"), - vec!(mk_name(cx, sp, ident.ident()))); + token::Literal(token::Str_(ident)) => { + return mk_lit!("Str_", mk_name(cx, sp, ident.ident())) } - token::LitStrRaw(ident, n) => { - return cx.expr_call(sp, - mk_token_path(cx, sp, "LitStrRaw"), - vec!(mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n))); + token::Literal(token::StrRaw(ident, n)) => { + return mk_lit!("StrRaw", mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n)) } token::Ident(ident, style) => { diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 01a66243a965f..b7598c7c42820 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -655,17 +655,17 @@ impl<'a> StringReader<'a> { } 'u' | 'i' => { self.scan_int_suffix(); - return token::LitInteger(self.name_from(start_bpos)); + return token::Literal(token::Integer(self.name_from(start_bpos))); }, 'f' => { let last_pos = self.last_pos; self.scan_float_suffix(); self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } _ => { // just a 0 - return token::LitInteger(self.name_from(start_bpos)); + return token::Literal(token::Integer(self.name_from(start_bpos))); } } } else if c.is_digit_radix(10) { @@ -678,7 +678,7 @@ impl<'a> StringReader<'a> { self.err_span_(start_bpos, self.last_pos, "no valid digits found for number"); // eat any suffix self.scan_int_suffix(); - return token::LitInteger(token::intern("0")); + return token::Literal(token::Integer(token::intern("0"))); } // might be a float, but don't be greedy if this is actually an @@ -696,13 +696,13 @@ impl<'a> StringReader<'a> { } let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } else if self.curr_is('f') { // or it might be an integer literal suffixed as a float self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } else { // it might be a float if it has an exponent if self.curr_is('e') || self.curr_is('E') { @@ -710,11 +710,11 @@ impl<'a> StringReader<'a> { self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::LitFloat(self.name_from(start_bpos)); + return token::Literal(token::Float(self.name_from(start_bpos))); } // but we certainly have an integer! self.scan_int_suffix(); - return token::LitInteger(self.name_from(start_bpos)); + return token::Literal(token::Integer(self.name_from(start_bpos))); } } @@ -1126,7 +1126,7 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("0") }; self.bump(); // advance curr past token - return token::LitChar(id); + return token::Literal(token::Char(id)); } 'b' => { self.bump(); @@ -1157,7 +1157,7 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start_bpos + BytePos(1)) } else { token::intern("??") }; self.bump(); - return token::LitStr(id); + return token::Literal(token::Str_(id)); } 'r' => { let start_bpos = self.last_pos; @@ -1224,7 +1224,7 @@ impl<'a> StringReader<'a> { } else { token::intern("??") }; - return token::LitStrRaw(id, hash_count); + return token::Literal(token::StrRaw(id, hash_count)); } '-' => { if self.nextch_is('>') { @@ -1314,7 +1314,7 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); // advance curr past token - return token::LitByte(id); + return token::Literal(token::Byte(id)); } fn scan_byte_string(&mut self) -> token::Token { @@ -1336,7 +1336,7 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); - return token::LitBinary(id); + return token::Literal(token::Binary(id)); } fn scan_raw_byte_string(&mut self) -> token::Token { @@ -1387,8 +1387,9 @@ impl<'a> StringReader<'a> { self.bump(); } self.bump(); - return token::LitBinaryRaw(self.name_from_to(content_start_bpos, content_end_bpos), - hash_count); + return token::Literal(token::BinaryRaw(self.name_from_to(content_start_bpos, + content_end_bpos), + hash_count)); } } @@ -1535,17 +1536,17 @@ mod test { #[test] fn character_a() { assert_eq!(setup(&mk_sh(), "'a'".to_string()).next_token().tok, - token::LitChar(token::intern("a"))); + token::Literal(token::Char(token::intern("a")))); } #[test] fn character_space() { assert_eq!(setup(&mk_sh(), "' '".to_string()).next_token().tok, - token::LitChar(token::intern(" "))); + token::Literal(token::Char(token::intern(" ")))); } #[test] fn character_escaped() { assert_eq!(setup(&mk_sh(), "'\\n'".to_string()).next_token().tok, - token::LitChar(token::intern("\\n"))); + token::Literal(token::Char(token::intern("\\n")))); } #[test] fn lifetime_name() { @@ -1557,7 +1558,7 @@ mod test { assert_eq!(setup(&mk_sh(), "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token() .tok, - token::LitStrRaw(token::intern("\"#a\\b\x00c\""), 3)); + token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3))); } #[test] fn line_doc_comments() { @@ -1573,7 +1574,7 @@ mod test { token::Comment => { }, _ => panic!("expected a comment!") } - assert_eq!(lexer.next_token().tok, token::LitChar(token::intern("a"))); + assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")))); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 40c4ac9f8c044..4edcb182e5385 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1640,23 +1640,23 @@ impl<'a> Parser<'a> { /// Matches token_lit = LIT_INTEGER | ... pub fn lit_from_token(&mut self, tok: &token::Token) -> Lit_ { match *tok { - token::LitByte(i) => LitByte(parse::byte_lit(i.as_str()).val0()), - token::LitChar(i) => LitChar(parse::char_lit(i.as_str()).val0()), - token::LitInteger(s) => parse::integer_lit(s.as_str(), + token::Literal(token::Byte(i)) => LitByte(parse::byte_lit(i.as_str()).val0()), + token::Literal(token::Char(i)) => LitChar(parse::char_lit(i.as_str()).val0()), + token::Literal(token::Integer(s)) => parse::integer_lit(s.as_str(), &self.sess.span_diagnostic, self.last_span), - token::LitFloat(s) => parse::float_lit(s.as_str()), - token::LitStr(s) => { + token::Literal(token::Float(s)) => parse::float_lit(s.as_str()), + token::Literal(token::Str_(s)) => { LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), ast::CookedStr) } - token::LitStrRaw(s, n) => { + token::Literal(token::StrRaw(s, n)) => { LitStr(token::intern_and_get_ident(parse::raw_str_lit(s.as_str()).as_slice()), ast::RawStr(n)) } - token::LitBinary(i) => + token::Literal(token::Binary(i)) => LitBinary(parse::binary_lit(i.as_str())), - token::LitBinaryRaw(i, _) => + token::Literal(token::BinaryRaw(i, _)) => LitBinary(Rc::new(i.as_str().as_bytes().iter().map(|&x| x).collect())), _ => { self.unexpected_last(tok); } } @@ -2424,7 +2424,7 @@ impl<'a> Parser<'a> { } } } - token::LitInteger(n) => { + token::Literal(token::Integer(n)) => { let index = n.as_str(); let dot = self.last_span.hi; hi = self.span.hi; @@ -2449,7 +2449,7 @@ impl<'a> Parser<'a> { } } } - token::LitFloat(n) => { + token::Literal(token::Float(n)) => { self.bump(); let last_span = self.last_span; let fstr = n.as_str(); @@ -5085,7 +5085,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi); (path, the_ident) }, - token::LitStr(..) | token::LitStrRaw(..) => { + token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => { let path = self.parse_str(); self.expect_keyword(keywords::As); let the_ident = self.parse_ident(); @@ -5267,7 +5267,7 @@ impl<'a> Parser<'a> { /// the `extern` keyword, if one is found. fn parse_opt_abi(&mut self) -> Option { match self.token { - token::LitStr(s) | token::LitStrRaw(s, _) => { + token::Literal(token::Str_(s)) | token::Literal(token::StrRaw(s, _)) => { self.bump(); let the_string = s.as_str(); match abi::lookup(the_string) { @@ -5904,8 +5904,8 @@ impl<'a> Parser<'a> { pub fn parse_optional_str(&mut self) -> Option<(InternedString, ast::StrStyle)> { let (s, style) = match self.token { - token::LitStr(s) => (self.id_to_interned_str(s.ident()), ast::CookedStr), - token::LitStrRaw(s, n) => { + token::Literal(token::Str_(s)) => (self.id_to_interned_str(s.ident()), ast::CookedStr), + token::Literal(token::StrRaw(s, n)) => { (self.id_to_interned_str(s.ident()), ast::RawStr(n)) } _ => return None diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 298328d73efb0..bfa6ca798b233 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -12,6 +12,7 @@ pub use self::BinOpToken::*; pub use self::Nonterminal::*; pub use self::DelimToken::*; pub use self::IdentStyle::*; +pub use self::Lit::*; pub use self::Token::*; use ast; @@ -59,6 +60,18 @@ pub enum IdentStyle { Plain, } +#[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] +pub enum Lit { + Byte(ast::Name), + Char(ast::Name), + Integer(ast::Name), + Float(ast::Name), + Str_(ast::Name), + StrRaw(ast::Name, uint), /* raw str delimited by n hash symbols */ + Binary(ast::Name), + BinaryRaw(ast::Name, uint), /* raw binary str delimited by n hash symbols */ +} + #[allow(non_camel_case_types)] #[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum Token { @@ -98,14 +111,7 @@ pub enum Token { CloseDelim(DelimToken), /* Literals */ - LitByte(ast::Name), - LitChar(ast::Name), - LitInteger(ast::Name), - LitFloat(ast::Name), - LitStr(ast::Name), - LitStrRaw(ast::Name, uint), /* raw str delimited by n hash symbols */ - LitBinary(ast::Name), - LitBinaryRaw(ast::Name, uint), /* raw binary str delimited by n hash symbols */ + Literal(Lit), /* Name components */ Ident(ast::Ident, IdentStyle), @@ -145,14 +151,7 @@ impl Token { Ident(_, _) => true, Underscore => true, Tilde => true, - LitByte(_) => true, - LitChar(_) => true, - LitInteger(_) => true, - LitFloat(_) => true, - LitStr(_) => true, - LitStrRaw(_, _) => true, - LitBinary(_) => true, - LitBinaryRaw(_, _) => true, + Literal(_) => true, Pound => true, At => true, Not => true, @@ -173,15 +172,8 @@ impl Token { /// Returns `true` if the token is any literal pub fn is_lit(&self) -> bool { match *self { - LitByte(_) => true, - LitChar(_) => true, - LitInteger(_) => true, - LitFloat(_) => true, - LitStr(_) => true, - LitStrRaw(_, _) => true, - LitBinary(_) => true, - LitBinaryRaw(_, _) => true, - _ => false, + Literal(_) => true, + _ => false, } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e6e0c33a42dbd..7997c1ba4efcf 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -236,18 +236,18 @@ pub fn token_to_string(tok: &Token) -> String { token::Question => "?".into_string(), /* Literals */ - token::LitByte(b) => format!("b'{}'", b.as_str()), - token::LitChar(c) => format!("'{}'", c.as_str()), - token::LitFloat(c) => c.as_str().into_string(), - token::LitInteger(c) => c.as_str().into_string(), - token::LitStr(s) => format!("\"{}\"", s.as_str()), - token::LitStrRaw(s, n) => format!("r{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), - token::LitBinary(v) => format!("b\"{}\"", v.as_str()), - token::LitBinaryRaw(s, n) => format!("br{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), + token::Literal(token::Byte(b)) => format!("b'{}'", b.as_str()), + token::Literal(token::Char(c)) => format!("'{}'", c.as_str()), + token::Literal(token::Float(c)) => c.as_str().into_string(), + token::Literal(token::Integer(c)) => c.as_str().into_string(), + token::Literal(token::Str_(s)) => format!("\"{}\"", s.as_str()), + token::Literal(token::StrRaw(s, n)) => format!("r{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), + token::Literal(token::Binary(v)) => format!("b\"{}\"", v.as_str()), + token::Literal(token::BinaryRaw(s, n)) => format!("br{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), /* Name components */ token::Ident(s, _) => token::get_ident(s).get().into_string(), From 9d20a46799178df9d2fb28dfec95ba55cbfb7f9c Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 12:52:44 +1100 Subject: [PATCH 10/25] Update src/grammar for language changes. --- src/grammar/verify.rs | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs index 84a288ef042d0..e3ff20f7874bf 100644 --- a/src/grammar/verify.rs +++ b/src/grammar/verify.rs @@ -26,21 +26,21 @@ use std::io::File; use syntax::parse; use syntax::parse::lexer; -use rustc::driver::{session, config}; +use rustc::session::{mod, config}; use syntax::ast; use syntax::ast::Name; use syntax::parse::token; use syntax::parse::lexer::TokenAndSpan; -fn parse_token_list(file: &str) -> HashMap { - fn id() -> Token { +fn parse_token_list(file: &str) -> HashMap { + fn id() -> token::Token { token::Ident(ast::Ident { name: Name(0), ctxt: 0, }, token::Plain) } let mut res = HashMap::new(); - res.insert("-1".to_string(), EOF); + res.insert("-1".to_string(), token::Eof); for line in file.split('\n') { let eq = match line.trim().rfind('=') { @@ -60,7 +60,7 @@ fn parse_token_list(file: &str) -> HashMap { "INT_SUFFIX" => id(), "SHL" => token::BinOp(token::Shl), "LBRACE" => token::OpenDelim(token::Brace), - "RARROW" => token::Rarrow, + "RARROW" => token::RArrow, "LIT_STR" => token::Literal(token::Str_(Name(0))), "DOTDOT" => token::DotDot, "MOD_SEP" => token::ModSep, @@ -78,7 +78,7 @@ fn parse_token_list(file: &str) -> HashMap { "LIFETIME" => token::Lifetime(ast::Ident { name: Name(0), ctxt: 0 }), "CARET" => token::BinOp(token::Caret), "TILDE" => token::Tilde, - "IDENT" => token::Id(), + "IDENT" => id(), "PLUS" => token::BinOp(token::Plus), "LIT_CHAR" => token::Literal(token::Char(Name(0))), "LIT_BYTE" => token::Literal(token::Byte(Name(0))), @@ -119,7 +119,7 @@ fn parse_token_list(file: &str) -> HashMap { res } -fn str_to_binop(s: &str) -> BinOpToken { +fn str_to_binop(s: &str) -> token::BinOpToken { match s { "+" => token::Plus, "/" => token::Slash, @@ -167,7 +167,7 @@ fn count(lit: &str) -> uint { lit.chars().take_while(|c| *c == '#').count() } -fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAndSpan { +fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAndSpan { let re = regex!( r"\[@(?P\d+),(?P\d+):(?P\d+)='(?P.+?)',<(?P-?\d+)>,\d+:\d+]" ); @@ -178,7 +178,7 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAndSpan { let toknum = m.name("toknum"); let content = m.name("content"); - let proto_tok = tokens.get(&toknum).expect(format!("didn't find token {} in the map", + let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map", toknum).as_slice()); let nm = parse::token::intern(content); @@ -206,7 +206,8 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAndSpan { ref t => t.clone() }; - let offset = if real_tok == EOF { + let offset = if real_tok == token::Eof + { 1 } else { 0 @@ -224,7 +225,7 @@ fn parse_antlr_token(s: &str, tokens: &HashMap) -> TokenAndSpan { } } -fn tok_cmp(a: &Token, b: &Token) -> bool { +fn tok_cmp(a: &token::Token, b: &token::Token) -> bool { match a { &token::Ident(id, _) => match b { &token::Ident(id2, _) => id == id2, @@ -242,17 +243,17 @@ fn main() { let args = std::os::args(); - let mut token_file = File::open(&Path::new(args.get(2).as_slice())); + let mut token_file = File::open(&Path::new(args[2].as_slice())); let token_map = parse_token_list(token_file.read_to_string().unwrap().as_slice()); let mut stdin = std::io::stdin(); let mut antlr_tokens = stdin.lines().map(|l| parse_antlr_token(l.unwrap().as_slice().trim(), &token_map)); - let code = File::open(&Path::new(args.get(1).as_slice())).unwrap().read_to_string().unwrap(); + let code = File::open(&Path::new(args[1].as_slice())).unwrap().read_to_string().unwrap(); let options = config::basic_options(); let session = session::build_session(options, None, - syntax::diagnostics::registry::Registry::new([])); + syntax::diagnostics::registry::Registry::new(&[])); let filemap = parse::string_to_filemap(&session.parse_sess, code, String::from_str("")); @@ -260,7 +261,7 @@ fn main() { for antlr_tok in antlr_tokens { let rustc_tok = next(&mut lexer); - if rustc_tok.tok == EOF && antlr_tok.tok == EOF { + if rustc_tok.tok == token::Eof && antlr_tok.tok == token::Eof { continue } @@ -294,11 +295,11 @@ fn main() { token::Literal(token::StrRaw(..)), token::Literal(token::Binary(..)), token::Literal(token::BinaryRaw(..)), - Ident(..), - Lifetime(..), - Interpolated(..), - DocComment(..), - Shebang(..) + token::Ident(..), + token::Lifetime(..), + token::Interpolated(..), + token::DocComment(..), + token::Shebang(..) ); } } From ff0278bc152c5e3072434615cf9861e98a160e71 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 13:11:24 +1100 Subject: [PATCH 11/25] Update makefiles to ensure src/grammar/verify.rs is built. It's not run, but this ensures that the code at least doesn't go out of date. --- mk/grammar.mk | 16 ++++++++++++---- mk/tests.mk | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/mk/grammar.mk b/mk/grammar.mk index 12190fb034854..a9f45907b8110 100644 --- a/mk/grammar.mk +++ b/mk/grammar.mk @@ -30,17 +30,25 @@ endef $(BG): $(Q)mkdir -p $(BG) -$(BG)RustLexer.class: $(SG)RustLexer.g4 +$(BG)RustLexer.class: $(BG) $(SG)RustLexer.g4 $(Q)$(CFG_ANTLR4) -o $(B)grammar $(SG)RustLexer.g4 $(Q)$(CFG_JAVAC) -d $(BG) $(BG)RustLexer.java -$(BG)verify: $(SG)verify.rs rustc-stage2-H-$(CFG_BUILD) $(LD)stamp.regex_macros $(LD)stamp.rustc - $(Q)$(RUSTC) -O --out-dir $(BG) -L $(L) $(SG)verify.rs +check-build-lexer-verifier: $(BG)verify + +ifeq ($(NO_REBUILD),) +VERIFY_DEPS := rustc-stage2-H-$(CFG_BUILD) $(LD)stamp.regex_macros $(LD)stamp.rustc +else +VERIFY_DEPS := +endif + +$(BG)verify: $(BG) $(SG)verify.rs $(VERIFY_DEPS) + $(Q)$(RUSTC) --out-dir $(BG) -L $(L) $(SG)verify.rs ifdef CFG_JAVAC ifdef CFG_ANTLR4 ifdef CFG_GRUN -check-lexer: $(BG) $(BG)RustLexer.class $(BG)verify +check-lexer: $(BG) $(BG)RustLexer.class check-build-lexer-verifier $(info Verifying libsyntax against the reference lexer ...) $(Q)$(SG)check.sh $(S) "$(BG)" \ "$(CFG_GRUN)" "$(BG)verify" "$(BG)RustLexer.tokens" diff --git a/mk/tests.mk b/mk/tests.mk index 4433d780dedf6..63a34e0f01007 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -199,7 +199,7 @@ check-docs: cleantestlibs cleantmptestlogs check-stage2-docs # Some less critical tests that are not prone to breakage. # Not run as part of the normal test suite, but tested by bors on checkin. -check-secondary: check-build-compiletest check-lexer check-pretty +check-secondary: check-build-compiletest check-build-lexer-verifier check-lexer check-pretty # check + check-secondary. # From 4af3494bb02e80badc978faa65e59625ade0c675 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 17 Nov 2014 11:29:38 -0800 Subject: [PATCH 12/25] std: Stabilize std::fmt This commit applies the stabilization of std::fmt as outlined in [RFC 380][rfc]. There are a number of breaking changes as a part of this commit which will need to be handled to migrated old code: * A number of formatting traits have been removed: String, Bool, Char, Unsigned, Signed, and Float. It is recommended to instead use Show wherever possible or to use adaptor structs to implement other methods of formatting. * The format specifier for Boolean has changed from `t` to `b`. * The enum `FormatError` has been renamed to `Error` as well as becoming a unit struct instead of an enum. The `WriteError` variant no longer exists. * The `format_args_method!` macro has been removed with no replacement. Alter code to use the `format_args!` macro instead. * The public fields of a `Formatter` have become read-only with no replacement. Use a new formatting string to alter the formatting flags in combination with the `write!` macro. The fields can be accessed through accessor methods on the `Formatter` structure. Other than these breaking changes, the contents of std::fmt should now also all contain stability markers. Most of them are still #[unstable] or #[experimental] [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0380-stabilize-std-fmt.md [breaking-change] Closes #18904 --- src/libcore/fmt/mod.rs | 149 ++++++++---------- src/libcore/fmt/num.rs | 5 +- src/libcore/fmt/rt.rs | 2 + src/libcore/macros.rs | 15 +- src/libcoretest/fmt/num.rs | 81 +++++----- src/libflate/lib.rs | 2 +- src/libgraphviz/lib.rs | 4 +- src/liblog/lib.rs | 7 - src/librand/lib.rs | 2 +- src/librustc/middle/borrowck/mod.rs | 2 +- src/librustc/middle/cfg/graphviz.rs | 2 +- src/librustc/middle/check_match.rs | 3 +- src/librustc/middle/dataflow.rs | 30 ++-- src/librustc/middle/graph.rs | 4 +- src/librustc/middle/ty.rs | 5 + src/librustc/middle/typeck/variance.rs | 2 +- src/librustc_trans/back/write.rs | 2 +- src/librustc_trans/driver/mod.rs | 10 +- src/librustc_trans/driver/pretty.rs | 4 +- src/librustc_trans/trans/base.rs | 2 +- src/librustc_trans/trans/cleanup.rs | 2 +- src/librustdoc/html/item_type.rs | 6 - src/librustdoc/html/render.rs | 10 +- src/librustdoc/lib.rs | 4 +- src/libserialize/json.rs | 2 +- src/libstd/fmt.rs | 39 ++--- src/libstd/io/mod.rs | 12 +- src/libstd/macros.rs | 8 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/base.rs | 3 - src/libsyntax/ext/deriving/generic/mod.rs | 2 +- src/libsyntax/ext/format.rs | 22 +-- src/libsyntax/ext/mtwt.rs | 2 +- src/libterm/terminfo/parm.rs | 4 +- src/libtest/lib.rs | 4 +- src/libtime/lib.rs | 38 ++--- src/test/bench/core-set.rs | 2 +- src/test/bench/noise.rs | 2 +- src/test/bench/shootout-k-nucleotide-pipes.rs | 2 +- src/test/bench/shootout-k-nucleotide.rs | 2 +- src/test/bench/shootout-nbody.rs | 4 +- src/test/bench/shootout-spectralnorm.rs | 2 +- src/test/compile-fail/ifmt-bad-arg.rs | 4 +- src/test/compile-fail/ifmt-unimpl.rs | 4 +- src/test/compile-fail/issue-1448-2.rs | 2 +- src/test/compile-fail/issue-14853.rs | 11 +- src/test/run-pass/ifmt.rs | 100 ++++++------ src/test/run-pass/realloc-16687.rs | 10 +- 48 files changed, 291 insertions(+), 347 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 1efb595610155..be8828b3ec833 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -12,8 +12,6 @@ #![allow(unused_variables)] -pub use self::FormatError::*; - use any; use cell::{Cell, Ref, RefMut}; use iter::{Iterator, range}; @@ -23,10 +21,9 @@ use option::{Option, Some, None}; use ops::Deref; use result::{Ok, Err}; use result; -use slice::{AsSlice, SlicePrelude}; +use slice::SlicePrelude; use slice; use str::StrPrelude; -use str; pub use self::num::radix; pub use self::num::Radix; @@ -36,18 +33,16 @@ mod num; mod float; pub mod rt; -pub type Result = result::Result<(), FormatError>; +#[experimental = "core and I/O reconciliation may alter this definition"] +pub type Result = result::Result<(), Error>; /// The error type which is returned from formatting a message into a stream. /// /// This type does not support transmission of an error other than that an error /// occurred. Any extra information must be arranged to be transmitted through /// some other means. -pub enum FormatError { - /// A generic write error occurred during formatting, no other information - /// is transmitted via this variant. - WriteError, -} +#[experimental = "core and I/O reconciliation may alter this definition"] +pub struct Error; /// A collection of methods that are required to format a message into a stream. /// @@ -58,6 +53,7 @@ pub enum FormatError { /// This trait should generally not be implemented by consumers of the standard /// library. The `write!` macro accepts an instance of `io::Writer`, and the /// `io::Writer` trait is favored over implementing this trait. +#[experimental = "waiting for core and I/O reconciliation"] pub trait FormatWriter { /// Writes a slice of bytes into this writer, returning whether the write /// succeeded. @@ -81,17 +77,13 @@ pub trait FormatWriter { /// A struct to represent both where to emit formatting strings to and how they /// should be formatted. A mutable version of this is passed to all formatting /// traits. +#[unstable = "name may change and implemented traits are also unstable"] pub struct Formatter<'a> { - /// Flags for formatting (packed version of rt::Flag) - pub flags: uint, - /// Character used as 'fill' whenever there is alignment - pub fill: char, - /// Boolean indication of whether the output should be left-aligned - pub align: rt::Alignment, - /// Optionally specified integer width that the output should be - pub width: Option, - /// Optionally specified precision for numeric types - pub precision: Option, + flags: uint, + fill: char, + align: rt::Alignment, + width: Option, + precision: Option, buf: &'a mut FormatWriter+'a, curarg: slice::Items<'a, Argument<'a>>, @@ -104,6 +96,7 @@ enum Void {} /// family of functions. It contains a function to format the given value. At /// 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. +#[experimental = "implementation detail of the `format_args!` macro"] pub struct Argument<'a> { formatter: extern "Rust" fn(&Void, &mut Formatter) -> Result, value: &'a Void, @@ -115,6 +108,7 @@ impl<'a> Arguments<'a> { /// which is valid because the compiler performs all necessary validation to /// ensure that the resulting call to format/write would be safe. #[doc(hidden)] #[inline] + #[experimental = "implementation detail of the `format_args!` macro"] pub unsafe fn new<'a>(pieces: &'static [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> { Arguments { @@ -128,6 +122,7 @@ impl<'a> Arguments<'a> { /// The `pieces` array must be at least as long as `fmt` to construct /// a valid Arguments structure. #[doc(hidden)] #[inline] + #[experimental = "implementation detail of the `format_args!` macro"] pub unsafe fn with_placeholders<'a>(pieces: &'static [&'static str], fmt: &'static [rt::Argument<'static>], args: &'a [Argument<'a>]) -> Arguments<'a> { @@ -148,6 +143,7 @@ impl<'a> Arguments<'a> { /// and pass it to a function or closure, passed as the first argument. The /// macro validates the format string at compile-time so usage of the `write` /// and `format` functions can be safely performed. +#[stable] pub struct Arguments<'a> { // Format string pieces to print. pieces: &'a [&'a str], @@ -169,84 +165,57 @@ impl<'a> Show for Arguments<'a> { /// When a format is not otherwise specified, types are formatted by ascribing /// to this trait. There is not an explicit way of selecting this trait to be /// used for formatting, it is only if no other format is specified. +#[unstable = "I/O and core have yet to be reconciled"] pub trait Show for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `b` character -pub trait Bool for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - -/// Format trait for the `c` character -pub trait Char for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - -/// Format trait for the `i` and `d` characters -pub trait Signed for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - -/// Format trait for the `u` character -pub trait Unsigned for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} /// Format trait for the `o` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait Octal for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `t` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait Binary for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `x` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait LowerHex for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `X` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait UpperHex for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `s` character -pub trait String for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - /// Format trait for the `p` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait Pointer for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } -/// Format trait for the `f` character -pub trait Float for Sized? { - /// Formats the value using the given formatter. - fn fmt(&self, &mut Formatter) -> Result; -} - /// Format trait for the `e` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait LowerExp for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; } /// Format trait for the `E` character +#[unstable = "I/O and core have yet to be reconciled"] pub trait UpperExp for Sized? { /// Formats the value using the given formatter. fn fmt(&self, &mut Formatter) -> Result; @@ -271,6 +240,8 @@ static DEFAULT_ARGUMENT: rt::Argument<'static> = rt::Argument { /// /// * output - the buffer to write output to /// * args - the precompiled arguments generated by `format_args!` +#[experimental = "libcore and I/O have yet to be reconciled, and this is an \ + implementation detail which should not otherwise be exported"] pub fn write(output: &mut FormatWriter, args: &Arguments) -> Result { let mut formatter = Formatter { flags: 0, @@ -368,6 +339,7 @@ impl<'a> Formatter<'a> { /// /// This function will correctly account for the flags provided as well as /// the minimum width. It will not take precision into account. + #[unstable = "definition may change slightly over time"] pub fn pad_integral(&mut self, is_positive: bool, prefix: &str, @@ -440,6 +412,7 @@ impl<'a> Formatter<'a> { /// is longer than this length /// /// Notably this function ignored the `flag` parameters + #[unstable = "definition may change slightly over time"] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front if self.width.is_none() && self.precision.is_none() { @@ -516,19 +489,48 @@ impl<'a> Formatter<'a> { /// Writes some data to the underlying buffer contained within this /// formatter. + #[unstable = "reconciling core and I/O may alter this definition"] pub fn write(&mut self, data: &[u8]) -> Result { self.buf.write(data) } /// Writes some formatted information into this instance + #[unstable = "reconciling core and I/O may alter this definition"] pub fn write_fmt(&mut self, fmt: &Arguments) -> Result { write(self.buf, fmt) } + + /// Flags for formatting (packed version of rt::Flag) + #[experimental = "return type may change and method was just created"] + pub fn flags(&self) -> uint { self.flags } + + /// Character used as 'fill' whenever there is alignment + #[unstable = "method was just created"] + pub fn fill(&self) -> char { self.fill } + + /// Flag indicating what form of alignment was requested + #[unstable = "method was just created"] + pub fn align(&self) -> rt::Alignment { self.align } + + /// Optionally specified integer width that the output should be + #[unstable = "method was just created"] + pub fn width(&self) -> Option { self.width } + + /// Optionally specified precision for numeric types + #[unstable = "method was just created"] + pub fn precision(&self) -> Option { self.precision } +} + +impl Show for Error { + fn fmt(&self, f: &mut Formatter) -> Result { + "an error occurred when formatting an argument".fmt(f) + } } /// This is a function which calls are emitted to by the compiler itself to /// create the Argument structures that are passed into the `format` function. #[doc(hidden)] #[inline] +#[experimental = "implementation detail of the `format_args!` macro"] pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result, t: &'a T) -> Argument<'a> { unsafe { @@ -542,15 +544,17 @@ pub fn argument<'a, T>(f: extern "Rust" fn(&T, &mut Formatter) -> Result, /// When the compiler determines that the type of an argument *must* be a string /// (such as for select), then it invokes this method. #[doc(hidden)] #[inline] +#[experimental = "implementation detail of the `format_args!` macro"] pub fn argumentstr<'a>(s: &'a &str) -> Argument<'a> { - argument(String::fmt, s) + argument(Show::fmt, s) } /// When the compiler determines that the type of an argument *must* be a uint /// (such as for plural), then it invokes this method. #[doc(hidden)] #[inline] +#[experimental = "implementation detail of the `format_args!` macro"] pub fn argumentuint<'a>(s: &'a uint) -> Argument<'a> { - argument(Unsigned::fmt, s) + argument(Show::fmt, s) } // Implementations of the core formatting traits @@ -565,32 +569,26 @@ impl<'a> Show for &'a Show+'a { fn fmt(&self, f: &mut Formatter) -> Result { (*self).fmt(f) } } -impl Bool for bool { - fn fmt(&self, f: &mut Formatter) -> Result { - String::fmt(if *self { "true" } else { "false" }, f) - } -} - -impl String for T { +impl Show for bool { fn fmt(&self, f: &mut Formatter) -> Result { - f.pad(self.as_slice()) + Show::fmt(if *self { "true" } else { "false" }, f) } } -impl String for str { +impl Show for str { fn fmt(&self, f: &mut Formatter) -> Result { f.pad(self) } } -impl Char for char { +impl Show for char { fn fmt(&self, f: &mut Formatter) -> Result { use char::Char; let mut utf8 = [0u8, ..4]; let amt = self.encode_utf8(&mut utf8).unwrap_or(0); let s: &str = unsafe { mem::transmute(utf8[..amt]) }; - String::fmt(s, f) + Show::fmt(s, f) } } @@ -620,7 +618,7 @@ impl<'a, T> Pointer for &'a mut T { } macro_rules! floating(($ty:ident) => { - impl Float for $ty { + impl Show for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { use num::Float; @@ -688,19 +686,6 @@ floating!(f64) // Implementation of Show for various core types -macro_rules! delegate(($ty:ty to $other:ident) => { - impl Show for $ty { - fn fmt(&self, f: &mut Formatter) -> Result { - $other::fmt(self, f) - } - } -}) -delegate!(str to String) -delegate!(bool to Bool) -delegate!(char to Char) -delegate!(f32 to Float) -delegate!(f64 to Float) - impl Show for *const T { fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) } } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 0a5af56217c8d..1c856a6e20870 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -109,6 +109,7 @@ radix!(UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x, /// A radix with in the range of `2..36`. #[deriving(Clone, PartialEq)] +#[unstable = "may be renamed or move to a different module"] pub struct Radix { base: u8, } @@ -132,6 +133,7 @@ impl GenericRadix for Radix { } /// A helper type for formatting radixes. +#[unstable = "may be renamed or move to a different module"] pub struct RadixFmt(T, R); /// Constructs a radix formatter in the range of `2..36`. @@ -142,6 +144,7 @@ pub struct RadixFmt(T, R); /// use std::fmt::radix; /// assert_eq!(format!("{}", radix(55i, 36)), "1j".to_string()); /// ``` +#[unstable = "may be renamed or move to a different module"] pub fn radix(x: T, base: u8) -> RadixFmt { RadixFmt(x, Radix::new(base)) } @@ -167,7 +170,6 @@ macro_rules! int_base { macro_rules! integer { ($Int:ident, $Uint:ident) => { int_base!(Show for $Int as $Int -> Decimal) - int_base!(Signed for $Int as $Int -> Decimal) int_base!(Binary for $Int as $Uint -> Binary) int_base!(Octal for $Int as $Uint -> Octal) int_base!(LowerHex for $Int as $Uint -> LowerHex) @@ -175,7 +177,6 @@ macro_rules! integer { radix_fmt!($Int as $Int, fmt_int) int_base!(Show for $Uint as $Uint -> Decimal) - int_base!(Unsigned for $Uint as $Uint -> Decimal) int_base!(Binary for $Uint as $Uint -> Binary) int_base!(Octal for $Uint as $Uint -> Octal) int_base!(LowerHex for $Uint as $Uint -> LowerHex) diff --git a/src/libcore/fmt/rt.rs b/src/libcore/fmt/rt.rs index 0e8504e7ee57c..145e78dc668ee 100644 --- a/src/libcore/fmt/rt.rs +++ b/src/libcore/fmt/rt.rs @@ -14,6 +14,8 @@ //! These definitions are similar to their `ct` equivalents, but differ in that //! these can be statically allocated and are slightly optimized for the runtime +#![experimental = "implementation detail of the `format_args!` macro"] + pub use self::Alignment::*; pub use self::Count::*; pub use self::Position::*; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 9ba67bb2e47dc..9016f40b1b834 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -108,7 +108,10 @@ macro_rules! try( /// Writing a formatted string into a writer #[macro_export] macro_rules! write( - ($dst:expr, $($arg:tt)*) => (format_args_method!($dst, write_fmt, $($arg)*)) + ($dst:expr, $($arg:tt)*) => ({ + let dst = &mut *$dst; + format_args!(|args| { dst.write_fmt(args) }, $($arg)*) + }) ) /// Writing a formatted string plus a newline into a writer @@ -119,15 +122,5 @@ macro_rules! writeln( ) ) -/// Write some formatted data into a stream. -/// -/// Identical to the macro in `std::macros` -#[macro_export] -macro_rules! write( - ($dst:expr, $($arg:tt)*) => ({ - format_args_method!($dst, write_fmt, $($arg)*) - }) -) - #[macro_export] macro_rules! unreachable( () => (panic!("unreachable code")) ) diff --git a/src/libcoretest/fmt/num.rs b/src/libcoretest/fmt/num.rs index 868e14b928a40..3b43d6ad33b44 100644 --- a/src/libcoretest/fmt/num.rs +++ b/src/libcoretest/fmt/num.rs @@ -21,16 +21,16 @@ fn test_format_int() { assert!(format!("{}", 1i16).as_slice() == "1"); assert!(format!("{}", 1i32).as_slice() == "1"); assert!(format!("{}", 1i64).as_slice() == "1"); - assert!(format!("{:d}", -1i).as_slice() == "-1"); - assert!(format!("{:d}", -1i8).as_slice() == "-1"); - assert!(format!("{:d}", -1i16).as_slice() == "-1"); - assert!(format!("{:d}", -1i32).as_slice() == "-1"); - assert!(format!("{:d}", -1i64).as_slice() == "-1"); - assert!(format!("{:t}", 1i).as_slice() == "1"); - assert!(format!("{:t}", 1i8).as_slice() == "1"); - assert!(format!("{:t}", 1i16).as_slice() == "1"); - assert!(format!("{:t}", 1i32).as_slice() == "1"); - assert!(format!("{:t}", 1i64).as_slice() == "1"); + assert!(format!("{}", -1i).as_slice() == "-1"); + assert!(format!("{}", -1i8).as_slice() == "-1"); + assert!(format!("{}", -1i16).as_slice() == "-1"); + assert!(format!("{}", -1i32).as_slice() == "-1"); + assert!(format!("{}", -1i64).as_slice() == "-1"); + assert!(format!("{:b}", 1i).as_slice() == "1"); + assert!(format!("{:b}", 1i8).as_slice() == "1"); + assert!(format!("{:b}", 1i16).as_slice() == "1"); + assert!(format!("{:b}", 1i32).as_slice() == "1"); + assert!(format!("{:b}", 1i64).as_slice() == "1"); assert!(format!("{:x}", 1i).as_slice() == "1"); assert!(format!("{:x}", 1i8).as_slice() == "1"); assert!(format!("{:x}", 1i16).as_slice() == "1"); @@ -52,16 +52,11 @@ fn test_format_int() { assert!(format!("{}", 1u16).as_slice() == "1"); assert!(format!("{}", 1u32).as_slice() == "1"); assert!(format!("{}", 1u64).as_slice() == "1"); - assert!(format!("{:u}", 1u).as_slice() == "1"); - assert!(format!("{:u}", 1u8).as_slice() == "1"); - assert!(format!("{:u}", 1u16).as_slice() == "1"); - assert!(format!("{:u}", 1u32).as_slice() == "1"); - assert!(format!("{:u}", 1u64).as_slice() == "1"); - assert!(format!("{:t}", 1u).as_slice() == "1"); - assert!(format!("{:t}", 1u8).as_slice() == "1"); - assert!(format!("{:t}", 1u16).as_slice() == "1"); - assert!(format!("{:t}", 1u32).as_slice() == "1"); - assert!(format!("{:t}", 1u64).as_slice() == "1"); + assert!(format!("{:b}", 1u).as_slice() == "1"); + assert!(format!("{:b}", 1u8).as_slice() == "1"); + assert!(format!("{:b}", 1u16).as_slice() == "1"); + assert!(format!("{:b}", 1u32).as_slice() == "1"); + assert!(format!("{:b}", 1u64).as_slice() == "1"); assert!(format!("{:x}", 1u).as_slice() == "1"); assert!(format!("{:x}", 1u8).as_slice() == "1"); assert!(format!("{:x}", 1u16).as_slice() == "1"); @@ -79,9 +74,9 @@ fn test_format_int() { assert!(format!("{:o}", 1u64).as_slice() == "1"); // Test a larger number - assert!(format!("{:t}", 55i).as_slice() == "110111"); + assert!(format!("{:b}", 55i).as_slice() == "110111"); assert!(format!("{:o}", 55i).as_slice() == "67"); - assert!(format!("{:d}", 55i).as_slice() == "55"); + assert!(format!("{}", 55i).as_slice() == "55"); assert!(format!("{:x}", 55i).as_slice() == "37"); assert!(format!("{:X}", 55i).as_slice() == "37"); } @@ -89,15 +84,13 @@ fn test_format_int() { #[test] fn test_format_int_zero() { assert!(format!("{}", 0i).as_slice() == "0"); - assert!(format!("{:d}", 0i).as_slice() == "0"); - assert!(format!("{:t}", 0i).as_slice() == "0"); + assert!(format!("{:b}", 0i).as_slice() == "0"); assert!(format!("{:o}", 0i).as_slice() == "0"); assert!(format!("{:x}", 0i).as_slice() == "0"); assert!(format!("{:X}", 0i).as_slice() == "0"); assert!(format!("{}", 0u).as_slice() == "0"); - assert!(format!("{:u}", 0u).as_slice() == "0"); - assert!(format!("{:t}", 0u).as_slice() == "0"); + assert!(format!("{:b}", 0u).as_slice() == "0"); assert!(format!("{:o}", 0u).as_slice() == "0"); assert!(format!("{:x}", 0u).as_slice() == "0"); assert!(format!("{:X}", 0u).as_slice() == "0"); @@ -105,11 +98,11 @@ fn test_format_int_zero() { #[test] fn test_format_int_flags() { - assert!(format!("{:3d}", 1i).as_slice() == " 1"); - assert!(format!("{:>3d}", 1i).as_slice() == " 1"); - assert!(format!("{:>+3d}", 1i).as_slice() == " +1"); - assert!(format!("{:<3d}", 1i).as_slice() == "1 "); - assert!(format!("{:#d}", 1i).as_slice() == "1"); + assert!(format!("{:3}", 1i).as_slice() == " 1"); + assert!(format!("{:>3}", 1i).as_slice() == " 1"); + assert!(format!("{:>+3}", 1i).as_slice() == " +1"); + assert!(format!("{:<3}", 1i).as_slice() == "1 "); + assert!(format!("{:#}", 1i).as_slice() == "1"); assert!(format!("{:#x}", 10i).as_slice() == "0xa"); assert!(format!("{:#X}", 10i).as_slice() == "0xA"); assert!(format!("{:#5x}", 10i).as_slice() == " 0xa"); @@ -119,25 +112,25 @@ fn test_format_int_flags() { assert!(format!("{:<8x}", 10i).as_slice() == "a "); assert!(format!("{:>8x}", 10i).as_slice() == " a"); assert!(format!("{:#08x}", 10i).as_slice() == "0x00000a"); - assert!(format!("{:08d}", -10i).as_slice() == "-0000010"); + assert!(format!("{:08}", -10i).as_slice() == "-0000010"); assert!(format!("{:x}", -1u8).as_slice() == "ff"); assert!(format!("{:X}", -1u8).as_slice() == "FF"); - assert!(format!("{:t}", -1u8).as_slice() == "11111111"); + assert!(format!("{:b}", -1u8).as_slice() == "11111111"); assert!(format!("{:o}", -1u8).as_slice() == "377"); assert!(format!("{:#x}", -1u8).as_slice() == "0xff"); assert!(format!("{:#X}", -1u8).as_slice() == "0xFF"); - assert!(format!("{:#t}", -1u8).as_slice() == "0b11111111"); + assert!(format!("{:#b}", -1u8).as_slice() == "0b11111111"); assert!(format!("{:#o}", -1u8).as_slice() == "0o377"); } #[test] fn test_format_int_sign_padding() { - assert!(format!("{:+5d}", 1i).as_slice() == " +1"); - assert!(format!("{:+5d}", -1i).as_slice() == " -1"); - assert!(format!("{:05d}", 1i).as_slice() == "00001"); - assert!(format!("{:05d}", -1i).as_slice() == "-0001"); - assert!(format!("{:+05d}", 1i).as_slice() == "+0001"); - assert!(format!("{:+05d}", -1i).as_slice() == "-0001"); + assert!(format!("{:+5}", 1i).as_slice() == " +1"); + assert!(format!("{:+5}", -1i).as_slice() == " -1"); + assert!(format!("{:05}", 1i).as_slice() == "00001"); + assert!(format!("{:05}", -1i).as_slice() == "-0001"); + assert!(format!("{:+05}", 1i).as_slice() == "+0001"); + assert!(format!("{:+05}", -1i).as_slice() == "-0001"); } #[test] @@ -169,7 +162,7 @@ mod uint { #[bench] fn format_bin(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:t}", rng.gen::()); }) + b.iter(|| { format!("{:b}", rng.gen::()); }) } #[bench] @@ -181,7 +174,7 @@ mod uint { #[bench] fn format_dec(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:u}", rng.gen::()); }) + b.iter(|| { format!("{}", rng.gen::()); }) } #[bench] @@ -205,7 +198,7 @@ mod int { #[bench] fn format_bin(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:t}", rng.gen::()); }) + b.iter(|| { format!("{:b}", rng.gen::()); }) } #[bench] @@ -217,7 +210,7 @@ mod int { #[bench] fn format_dec(b: &mut Bencher) { let mut rng = weak_rng(); - b.iter(|| { format!("{:d}", rng.gen::()); }) + b.iter(|| { format!("{}", rng.gen::()); }) } #[bench] diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index e5bd81cb81607..568210118a8ae 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -130,7 +130,7 @@ mod tests { input.len()); let cmp = deflate_bytes(input.as_slice()).expect("deflation failed"); let out = inflate_bytes(cmp.as_slice()).expect("inflation failed"); - debug!("{} bytes deflated to {} ({:.1f}% size)", + debug!("{} bytes deflated to {} ({:.1}% size)", input.len(), cmp.len(), 100.0 * ((cmp.len() as f64) / (input.len() as f64))); assert_eq!(input.as_slice(), out.as_slice()); diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index cd9ef215720f8..df8cdabbcaa43 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -221,7 +221,7 @@ pub fn render_to(output: &mut W) { impl<'a> dot::Labeller<'a, Nd<'a>, Ed<'a>> for Graph { fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3").unwrap() } fn node_id(&'a self, n: &Nd<'a>) -> dot::Id<'a> { - dot::Id::new(format!("N{:u}", n.val0())).unwrap() + dot::Id::new(format!("N{}", n.val0())).unwrap() } fn node_label<'a>(&'a self, n: &Nd<'a>) -> dot::LabelText<'a> { let &(i, _) = n; @@ -635,7 +635,7 @@ mod tests { } fn id_name<'a>(n: &Node) -> Id<'a> { - Id::new(format!("N{:u}", *n)).unwrap() + Id::new(format!("N{}", *n)).unwrap() } impl<'a> Labeller<'a, Node, &'a Edge> for LabelledGraph { diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 2e60ce31d5e5e..fd2d97d4deb5c 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -241,13 +241,6 @@ impl fmt::Show for LogLevel { } } -impl fmt::Signed for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - write!(fmt, "{}", level) - } -} - impl Logger for DefaultLogger { fn log(&mut self, record: &LogRecord) { match writeln!(&mut self.handle, diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 117cca1b8b572..d6a68dd07d76c 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -237,7 +237,7 @@ pub trait Rng { /// use std::rand::{task_rng, Rng}; /// /// let mut rng = task_rng(); - /// println!("{:b}", rng.gen_weighted_bool(3)); + /// println!("{}", rng.gen_weighted_bool(3)); /// ``` fn gen_weighted_bool(&mut self, n: uint) -> bool { n == 0 || self.gen_range(0, n) == 0 diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index d7925177c29db..62032beaacd80 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -102,7 +102,7 @@ pub fn check_crate(tcx: &ty::ctxt) { fn make_stat(bccx: &BorrowckCtxt, stat: uint) -> String { let total = bccx.stats.guaranteed_paths as f64; let perc = if total == 0.0 { 0.0 } else { stat as f64 * 100.0 / total }; - format!("{} ({:.0f}%)", stat, perc) + format!("{} ({:.0}%)", stat, perc) } } diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs index 78b3a1179ca59..ba6dd2a5107a6 100644 --- a/src/librustc/middle/cfg/graphviz.rs +++ b/src/librustc/middle/cfg/graphviz.rs @@ -53,7 +53,7 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> { fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(self.name.as_slice()).unwrap() } fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> { - dot::Id::new(format!("N{:u}", i.node_id())).unwrap() + dot::Id::new(format!("N{}", i.node_id())).unwrap() } fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index c733084e9818a..6881f75ac18b0 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -81,8 +81,7 @@ impl<'a> fmt::Show for Matrix<'a> { try!(write!(f, "+")); for (column, pat_str) in row.into_iter().enumerate() { try!(write!(f, " ")); - f.width = Some(column_widths[column]); - try!(f.pad(pat_str.as_slice())); + try!(write!(f, "{:1$}", pat_str, column_widths[column])); try!(write!(f, " +")); } try!(write!(f, "\n")); diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 366f4bd024998..141504cb6f7d5 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS; let num_nodes = cfg.graph.all_nodes().len(); - debug!("DataFlowContext::new(analysis_name: {:s}, id_range={}, \ + debug!("DataFlowContext::new(analysis_name: {}, id_range={}, \ bits_per_id={}, words_per_id={}) \ num_nodes: {}", analysis_name, id_range, bits_per_id, words_per_id, @@ -223,7 +223,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { pub fn add_gen(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` generates `bit` - debug!("{:s} add_gen(id={}, bit={})", + debug!("{} add_gen(id={}, bit={})", self.analysis_name, id, bit); assert!(self.nodeid_to_index.contains_key(&id)); assert!(self.bits_per_id > 0); @@ -236,7 +236,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { pub fn add_kill(&mut self, id: ast::NodeId, bit: uint) { //! Indicates that `id` kills `bit` - debug!("{:s} add_kill(id={}, bit={})", + debug!("{} add_kill(id={}, bit={})", self.analysis_name, id, bit); assert!(self.nodeid_to_index.contains_key(&id)); assert!(self.bits_per_id > 0); @@ -249,7 +249,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { fn apply_gen_kill(&self, cfgidx: CFGIndex, bits: &mut [uint]) { //! Applies the gen and kill sets for `cfgidx` to `bits` - debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [before]", + debug!("{} apply_gen_kill(cfgidx={}, bits={}) [before]", self.analysis_name, cfgidx, mut_bits_to_string(bits)); assert!(self.bits_per_id > 0); @@ -259,7 +259,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let kills = self.kills.slice(start, end); bitwise(bits, kills, &Subtract); - debug!("{:s} apply_gen_kill(cfgidx={}, bits={}) [after]", + debug!("{} apply_gen_kill(cfgidx={}, bits={}) [after]", self.analysis_name, cfgidx, mut_bits_to_string(bits)); } @@ -316,7 +316,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { temp_bits.as_slice() } }; - debug!("{:s} each_bit_for_node({}, cfgidx={}) bits={}", + debug!("{} each_bit_for_node({}, cfgidx={}) bits={}", self.analysis_name, e, cfgidx, bits_to_string(slice)); self.each_bit(slice, f) } @@ -337,7 +337,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { let cfgidx = to_cfgidx_or_die(id, &self.nodeid_to_index); let (start, end) = self.compute_id_range(cfgidx); let gens = self.gens.slice(start, end); - debug!("{:s} each_gen_bit(id={}, gens={})", + debug!("{} each_gen_bit(id={}, gens={})", self.analysis_name, id, bits_to_string(gens)); self.each_bit(gens, f) } @@ -385,7 +385,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { //! This is usually called (if it is called at all), after //! all add_gen and add_kill calls, but before propagate. - debug!("{:s} add_kills_from_flow_exits", self.analysis_name); + debug!("{} add_kills_from_flow_exits", self.analysis_name); if self.bits_per_id == 0 { // Skip the surprisingly common degenerate case. (Note // compute_id_range requires self.words_per_id > 0.) @@ -408,7 +408,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { } } None => { - debug!("{:s} add_kills_from_flow_exits flow_exit={} \ + debug!("{} add_kills_from_flow_exits flow_exit={} \ no cfg_idx for exiting_scope={}", self.analysis_name, flow_exit, node_id); } @@ -417,10 +417,10 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { if changed { let bits = self.kills.slice_mut(start, end); - debug!("{:s} add_kills_from_flow_exits flow_exit={} bits={} [before]", + debug!("{} add_kills_from_flow_exits flow_exit={} bits={} [before]", self.analysis_name, flow_exit, mut_bits_to_string(bits)); bits.clone_from_slice(orig_kills.as_slice()); - debug!("{:s} add_kills_from_flow_exits flow_exit={} bits={} [after]", + debug!("{} add_kills_from_flow_exits flow_exit={} bits={} [after]", self.analysis_name, flow_exit, mut_bits_to_string(bits)); } true @@ -453,7 +453,7 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { } } - debug!("Dataflow result for {:s}:", self.analysis_name); + debug!("Dataflow result for {}:", self.analysis_name); debug!("{}", { self.pretty_print_to(box io::stderr(), blk).unwrap(); "" @@ -474,7 +474,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { fn walk_cfg(&mut self, cfg: &cfg::CFG, in_out: &mut [uint]) { - debug!("DataFlowContext::walk_cfg(in_out={}) {:s}", + debug!("DataFlowContext::walk_cfg(in_out={}) {}", bits_to_string(in_out), self.dfcx.analysis_name); assert!(self.dfcx.bits_per_id > 0); @@ -519,7 +519,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { edge: &cfg::CFGEdge) { let source = edge.source(); let cfgidx = edge.target(); - debug!("{:s} propagate_bits_into_entry_set_for(pred_bits={}, {} to {})", + debug!("{} propagate_bits_into_entry_set_for(pred_bits={}, {} to {})", self.dfcx.analysis_name, bits_to_string(pred_bits), source, cfgidx); assert!(self.dfcx.bits_per_id > 0); @@ -530,7 +530,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { bitwise(on_entry, pred_bits, &self.dfcx.oper) }; if changed { - debug!("{:s} changed entry set for {} to {}", + debug!("{} changed entry set for {} to {}", self.dfcx.analysis_name, cfgidx, bits_to_string(self.dfcx.on_entry.slice(start, end))); self.changed = true; diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index d2a7ec1e186e1..ac132477b8772 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -36,7 +36,7 @@ be indexed by the direction (see the type `Direction`). #![allow(dead_code)] // still WIP -use std::fmt::{Formatter, FormatError, Show}; +use std::fmt::{Formatter, Error, Show}; use std::uint; pub struct Graph { @@ -57,7 +57,7 @@ pub struct Edge { } impl Show for Edge { - fn fmt(&self, f: &mut Formatter) -> Result<(), FormatError> { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!(f, "Edge {{ next_edge: [{}, {}], source: {}, target: {}, data: {} }}", self.next_edge[0], self.next_edge[1], self.source, self.target, self.data) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 9f90afa37490c..70567f52c06f8 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2678,9 +2678,14 @@ impl ops::Sub for TypeContents { } impl fmt::Show for TypeContents { + #[cfg(stage0)] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TypeContents({:t})", self.bits) } + #[cfg(not(stage0))] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TypeContents({:b})", self.bits) + } } pub fn type_interior_is_unsafe(cx: &ctxt, t: ty::t) -> bool { diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 76250d44baf6e..dfc9f392452d2 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let is_inferred; macro_rules! cannot_happen { () => { { - panic!("invalid parent: {:s} for {:s}", + panic!("invalid parent: {} for {}", tcx.map.node_to_string(parent_id), tcx.map.node_to_string(param_id)); } } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index abf29fe3a4cf9..47bba3e4327c1 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -368,7 +368,7 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo if enabled { let loc = llvm::debug_loc_to_string(llcx, opt.debug_loc); - cgcx.handler.note(format!("optimization {:s} for {:s} at {:s}: {:s}", + cgcx.handler.note(format!("optimization {} for {} at {}: {}", opt.kind.describe(), pass_name, if loc.is_empty() { "[unknown]" } else { loc.as_slice() }, diff --git a/src/librustc_trans/driver/mod.rs b/src/librustc_trans/driver/mod.rs index 8985d05b6ca84..a73afdf68e33c 100644 --- a/src/librustc_trans/driver/mod.rs +++ b/src/librustc_trans/driver/mod.rs @@ -224,13 +224,13 @@ Available lint options: }; println!("Lint checks provided by rustc:\n"); - println!(" {} {:7.7s} {}", padded("name"), "default", "meaning"); - println!(" {} {:7.7s} {}", padded("----"), "-------", "-------"); + println!(" {} {:7.7} {}", padded("name"), "default", "meaning"); + println!(" {} {:7.7} {}", padded("----"), "-------", "-------"); let print_lints = |lints: Vec<&Lint>| { for lint in lints.into_iter() { let name = lint.name_lower().replace("_", "-"); - println!(" {} {:7.7s} {}", + println!(" {} {:7.7} {}", padded(name.as_slice()), lint.default_level.as_str(), lint.desc); } println!("\n"); @@ -293,7 +293,7 @@ fn describe_debug_flags() { for tuple in r.iter() { match *tuple { (ref name, ref desc, _) => { - println!(" -Z {:>20s} -- {}", *name, *desc); + println!(" -Z {:>20} -- {}", *name, *desc); } } } @@ -306,7 +306,7 @@ fn describe_codegen_flags() { Some(..) => (21, "=val"), None => (25, "") }; - println!(" -C {:>width$s}{} -- {}", name.replace("_", "-"), + println!(" -C {:>width$}{} -- {}", name.replace("_", "-"), extra, desc, width=width); } } diff --git a/src/librustc_trans/driver/pretty.rs b/src/librustc_trans/driver/pretty.rs index c20f2e097f31f..420a0ed5e8ac4 100644 --- a/src/librustc_trans/driver/pretty.rs +++ b/src/librustc_trans/driver/pretty.rs @@ -355,8 +355,8 @@ impl UserIdentifiedItem { fn to_one_node_id(self, user_option: &str, sess: &Session, map: &ast_map::Map) -> ast::NodeId { let fail_because = |is_wrong_because| -> ast::NodeId { let message = - format!("{:s} needs NodeId (int) or unique \ - path suffix (b::c::d); got {:s}, which {:s}", + format!("{} needs NodeId (int) or unique \ + path suffix (b::c::d); got {}, which {}", user_option, self.reconstructed_input(), is_wrong_because); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 9c4a532790dde..98cdea73a990a 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -3135,7 +3135,7 @@ pub fn trans_crate<'tcx>(analysis: CrateAnalysis<'tcx>) } if shared_ccx.sess().count_llvm_insns() { for (k, v) in shared_ccx.stats().llvm_insns.borrow().iter() { - println!("{:7u} {}", *v, *k); + println!("{:7} {}", *v, *k); } } diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 02909b0e3a921..58c67c8c0914b 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -67,7 +67,7 @@ pub enum CleanupScopeKind<'blk, 'tcx: 'blk> { } impl<'blk, 'tcx: 'blk> fmt::Show for CleanupScopeKind<'blk, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::FormatError> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CustomScopeKind => write!(f, "CustomScopeKind"), AstScopeKind(nid) => write!(f, "AstScopeKind({})", nid), diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 901761ba806ff..daa5f155d511e 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -75,12 +75,6 @@ impl fmt::Show for ItemType { } } -impl fmt::Unsigned for ItemType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - (*self as uint).fmt(f) - } -} - pub fn shortty(item: &clean::Item) -> ItemType { match item.inner { clean::ModuleItem(..) => Module, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0ecb86d8bdd61..5e4ac259e7180 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -437,8 +437,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, r#"[{:u},"{}","{}",{}"#, - item.ty, item.name, path, + try!(write!(&mut w, r#"[{},"{}","{}",{}"#, + item.ty as uint, item.name, path, item.desc.to_json().to_string())); match item.parent { Some(nodeid) => { @@ -457,8 +457,8 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult if i > 0 { try!(write!(&mut w, ",")); } - try!(write!(&mut w, r#"[{:u},"{}"]"#, - short, *fqp.last().unwrap())); + try!(write!(&mut w, r#"[{},"{}"]"#, + short as uint, *fqp.last().unwrap())); } try!(write!(&mut w, "]}};")); @@ -2192,7 +2192,7 @@ impl<'a> fmt::Show for Source<'a> { } try!(write!(fmt, "
"));
         for i in range(1, lines + 1) {
-            try!(write!(fmt, "{0:1$u}\n", i, cols));
+            try!(write!(fmt, "{0:1$}\n", i, cols));
         }
         try!(write!(fmt, "
")); try!(write!(fmt, "{}", highlight::highlight(s.as_slice(), None, None))); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0350fe72e110d..4a512ca33fc45 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -168,11 +168,11 @@ pub fn main_args(args: &[String]) -> int { if matches.opt_strs("passes").as_slice() == &["list".to_string()] { println!("Available passes for running rustdoc:"); for &(name, _, description) in PASSES.iter() { - println!("{:>20s} - {}", name, description); + println!("{:>20} - {}", name, description); } println!("{}", "\nDefault passes for rustdoc:"); // FIXME: #9970 for &name in DEFAULT_PASSES.iter() { - println!("{:>20s}", name); + println!("{:>20}", name); } return 0; } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 2968c53de9aba..030ee1d4352b5 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -2403,7 +2403,7 @@ impl ToJson for Option
{ impl fmt::Show for Json { /// Encodes a json value into a string fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.to_writer(f).map_err(|_| fmt::WriteError) + self.to_writer(f).map_err(|_| fmt::Error) } } diff --git a/src/libstd/fmt.rs b/src/libstd/fmt.rs index e140ddba723d2..2482fe63028d1 100644 --- a/src/libstd/fmt.rs +++ b/src/libstd/fmt.rs @@ -38,11 +38,11 @@ Some examples of the `format!` extension are: ```rust # fn main() { format!("Hello"); // => "Hello" -format!("Hello, {:s}!", "world"); // => "Hello, world!" -format!("The number is {:d}", 1i); // => "The number is 1" +format!("Hello, {}!", "world"); // => "Hello, world!" +format!("The number is {}", 1i); // => "The number is 1" format!("{}", (3i, 4i)); // => "(3, 4)" format!("{value}", value=4i); // => "4" -format!("{} {}", 1i, 2i); // => "1 2" +format!("{} {}", 1i, 2u); // => "1 2" # } ``` @@ -94,9 +94,9 @@ For example, the following `format!` expressions all use named argument: ```rust # fn main() { -format!("{argument}", argument = "test"); // => "test" -format!("{name} {}", 1i, name = 2i); // => "2 1" -format!("{a:s} {c:d} {b}", a="a", b=(), c=3i); // => "a 3 ()" +format!("{argument}", argument = "test"); // => "test" +format!("{name} {}", 1i, name = 2i); // => "2 1" +format!("{a} {c} {b}", a="a", b=(), c=3i); // => "a 3 ()" # } ``` @@ -138,23 +138,16 @@ multiple actual types to be formatted via `{:d}` (like `i8` as well as `int`). The current mapping of types to traits is: * *nothing* ⇒ `Show` -* `d` ⇒ `Signed` -* `i` ⇒ `Signed` -* `u` ⇒ `Unsigned` -* `b` ⇒ `Bool` -* `c` ⇒ `Char` * `o` ⇒ `Octal` * `x` ⇒ `LowerHex` * `X` ⇒ `UpperHex` -* `s` ⇒ `String` * `p` ⇒ `Pointer` -* `t` ⇒ `Binary` -* `f` ⇒ `Float` +* `b` ⇒ `Binary` * `e` ⇒ `LowerExp` * `E` ⇒ `UpperExp` What this means is that any type of argument which implements the -`std::fmt::Binary` trait can then be formatted with `{:t}`. Implementations are +`std::fmt::Binary` trait can then be formatted with `{:b}`. Implementations are provided for these traits for a number of primitive types by the standard library as well. If no format is specified (as in `{}` or `{:6}`), then the format trait used is the `Show` trait. This is one of the more commonly @@ -216,7 +209,7 @@ impl fmt::Binary for Vector2D { // Respect the formatting flags by using the helper method // `pad_integral` on the Formatter object. See the method documentation // for details, and the function `pad` can be used to pad strings. - let decimals = f.precision.unwrap_or(3); + let decimals = f.precision().unwrap_or(3); let string = f64::to_str_exact(magnitude, decimals); f.pad_integral(true, "", string.as_bytes()) } @@ -226,7 +219,7 @@ fn main() { let myvector = Vector2D { x: 3, y: 4 }; println!("{}", myvector); // => "(3, 4)" - println!("{:10.3t}", myvector); // => " 5.000" + println!("{:10.3b}", myvector); // => " 5.000" } ``` @@ -418,10 +411,10 @@ use string; use vec::Vec; pub use core::fmt::{Formatter, Result, FormatWriter, rt}; -pub use core::fmt::{Show, Bool, Char, Signed, Unsigned, Octal, Binary}; -pub use core::fmt::{LowerHex, UpperHex, String, Pointer}; -pub use core::fmt::{Float, LowerExp, UpperExp}; -pub use core::fmt::{FormatError, WriteError}; +pub use core::fmt::{Show, Octal, Binary}; +pub use core::fmt::{LowerHex, UpperHex, Pointer}; +pub use core::fmt::{LowerExp, UpperExp}; +pub use core::fmt::Error; pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt}; #[doc(hidden)] @@ -444,6 +437,8 @@ pub use core::fmt::{argument, argumentstr, argumentuint}; /// let s = format_args!(fmt::format, "Hello, {}!", "world"); /// assert_eq!(s, "Hello, world!".to_string()); /// ``` +#[experimental = "this is an implementation detail of format! and should not \ + be called directly"] pub fn format(args: &Arguments) -> string::String { let mut output = Vec::new(); let _ = write!(&mut output as &mut Writer, "{}", args); @@ -454,7 +449,7 @@ impl<'a> Writer for Formatter<'a> { fn write(&mut self, b: &[u8]) -> io::IoResult<()> { match (*self).write(b) { Ok(()) => Ok(()), - Err(WriteError) => Err(io::standard_error(io::OtherIoError)) + Err(Error) => Err(io::standard_error(io::OtherIoError)) } } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 82bfa3c4e80ff..681400e9db581 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1034,7 +1034,7 @@ pub trait Writer { Ok(()) => Ok(()), Err(e) => { self.error = Err(e); - Err(fmt::WriteError) + Err(fmt::Error) } } } @@ -1081,13 +1081,13 @@ pub trait Writer { /// Write the result of passing n through `int::to_str_bytes`. #[inline] fn write_int(&mut self, n: int) -> IoResult<()> { - write!(self, "{:d}", n) + write!(self, "{}", n) } /// Write the result of passing n through `uint::to_str_bytes`. #[inline] fn write_uint(&mut self, n: uint) -> IoResult<()> { - write!(self, "{:u}", n) + write!(self, "{}", n) } /// Write a little-endian uint (number of bytes depends on system). @@ -1896,10 +1896,8 @@ impl Default for FilePermission { } impl fmt::Show for FilePermission { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.fill = '0'; - formatter.width = Some(4); - (&self.bits as &fmt::Octal).fmt(formatter) + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:04o}", self.bits) } } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 26e9e70dff3e8..4e5dd5d8818f4 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -240,6 +240,7 @@ macro_rules! unimplemented( /// format!("x = {}, y = {y}", 10i, y = 30i); /// ``` #[macro_export] +#[stable] macro_rules! format( ($($arg:tt)*) => ( format_args!(::std::fmt::format, $($arg)*) @@ -259,15 +260,18 @@ macro_rules! format( /// write!(&mut w, "formatted {}", "arguments"); /// ``` #[macro_export] +#[stable] macro_rules! write( ($dst:expr, $($arg:tt)*) => ({ - format_args_method!($dst, write_fmt, $($arg)*) + let dst = &mut *$dst; + format_args!(|args| { dst.write_fmt(args) }, $($arg)*) }) ) /// Equivalent to the `write!` macro, except that a newline is appended after /// the message is written. #[macro_export] +#[stable] macro_rules! writeln( ($dst:expr, $fmt:expr $($arg:tt)*) => ( write!($dst, concat!($fmt, "\n") $($arg)*) @@ -277,6 +281,7 @@ macro_rules! writeln( /// Equivalent to the `println!` macro except that a newline is not printed at /// the end of the message. #[macro_export] +#[stable] macro_rules! print( ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*)) ) @@ -294,6 +299,7 @@ macro_rules! print( /// println!("format {} arguments", "some"); /// ``` #[macro_export] +#[stable] macro_rules! println( ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*)) ) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 15e14902727f5..497a2d49faf20 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -95,7 +95,7 @@ impl Ident { } pub fn encode_with_hygiene(&self) -> String { - format!("\x00name_{:u},ctxt_{:u}\x00", + format!("\x00name_{},ctxt_{}\x00", self.name.uint(), self.ctxt) } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 9292825ffe828..8c70a95443bc9 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -361,9 +361,6 @@ fn initial_syntax_expander_table(ecfg: &expand::ExpansionConfig) -> SyntaxEnv { syntax_expanders.insert(intern("format_args"), builtin_normal_expander( ext::format::expand_format_args)); - syntax_expanders.insert(intern("format_args_method"), - builtin_normal_expander( - ext::format::expand_format_args_method)); syntax_expanders.insert(intern("env"), builtin_normal_expander( ext::env::expand_env)); diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index dccc12e406bdc..8fccb0755f438 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -887,7 +887,7 @@ impl<'a> MethodDef<'a> { // a series of let statements mapping each self_arg to a uint // corresponding to its variant index. let vi_idents: Vec = self_arg_names.iter() - .map(|name| { let vi_suffix = format!("{:s}_vi", name.as_slice()); + .map(|name| { let vi_suffix = format!("{}_vi", name.as_slice()); cx.ident_of(vi_suffix.as_slice()) }) .collect::>(); diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index f1b92b4d6bc1d..b04a800a32d2a 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -237,7 +237,7 @@ impl<'a, 'b> Context<'a, 'b> { match arg { Exact(arg) => { if self.args.len() <= arg { - let msg = format!("invalid reference to argument `{}` ({:s})", + let msg = format!("invalid reference to argument `{}` ({})", arg, self.describe_num_args()); self.ecx.span_err(self.fmtsp, msg.as_slice()); @@ -670,17 +670,11 @@ impl<'a, 'b> Context<'a, 'b> { Known(ref tyname) => { match tyname.as_slice() { "" => "Show", - "b" => "Bool", - "c" => "Char", - "d" | "i" => "Signed", "e" => "LowerExp", "E" => "UpperExp", - "f" => "Float", "o" => "Octal", "p" => "Pointer", - "s" => "String", - "t" => "Binary", - "u" => "Unsigned", + "b" => "Binary", "x" => "LowerHex", "X" => "UpperHex", _ => { @@ -724,18 +718,6 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, } } -pub fn expand_format_args_method<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> Box { - - match parse_args(ecx, sp, true, tts) { - (invocation, Some((efmt, args, order, names))) => { - MacExpr::new(expand_preparsed_format_args(ecx, sp, invocation, efmt, - args, order, names)) - } - (_, None) => MacExpr::new(ecx.expr_uint(sp, 2)) - } -} - /// Take the various parts of `format_args!(extra, efmt, args..., /// name=names...)` and construct the appropriate formatting /// expression. diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index b50a4690e420b..2ddcab10cdafd 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -131,7 +131,7 @@ fn new_sctable_internal() -> SCTable { pub fn display_sctable(table: &SCTable) { error!("SC table:"); for (idx,val) in table.table.borrow().iter().enumerate() { - error!("{:4u} : {}",idx,val); + error!("{:4} : {}",idx,val); } } diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index ec6e286b9b961..f910bfc5bd446 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -497,8 +497,8 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result ,String> { let mut s = match val { Number(d) => { let s = match (op, flags.sign) { - (FormatDigit, true) => format!("{:+d}", d).into_bytes(), - (FormatDigit, false) => format!("{:d}", d).into_bytes(), + (FormatDigit, true) => format!("{:+}", d).into_bytes(), + (FormatDigit, false) => format!("{}", d).into_bytes(), (FormatOctal, _) => format!("{:o}", d).into_bytes(), (FormatHex, _) => format!("{:x}", d).into_bytes(), (FormatHEX, _) => format!("{:X}", d).into_bytes(), diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index d5d0e7aeb1736..0ea8ca84ef8bd 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -687,14 +687,14 @@ impl ConsoleTestState { improved += 1; try!(self.write_plain(format!(": {}", *k).as_slice())); try!(self.write_improved()); - try!(self.write_plain(format!(" by {:.2f}%\n", + try!(self.write_plain(format!(" by {:.2}%\n", pct as f64).as_slice())); } Regression(pct) => { regressed += 1; try!(self.write_plain(format!(": {}", *k).as_slice())); try!(self.write_regressed()); - try!(self.write_plain(format!(" by {:.2f}%\n", + try!(self.write_plain(format!(" by {:.2}%\n", pct as f64).as_slice())); } } diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index 4fb387db3a2c4..062035c23f906 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -602,8 +602,8 @@ impl<'a> fmt::Show for TmFmt<'a> { match ch { 'G' => write!(fmt, "{}", year), - 'g' => write!(fmt, "{:02d}", (year % 100 + 100) % 100), - 'V' => write!(fmt, "{:02d}", days / 7 + 1), + 'g' => write!(fmt, "{:02}", (year % 100 + 100) % 100), + 'V' => write!(fmt, "{:02}", days / 7 + 1), _ => Ok(()) } } @@ -663,7 +663,7 @@ impl<'a> fmt::Show for TmFmt<'a> { 11 => "Dec", _ => return die() }, - 'C' => return write!(fmt, "{:02d}", (tm.tm_year as int + 1900) / 100), + 'C' => return write!(fmt, "{:02}", (tm.tm_year as int + 1900) / 100), 'c' => { try!(parse_type(fmt, 'a', tm)); try!(' '.fmt(fmt)); @@ -682,9 +682,9 @@ impl<'a> fmt::Show for TmFmt<'a> { try!('/'.fmt(fmt)); return parse_type(fmt, 'y', tm); } - 'd' => return write!(fmt, "{:02d}", tm.tm_mday), - 'e' => return write!(fmt, "{:2d}", tm.tm_mday), - 'f' => return write!(fmt, "{:09d}", tm.tm_nsec), + 'd' => return write!(fmt, "{:02}", tm.tm_mday), + 'e' => return write!(fmt, "{:2}", tm.tm_mday), + 'f' => return write!(fmt, "{:09}", tm.tm_nsec), 'F' => { try!(parse_type(fmt, 'Y', tm)); try!('-'.fmt(fmt)); @@ -694,23 +694,23 @@ impl<'a> fmt::Show for TmFmt<'a> { } 'G' => return iso_week(fmt, 'G', tm), 'g' => return iso_week(fmt, 'g', tm), - 'H' => return write!(fmt, "{:02d}", tm.tm_hour), + 'H' => return write!(fmt, "{:02}", tm.tm_hour), 'I' => { let mut h = tm.tm_hour; if h == 0 { h = 12 } if h > 12 { h -= 12 } - return write!(fmt, "{:02d}", h) + return write!(fmt, "{:02}", h) } - 'j' => return write!(fmt, "{:03d}", tm.tm_yday + 1), - 'k' => return write!(fmt, "{:2d}", tm.tm_hour), + 'j' => return write!(fmt, "{:03}", tm.tm_yday + 1), + 'k' => return write!(fmt, "{:2}", tm.tm_hour), 'l' => { let mut h = tm.tm_hour; if h == 0 { h = 12 } if h > 12 { h -= 12 } - return write!(fmt, "{:2d}", h) + return write!(fmt, "{:2}", h) } - 'M' => return write!(fmt, "{:02d}", tm.tm_min), - 'm' => return write!(fmt, "{:02d}", tm.tm_mon + 1), + 'M' => return write!(fmt, "{:02}", tm.tm_min), + 'm' => return write!(fmt, "{:02}", tm.tm_mon + 1), 'n' => "\n", 'P' => if (tm.tm_hour as int) < 12 { "am" } else { "pm" }, 'p' => if (tm.tm_hour as int) < 12 { "AM" } else { "PM" }, @@ -728,7 +728,7 @@ impl<'a> fmt::Show for TmFmt<'a> { try!(' '.fmt(fmt)); return parse_type(fmt, 'p', tm); } - 'S' => return write!(fmt, "{:02d}", tm.tm_sec), + 'S' => return write!(fmt, "{:02}", tm.tm_sec), 's' => return write!(fmt, "{}", tm.to_timespec().sec), 'T' | 'X' => { try!(parse_type(fmt, 'H', tm)); @@ -738,7 +738,7 @@ impl<'a> fmt::Show for TmFmt<'a> { return parse_type(fmt, 'S', tm); } 't' => "\t", - 'U' => return write!(fmt, "{:02d}", (tm.tm_yday - tm.tm_wday + 7) / 7), + 'U' => return write!(fmt, "{:02}", (tm.tm_yday - tm.tm_wday + 7) / 7), 'u' => { let i = tm.tm_wday as int; return (if i == 0 { 7 } else { i }).fmt(fmt); @@ -752,19 +752,19 @@ impl<'a> fmt::Show for TmFmt<'a> { return parse_type(fmt, 'Y', tm); } 'W' => { - return write!(fmt, "{:02d}", + return write!(fmt, "{:02}", (tm.tm_yday - (tm.tm_wday - 1 + 7) % 7 + 7) / 7) } 'w' => return (tm.tm_wday as int).fmt(fmt), 'Y' => return (tm.tm_year as int + 1900).fmt(fmt), - 'y' => return write!(fmt, "{:02d}", (tm.tm_year as int + 1900) % 100), + 'y' => return write!(fmt, "{:02}", (tm.tm_year as int + 1900) % 100), 'Z' => if tm.tm_gmtoff == 0_i32 { "GMT"} else { "" }, // FIXME (#2350): support locale 'z' => { let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' }; let mut m = tm.tm_gmtoff.abs() / 60_i32; let h = m / 60_i32; m -= h * 60_i32; - return write!(fmt, "{}{:02d}{:02d}", sign, h, m); + return write!(fmt, "{}{:02}{:02}", sign, h, m); } '+' => return tm.rfc3339().fmt(fmt), '%' => "%", @@ -806,7 +806,7 @@ impl<'a> fmt::Show for TmFmt<'a> { let mut m = self.tm.tm_gmtoff.abs() / 60_i32; let h = m / 60_i32; m -= h * 60_i32; - write!(fmt, "{}{}{:02d}:{:02d}", s, sign, h as int, m as int) + write!(fmt, "{}{}{:02}:{:02}", s, sign, h as int, m as int) } } } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 15d89bebf759a..07300b73c85a7 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -148,7 +148,7 @@ fn write_header(header: &str) { } fn write_row(label: &str, value: Duration) { - println!("{:30s} {} s\n", label, value); + println!("{:30} {} s\n", label, value); } fn write_results(label: &str, results: &Results) { diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index 1c530e3851e18..419e39b53cf81 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -115,7 +115,7 @@ fn main() { for y in range(0u, 256) { for x in range(0u, 256) { let idx = (pixels[y*256+x] / 0.2) as uint; - print!("{:c}", symbols[idx]); + print!("{}", symbols[idx]); } print!("\n"); } diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index e39cd743ad55a..4005c11e6b614 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -63,7 +63,7 @@ fn sort_and_fmt(mm: &HashMap , uint>, total: uint) -> String { let mut buffer = String::new(); for &(ref k, v) in pairs_sorted.iter() { - buffer.push_str(format!("{} {:0.3f}\n", + buffer.push_str(format!("{} {:0.3}\n", k.as_slice() .to_ascii() .to_uppercase() diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 6ada34a5a584d..b030e7bb93e87 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -266,7 +266,7 @@ fn print_frequencies(frequencies: &Table, frame: uint) { } for &(count, key) in vector.iter().rev() { - println!("{} {:.3f}", + println!("{} {:.3}", key.unpack(frame).as_slice(), (count as f32 * 100.0) / (total_count as f32)); } diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 3bcc0c25df8ac..b62504d7ba85d 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -179,11 +179,11 @@ fn main() { let mut bodies = BODIES; offset_momentum(&mut bodies); - println!("{:.9f}", energy(&bodies)); + println!("{:.9}", energy(&bodies)); advance(&mut bodies, 0.01, n); - println!("{:.9f}", energy(&bodies)); + println!("{:.9}", energy(&bodies)); } /// Pop a mutable reference off the head of a slice, mutating the slice to no diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index acb289aa3ade8..f76391b596bb3 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -59,7 +59,7 @@ fn main() { } else { from_str(args[1].as_slice()).unwrap() }); - println!("{:.9f}", answer); + println!("{:.9}", answer); } fn spectralnorm(n: uint) -> f64 { diff --git a/src/test/compile-fail/ifmt-bad-arg.rs b/src/test/compile-fail/ifmt-bad-arg.rs index 6829b1e2721a7..db7f49272aac8 100644 --- a/src/test/compile-fail/ifmt-bad-arg.rs +++ b/src/test/compile-fail/ifmt-bad-arg.rs @@ -23,8 +23,8 @@ fn main() { format!("{foo}", 1, foo=2); //~ ERROR: argument never used format!("", foo=2); //~ ERROR: named argument never used - format!("{0:d} {0:s}", 1); //~ ERROR: redeclared with type `s` - format!("{foo:d} {foo:s}", foo=1); //~ ERROR: redeclared with type `s` + format!("{0:x} {0:X}", 1); //~ ERROR: redeclared with type `X` + format!("{foo:x} {foo:X}", foo=1); //~ ERROR: redeclared with type `X` format!("{foo}", foo=1, foo=2); //~ ERROR: duplicate argument format!("", foo=1, 2); //~ ERROR: positional arguments cannot follow diff --git a/src/test/compile-fail/ifmt-unimpl.rs b/src/test/compile-fail/ifmt-unimpl.rs index 194047ce848f6..948040496bd39 100644 --- a/src/test/compile-fail/ifmt-unimpl.rs +++ b/src/test/compile-fail/ifmt-unimpl.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - format!("{:d}", "3"); - //~^ ERROR: the trait `core::fmt::Signed` is not implemented + format!("{:X}", "3"); + //~^ ERROR: the trait `core::fmt::UpperHex` is not implemented } diff --git a/src/test/compile-fail/issue-1448-2.rs b/src/test/compile-fail/issue-1448-2.rs index 3daced7a5ac18..234fa85c89afd 100644 --- a/src/test/compile-fail/issue-1448-2.rs +++ b/src/test/compile-fail/issue-1448-2.rs @@ -13,5 +13,5 @@ fn foo(a: uint) -> uint { a } fn main() { - println!("{:u}", foo(10i)); //~ ERROR mismatched types + println!("{}", foo(10i)); //~ ERROR mismatched types } diff --git a/src/test/compile-fail/issue-14853.rs b/src/test/compile-fail/issue-14853.rs index 4243b98e0dde5..6515b34d964e1 100644 --- a/src/test/compile-fail/issue-14853.rs +++ b/src/test/compile-fail/issue-14853.rs @@ -10,17 +10,18 @@ use std::fmt::Show; +trait Str {} + trait Something { - fn yay(_: Option, thing: &[T]) -> String { - } + fn yay(_: Option, thing: &[T]); } struct X { data: u32 } impl Something for X { - fn yay(_:Option, thing: &[T]) -> String { -//~^ ERROR in method `yay`, type parameter 0 requires bound `core::str::Str`, which is not required - format!("{:s}", thing[0]) + fn yay(_:Option, thing: &[T]) { +//~^ ERROR in method `yay`, type parameter 0 requires bound `Str`, which is not required + } } diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs index 59f7eda41610c..b78371c51e432 100644 --- a/src/test/run-pass/ifmt.rs +++ b/src/test/run-pass/ifmt.rs @@ -22,12 +22,12 @@ struct A; struct B; struct C; -impl fmt::Signed for A { +impl fmt::LowerHex for A { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write("aloha".as_bytes()) } } -impl fmt::Signed for B { +impl fmt::UpperHex for B { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write("adios".as_bytes()) } @@ -55,71 +55,71 @@ pub fn main() { t!(format!("{}", 'a'), "a"); // At least exercise all the formats - t!(format!("{:b}", true), "true"); - t!(format!("{:c}", '☃'), "☃"); - t!(format!("{:d}", 10i), "10"); - t!(format!("{:i}", 10i), "10"); - t!(format!("{:u}", 10u), "10"); + t!(format!("{}", true), "true"); + t!(format!("{}", '☃'), "☃"); + t!(format!("{}", 10i), "10"); + t!(format!("{}", 10i), "10"); + t!(format!("{}", 10u), "10"); t!(format!("{:o}", 10u), "12"); t!(format!("{:x}", 10u), "a"); t!(format!("{:X}", 10u), "A"); - t!(format!("{:s}", "foo"), "foo"); - t!(format!("{:s}", "foo".to_string()), "foo"); + t!(format!("{}", "foo"), "foo"); + t!(format!("{}", "foo".to_string()), "foo"); t!(format!("{:p}", 0x1234 as *const int), "0x1234"); t!(format!("{:p}", 0x1234 as *mut int), "0x1234"); - t!(format!("{:d}", A), "aloha"); - t!(format!("{:d}", B), "adios"); - t!(format!("foo {:s} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t!(format!("{:x}", A), "aloha"); + t!(format!("{:X}", B), "adios"); + t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); t!(format!("{1} {0}", 0i, 1i), "1 0"); t!(format!("{foo} {bar}", foo=0i, bar=1i), "0 1"); t!(format!("{foo} {1} {bar} {0}", 0i, 1i, foo=2i, bar=3i), "2 1 3 0"); t!(format!("{} {0}", "a"), "a a"); t!(format!("{foo_bar}", foo_bar=1i), "1"); - t!(format!("{:d}", 5i + 5i), "10"); + t!(format!("{}", 5i + 5i), "10"); t!(format!("{:#4}", C), "☃123"); let a: &fmt::Show = &1i; t!(format!("{}", a), "1"); // Formatting strings and their arguments - t!(format!("{:s}", "a"), "a"); - t!(format!("{:4s}", "a"), "a "); - t!(format!("{:4s}", "☃"), "☃ "); - t!(format!("{:>4s}", "a"), " a"); - t!(format!("{:<4s}", "a"), "a "); - t!(format!("{:^5s}", "a"), " a "); - t!(format!("{:^5s}", "aa"), " aa "); - t!(format!("{:^4s}", "a"), " a "); - t!(format!("{:^4s}", "aa"), " aa "); - t!(format!("{:.4s}", "a"), "a"); - t!(format!("{:4.4s}", "a"), "a "); - t!(format!("{:4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:<4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:^4.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>10.4s}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:2.4s}", "aaaaa"), "aaaa"); - t!(format!("{:2.4s}", "aaaa"), "aaaa"); - t!(format!("{:2.4s}", "aaa"), "aaa"); - t!(format!("{:2.4s}", "aa"), "aa"); - t!(format!("{:2.4s}", "a"), "a "); - t!(format!("{:0>2s}", "a"), "0a"); - t!(format!("{:.*s}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:.1$s}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); - t!(format!("{:.a$s}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa"); - t!(format!("{:1$s}", "a", 4), "a "); - t!(format!("{1:0$s}", 4, "a"), "a "); - t!(format!("{:a$s}", "a", a=4), "a "); - t!(format!("{:-#s}", "a"), "a"); - t!(format!("{:+#s}", "a"), "a"); + t!(format!("{}", "a"), "a"); + t!(format!("{:4}", "a"), "a "); + t!(format!("{:4}", "☃"), "☃ "); + t!(format!("{:>4}", "a"), " a"); + t!(format!("{:<4}", "a"), "a "); + t!(format!("{:^5}", "a"), " a "); + t!(format!("{:^5}", "aa"), " aa "); + t!(format!("{:^4}", "a"), " a "); + t!(format!("{:^4}", "aa"), " aa "); + t!(format!("{:.4}", "a"), "a"); + t!(format!("{:4.4}", "a"), "a "); + t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:2.4}", "aaaaa"), "aaaa"); + t!(format!("{:2.4}", "aaaa"), "aaaa"); + t!(format!("{:2.4}", "aaa"), "aaa"); + t!(format!("{:2.4}", "aa"), "aa"); + t!(format!("{:2.4}", "a"), "a "); + t!(format!("{:0>2}", "a"), "0a"); + t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); + t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa"); + t!(format!("{:1$}", "a", 4), "a "); + t!(format!("{1:0$}", 4, "a"), "a "); + t!(format!("{:a$}", "a", a=4), "a "); + t!(format!("{:-#}", "a"), "a"); + t!(format!("{:+#}", "a"), "a"); // Some float stuff - t!(format!("{:f}", 1.0f32), "1"); - t!(format!("{:f}", 1.0f64), "1"); - t!(format!("{:.3f}", 1.0f64), "1.000"); - t!(format!("{:10.3f}", 1.0f64), " 1.000"); - t!(format!("{:+10.3f}", 1.0f64), " +1.000"); - t!(format!("{:+10.3f}", -1.0f64), " -1.000"); + t!(format!("{:}", 1.0f32), "1"); + t!(format!("{:}", 1.0f64), "1"); + t!(format!("{:.3}", 1.0f64), "1.000"); + t!(format!("{:10.3}", 1.0f64), " 1.000"); + t!(format!("{:+10.3}", 1.0f64), " +1.000"); + t!(format!("{:+10.3}", -1.0f64), " -1.000"); t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); @@ -164,7 +164,7 @@ fn test_write() { { let w = &mut buf as &mut io::Writer; write!(w, "{foo}", foo=4i); - write!(w, "{:s}", "hello"); + write!(w, "{}", "hello"); writeln!(w, "{}", "line"); writeln!(w, "{foo}", foo="bar"); } diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index bd581dd657f59..a29ed712d400b 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -46,19 +46,19 @@ unsafe fn test_triangle() -> bool { static PRINT : bool = false; unsafe fn allocate(size: uint, align: uint) -> *mut u8 { - if PRINT { println!("allocate(size={:u} align={:u})", size, align); } + if PRINT { println!("allocate(size={} align={})", size, align); } let ret = heap::allocate(size, align); if ret.is_null() { alloc::oom() } - if PRINT { println!("allocate(size={:u} align={:u}) ret: 0x{:010x}", + if PRINT { println!("allocate(size={} align={}) ret: 0x{:010x}", size, align, ret as uint); } ret } unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) { - if PRINT { println!("deallocate(ptr=0x{:010x} size={:u} align={:u})", + if PRINT { println!("deallocate(ptr=0x{:010x} size={} align={})", ptr as uint, size, align); } @@ -66,7 +66,7 @@ unsafe fn test_triangle() -> bool { } unsafe fn reallocate(ptr: *mut u8, old_size: uint, size: uint, align: uint) -> *mut u8 { if PRINT { - println!("reallocate(ptr=0x{:010x} old_size={:u} size={:u} align={:u})", + println!("reallocate(ptr=0x{:010x} old_size={} size={} align={})", ptr as uint, old_size, size, align); } @@ -74,7 +74,7 @@ unsafe fn test_triangle() -> bool { if ret.is_null() { alloc::oom() } if PRINT { - println!("reallocate(ptr=0x{:010x} old_size={:u} size={:u} align={:u}) \ + println!("reallocate(ptr=0x{:010x} old_size={} size={} align={}) \ ret: 0x{:010x}", ptr as uint, old_size, size, align, ret as uint); } From 38b14258a38dd69da85ffb920db8b184d37ccaf3 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Wed, 19 Nov 2014 08:54:52 +0200 Subject: [PATCH 13/25] iOS: fixed broken build after disallowed coercions --- src/libstd/rand/os.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 43a79770fbb84..2a4d8347c30c9 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -212,12 +212,12 @@ mod imp { impl Rng for OsRng { fn next_u32(&mut self) -> u32 { let mut v = [0u8, .. 4]; - self.fill_bytes(v); + self.fill_bytes(&mut v); unsafe { mem::transmute(v) } } fn next_u64(&mut self) -> u64 { let mut v = [0u8, .. 8]; - self.fill_bytes(v); + self.fill_bytes(&mut v); unsafe { mem::transmute(v) } } fn fill_bytes(&mut self, v: &mut [u8]) { From 210e059750911193af87eb514da0517d6d122189 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 6 Nov 2014 21:30:49 -0500 Subject: [PATCH 14/25] clearly define `int` and `uint` to fix unsoundness This fixes the gap in the language definition causing #18726 by defining a clear bound on the maximum size for libraries to enforce. Closes #18069 --- src/doc/reference.md | 19 ++++++++----------- src/librustc_trans/trans/adt.rs | 12 ++++++------ src/librustc_trans/trans/context.rs | 19 +++++++++++++++++-- src/librustc_trans/trans/type_of.rs | 2 +- src/test/compile-fail/huge-enum.rs | 6 ++++++ src/test/run-pass/huge-largest-array.rs | 21 +++++++++++++++++++++ 6 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 src/test/run-pass/huge-largest-array.rs diff --git a/src/doc/reference.md b/src/doc/reference.md index 62e0f5e4f1f48..5ee03f1b1d338 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3557,17 +3557,14 @@ The machine types are the following: #### Machine-dependent integer types -The Rust type `uint` [^rustuint] is an -unsigned integer type with target-machine-dependent size. Its size, in -bits, is equal to the number of bits required to hold any memory address on -the target machine. - -The Rust type `int` [^rustint] is a two's complement signed integer type with -target-machine-dependent size. Its size, in bits, is equal to the size of the -rust type `uint` on the same target machine. - -[^rustuint]: A Rust `uint` is analogous to a C99 `uintptr_t`. -[^rustint]: A Rust `int` is analogous to a C99 `intptr_t`. +The `uint` type is an unsigned integer type with the same number of bits as the +platform's pointer type. It can represent every memory address in the process. + +The `int` type is a signed integer type with the same number of bits as the +platform's pointer type. The theoretical upper bound on object and array size +is the maximum `int` value. This ensures that `int` can be used to calculate +differences between pointers into an object or array and can address every byte +within an object along with one byte past the end. ### Textual types diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 806c4a68ba281..5ef78c1475bf5 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -464,17 +464,17 @@ fn ensure_struct_fits_in_address_space(ccx: &CrateContext, scapegoat: ty::t) { let mut offset = 0; for &llty in fields.iter() { - // Invariant: offset < ccx.max_obj_size() <= 1<<61 + // Invariant: offset < ccx.obj_size_bound() <= 1<<61 if !packed { let type_align = machine::llalign_of_min(ccx, llty); offset = roundup(offset, type_align); } - // type_align is a power-of-2, so still offset < ccx.max_obj_size() - // llsize_of_alloc(ccx, llty) is also less than ccx.max_obj_size() + // type_align is a power-of-2, so still offset < ccx.obj_size_bound() + // llsize_of_alloc(ccx, llty) is also less than ccx.obj_size_bound() // so the sum is less than 1<<62 (and therefore can't overflow). offset += machine::llsize_of_alloc(ccx, llty); - if offset >= ccx.max_obj_size() { + if offset >= ccx.obj_size_bound() { ccx.report_overbig_object(scapegoat); } } @@ -493,11 +493,11 @@ fn ensure_enum_fits_in_address_space(ccx: &CrateContext, let discr_size = machine::llsize_of_alloc(ccx, ll_inttype(ccx, discr)); let (field_size, field_align) = union_size_and_align(fields); - // field_align < 1<<32, discr_size <= 8, field_size < MAX_OBJ_SIZE <= 1<<61 + // field_align < 1<<32, discr_size <= 8, field_size < OBJ_SIZE_BOUND <= 1<<61 // so the sum is less than 1<<62 (and can't overflow). let total_size = roundup(discr_size, field_align) + field_size; - if total_size >= ccx.max_obj_size() { + if total_size >= ccx.obj_size_bound() { ccx.report_overbig_object(scapegoat); } } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index c2c1f8bb5f5ac..c0066ff4d81e1 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -703,8 +703,23 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.trait_cache } - pub fn max_obj_size(&self) -> u64 { - 1<<31 /* FIXME #18069: select based on architecture */ + /// Return exclusive upper bound on object size. + /// + /// The theoretical maximum object size is defined as the maximum positive `int` value. This + /// ensures that the `offset` semantics remain well-defined by allowing it to correctly index + /// every address within an object along with one byte past the end, along with allowing `int` + /// to store the difference between any two pointers into an object. + /// + /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer to + /// represent object size in bits. It would need to be 1 << 61 to account for this, but is + /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable + /// address space on 64-bit ARMv8 and x86_64. + pub fn obj_size_bound(&self) -> u64 { + match self.sess().target.target.target_word_size[] { + "32" => 1 << 31, + "64" => 1 << 47, + _ => unreachable!() // error handled by config::build_target_config + } } pub fn report_overbig_object(&self, obj: ty::t) -> ! { diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 5fa2198463793..6bba40ccc7a71 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -34,7 +34,7 @@ fn ensure_array_fits_in_address_space(ccx: &CrateContext, scapegoat: ty::t) { let esz = machine::llsize_of_alloc(ccx, llet); match esz.checked_mul(size) { - Some(n) if n < ccx.max_obj_size() => {} + Some(n) if n < ccx.obj_size_bound() => {} _ => { ccx.report_overbig_object(scapegoat) } } } diff --git a/src/test/compile-fail/huge-enum.rs b/src/test/compile-fail/huge-enum.rs index 92f9c41e7ea30..4a85cb5753b7f 100644 --- a/src/test/compile-fail/huge-enum.rs +++ b/src/test/compile-fail/huge-enum.rs @@ -12,6 +12,12 @@ // FIXME: work properly with higher limits +#[cfg(target_word_size = "32")] fn main() { let big: Option<[u32, ..(1<<29)-1]> = None; } + +#[cfg(target_word_size = "64")] +fn main() { + let big: Option<[u32, ..(1<<45)-1]> = None; +} diff --git a/src/test/run-pass/huge-largest-array.rs b/src/test/run-pass/huge-largest-array.rs new file mode 100644 index 0000000000000..d494e0bf40dea --- /dev/null +++ b/src/test/run-pass/huge-largest-array.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem::size_of; + +#[cfg(target_word_size = "32")] +pub fn main() { + assert_eq!(size_of::<[u8, ..(1 << 31) - 1]>(), (1 << 31) - 1); +} + +#[cfg(target_word_size = "64")] +pub fn main() { + assert_eq!(size_of::<[u8, ..(1 << 47) - 1]>(), (1 << 47) - 1); +} From b64c7b83dd08c7c3afc643564d65975d57785172 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 8 Nov 2014 06:59:10 -0500 Subject: [PATCH 15/25] Refactor QPath to take an ast::TraitRef --- src/librustc/middle/resolve.rs | 63 +-------- src/librustc/middle/subst.rs | 4 + src/librustc/middle/traits/mod.rs | 5 +- src/librustc/middle/traits/select.rs | 2 +- src/librustc/middle/traits/util.rs | 3 +- src/librustc/middle/typeck/astconv.rs | 128 ++++++------------ src/librustc/middle/typeck/collect.rs | 31 +++-- src/librustc/util/common.rs | 4 + src/libsyntax/ast.rs | 6 +- src/libsyntax/fold.rs | 22 ++- src/libsyntax/parse/parser.rs | 10 +- src/libsyntax/print/pprust.rs | 4 +- src/libsyntax/visit.rs | 4 +- .../associated-types-in-ambiguous-context.rs | 4 +- .../associated-types-in-wrong-context.rs | 4 +- ...ed-path-with-trait-with-type-parameters.rs | 18 +++ 16 files changed, 122 insertions(+), 190 deletions(-) create mode 100644 src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index baf53cc34ba94..f369f00a14e30 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -633,6 +633,7 @@ enum TraitReferenceType { TraitDerivation, // trait T : SomeTrait { ... } TraitBoundingTypeParameter, // fn f() { ... } TraitObject, // Box SomeTrait> + TraitQPath, // :: } impl NameBindings { @@ -4532,6 +4533,7 @@ impl<'a> Resolver<'a> { TraitImplementation => "implement", TraitDerivation => "derive", TraitObject => "reference", + TraitQPath => "extract an associated type from", }; let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str); @@ -4969,65 +4971,8 @@ impl<'a> Resolver<'a> { } TyQPath(ref qpath) => { - self.resolve_type(&*qpath.for_type); - - let current_module = self.current_module.clone(); - let module_path: Vec<_> = - qpath.trait_name - .segments - .iter() - .map(|ps| ps.identifier.name) - .collect(); - match self.resolve_module_path( - current_module, - module_path.as_slice(), - UseLexicalScope, - qpath.trait_name.span, - PathSearch) { - Success((ref module, _)) if module.kind.get() == - TraitModuleKind => { - match self.resolve_definition_of_name_in_module( - (*module).clone(), - qpath.item_name.name, - TypeNS) { - ChildNameDefinition(def, lp) | - ImportNameDefinition(def, lp) => { - match def { - DefAssociatedTy(trait_type_id) => { - let def = DefAssociatedTy( - trait_type_id); - self.record_def(ty.id, (def, lp)); - } - _ => { - self.resolve_error( - ty.span, - "not an associated type"); - } - } - } - NoNameDefinition => { - self.resolve_error(ty.span, - "unresolved associated \ - type"); - } - } - } - Success(..) => self.resolve_error(ty.span, "not a trait"), - Indeterminate => { - self.session.span_bug(ty.span, - "indeterminate result when \ - resolving associated type") - } - Failed(error) => { - let (span, help) = match error { - Some((span, msg)) => (span, format!("; {}", msg)), - None => (ty.span, String::new()), - }; - self.resolve_error(span, - format!("unresolved trait: {}", - help).as_slice()) - } - } + self.resolve_type(&*qpath.self_type); + self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath); } TyClosure(ref c) | TyProc(ref c) => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index bac417c8218a4..b030867fc841c 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -100,6 +100,10 @@ impl<'tcx> Substs<'tcx> { regions_is_noop && self.types.is_empty() } + pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> { + *self.types.get(ty_param_def.space, ty_param_def.index) + } + pub fn has_regions_escaping_depth(&self, depth: uint) -> bool { self.types.iter().any(|&t| ty::type_escapes_depth(t, depth)) || { match self.regions { diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index c5eacf35da92f..d34d413225e80 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -25,6 +25,7 @@ use std::rc::Rc; use std::slice::Items; use syntax::ast; use syntax::codemap::{Span, DUMMY_SP}; +use util::common::ErrorReported; pub use self::fulfill::FulfillmentContext; pub use self::select::SelectionContext; @@ -95,10 +96,6 @@ pub enum ObligationCauseCode<'tcx> { FieldSized, } -// An error has already been reported to the user, so no need to continue checking. -#[deriving(Clone,Show)] -pub struct ErrorReported; - pub type Obligations<'tcx> = subst::VecPerParamSpace>; pub type Selection<'tcx> = Vtable<'tcx, Obligation<'tcx>>; diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index b884cb535d7a5..9cb7023e1b59f 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,7 +17,6 @@ use self::Candidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; -use super::{ErrorReported}; use super::{Obligation, ObligationCause}; use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; @@ -38,6 +37,7 @@ use std::cell::RefCell; use std::collections::hash_map::HashMap; use std::rc::Rc; use syntax::ast; +use util::common::ErrorReported; use util::ppaux::Repr; pub struct SelectionContext<'cx, 'tcx:'cx> { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index dfd436bdc4d30..ec49d5010562b 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -18,9 +18,10 @@ use std::fmt; use std::rc::Rc; use syntax::ast; use syntax::codemap::Span; +use util::common::ErrorReported; use util::ppaux::Repr; -use super::{ErrorReported, Obligation, ObligationCause, VtableImpl, +use super::{Obligation, ObligationCause, VtableImpl, VtableParam, VtableParamData, VtableImplData}; /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index ea652bc7e6599..637c1f58157e2 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -207,7 +207,6 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( decl_def_id: ast::DefId, decl_generics: &ty::Generics<'tcx>, self_ty: Option>, - associated_ty: Option>, path: &ast::Path) -> Substs<'tcx> where AC: AstConv<'tcx>, RS: RegionScope @@ -243,7 +242,7 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>( }; create_substs_for_ast_path(this, rscope, path.span, decl_def_id, - decl_generics, self_ty, types, regions, associated_ty) + decl_generics, self_ty, types, regions) } fn create_substs_for_ast_path<'tcx,AC,RS>( @@ -254,8 +253,7 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( decl_generics: &ty::Generics<'tcx>, self_ty: Option>, types: Vec>, - regions: Vec, - associated_ty: Option>) + regions: Vec) -> Substs<'tcx> where AC: AstConv<'tcx>, RS: RegionScope { @@ -366,9 +364,9 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( substs.types.push( AssocSpace, this.associated_type_binding(span, - associated_ty, + self_ty, decl_def_id, - param.def_id)) + param.def_id)); } return substs; @@ -417,19 +415,17 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( this: &AC, rscope: &RS, ast_trait_ref: &ast::PolyTraitRef, - self_ty: Option>, - associated_type: Option>) + self_ty: Option>) -> Rc> where AC: AstConv<'tcx>, RS: RegionScope { - instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, associated_type) + instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty) } pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, rscope: &RS, ast_trait_ref: &ast::TraitRef, - self_ty: Option>, - associated_type: Option>) + self_ty: Option>) -> Rc> where AC: AstConv<'tcx>, RS: RegionScope @@ -444,8 +440,8 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC, ast_trait_ref.path.span, ast_trait_ref.ref_id) { def::DefTrait(trait_def_id) => { - let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, trait_def_id, self_ty, - associated_type, &ast_trait_ref.path)); + let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, trait_def_id, + self_ty, &ast_trait_ref.path)); this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id, trait_ref.clone()); trait_ref @@ -463,7 +459,6 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>( rscope: &RS, trait_def_id: ast::DefId, self_ty: Option>, - associated_type: Option>, path: &ast::Path) -> ty::TraitRef<'tcx> where AC: AstConv<'tcx>, RS: RegionScope @@ -493,8 +488,7 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>( &trait_def.generics, self_ty, types, - regions, - associated_type); + regions); ty::TraitRef::new(trait_def_id, substs) } @@ -517,7 +511,6 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( did, &generics, None, - None, path); let ty = decl_ty.subst(tcx, &substs); TypeAndSubsts { substs: substs, ty: ty } @@ -558,7 +551,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( Substs::new(VecPerParamSpace::params_from_type(type_params), VecPerParamSpace::params_from_type(region_params)) } else { - ast_path_substs_for_ty(this, rscope, did, &generics, None, None, path) + ast_path_substs_for_ty(this, rscope, did, &generics, None, path) }; let ty = decl_ty.subst(tcx, &substs); @@ -726,7 +719,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( rscope, trait_def_id, None, - None, path); let empty_vec = []; let bounds = match *opt_bounds { None => empty_vec.as_slice(), @@ -750,61 +742,37 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( constr(ast_ty_to_ty(this, rscope, a_seq_ty)) } -fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, - rscope: &RS, - trait_path: &ast::Path, - for_ast_type: &ast::Ty, - trait_type_id: ast::DefId, - span: Span) - -> Ty<'tcx> - where AC: AstConv<'tcx>, RS: RegionScope +fn qpath_to_ty<'tcx,AC,RS>(this: &AC, + rscope: &RS, + ast_ty: &ast::Ty, // the TyQPath + qpath: &ast::QPath) + -> Ty<'tcx> + where AC: AstConv<'tcx>, RS: RegionScope { - debug!("associated_ty_to_ty(trait_path={}, for_ast_type={}, trait_type_id={})", - trait_path.repr(this.tcx()), - for_ast_type.repr(this.tcx()), - trait_type_id.repr(this.tcx())); - - // Find the trait that this associated type belongs to. - let trait_did = match ty::impl_or_trait_item(this.tcx(), - trait_type_id).container() { - ty::ImplContainer(_) => { - this.tcx().sess.span_bug(span, - "associated_ty_to_ty(): impl associated \ - types shouldn't go through this \ - function") - } - ty::TraitContainer(trait_id) => trait_id, - }; + debug!("qpath_to_ty(ast_ty={})", + ast_ty.repr(this.tcx())); - let for_type = ast_ty_to_ty(this, rscope, for_ast_type); - if !this.associated_types_of_trait_are_valid(for_type, trait_did) { - this.tcx().sess.span_err(span, - "this associated type is not \ - allowed in this context"); - return ty::mk_err() - } + let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type); + + debug!("qpath_to_ty: self_type={}", self_type.repr(this.tcx())); - let trait_ref = ast_path_to_trait_ref(this, + let trait_ref = instantiate_trait_ref(this, rscope, - trait_did, - None, - Some(for_type), - trait_path); - - debug!("associated_ty_to_ty(trait_ref={})", - trait_ref.repr(this.tcx())); - - let trait_def = this.get_trait_def(trait_did); - for type_parameter in trait_def.generics.types.iter() { - if type_parameter.def_id == trait_type_id { - debug!("associated_ty_to_ty(type_parameter={} substs={})", - type_parameter.repr(this.tcx()), - trait_ref.substs.repr(this.tcx())); - return *trait_ref.substs.types.get(type_parameter.space, - type_parameter.index) + &*qpath.trait_ref, + Some(self_type)); + + debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx())); + + let trait_def = this.get_trait_def(trait_ref.def_id); + + for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() { + if ty_param_def.name == qpath.item_name.name { + debug!("qpath_to_ty: corresponding ty_param_def={}", ty_param_def); + return trait_ref.substs.type_for_def(ty_param_def); } } - this.tcx().sess.span_bug(span, + + this.tcx().sess.span_bug(ast_ty.span, "this associated type didn't get added \ as a parameter for some reason") } @@ -931,7 +899,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( rscope, trait_def_id, None, - None, path); let empty_bounds: &[ast::TyParamBound] = &[]; let ast_bounds = match *bounds { @@ -996,26 +963,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } } ast::TyQPath(ref qpath) => { - match tcx.def_map.borrow().get(&ast_ty.id) { - None => { - tcx.sess.span_bug(ast_ty.span, - "unbound qualified path") - } - Some(&def::DefAssociatedTy(trait_type_id)) => { - associated_ty_to_ty(this, - rscope, - &qpath.trait_name, - &*qpath.for_type, - trait_type_id, - ast_ty.span) - } - Some(_) => { - tcx.sess.span_err(ast_ty.span, - "this qualified path does not name \ - an associated type"); - ty::mk_err() - } - } + qpath_to_ty(this, rscope, ast_ty, &**qpath) } ast::TyFixedLengthVec(ref ty, ref e) => { match const_eval::eval_const_expr_partial(tcx, &**e) { @@ -1411,7 +1359,7 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>( let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) { Some(trait_bound) => { - Some(instantiate_poly_trait_ref(this, rscope, trait_bound, None, None)) + Some(instantiate_poly_trait_ref(this, rscope, trait_bound, None)) } None => { this.tcx().sess.span_err( diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index b0e8b664d06d7..90ad0d2f3e5e2 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -684,7 +684,11 @@ fn find_associated_type_in_generics<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Option>, associated_type_id: ast::DefId, generics: &ty::Generics<'tcx>) - -> Ty<'tcx> { + -> Ty<'tcx> +{ + debug!("find_associated_type_in_generics(ty={}, associated_type_id={}, generics={}", + ty.repr(tcx), associated_type_id.repr(tcx), generics.repr(tcx)); + let ty = match ty { None => { tcx.sess.span_bug(span, @@ -703,20 +707,22 @@ fn find_associated_type_in_generics<'tcx>(tcx: &ty::ctxt<'tcx>, for type_parameter in generics.types.iter() { if type_parameter.def_id == associated_type_id && type_parameter.associated_with == Some(param_id) { - return ty::mk_param_from_def(tcx, type_parameter) + return ty::mk_param_from_def(tcx, type_parameter); } } - tcx.sess.span_bug(span, - "find_associated_type_in_generics(): didn't \ - find associated type anywhere in the generics \ - list") + tcx.sess.span_err( + span, + format!("no suitable bound on `{}`", + ty.user_string(tcx))[]); + ty::mk_err() } _ => { - tcx.sess.span_bug(span, - "find_associated_type_in_generics(): self type \ - is not a parameter") - + tcx.sess.span_err( + span, + "it is currently unsupported to access associated types except \ + through a type parameter; this restriction will be lifted in time"); + ty::mk_err() } } } @@ -1155,7 +1161,7 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) { for trait_ref in opt_trait_ref.iter() { astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref, - Some(selfty), None); + Some(selfty)); } }, ast::ItemTrait(_, _, _, ref trait_methods) => { @@ -1627,7 +1633,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ccx, subst::AssocSpace, &associated_type.ty_param, - generics.types.len(subst::TypeSpace), + generics.types.len(subst::AssocSpace), &ast_generics.where_clause, Some(local_def(trait_id))); ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id, @@ -2019,7 +2025,6 @@ fn conv_param_bounds<'tcx,AC>(this: &AC, astconv::instantiate_poly_trait_ref(this, &ExplicitRscope, bound, - Some(param_ty.to_ty(this.tcx())), Some(param_ty.to_ty(this.tcx()))) }) .collect(); diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 06154f68613e7..cdbe107e11c95 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -20,6 +20,10 @@ use syntax::ast; use syntax::visit; use syntax::visit::Visitor; +// An error has already been reported to the user, so no need to continue checking. +#[deriving(Clone,Show)] +pub struct ErrorReported; + pub fn time(do_it: bool, what: &str, u: U, f: |U| -> T) -> T { local_data_key!(depth: uint); if !do_it { return f(u); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 15e14902727f5..61e56f0cc42e4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -706,11 +706,11 @@ pub enum Expr_ { /// /// as SomeTrait>::SomeAssociatedItem /// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~ -/// for_type trait_name item_name +/// self_type trait_name item_name #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct QPath { - pub for_type: P, - pub trait_name: Path, + pub self_type: P, + pub trait_ref: P, pub item_name: Ident, } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b3137ff5f7e52..2e6ee49f0ff72 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -142,6 +142,10 @@ pub trait Folder { noop_fold_ty(t, self) } + fn fold_qpath(&mut self, t: P) -> P { + noop_fold_qpath(t, self) + } + fn fold_mod(&mut self, m: Mod) -> Mod { noop_fold_mod(m, self) } @@ -435,12 +439,8 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { fld.fold_opt_bounds(bounds), id) } - TyQPath(ref qpath) => { - TyQPath(P(QPath { - for_type: fld.fold_ty(qpath.for_type.clone()), - trait_name: fld.fold_path(qpath.trait_name.clone()), - item_name: fld.fold_ident(qpath.item_name.clone()), - })) + TyQPath(qpath) => { + TyQPath(fld.fold_qpath(qpath)) } TyFixedLengthVec(ty, e) => { TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) @@ -456,6 +456,16 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { }) } +pub fn noop_fold_qpath(qpath: P, fld: &mut T) -> P { + qpath.map(|qpath| { + QPath { + self_type: fld.fold_ty(qpath.self_type), + trait_ref: qpath.trait_ref.map(|tr| fld.fold_trait_ref(tr)), + item_name: fld.fold_ident(qpath.item_name), + } + }) +} + pub fn noop_fold_foreign_mod(ForeignMod {abi, view_items, items}: ForeignMod, fld: &mut T) -> ForeignMod { ForeignMod { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 50b1a2204b041..d3ae9838c6d14 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1502,17 +1502,17 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Proc) { self.parse_proc_type(Vec::new()) } else if self.token == token::Lt { - // QUALIFIED PATH + // QUALIFIED PATH `::item` self.bump(); - let for_type = self.parse_ty(true); + let self_type = self.parse_ty(true); self.expect_keyword(keywords::As); - let trait_name = self.parse_path(LifetimeAndTypesWithoutColons); + let trait_ref = self.parse_trait_ref(); self.expect(&token::Gt); self.expect(&token::ModSep); let item_name = self.parse_ident(); TyQPath(P(QPath { - for_type: for_type, - trait_name: trait_name.path, + self_type: self_type, + trait_ref: P(trait_ref), item_name: item_name, })) } else if self.token == token::ModSep || diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e6e0c33a42dbd..fa6b70389b4c8 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -744,10 +744,10 @@ impl<'a> State<'a> { } ast::TyQPath(ref qpath) => { try!(word(&mut self.s, "<")); - try!(self.print_type(&*qpath.for_type)); + try!(self.print_type(&*qpath.self_type)); try!(space(&mut self.s)); try!(self.word_space("as")); - try!(self.print_path(&qpath.trait_name, false)); + try!(self.print_trait_ref(&*qpath.trait_ref)); try!(word(&mut self.s, ">")); try!(word(&mut self.s, "::")); try!(self.print_ident(qpath.item_name)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index efe1e18eda928..bbbec5e0626c5 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -403,8 +403,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { } } TyQPath(ref qpath) => { - visitor.visit_ty(&*qpath.for_type); - visitor.visit_path(&qpath.trait_name, typ.id); + visitor.visit_ty(&*qpath.self_type); + visitor.visit_trait_ref(&*qpath.trait_ref); visitor.visit_ident(typ.span, qpath.item_name); } TyFixedLengthVec(ref ty, ref expression) => { diff --git a/src/test/compile-fail/associated-types-in-ambiguous-context.rs b/src/test/compile-fail/associated-types-in-ambiguous-context.rs index a2c01fe62f6bb..24de1fa2f7844 100644 --- a/src/test/compile-fail/associated-types-in-ambiguous-context.rs +++ b/src/test/compile-fail/associated-types-in-ambiguous-context.rs @@ -20,12 +20,12 @@ fn get(x: T, y: U) -> Get::Value {} trait Other { fn uhoh(&self, foo: U, bar: ::Value) {} - //~^ ERROR this associated type is not allowed in this context + //~^ ERROR no suitable bound on `Self` } impl Other for T { fn uhoh(&self, foo: U, bar: <(T, U) as Get>::Value) {} - //~^ ERROR this associated type is not allowed in this context + //~^ ERROR currently unsupported } trait Grab { diff --git a/src/test/compile-fail/associated-types-in-wrong-context.rs b/src/test/compile-fail/associated-types-in-wrong-context.rs index 8fbfc33896b41..8cab2759ad55a 100644 --- a/src/test/compile-fail/associated-types-in-wrong-context.rs +++ b/src/test/compile-fail/associated-types-in-wrong-context.rs @@ -16,7 +16,7 @@ trait Get { } fn get(x: int) -> ::Value {} -//~^ ERROR this associated type is not allowed in this context +//~^ ERROR unsupported struct Struct { x: int, @@ -24,7 +24,7 @@ struct Struct { impl Struct { fn uhoh(foo: ::Value) {} - //~^ ERROR this associated type is not allowed in this context + //~^ ERROR no suitable bound on `T` } fn main() { diff --git a/src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs b/src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs new file mode 100644 index 0000000000000..1b4eb2604a82b --- /dev/null +++ b/src/test/run-pass/associated-types-qualified-path-with-trait-with-type-parameters.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Foo { + type Bar; + fn get_bar() -> >::Bar; +} + +fn main() { } From 0b6ec701974096b68e666693b8a750fb6a5d65c6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 13 Nov 2014 21:20:01 -0500 Subject: [PATCH 16/25] Ensure that the type parameters passed to methods outlive the call expression. Fixes #18899. --- .../middle/typeck/check/method/confirm.rs | 13 +++++++--- .../middle/typeck/check/method/mod.rs | 10 +++---- src/librustc/middle/typeck/check/mod.rs | 19 +++++++++----- .../compile-fail/regions-escape-method.rs | 26 +++++++++++++++++++ 4 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 src/test/compile-fail/regions-escape-method.rs diff --git a/src/librustc/middle/typeck/check/method/confirm.rs b/src/librustc/middle/typeck/check/method/confirm.rs index af8ef09d2a072..c53befcc10d6b 100644 --- a/src/librustc/middle/typeck/check/method/confirm.rs +++ b/src/librustc/middle/typeck/check/method/confirm.rs @@ -31,6 +31,7 @@ struct ConfirmContext<'a, 'tcx:'a> { fcx: &'a FnCtxt<'a, 'tcx>, span: Span, self_expr: &'a ast::Expr, + call_expr: &'a ast::Expr, } struct InstantiatedMethodSig<'tcx> { @@ -56,6 +57,7 @@ struct InstantiatedMethodSig<'tcx> { pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, self_expr: &ast::Expr, + call_expr: &ast::Expr, unadjusted_self_ty: Ty<'tcx>, pick: probe::Pick<'tcx>, supplied_method_types: Vec>) @@ -66,17 +68,18 @@ pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, pick.repr(fcx.tcx()), supplied_method_types.repr(fcx.tcx())); - let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr); + let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr); confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types) } impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn new(fcx: &'a FnCtxt<'a, 'tcx>, span: Span, - self_expr: &'a ast::Expr) + self_expr: &'a ast::Expr, + call_expr: &'a ast::Expr) -> ConfirmContext<'a, 'tcx> { - ConfirmContext { fcx: fcx, span: span, self_expr: self_expr } + ConfirmContext { fcx: fcx, span: span, self_expr: self_expr, call_expr: call_expr } } fn confirm(&mut self, @@ -469,6 +472,10 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { traits::ObligationCause::misc(self.span), method_bounds_substs, method_bounds); + + self.fcx.add_default_region_param_bounds( + method_bounds_substs, + self.call_expr); } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc/middle/typeck/check/method/mod.rs b/src/librustc/middle/typeck/check/method/mod.rs index 411948ed6b4ac..0f4152644adaf 100644 --- a/src/librustc/middle/typeck/check/method/mod.rs +++ b/src/librustc/middle/typeck/check/method/mod.rs @@ -79,7 +79,7 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_name: ast::Name, self_ty: Ty<'tcx>, supplied_method_types: Vec>, - call_expr_id: ast::NodeId, + call_expr: &ast::Expr, self_expr: &ast::Expr) -> Result, MethodError> { @@ -100,14 +100,14 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, * - `self_expr`: the self expression (`foo`) */ - debug!("lookup(method_name={}, self_ty={}, call_expr_id={}, self_expr={})", + debug!("lookup(method_name={}, self_ty={}, call_expr={}, self_expr={})", method_name.repr(fcx.tcx()), self_ty.repr(fcx.tcx()), - call_expr_id, + call_expr.repr(fcx.tcx()), self_expr.repr(fcx.tcx())); - let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr_id)); - Ok(confirm::confirm(fcx, span, self_expr, self_ty, pick, supplied_method_types)) + let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id)); + Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types)) } pub fn lookup_in_trait<'a, 'tcx>(fcx: &'a FnCtxt<'a, 'tcx>, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 543eb44697c06..266b105efc28c 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2050,6 +2050,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub fn add_default_region_param_bounds(&self, + substs: &Substs<'tcx>, + expr: &ast::Expr) + { + for &ty in substs.types.iter() { + let default_bound = ty::ReScope(expr.id); + let origin = infer::RelateDefaultParamBound(expr.span, ty); + self.register_region_obligation(origin, ty, default_bound); + } + } + pub fn add_obligations_for_parameters(&self, cause: traits::ObligationCause<'tcx>, substs: &Substs<'tcx>, @@ -3180,7 +3191,7 @@ fn check_expr_with_unifier<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, method_name.node.name, expr_t, tps, - expr.id, + expr, rcvr) { Ok(method) => { let method_ty = method.ty; @@ -4693,11 +4704,7 @@ fn constrain_path_type_parameters(fcx: &FnCtxt, expr: &ast::Expr) { fcx.opt_node_ty_substs(expr.id, |item_substs| { - for &ty in item_substs.substs.types.iter() { - let default_bound = ty::ReScope(expr.id); - let origin = infer::RelateDefaultParamBound(expr.span, ty); - fcx.register_region_obligation(origin, ty, default_bound); - } + fcx.add_default_region_param_bounds(&item_substs.substs, expr); }); } diff --git a/src/test/compile-fail/regions-escape-method.rs b/src/test/compile-fail/regions-escape-method.rs new file mode 100644 index 0000000000000..f92c264784ae6 --- /dev/null +++ b/src/test/compile-fail/regions-escape-method.rs @@ -0,0 +1,26 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test a method call where the parameter `B` would (illegally) be +// inferred to a region bound in the method argument. If this program +// were accepted, then the closure passed to `s.f` could escape its +// argument. + +struct S; + +impl S { + fn f(&self, _: |&i32| -> B) { + } +} + +fn main() { + let s = S; + s.f(|p| p) //~ ERROR cannot infer +} From 2477bc4451dc93b9e89c3e1e1621b4333675d94b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Nov 2014 05:55:10 -0500 Subject: [PATCH 17/25] Update libcollections tests to pass the new type rules. They used to return a pointer to the value they were modifying, but this should not have been legal, since that pointer would have to outlive the closure, and the closure continues to modify the value during the execution. This return value was just passed to `black_box` so as to convince llvm that the value was live, so rather than returning a pointer, modify to just call `black_box` directly inside the fn. --- src/libcollections/bit.rs | 28 ++++++++++++++-------------- src/libcollections/slice.rs | 6 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 0529bb8904ab9..64abc78daf309 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -1678,10 +1678,10 @@ impl<'a> Iterator for TwoBitPositions<'a> { mod tests { use std::prelude::*; use std::iter::range_step; - use std::u32; use std::rand; use std::rand::Rng; - use test::Bencher; + use std::u32; + use test::{Bencher, black_box}; use super::{Bitv, BitvSet, from_fn, from_bytes}; use bitv; @@ -2676,8 +2676,8 @@ mod tests { for _ in range(0u, 100) { bitv |= 1 << ((r.next_u32() as uint) % u32::BITS); } - &bitv - }) + black_box(&bitv) + }); } #[bench] @@ -2688,8 +2688,8 @@ mod tests { for _ in range(0u, 100) { bitv.set((r.next_u32() as uint) % BENCH_BITS, true); } - &bitv - }) + black_box(&bitv) + }); } #[bench] @@ -2700,8 +2700,8 @@ mod tests { for _ in range(0u, 100) { bitv.set((r.next_u32() as uint) % BENCH_BITS, r.gen()); } - &bitv - }) + black_box(&bitv); + }); } #[bench] @@ -2712,8 +2712,8 @@ mod tests { for _ in range(0u, 100) { bitv.set((r.next_u32() as uint) % u32::BITS, true); } - &bitv - }) + black_box(&bitv); + }); } #[bench] @@ -2724,8 +2724,8 @@ mod tests { for _ in range(0u, 100) { bitv.insert((r.next_u32() as uint) % u32::BITS); } - &bitv - }) + black_box(&bitv); + }); } #[bench] @@ -2736,8 +2736,8 @@ mod tests { for _ in range(0u, 100) { bitv.insert((r.next_u32() as uint) % BENCH_BITS); } - &bitv - }) + black_box(&bitv); + }); } #[bench] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 132a07af6b67b..5e341ba8b04d3 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -2084,7 +2084,7 @@ mod bench { use std::rand::{weak_rng, Rng}; use std::mem; use std::ptr; - use test::Bencher; + use test::{Bencher, black_box}; use vec::Vec; @@ -2140,8 +2140,8 @@ mod bench { let mut vec: Vec = vec![]; b.iter(|| { vec.push(0); - &vec - }) + black_box(&vec); + }); } #[bench] From 6679595853705ca11f64984a055be60233321a4a Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 15:48:38 +1100 Subject: [PATCH 18/25] Parse and store suffixes on literals. This adds an optional suffix at the end of a literal token: `"foo"bar`. An actual use of a suffix in a expression (or other literal that the compiler reads) is rejected in the parser. This doesn't switch the handling of numbers to this system, and doesn't outlaw illegal suffixes for them yet. --- src/librustdoc/html/highlight.rs | 18 ++-- src/libsyntax/ast.rs | 2 +- src/libsyntax/diagnostics/plugin.rs | 2 +- src/libsyntax/ext/quote.rs | 33 ++++--- src/libsyntax/parse/lexer/mod.rs | 112 ++++++++++++++++------ src/libsyntax/parse/parser.rs | 109 +++++++++++++++------ src/libsyntax/parse/token.rs | 19 +++- src/libsyntax/print/pprust.rs | 34 ++++--- src/test/compile-fail/bad-lit-suffixes.rs | 36 +++++++ 9 files changed, 268 insertions(+), 97 deletions(-) create mode 100644 src/test/compile-fail/bad-lit-suffixes.rs diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 527ef553d99e5..111650f565cf6 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -128,13 +128,17 @@ fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, } } - // text literals - token::Literal(token::Byte(..)) | token::Literal(token::Char(..)) | - token::Literal(token::Binary(..)) | token::Literal(token::BinaryRaw(..)) | - token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => "string", - - // number literals - token::Literal(token::Integer(..)) | token::Literal(token::Float(..)) => "number", + token::Literal(lit, _suf) => { + match lit { + // text literals + token::Byte(..) | token::Char(..) | + token::Binary(..) | token::BinaryRaw(..) | + token::Str_(..) | token::StrRaw(..) => "string", + + // number literals + token::Integer(..) | token::Float(..) => "number", + } + } // keywords are also included in the identifier set token::Ident(ident, _is_mod_sep) => { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2158bdb416c7e..7b16c08785926 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -838,7 +838,7 @@ impl TokenTree { tts: vec![TtToken(sp, token::Ident(token::str_to_ident("doc"), token::Plain)), TtToken(sp, token::Eq), - TtToken(sp, token::Literal(token::Str_(name)))], + TtToken(sp, token::Literal(token::Str_(name), None))], close_span: sp, })) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index b928fc778e8bc..281bde3129aba 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -87,7 +87,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, }, [ast::TtToken(_, token::Ident(ref code, _)), ast::TtToken(_, token::Comma), - ast::TtToken(_, token::Literal(token::StrRaw(description, _)))] => { + ast::TtToken(_, token::Literal(token::StrRaw(description, _), None))] => { (code, Some(description)) } _ => unreachable!() diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index ec51ce00605fd..eaa3632cf499e 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -543,10 +543,13 @@ fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P { #[allow(non_upper_case_globals)] fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { macro_rules! mk_lit { - ($name: expr, $($args: expr),*) => {{ + ($name: expr, $suffix: expr, $($args: expr),*) => {{ let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]); - - cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner]) + let suffix = match $suffix { + Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::new(name))), + None => cx.expr_none(sp) + }; + cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix]) }} } match *tok { @@ -567,32 +570,32 @@ fn mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P { vec![mk_delim(cx, sp, delim)]); } - token::Literal(token::Byte(i)) => { + token::Literal(token::Byte(i), suf) => { let e_byte = mk_name(cx, sp, i.ident()); - return mk_lit!("Byte", e_byte); + return mk_lit!("Byte", suf, e_byte); } - token::Literal(token::Char(i)) => { + token::Literal(token::Char(i), suf) => { let e_char = mk_name(cx, sp, i.ident()); - return mk_lit!("Char", e_char); + return mk_lit!("Char", suf, e_char); } - token::Literal(token::Integer(i)) => { + token::Literal(token::Integer(i), suf) => { let e_int = mk_name(cx, sp, i.ident()); - return mk_lit!("Integer", e_int); + return mk_lit!("Integer", suf, e_int); } - token::Literal(token::Float(fident)) => { + token::Literal(token::Float(fident), suf) => { let e_fident = mk_name(cx, sp, fident.ident()); - return mk_lit!("Float", e_fident); + return mk_lit!("Float", suf, e_fident); } - token::Literal(token::Str_(ident)) => { - return mk_lit!("Str_", mk_name(cx, sp, ident.ident())) + token::Literal(token::Str_(ident), suf) => { + return mk_lit!("Str_", suf, mk_name(cx, sp, ident.ident())) } - token::Literal(token::StrRaw(ident, n)) => { - return mk_lit!("StrRaw", mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n)) + token::Literal(token::StrRaw(ident, n), suf) => { + return mk_lit!("StrRaw", suf, mk_name(cx, sp, ident.ident()), cx.expr_uint(sp, n)) } token::Ident(ident, style) => { diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b7598c7c42820..55c4335941dbc 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -369,6 +369,25 @@ impl<'a> StringReader<'a> { self.nextnextch() == Some(c) } + /// Eats *, if possible. + fn scan_optional_raw_name(&mut self) -> Option { + if !ident_start(self.curr) { + return None + } + let start = self.last_pos; + while ident_continue(self.curr) { + self.bump(); + } + + self.with_str_from(start, |string| { + if string == "_" { + None + } else { + Some(token::intern(string)) + } + }) + } + /// PRECONDITION: self.curr is not whitespace /// Eats any kind of comment. fn scan_comment(&mut self) -> Option { @@ -638,7 +657,7 @@ impl<'a> StringReader<'a> { } /// Lex a LIT_INTEGER or a LIT_FLOAT - fn scan_number(&mut self, c: char) -> token::Token { + fn scan_number(&mut self, c: char) -> token::Lit { let mut num_digits; let mut base = 10; let start_bpos = self.last_pos; @@ -655,17 +674,17 @@ impl<'a> StringReader<'a> { } 'u' | 'i' => { self.scan_int_suffix(); - return token::Literal(token::Integer(self.name_from(start_bpos))); + return token::Integer(self.name_from(start_bpos)); }, 'f' => { let last_pos = self.last_pos; self.scan_float_suffix(); self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } _ => { // just a 0 - return token::Literal(token::Integer(self.name_from(start_bpos))); + return token::Integer(self.name_from(start_bpos)); } } } else if c.is_digit_radix(10) { @@ -678,7 +697,7 @@ impl<'a> StringReader<'a> { self.err_span_(start_bpos, self.last_pos, "no valid digits found for number"); // eat any suffix self.scan_int_suffix(); - return token::Literal(token::Integer(token::intern("0"))); + return token::Integer(token::intern("0")); } // might be a float, but don't be greedy if this is actually an @@ -696,13 +715,13 @@ impl<'a> StringReader<'a> { } let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } else if self.curr_is('f') { // or it might be an integer literal suffixed as a float self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } else { // it might be a float if it has an exponent if self.curr_is('e') || self.curr_is('E') { @@ -710,11 +729,11 @@ impl<'a> StringReader<'a> { self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); - return token::Literal(token::Float(self.name_from(start_bpos))); + return token::Float(self.name_from(start_bpos)); } // but we certainly have an integer! self.scan_int_suffix(); - return token::Literal(token::Integer(self.name_from(start_bpos))); + return token::Integer(self.name_from(start_bpos)); } } @@ -967,7 +986,9 @@ impl<'a> StringReader<'a> { } if is_dec_digit(c) { - return self.scan_number(c.unwrap()); + let num = self.scan_number(c.unwrap()); + let suffix = self.scan_optional_raw_name(); + return token::Literal(num, suffix) } if self.read_embedded_ident { @@ -1126,17 +1147,19 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("0") }; self.bump(); // advance curr past token - return token::Literal(token::Char(id)); + let suffix = self.scan_optional_raw_name(); + return token::Literal(token::Char(id), suffix); } 'b' => { self.bump(); - return match self.curr { + let lit = match self.curr { Some('\'') => self.scan_byte(), Some('"') => self.scan_byte_string(), Some('r') => self.scan_raw_byte_string(), _ => unreachable!() // Should have been a token::Ident above. }; - + let suffix = self.scan_optional_raw_name(); + return token::Literal(lit, suffix); } '"' => { let start_bpos = self.last_pos; @@ -1157,7 +1180,8 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start_bpos + BytePos(1)) } else { token::intern("??") }; self.bump(); - return token::Literal(token::Str_(id)); + let suffix = self.scan_optional_raw_name(); + return token::Literal(token::Str_(id), suffix); } 'r' => { let start_bpos = self.last_pos; @@ -1224,7 +1248,8 @@ impl<'a> StringReader<'a> { } else { token::intern("??") }; - return token::Literal(token::StrRaw(id, hash_count)); + let suffix = self.scan_optional_raw_name(); + return token::Literal(token::StrRaw(id, hash_count), suffix); } '-' => { if self.nextch_is('>') { @@ -1293,7 +1318,7 @@ impl<'a> StringReader<'a> { || (self.curr_is('#') && self.nextch_is('!') && !self.nextnextch_is('[')) } - fn scan_byte(&mut self) -> token::Token { + fn scan_byte(&mut self) -> token::Lit { self.bump(); let start = self.last_pos; @@ -1314,10 +1339,10 @@ impl<'a> StringReader<'a> { let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); // advance curr past token - return token::Literal(token::Byte(id)); + return token::Byte(id); } - fn scan_byte_string(&mut self) -> token::Token { + fn scan_byte_string(&mut self) -> token::Lit { self.bump(); let start = self.last_pos; let mut valid = true; @@ -1336,10 +1361,10 @@ impl<'a> StringReader<'a> { } let id = if valid { self.name_from(start) } else { token::intern("??") }; self.bump(); - return token::Literal(token::Binary(id)); + return token::Binary(id); } - fn scan_raw_byte_string(&mut self) -> token::Token { + fn scan_raw_byte_string(&mut self) -> token::Lit { let start_bpos = self.last_pos; self.bump(); let mut hash_count = 0u; @@ -1387,9 +1412,9 @@ impl<'a> StringReader<'a> { self.bump(); } self.bump(); - return token::Literal(token::BinaryRaw(self.name_from_to(content_start_bpos, - content_end_bpos), - hash_count)); + return token::BinaryRaw(self.name_from_to(content_start_bpos, + content_end_bpos), + hash_count); } } @@ -1536,17 +1561,17 @@ mod test { #[test] fn character_a() { assert_eq!(setup(&mk_sh(), "'a'".to_string()).next_token().tok, - token::Literal(token::Char(token::intern("a")))); + token::Literal(token::Char(token::intern("a")), None)); } #[test] fn character_space() { assert_eq!(setup(&mk_sh(), "' '".to_string()).next_token().tok, - token::Literal(token::Char(token::intern(" ")))); + token::Literal(token::Char(token::intern(" ")), None)); } #[test] fn character_escaped() { assert_eq!(setup(&mk_sh(), "'\\n'".to_string()).next_token().tok, - token::Literal(token::Char(token::intern("\\n")))); + token::Literal(token::Char(token::intern("\\n")), None)); } #[test] fn lifetime_name() { @@ -1558,7 +1583,38 @@ mod test { assert_eq!(setup(&mk_sh(), "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token() .tok, - token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3))); + token::Literal(token::StrRaw(token::intern("\"#a\\b\x00c\""), 3), None)); + } + + #[test] fn literal_suffixes() { + macro_rules! test { + ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ + assert_eq!(setup(&mk_sh(), format!("{}suffix", $input)).next_token().tok, + token::Literal(token::$tok_type(token::intern($tok_contents)), + Some(token::intern("suffix")))); + // with a whitespace separator: + assert_eq!(setup(&mk_sh(), format!("{} suffix", $input)).next_token().tok, + token::Literal(token::$tok_type(token::intern($tok_contents)), + None)); + }} + } + + test!("'a'", Char, "a"); + test!("b'a'", Byte, "a"); + test!("\"a\"", Str_, "a"); + test!("b\"a\"", Binary, "a"); + test!("1234", Integer, "1234"); + test!("0b101", Integer, "0b101"); + test!("0xABC", Integer, "0xABC"); + test!("1.0", Float, "1.0"); + test!("1.0e10", Float, "1.0e10"); + + assert_eq!(setup(&mk_sh(), "r###\"raw\"###suffix".to_string()).next_token().tok, + token::Literal(token::StrRaw(token::intern("raw"), 3), + Some(token::intern("suffix")))); + assert_eq!(setup(&mk_sh(), "br###\"raw\"###suffix".to_string()).next_token().tok, + token::Literal(token::BinaryRaw(token::intern("raw"), 3), + Some(token::intern("suffix")))); } #[test] fn line_doc_comments() { @@ -1574,7 +1630,7 @@ mod test { token::Comment => { }, _ => panic!("expected a comment!") } - assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")))); + assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")), None)); } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4edcb182e5385..b9e1fe07e712a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -646,6 +646,20 @@ impl<'a> Parser<'a> { } } + pub fn expect_no_suffix(&mut self, sp: Span, kind: &str, suffix: Option) { + match suffix { + None => {/* everything ok */} + Some(suf) => { + let text = suf.as_str(); + if text.is_empty() { + self.span_bug(sp, "found empty non-None literal suffix") + } + self.span_err(sp, &*format!("a {} with a suffix is illegal", kind)); + } + } + } + + /// Attempt to consume a `<`. If `<<` is seen, replace it with a single /// `<` and continue. If a `<` is not seen, return false. /// @@ -968,6 +982,9 @@ impl<'a> Parser<'a> { pub fn span_err(&mut self, sp: Span, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } + pub fn span_bug(&mut self, sp: Span, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(sp, m) + } pub fn abort_if_errors(&mut self) { self.sess.span_diagnostic.handler().abort_if_errors(); } @@ -1640,24 +1657,40 @@ impl<'a> Parser<'a> { /// Matches token_lit = LIT_INTEGER | ... pub fn lit_from_token(&mut self, tok: &token::Token) -> Lit_ { match *tok { - token::Literal(token::Byte(i)) => LitByte(parse::byte_lit(i.as_str()).val0()), - token::Literal(token::Char(i)) => LitChar(parse::char_lit(i.as_str()).val0()), - token::Literal(token::Integer(s)) => parse::integer_lit(s.as_str(), - &self.sess.span_diagnostic, - self.last_span), - token::Literal(token::Float(s)) => parse::float_lit(s.as_str()), - token::Literal(token::Str_(s)) => { - LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), - ast::CookedStr) - } - token::Literal(token::StrRaw(s, n)) => { - LitStr(token::intern_and_get_ident(parse::raw_str_lit(s.as_str()).as_slice()), - ast::RawStr(n)) + token::Literal(lit, suf) => { + let (suffix_illegal, out) = match lit { + token::Byte(i) => (true, LitByte(parse::byte_lit(i.as_str()).val0())), + token::Char(i) => (true, LitChar(parse::char_lit(i.as_str()).val0())), + token::Integer(s) => (false, parse::integer_lit(s.as_str(), + &self.sess.span_diagnostic, + self.last_span)), + token::Float(s) => (false, parse::float_lit(s.as_str())), + token::Str_(s) => { + (true, + LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), + ast::CookedStr)) + } + token::StrRaw(s, n) => { + (true, + LitStr( + token::intern_and_get_ident( + parse::raw_str_lit(s.as_str()).as_slice()), + ast::RawStr(n))) + } + token::Binary(i) => + (true, LitBinary(parse::binary_lit(i.as_str()))), + token::BinaryRaw(i, _) => + (true, + LitBinary(Rc::new(i.as_str().as_bytes().iter().map(|&x| x).collect()))), + }; + + if suffix_illegal { + let sp = self.last_span; + self.expect_no_suffix(sp, &*format!("{} literal", lit.short_name()), suf) + } + + out } - token::Literal(token::Binary(i)) => - LitBinary(parse::binary_lit(i.as_str())), - token::Literal(token::BinaryRaw(i, _)) => - LitBinary(Rc::new(i.as_str().as_bytes().iter().map(|&x| x).collect())), _ => { self.unexpected_last(tok); } } } @@ -2424,7 +2457,10 @@ impl<'a> Parser<'a> { } } } - token::Literal(token::Integer(n)) => { + token::Literal(token::Integer(n), suf) => { + let sp = self.span; + self.expect_no_suffix(sp, "tuple index", suf); + let index = n.as_str(); let dot = self.last_span.hi; hi = self.span.hi; @@ -2449,7 +2485,7 @@ impl<'a> Parser<'a> { } } } - token::Literal(token::Float(n)) => { + token::Literal(token::Float(n), _suf) => { self.bump(); let last_span = self.last_span; let fstr = n.as_str(); @@ -5085,12 +5121,17 @@ impl<'a> Parser<'a> { self.expect(&token::Semi); (path, the_ident) }, - token::Literal(token::Str_(..)) | token::Literal(token::StrRaw(..)) => { - let path = self.parse_str(); + token::Literal(token::Str_(..), suf) | token::Literal(token::StrRaw(..), suf) => { + let sp = self.span; + self.expect_no_suffix(sp, "extern crate name", suf); + // forgo the internal suffix check of `parse_str` to + // avoid repeats (this unwrap will always succeed due + // to the restriction of the `match`) + let (s, style, _) = self.parse_optional_str().unwrap(); self.expect_keyword(keywords::As); let the_ident = self.parse_ident(); self.expect(&token::Semi); - (Some(path), the_ident) + (Some((s, style)), the_ident) }, _ => { let span = self.span; @@ -5267,7 +5308,9 @@ impl<'a> Parser<'a> { /// the `extern` keyword, if one is found. fn parse_opt_abi(&mut self) -> Option { match self.token { - token::Literal(token::Str_(s)) | token::Literal(token::StrRaw(s, _)) => { + token::Literal(token::Str_(s), suf) | token::Literal(token::StrRaw(s, _), suf) => { + let sp = self.span; + self.expect_no_suffix(sp, "ABI spec", suf); self.bump(); let the_string = s.as_str(); match abi::lookup(the_string) { @@ -5902,21 +5945,27 @@ impl<'a> Parser<'a> { } pub fn parse_optional_str(&mut self) - -> Option<(InternedString, ast::StrStyle)> { - let (s, style) = match self.token { - token::Literal(token::Str_(s)) => (self.id_to_interned_str(s.ident()), ast::CookedStr), - token::Literal(token::StrRaw(s, n)) => { - (self.id_to_interned_str(s.ident()), ast::RawStr(n)) + -> Option<(InternedString, ast::StrStyle, Option)> { + let ret = match self.token { + token::Literal(token::Str_(s), suf) => { + (self.id_to_interned_str(s.ident()), ast::CookedStr, suf) + } + token::Literal(token::StrRaw(s, n), suf) => { + (self.id_to_interned_str(s.ident()), ast::RawStr(n), suf) } _ => return None }; self.bump(); - Some((s, style)) + Some(ret) } pub fn parse_str(&mut self) -> (InternedString, StrStyle) { match self.parse_optional_str() { - Some(s) => { s } + Some((s, style, suf)) => { + let sp = self.last_span; + self.expect_no_suffix(sp, "str literal", suf); + (s, style) + } _ => self.fatal("expected string literal") } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index bfa6ca798b233..4272b57a4dc51 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -72,6 +72,19 @@ pub enum Lit { BinaryRaw(ast::Name, uint), /* raw binary str delimited by n hash symbols */ } +impl Lit { + pub fn short_name(&self) -> &'static str { + match *self { + Byte(_) => "byte", + Char(_) => "char", + Integer(_) => "integer", + Float(_) => "float", + Str_(_) | StrRaw(..) => "str", + Binary(_) | BinaryRaw(..) => "binary str" + } + } +} + #[allow(non_camel_case_types)] #[deriving(Clone, Encodable, Decodable, PartialEq, Eq, Hash, Show)] pub enum Token { @@ -111,7 +124,7 @@ pub enum Token { CloseDelim(DelimToken), /* Literals */ - Literal(Lit), + Literal(Lit, Option), /* Name components */ Ident(ast::Ident, IdentStyle), @@ -151,7 +164,7 @@ impl Token { Ident(_, _) => true, Underscore => true, Tilde => true, - Literal(_) => true, + Literal(_, _) => true, Pound => true, At => true, Not => true, @@ -172,7 +185,7 @@ impl Token { /// Returns `true` if the token is any literal pub fn is_lit(&self) -> bool { match *self { - Literal(_) => true, + Literal(_, _) => true, _ => false, } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7997c1ba4efcf..642ffa3745d9f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -236,18 +236,28 @@ pub fn token_to_string(tok: &Token) -> String { token::Question => "?".into_string(), /* Literals */ - token::Literal(token::Byte(b)) => format!("b'{}'", b.as_str()), - token::Literal(token::Char(c)) => format!("'{}'", c.as_str()), - token::Literal(token::Float(c)) => c.as_str().into_string(), - token::Literal(token::Integer(c)) => c.as_str().into_string(), - token::Literal(token::Str_(s)) => format!("\"{}\"", s.as_str()), - token::Literal(token::StrRaw(s, n)) => format!("r{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), - token::Literal(token::Binary(v)) => format!("b\"{}\"", v.as_str()), - token::Literal(token::BinaryRaw(s, n)) => format!("br{delim}\"{string}\"{delim}", - delim="#".repeat(n), - string=s.as_str()), + token::Literal(lit, suf) => { + let mut out = match lit { + token::Byte(b) => format!("b'{}'", b.as_str()), + token::Char(c) => format!("'{}'", c.as_str()), + token::Float(c) => c.as_str().into_string(), + token::Integer(c) => c.as_str().into_string(), + token::Str_(s) => format!("\"{}\"", s.as_str()), + token::StrRaw(s, n) => format!("r{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), + token::Binary(v) => format!("b\"{}\"", v.as_str()), + token::BinaryRaw(s, n) => format!("br{delim}\"{string}\"{delim}", + delim="#".repeat(n), + string=s.as_str()), + }; + + if let Some(s) = suf { + out.push_str(s.as_str()) + } + + out + } /* Name components */ token::Ident(s, _) => token::get_ident(s).get().into_string(), diff --git a/src/test/compile-fail/bad-lit-suffixes.rs b/src/test/compile-fail/bad-lit-suffixes.rs new file mode 100644 index 0000000000000..e48bb807488a0 --- /dev/null +++ b/src/test/compile-fail/bad-lit-suffixes.rs @@ -0,0 +1,36 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +extern crate + "foo"suffix //~ ERROR extern crate name with a suffix is illegal + as foo; + +extern + "C"suffix //~ ERROR ABI spec with a suffix is illegal + fn foo() {} + +extern + "C"suffix //~ ERROR ABI spec with a suffix is illegal +{} + +fn main() { + ""suffix; //~ ERROR str literal with a suffix is illegal + b""suffix; //~ ERROR binary str literal with a suffix is illegal + r#""#suffix; //~ ERROR str literal with a suffix is illegal + br#""#suffix; //~ ERROR binary str literal with a suffix is illegal + 'a'suffix; //~ ERROR char literal with a suffix is illegal + b'a'suffix; //~ ERROR byte literal with a suffix is illegal + + 1234suffix; + 0b101suffix; + 1.0suffix; + 1.0e10suffix; +} From 606a309d4aeb09ba88a0962c633a5b3fd4b300f6 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 20:22:54 +1100 Subject: [PATCH 19/25] Switch numeric suffix parsing to use the new system. This moves errors and all handling of numeric suffixes into the parser rather than the lexer. --- src/libsyntax/parse/lexer/mod.rs | 74 +---------- src/libsyntax/parse/mod.rs | 145 ++++++++++++---------- src/libsyntax/parse/parser.rs | 25 +++- src/test/compile-fail/bad-lit-suffixes.rs | 13 +- 4 files changed, 108 insertions(+), 149 deletions(-) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 55c4335941dbc..fbca4868255ff 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -672,16 +672,6 @@ impl<'a> StringReader<'a> { '0'...'9' | '_' | '.' => { num_digits = self.scan_digits(10) + 1; } - 'u' | 'i' => { - self.scan_int_suffix(); - return token::Integer(self.name_from(start_bpos)); - }, - 'f' => { - let last_pos = self.last_pos; - self.scan_float_suffix(); - self.check_float_base(start_bpos, last_pos, base); - return token::Float(self.name_from(start_bpos)); - } _ => { // just a 0 return token::Integer(self.name_from(start_bpos)); @@ -695,8 +685,6 @@ impl<'a> StringReader<'a> { if num_digits == 0 { self.err_span_(start_bpos, self.last_pos, "no valid digits found for number"); - // eat any suffix - self.scan_int_suffix(); return token::Integer(token::intern("0")); } @@ -711,28 +699,19 @@ impl<'a> StringReader<'a> { if self.curr.unwrap_or('\0').is_digit_radix(10) { self.scan_digits(10); self.scan_float_exponent(); - self.scan_float_suffix(); } let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); return token::Float(self.name_from(start_bpos)); - } else if self.curr_is('f') { - // or it might be an integer literal suffixed as a float - self.scan_float_suffix(); - let last_pos = self.last_pos; - self.check_float_base(start_bpos, last_pos, base); - return token::Float(self.name_from(start_bpos)); } else { // it might be a float if it has an exponent if self.curr_is('e') || self.curr_is('E') { self.scan_float_exponent(); - self.scan_float_suffix(); let last_pos = self.last_pos; self.check_float_base(start_bpos, last_pos, base); return token::Float(self.name_from(start_bpos)); } // but we certainly have an integer! - self.scan_int_suffix(); return token::Integer(self.name_from(start_bpos)); } } @@ -869,55 +848,6 @@ impl<'a> StringReader<'a> { true } - /// Scan over an int literal suffix. - fn scan_int_suffix(&mut self) { - match self.curr { - Some('i') | Some('u') => { - self.bump(); - - if self.curr_is('8') { - self.bump(); - } else if self.curr_is('1') { - if !self.nextch_is('6') { - self.err_span_(self.last_pos, self.pos, - "illegal int suffix"); - } else { - self.bump(); self.bump(); - } - } else if self.curr_is('3') { - if !self.nextch_is('2') { - self.err_span_(self.last_pos, self.pos, - "illegal int suffix"); - } else { - self.bump(); self.bump(); - } - } else if self.curr_is('6') { - if !self.nextch_is('4') { - self.err_span_(self.last_pos, self.pos, - "illegal int suffix"); - } else { - self.bump(); self.bump(); - } - } - }, - _ => { } - } - } - - /// Scan over a float literal suffix - fn scan_float_suffix(&mut self) { - if self.curr_is('f') { - if (self.nextch_is('3') && self.nextnextch_is('2')) - || (self.nextch_is('6') && self.nextnextch_is('4')) { - self.bump(); - self.bump(); - self.bump(); - } else { - self.err_span_(self.last_pos, self.pos, "illegal float suffix"); - } - } - } - /// Scan over a float exponent. fn scan_float_exponent(&mut self) { if self.curr_is('e') || self.curr_is('E') { @@ -988,6 +918,7 @@ impl<'a> StringReader<'a> { if is_dec_digit(c) { let num = self.scan_number(c.unwrap()); let suffix = self.scan_optional_raw_name(); + debug!("next_token_inner: scanned number {}, {}", num, suffix); return token::Literal(num, suffix) } @@ -1609,6 +1540,9 @@ mod test { test!("1.0", Float, "1.0"); test!("1.0e10", Float, "1.0e10"); + assert_eq!(setup(&mk_sh(), "2u".to_string()).next_token().tok, + token::Literal(token::Integer(token::intern("2")), + Some(token::intern("u")))); assert_eq!(setup(&mk_sh(), "r###\"raw\"###suffix".to_string()).next_token().tok, token::Literal(token::StrRaw(token::intern("raw"), 3), Some(token::intern("suffix")))); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 2810db4eaddd8..d111108269dfe 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -511,28 +511,41 @@ pub fn raw_str_lit(lit: &str) -> String { res } -pub fn float_lit(s: &str) -> ast::Lit_ { - debug!("float_lit: {}", s); - // FIXME #2252: bounds checking float literals is defered until trans - let s2 = s.chars().filter(|&c| c != '_').collect::(); - let s = s2.as_slice(); - - let mut ty = None; - - if s.ends_with("f32") { - ty = Some(ast::TyF32); - } else if s.ends_with("f64") { - ty = Some(ast::TyF64); - } +// check if `s` looks like i32 or u1234 etc. +fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { + s.len() > 1 && + first_chars.contains(&s.char_at(0)) && + s.slice_from(1).chars().all(|c| '0' <= c && c <= '9') +} +fn filtered_float_lit(data: token::InternedString, suffix: Option<&str>, + sd: &SpanHandler, sp: Span) -> ast::Lit_ { + debug!("filtered_float_lit: {}, {}", data, suffix); + match suffix { + Some("f32") => ast::LitFloat(data, ast::TyF32), + Some("f64") => ast::LitFloat(data, ast::TyF64), + Some(suf) => { + if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { + // if it looks like a width, lets try to be helpful. + sd.span_err(sp, &*format!("illegal width `{}` for float literal, \ + valid widths are 32 and 64", suf.slice_from(1))); + } else { + sd.span_err(sp, &*format!("illegal suffix `{}` for float literal, \ + valid suffixes are `f32` and `f64`", suf)); + } - match ty { - Some(t) => { - ast::LitFloat(token::intern_and_get_ident(s.slice_to(s.len() - t.suffix_len())), t) - }, - None => ast::LitFloatUnsuffixed(token::intern_and_get_ident(s)) + ast::LitFloatUnsuffixed(data) + } + None => ast::LitFloatUnsuffixed(data) } } +pub fn float_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> ast::Lit_ { + debug!("float_lit: {}, {}", s, suffix); + // FIXME #2252: bounds checking float literals is defered until trans + let s = s.chars().filter(|&c| c != '_').collect::(); + let data = token::intern_and_get_ident(&*s); + filtered_float_lit(data, suffix, sd, sp) +} /// Parse a string representing a byte literal into its final form. Similar to `char_lit` pub fn byte_lit(lit: &str) -> (u8, uint) { @@ -626,24 +639,19 @@ pub fn binary_lit(lit: &str) -> Rc> { Rc::new(res) } -pub fn integer_lit(s: &str, sd: &SpanHandler, sp: Span) -> ast::Lit_ { +pub fn integer_lit(s: &str, suffix: Option<&str>, sd: &SpanHandler, sp: Span) -> ast::Lit_ { // s can only be ascii, byte indexing is fine let s2 = s.chars().filter(|&c| c != '_').collect::(); let mut s = s2.as_slice(); - debug!("parse_integer_lit: {}", s); - - if s.len() == 1 { - let n = (s.char_at(0)).to_digit(10).unwrap(); - return ast::LitInt(n as u64, ast::UnsuffixedIntLit(ast::Sign::new(n))); - } + debug!("integer_lit: {}, {}", s, suffix); let mut base = 10; let orig = s; let mut ty = ast::UnsuffixedIntLit(ast::Plus); - if s.char_at(0) == '0' { + if s.char_at(0) == '0' && s.len() > 1 { match s.char_at(1) { 'x' => base = 16, 'o' => base = 8, @@ -652,57 +660,56 @@ pub fn integer_lit(s: &str, sd: &SpanHandler, sp: Span) -> ast::Lit_ { } } + // 1f64 and 2f32 etc. are valid float literals. + match suffix { + Some(suf) if looks_like_width_suffix(&['f'], suf) => { + match base { + 16u => sd.span_err(sp, "hexadecimal float literal is not supported"), + 8u => sd.span_err(sp, "octal float literal is not supported"), + 2u => sd.span_err(sp, "binary float literal is not supported"), + _ => () + } + let ident = token::intern_and_get_ident(&*s); + return filtered_float_lit(ident, suffix, sd, sp) + } + _ => {} + } + if base != 10 { s = s.slice_from(2); } - let last = s.len() - 1; - match s.char_at(last) { - 'i' => ty = ast::SignedIntLit(ast::TyI, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU), - '8' => { - if s.len() > 2 { - match s.char_at(last - 1) { - 'i' => ty = ast::SignedIntLit(ast::TyI8, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU8), - _ => { } - } - } - }, - '6' => { - if s.len() > 3 && s.char_at(last - 1) == '1' { - match s.char_at(last - 2) { - 'i' => ty = ast::SignedIntLit(ast::TyI16, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU16), - _ => { } - } - } - }, - '2' => { - if s.len() > 3 && s.char_at(last - 1) == '3' { - match s.char_at(last - 2) { - 'i' => ty = ast::SignedIntLit(ast::TyI32, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU32), - _ => { } - } - } - }, - '4' => { - if s.len() > 3 && s.char_at(last - 1) == '6' { - match s.char_at(last - 2) { - 'i' => ty = ast::SignedIntLit(ast::TyI64, ast::Plus), - 'u' => ty = ast::UnsignedIntLit(ast::TyU64), - _ => { } + if let Some(suf) = suffix { + if suf.is_empty() { sd.span_bug(sp, "found empty literal suffix in Some")} + ty = match suf { + "i" => ast::SignedIntLit(ast::TyI, ast::Plus), + "i8" => ast::SignedIntLit(ast::TyI8, ast::Plus), + "i16" => ast::SignedIntLit(ast::TyI16, ast::Plus), + "i32" => ast::SignedIntLit(ast::TyI32, ast::Plus), + "i64" => ast::SignedIntLit(ast::TyI64, ast::Plus), + "u" => ast::UnsignedIntLit(ast::TyU), + "u8" => ast::UnsignedIntLit(ast::TyU8), + "u16" => ast::UnsignedIntLit(ast::TyU16), + "u32" => ast::UnsignedIntLit(ast::TyU32), + "u64" => ast::UnsignedIntLit(ast::TyU64), + _ => { + // i and u look like widths, so lets + // give an error message along those lines + if looks_like_width_suffix(&['i', 'u'], suf) { + sd.span_err(sp, &*format!("illegal width `{}` for integer literal; \ + valid widths are 8, 16, 32 and 64", + suf.slice_from(1))); + } else { + sd.span_err(sp, &*format!("illegal suffix `{}` for numeric literal", suf)); } + + ty } - }, - _ => { } + } } - debug!("The suffix is {}, base {}, the new string is {}, the original \ - string was {}", ty, base, s, orig); - - s = s.slice_to(s.len() - ty.suffix_len()); + debug!("integer_lit: the type is {}, base {}, the new string is {}, the original \ + string was {}, the original suffix was {}", ty, base, s, orig, suffix); let res: u64 = match ::std::num::from_str_radix(s, base) { Some(r) => r, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b9e1fe07e712a..85364b8f65ffa 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -652,9 +652,9 @@ impl<'a> Parser<'a> { Some(suf) => { let text = suf.as_str(); if text.is_empty() { - self.span_bug(sp, "found empty non-None literal suffix") + self.span_bug(sp, "found empty literal suffix in Some") } - self.span_err(sp, &*format!("a {} with a suffix is illegal", kind)); + self.span_err(sp, &*format!("{} with a suffix is illegal", kind)); } } } @@ -1661,10 +1661,23 @@ impl<'a> Parser<'a> { let (suffix_illegal, out) = match lit { token::Byte(i) => (true, LitByte(parse::byte_lit(i.as_str()).val0())), token::Char(i) => (true, LitChar(parse::char_lit(i.as_str()).val0())), - token::Integer(s) => (false, parse::integer_lit(s.as_str(), - &self.sess.span_diagnostic, - self.last_span)), - token::Float(s) => (false, parse::float_lit(s.as_str())), + + // there are some valid suffixes for integer and + // float literals, so all the handling is done + // internally. + token::Integer(s) => { + (false, parse::integer_lit(s.as_str(), + suf.as_ref().map(|s| s.as_str()), + &self.sess.span_diagnostic, + self.last_span)) + } + token::Float(s) => { + (false, parse::float_lit(s.as_str(), + suf.as_ref().map(|s| s.as_str()), + &self.sess.span_diagnostic, + self.last_span)) + } + token::Str_(s) => { (true, LitStr(token::intern_and_get_ident(parse::str_lit(s.as_str()).as_slice()), diff --git a/src/test/compile-fail/bad-lit-suffixes.rs b/src/test/compile-fail/bad-lit-suffixes.rs index e48bb807488a0..e142365a8ca07 100644 --- a/src/test/compile-fail/bad-lit-suffixes.rs +++ b/src/test/compile-fail/bad-lit-suffixes.rs @@ -29,8 +29,13 @@ fn main() { 'a'suffix; //~ ERROR char literal with a suffix is illegal b'a'suffix; //~ ERROR byte literal with a suffix is illegal - 1234suffix; - 0b101suffix; - 1.0suffix; - 1.0e10suffix; + 1234u1024; //~ ERROR illegal width `1024` for integer literal + 1234i1024; //~ ERROR illegal width `1024` for integer literal + 1234f1024; //~ ERROR illegal width `1024` for float literal + 1234.5f1024; //~ ERROR illegal width `1024` for float literal + + 1234suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 0b101suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 1.0suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 1.0e10suffix; //~ ERROR illegal suffix `suffix` for numeric literal } From 7586abf01b5c6fcbb60926c7cab7d3e5d133fa9a Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 20:25:48 +1100 Subject: [PATCH 20/25] Adjust Antlr4 lexer to include suffixes. This makes the formal lexical grammar (more closely) reflect the one implemented by the compiler. --- src/grammar/RustLexer.g4 | 44 ++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/src/grammar/RustLexer.g4 b/src/grammar/RustLexer.g4 index e8165dabce5cd..0ff9af7aca133 100644 --- a/src/grammar/RustLexer.g4 +++ b/src/grammar/RustLexer.g4 @@ -92,49 +92,35 @@ fragment CHAR_ESCAPE | 'U' HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT ; -LIT_CHAR - : '\'' ( '\\' CHAR_ESCAPE | ~[\\'\n\t\r] ) '\'' +fragment SUFFIX + : IDENT ; -LIT_BYTE - : 'b\'' ( '\\' ( [xX] HEXIT HEXIT | [nrt\\'"0] ) | ~[\\'\n\t\r] ) '\'' +LIT_CHAR + : '\'' ( '\\' CHAR_ESCAPE | ~[\\'\n\t\r] ) '\'' SUFFIX? ; -fragment INT_SUFFIX - : 'i' - | 'i8' - | 'i16' - | 'i32' - | 'i64' - | 'u' - | 'u8' - | 'u16' - | 'u32' - | 'u64' +LIT_BYTE + : 'b\'' ( '\\' ( [xX] HEXIT HEXIT | [nrt\\'"0] ) | ~[\\'\n\t\r] ) '\'' SUFFIX? ; LIT_INTEGER - : [0-9][0-9_]* INT_SUFFIX? - | '0b' [01][01_]* INT_SUFFIX? - | '0o' [0-7][0-7_]* INT_SUFFIX? - | '0x' [0-9a-fA-F][0-9a-fA-F_]* INT_SUFFIX? - ; - -fragment FLOAT_SUFFIX - : 'f32' - | 'f64' + : [0-9][0-9_]* SUFFIX? + | '0b' [01][01_]* SUFFIX? + | '0o' [0-7][0-7_]* SUFFIX? + | '0x' [0-9a-fA-F][0-9a-fA-F_]* SUFFIX? ; LIT_FLOAT - : [0-9][0-9_]* ('.' | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? FLOAT_SUFFIX?) + : [0-9][0-9_]* ('.' | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? SUFFIX?) ; LIT_STR - : '"' ('\\\n' | '\\\r\n' | '\\' CHAR_ESCAPE | .)*? '"' + : '"' ('\\\n' | '\\\r\n' | '\\' CHAR_ESCAPE | .)*? '"' SUFFIX? ; -LIT_BINARY : 'b' LIT_STR ; -LIT_BINARY_RAW : 'rb' LIT_STR_RAW ; +LIT_BINARY : 'b' LIT_STR SUFFIX?; +LIT_BINARY_RAW : 'rb' LIT_STR_RAW SUFFIX?; /* this is a bit messy */ @@ -148,7 +134,7 @@ fragment LIT_STR_RAW_INNER2 ; LIT_STR_RAW - : 'r' LIT_STR_RAW_INNER + : 'r' LIT_STR_RAW_INNER SUFFIX? ; IDENT : XID_start XID_continue* ; From a11078f8c3a69f0d4ea20ca10aaf96622770615b Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Wed, 19 Nov 2014 21:12:40 +1100 Subject: [PATCH 21/25] Update documentation for literal suffixes. This changes the stated grammar of literals to move all suffixes into the generic literal production. --- src/doc/reference.md | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 62e0f5e4f1f48..0b4a745f98716 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -216,9 +216,15 @@ rather than referring to it by name or some other evaluation rule. A literal is a form of constant expression, so is evaluated (primarily) at compile time. ```{.ebnf .gram} -literal : string_lit | char_lit | byte_string_lit | byte_lit | num_lit ; +lit_suffix : ident; +literal : [ string_lit | char_lit | byte_string_lit | byte_lit | num_lit ] lit_suffix ?; ``` +The optional suffix is only used for certain numeric literals, but is +reserved for future extension, that is, the above gives the lexical +grammar, but a Rust parser will reject everything but the 12 special +cases mentioned in [Number literals](#number-literals) below. + #### Character and string literals ```{.ebnf .gram} @@ -371,27 +377,20 @@ b"\\x52"; br"\x52"; // \x52 #### Number literals ```{.ebnf .gram} -num_lit : nonzero_dec [ dec_digit | '_' ] * num_suffix ? - | '0' [ [ dec_digit | '_' ] * num_suffix ? - | 'b' [ '1' | '0' | '_' ] + int_suffix ? - | 'o' [ oct_digit | '_' ] + int_suffix ? - | 'x' [ hex_digit | '_' ] + int_suffix ? ] ; - -num_suffix : int_suffix | float_suffix ; +num_lit : nonzero_dec [ dec_digit | '_' ] * float_suffix ? + | '0' [ [ dec_digit | '_' ] * float_suffix ? + | 'b' [ '1' | '0' | '_' ] + + | 'o' [ oct_digit | '_' ] + + | 'x' [ hex_digit | '_' ] + ] ; -int_suffix : 'u' int_suffix_size ? - | 'i' int_suffix_size ? ; -int_suffix_size : [ '8' | "16" | "32" | "64" ] ; +float_suffix : [ exponent | '.' dec_lit exponent ? ] ? ; -float_suffix : [ exponent | '.' dec_lit exponent ? ] ? float_suffix_ty ? ; -float_suffix_ty : 'f' [ "32" | "64" ] ; exponent : ['E' | 'e'] ['-' | '+' ] ? dec_lit ; dec_lit : [ dec_digit | '_' ] + ; ``` A _number literal_ is either an _integer literal_ or a _floating-point -literal_. The grammar for recognizing the two kinds of literals is mixed, as -they are differentiated by suffixes. +literal_. The grammar for recognizing the two kinds of literals is mixed. ##### Integer literals @@ -406,9 +405,9 @@ An _integer literal_ has one of four forms: * A _binary literal_ starts with the character sequence `U+0030` `U+0062` (`0b`) and continues as any mixture of binary digits and underscores. -An integer literal may be followed (immediately, without any spaces) by an -_integer suffix_, which changes the type of the literal. There are two kinds of -integer literal suffix: +Like any literal, an integer literal may be followed (immediately, +without any spaces) by an _integer suffix_, which forcibly sets the +type of the literal. There are 10 valid values for an integer suffix: * The `i` and `u` suffixes give the literal type `int` or `uint`, respectively. @@ -443,11 +442,9 @@ A _floating-point literal_ has one of two forms: * A single _decimal literal_ followed by an _exponent_. By default, a floating-point literal has a generic type, and, like integer -literals, the type must be uniquely determined from the context. A -floating-point literal may be followed (immediately, without any spaces) by a -_floating-point suffix_, which changes the type of the literal. There are two -floating-point suffixes: `f32`, and `f64` (the 32-bit and 64-bit floating point -types). +literals, the type must be uniquely determined from the context. There are two valid +_floating-point suffixes_, `f32` and `f64` (the 32-bit and 64-bit floating point +types), which explicitly determine the type of the literal. Examples of floating-point literals of various forms: From ebe812f0c637968b298edb8109d39002277ec4fd Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Wed, 19 Nov 2014 15:11:09 +0100 Subject: [PATCH 22/25] Reference: Change "an box" to "a box" --- src/doc/reference.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 62e0f5e4f1f48..4d6225291907c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -4045,19 +4045,19 @@ initialized; this is enforced by the compiler. ### Boxes -An _box_ is a reference to a heap allocation holding another value, which is +A _box_ is a reference to a heap allocation holding another value, which is constructed by the prefix operator `box`. When the standard library is in use, -the type of an box is `std::owned::Box`. +the type of a box is `std::owned::Box`. -An example of an box type and value: +An example of a box type and value: ``` let x: Box = box 10; ``` -Box values exist in 1:1 correspondence with their heap allocation, copying an +Box values exist in 1:1 correspondence with their heap allocation, copying a box value makes a shallow copy of the pointer. Rust will consider a shallow -copy of an box to move ownership of the value. After a value has been moved, +copy of a box to move ownership of the value. After a value has been moved, the source location cannot be used unless it is reinitialized. ``` From 40aa833fa3f31c0d9e657263f22d870566801e9a Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 19 Nov 2014 10:35:47 -0500 Subject: [PATCH 23/25] Document almost all of atomics. I don't know enough about the free functions to give them better docs right now. --- src/libcore/atomic.rs | 394 +++++++++++++++++++++++++++++++----------- 1 file changed, 296 insertions(+), 98 deletions(-) diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index d2bca1e6ec7d0..e930f353b5225 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -18,28 +18,28 @@ use intrinsics; use std::kinds::marker; use cell::UnsafeCell; -/// An atomic boolean type. +/// A boolean type which can be safely shared between threads. #[stable] pub struct AtomicBool { v: UnsafeCell, nocopy: marker::NoCopy } -/// A signed atomic integer type, supporting basic atomic arithmetic operations +/// A signed integer type which can be safely shared between threads. #[stable] pub struct AtomicInt { v: UnsafeCell, nocopy: marker::NoCopy } -/// An unsigned atomic integer type, supporting basic atomic arithmetic operations +/// An unsigned integer type which can be safely shared between threads. #[stable] pub struct AtomicUint { v: UnsafeCell, nocopy: marker::NoCopy } -/// An unsafe atomic pointer. Only supports basic atomic operations +/// A raw pointer type which can be safely shared between threads. #[stable] pub struct AtomicPtr { p: UnsafeCell, @@ -54,43 +54,42 @@ pub struct AtomicPtr { /// to be moved either before or after the atomic operation; on the other end /// "relaxed" atomics allow all reorderings. /// -/// Rust's memory orderings are the same as in C++[1]. -/// -/// 1: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync +/// Rust's memory orderings are [the same as +/// C++'s](http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync). #[stable] pub enum Ordering { - /// No ordering constraints, only atomic operations + /// No ordering constraints, only atomic operations. #[stable] Relaxed, /// When coupled with a store, all previous writes become visible /// to another thread that performs a load with `Acquire` ordering - /// on the same value + /// on the same value. #[stable] Release, /// When coupled with a load, all subsequent loads will see data /// written before a store with `Release` ordering on the same value - /// in another thread + /// in another thread. #[stable] Acquire, /// When coupled with a load, uses `Acquire` ordering, and with a store - /// `Release` ordering + /// `Release` ordering. #[stable] AcqRel, /// Like `AcqRel` with the additional guarantee that all threads see all /// sequentially consistent operations in the same order. #[stable] - SeqCst + SeqCst, } -/// An `AtomicBool` initialized to `false` +/// An `AtomicBool` initialized to `false`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_BOOL: AtomicBool = AtomicBool { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy }; -/// An `AtomicInt` initialized to `0` +/// An `AtomicInt` initialized to `0`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_INT: AtomicInt = AtomicInt { v: UnsafeCell { value: 0 }, nocopy: marker::NoCopy }; -/// An `AtomicUint` initialized to `0` +/// An `AtomicUint` initialized to `0`. #[unstable = "may be renamed, pending conventions for static initalizers"] pub const INIT_ATOMIC_UINT: AtomicUint = AtomicUint { v: UnsafeCell { value: 0, }, nocopy: marker::NoCopy }; @@ -99,7 +98,16 @@ pub const INIT_ATOMIC_UINT: AtomicUint = const UINT_TRUE: uint = -1; impl AtomicBool { - /// Create a new `AtomicBool` + /// Creates a new `AtomicBool`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::AtomicBool; + /// + /// let atomic_true = AtomicBool::new(true); + /// let atomic_false = AtomicBool::new(false); + /// ``` #[inline] #[stable] pub fn new(v: bool) -> AtomicBool { @@ -107,18 +115,42 @@ impl AtomicBool { AtomicBool { v: UnsafeCell::new(val), nocopy: marker::NoCopy } } - /// Load the value + /// Loads a value from the bool. + /// + /// `load` takes an `Ordering` argument which describes the memory ordering of this operation. /// /// # Panics /// /// Panics if `order` is `Release` or `AcqRel`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let some_bool = AtomicBool::new(true); + /// + /// let value = some_bool.load(Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn load(&self, order: Ordering) -> bool { unsafe { atomic_load(self.v.get() as *const uint, order) > 0 } } - /// Store the value + /// Stores a value into the bool. + /// + /// `store` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let some_bool = AtomicBool::new(true); + /// + /// some_bool.store(false, Ordering::Relaxed); + /// ``` /// /// # Panics /// @@ -131,7 +163,19 @@ impl AtomicBool { unsafe { atomic_store(self.v.get(), val, order); } } - /// Store a value, returning the old value + /// Stores a value into the bool, returning the old value. + /// + /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let some_bool = AtomicBool::new(true); + /// + /// let value = some_bool.swap(false, Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn swap(&self, val: bool, order: Ordering) -> bool { @@ -140,48 +184,21 @@ impl AtomicBool { unsafe { atomic_swap(self.v.get(), val, order) > 0 } } - /// If the current value is the same as expected, store a new value + /// Stores a value into the bool if the current value is the same as the expected value. /// - /// Compare the current value with `old`; if they are the same then - /// replace the current value with `new`. Return the previous value. /// If the return value is equal to `old` then the value was updated. /// - /// # Examples - /// - /// ```rust - /// use std::sync::Arc; - /// use std::sync::atomic::{AtomicBool, SeqCst}; - /// use std::task::deschedule; - /// - /// fn main() { - /// let spinlock = Arc::new(AtomicBool::new(false)); - /// let spinlock_clone = spinlock.clone(); + /// `swap` also takes an `Ordering` argument which describes the memory ordering of this + /// operation. /// - /// spawn(proc() { - /// with_lock(&spinlock, || println!("task 1 in lock")); - /// }); - /// - /// spawn(proc() { - /// with_lock(&spinlock_clone, || println!("task 2 in lock")); - /// }); - /// } + /// # Examples /// - /// fn with_lock(spinlock: &Arc, f: || -> ()) { - /// // CAS loop until we are able to replace `false` with `true` - /// while spinlock.compare_and_swap(false, true, SeqCst) != false { - /// // Since tasks may not be preemptive (if they are green threads) - /// // yield to the scheduler to let the other task run. Low level - /// // concurrent code needs to take into account Rust's two threading - /// // models. - /// deschedule(); - /// } + /// ``` + /// use std::sync::atomic::{AtomicBool, Ordering}; /// - /// // Now we have the spinlock - /// f(); + /// let some_bool = AtomicBool::new(true); /// - /// // Release the lock - /// spinlock.store(false, SeqCst); - /// } + /// let value = some_bool.store(false, Ordering::Relaxed); /// ``` #[inline] #[stable] @@ -192,10 +209,11 @@ impl AtomicBool { unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) > 0 } } - /// A logical "and" operation + /// Logical "and" with a boolean value. + /// + /// Performs a logical "and" operation on the current value and the argument `val`, and sets + /// the new value to the result. /// - /// Performs a logical "and" operation on the current value and the - /// argument `val`, and sets the new value to the result. /// Returns the previous value. /// /// # Examples @@ -223,10 +241,11 @@ impl AtomicBool { unsafe { atomic_and(self.v.get(), val, order) > 0 } } - /// A logical "nand" operation + /// Logical "nand" with a boolean value. + /// + /// Performs a logical "nand" operation on the current value and the argument `val`, and sets + /// the new value to the result. /// - /// Performs a logical "nand" operation on the current value and the - /// argument `val`, and sets the new value to the result. /// Returns the previous value. /// /// # Examples @@ -255,10 +274,11 @@ impl AtomicBool { unsafe { atomic_nand(self.v.get(), val, order) > 0 } } - /// A logical "or" operation + /// Logical "or" with a boolean value. + /// + /// Performs a logical "or" operation on the current value and the argument `val`, and sets the + /// new value to the result. /// - /// Performs a logical "or" operation on the current value and the - /// argument `val`, and sets the new value to the result. /// Returns the previous value. /// /// # Examples @@ -286,10 +306,11 @@ impl AtomicBool { unsafe { atomic_or(self.v.get(), val, order) > 0 } } - /// A logical "xor" operation + /// Logical "xor" with a boolean value. + /// + /// Performs a logical "xor" operation on the current value and the argument `val`, and sets + /// the new value to the result. /// - /// Performs a logical "xor" operation on the current value and the - /// argument `val`, and sets the new value to the result. /// Returns the previous value. /// /// # Examples @@ -319,25 +340,57 @@ impl AtomicBool { } impl AtomicInt { - /// Create a new `AtomicInt` + /// Creates a new `AtomicInt`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::AtomicInt; + /// + /// let atomic_forty_two = AtomicInt::new(42); + /// ``` #[inline] #[stable] pub fn new(v: int) -> AtomicInt { AtomicInt {v: UnsafeCell::new(v), nocopy: marker::NoCopy} } - /// Load the value + /// Loads a value from the int. + /// + /// `load` takes an `Ordering` argument which describes the memory ordering of this operation. /// /// # Panics /// /// Panics if `order` is `Release` or `AcqRel`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicInt, Ordering}; + /// + /// let some_int = AtomicInt::new(5); + /// + /// let value = some_int.load(Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn load(&self, order: Ordering) -> int { unsafe { atomic_load(self.v.get() as *const int, order) } } - /// Store the value + /// Stores a value into the int. + /// + /// `store` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicInt, Ordering}; + /// + /// let some_int = AtomicInt::new(5); + /// + /// some_int.store(10, Ordering::Relaxed); + /// ``` /// /// # Panics /// @@ -348,25 +401,48 @@ impl AtomicInt { unsafe { atomic_store(self.v.get(), val, order); } } - /// Store a value, returning the old value + /// Stores a value into the int, returning the old value. + /// + /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicInt, Ordering}; + /// + /// let some_int = AtomicInt::new(5); + /// + /// let value = some_int.swap(10, Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn swap(&self, val: int, order: Ordering) -> int { unsafe { atomic_swap(self.v.get(), val, order) } } - /// If the current value is the same as expected, store a new value + /// Stores a value into the int if the current value is the same as the expected value. /// - /// Compare the current value with `old`; if they are the same then - /// replace the current value with `new`. Return the previous value. /// If the return value is equal to `old` then the value was updated. + /// + /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of + /// this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicInt, Ordering}; + /// + /// let some_int = AtomicInt::new(5); + /// + /// let value = some_int.compare_and_swap(5, 10, Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn compare_and_swap(&self, old: int, new: int, order: Ordering) -> int { unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } } - /// Add to the current value, returning the previous + /// Add an int to the current value, returning the previous value. /// /// # Examples /// @@ -383,7 +459,7 @@ impl AtomicInt { unsafe { atomic_add(self.v.get(), val, order) } } - /// Subtract from the current value, returning the previous + /// Subtract an int from the current value, returning the previous value. /// /// # Examples /// @@ -400,7 +476,7 @@ impl AtomicInt { unsafe { atomic_sub(self.v.get(), val, order) } } - /// Bitwise and with the current value, returning the previous + /// Bitwise and with the current int, returning the previous value. /// /// # Examples /// @@ -416,7 +492,7 @@ impl AtomicInt { unsafe { atomic_and(self.v.get(), val, order) } } - /// Bitwise or with the current value, returning the previous + /// Bitwise or with the current int, returning the previous value. /// /// # Examples /// @@ -432,7 +508,7 @@ impl AtomicInt { unsafe { atomic_or(self.v.get(), val, order) } } - /// Bitwise xor with the current value, returning the previous + /// Bitwise xor with the current int, returning the previous value. /// /// # Examples /// @@ -450,25 +526,57 @@ impl AtomicInt { } impl AtomicUint { - /// Create a new `AtomicUint` + /// Creates a new `AtomicUint`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::AtomicUint; + /// + /// let atomic_forty_two = AtomicUint::new(42u); + /// ``` #[inline] #[stable] pub fn new(v: uint) -> AtomicUint { AtomicUint { v: UnsafeCell::new(v), nocopy: marker::NoCopy } } - /// Load the value + /// Loads a value from the uint. + /// + /// `load` takes an `Ordering` argument which describes the memory ordering of this operation. /// /// # Panics /// /// Panics if `order` is `Release` or `AcqRel`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicUint, Ordering}; + /// + /// let some_uint = AtomicUint::new(5); + /// + /// let value = some_uint.load(Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn load(&self, order: Ordering) -> uint { unsafe { atomic_load(self.v.get() as *const uint, order) } } - /// Store the value + /// Stores a value into the uint. + /// + /// `store` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicUint, Ordering}; + /// + /// let some_uint = AtomicUint::new(5); + /// + /// some_uint.store(10, Ordering::Relaxed); + /// ``` /// /// # Panics /// @@ -479,25 +587,48 @@ impl AtomicUint { unsafe { atomic_store(self.v.get(), val, order); } } - /// Store a value, returning the old value + /// Stores a value into the uint, returning the old value. + /// + /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicUint, Ordering}; + /// + /// let some_uint = AtomicUint::new(5); + /// + /// let value = some_uint.swap(10, Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn swap(&self, val: uint, order: Ordering) -> uint { unsafe { atomic_swap(self.v.get(), val, order) } } - /// If the current value is the same as expected, store a new value + /// Stores a value into the uint if the current value is the same as the expected value. /// - /// Compare the current value with `old`; if they are the same then - /// replace the current value with `new`. Return the previous value. /// If the return value is equal to `old` then the value was updated. + /// + /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of + /// this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicUint, Ordering}; + /// + /// let some_uint = AtomicUint::new(5); + /// + /// let value = some_uint.compare_and_swap(5, 10, Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn compare_and_swap(&self, old: uint, new: uint, order: Ordering) -> uint { unsafe { atomic_compare_and_swap(self.v.get(), old, new, order) } } - /// Add to the current value, returning the previous + /// Add to the current uint, returning the previous value. /// /// # Examples /// @@ -514,7 +645,7 @@ impl AtomicUint { unsafe { atomic_add(self.v.get(), val, order) } } - /// Subtract from the current value, returning the previous + /// Subtract from the current uint, returning the previous value. /// /// # Examples /// @@ -531,7 +662,7 @@ impl AtomicUint { unsafe { atomic_sub(self.v.get(), val, order) } } - /// Bitwise and with the current value, returning the previous + /// Bitwise and with the current uint, returning the previous value. /// /// # Examples /// @@ -547,7 +678,7 @@ impl AtomicUint { unsafe { atomic_and(self.v.get(), val, order) } } - /// Bitwise or with the current value, returning the previous + /// Bitwise or with the current uint, returning the previous value. /// /// # Examples /// @@ -563,7 +694,7 @@ impl AtomicUint { unsafe { atomic_or(self.v.get(), val, order) } } - /// Bitwise xor with the current value, returning the previous + /// Bitwise xor with the current uint, returning the previous value. /// /// # Examples /// @@ -581,18 +712,40 @@ impl AtomicUint { } impl AtomicPtr { - /// Create a new `AtomicPtr` + /// Creates a new `AtomicPtr`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::AtomicPtr; + /// + /// let ptr = &mut 5i; + /// let atomic_ptr = AtomicPtr::new(ptr); + /// ``` #[inline] #[stable] pub fn new(p: *mut T) -> AtomicPtr { AtomicPtr { p: UnsafeCell::new(p as uint), nocopy: marker::NoCopy } } - /// Load the value + /// Loads a value from the pointer. + /// + /// `load` takes an `Ordering` argument which describes the memory ordering of this operation. /// /// # Panics /// /// Panics if `order` is `Release` or `AcqRel`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr = &mut 5i; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let value = some_ptr.load(Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn load(&self, order: Ordering) -> *mut T { @@ -601,7 +754,22 @@ impl AtomicPtr { } } - /// Store the value + /// Stores a value into the pointer. + /// + /// `store` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr = &mut 5i; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let other_ptr = &mut 10i; + /// + /// some_ptr.store(other_ptr, Ordering::Relaxed); + /// ``` /// /// # Panics /// @@ -612,18 +780,48 @@ impl AtomicPtr { unsafe { atomic_store(self.p.get(), ptr as uint, order); } } - /// Store a value, returning the old value + /// Stores a value into the pointer, returning the old value. + /// + /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr = &mut 5i; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let other_ptr = &mut 10i; + /// + /// let value = some_ptr.swap(other_ptr, Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { unsafe { atomic_swap(self.p.get(), ptr as uint, order) as *mut T } } - /// If the current value is the same as expected, store a new value + /// Stores a value into the pointer if the current value is the same as the expected value. /// - /// Compare the current value with `old`; if they are the same then - /// replace the current value with `new`. Return the previous value. /// If the return value is equal to `old` then the value was updated. + /// + /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of + /// this operation. + /// + /// # Examples + /// + /// ``` + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let ptr = &mut 5i; + /// let some_ptr = AtomicPtr::new(ptr); + /// + /// let other_ptr = &mut 10i; + /// let another_ptr = &mut 10i; + /// + /// let value = some_ptr.compare_and_swap(other_ptr, another_ptr, Ordering::Relaxed); + /// ``` #[inline] #[stable] pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T { @@ -777,7 +975,7 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { /// /// # Panics /// -/// Panics if `order` is `Relaxed` +/// Panics if `order` is `Relaxed`. #[inline] #[stable] pub fn fence(order: Ordering) { From 1b5cbd0036bfd4623a6e38897978819f737eb298 Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Tue, 18 Nov 2014 22:46:49 +0100 Subject: [PATCH 24/25] Forbid matching struct variants with tuple variant patterns --- src/librustc/middle/typeck/check/_match.rs | 5 +++-- src/test/compile-fail/issue-19086.rs | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-19086.rs diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 92b30cd7af8f7..cdfd607d06710 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -379,7 +379,8 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat, let real_path_ty = fcx.node_ty(pat.id); let (arg_tys, kind_name) = match real_path_ty.sty { - ty::ty_enum(enum_def_id, ref expected_substs) => { + ty::ty_enum(enum_def_id, ref expected_substs) + if def == def::DefVariant(enum_def_id, def.def_id(), false) => { let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id()); (variant.args.iter().map(|t| t.subst(tcx, expected_substs)).collect::>(), "variant") @@ -392,7 +393,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &ast::Pat, _ => { let name = pprust::path_to_string(path); span_err!(tcx.sess, pat.span, E0164, - "`{}` does not name a variant or a tuple struct", name); + "`{}` does not name a non-struct variant or a tuple struct", name); fcx.write_error(pat.id); if let Some(ref subpats) = *subpats { diff --git a/src/test/compile-fail/issue-19086.rs b/src/test/compile-fail/issue-19086.rs new file mode 100644 index 0000000000000..9fd1f228984bb --- /dev/null +++ b/src/test/compile-fail/issue-19086.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + enum Foo { + FooB { x: i32, y: i32 } + } + + let f = FooB { x: 3, y: 4 }; + match f { + FooB(a, b) => println!("{} {}", a, b), +//~^ ERROR `FooB` does not name a non-struct variant or a tuple struct + } +} From ee66c841655c3abb528841704d991c4a5a67ff9d Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Wed, 19 Nov 2014 23:06:53 +0100 Subject: [PATCH 25/25] Fixes to the roll-up --- src/doc/guide-error-handling.md | 13 +++++++------ src/libsyntax/visit.rs | 2 +- src/test/compile-fail/bad-lit-suffixes.rs | 4 ++-- src/test/compile-fail/issue-19086.rs | 10 ++++++---- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/doc/guide-error-handling.md b/src/doc/guide-error-handling.md index 427ca4ba1a163..e2a706e59f0f1 100644 --- a/src/doc/guide-error-handling.md +++ b/src/doc/guide-error-handling.md @@ -84,6 +84,8 @@ While we know that we've covered all possible cases, Rust can't tell. It doesn't know that probability is between 0.0 and 1.0. So we add another case: ```rust +use Event::NewRelease; + enum Event { NewRelease, } @@ -106,7 +108,7 @@ fn descriptive_probability(event: Event) -> &'static str { } fn main() { - std::io::println(descriptive_probability(NewRelease)); + println!("{}", descriptive_probability(NewRelease)); } ``` @@ -151,15 +153,14 @@ enum Version { Version1, Version2 } #[deriving(Show)] enum ParseError { InvalidHeaderLength, InvalidVersion } - fn parse_version(header: &[u8]) -> Result { if header.len() < 1 { - return Err(InvalidHeaderLength); + return Err(ParseError::InvalidHeaderLength); } match header[0] { - 1 => Ok(Version1), - 2 => Ok(Version2), - _ => Err(InvalidVersion) + 1 => Ok(Version::Version1), + 2 => Ok(Version::Version2), + _ => Err(ParseError::InvalidVersion) } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 1eae5286d79ac..41a7ce7d78e57 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -212,7 +212,7 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) { - visitor.visit_lifetime_ref(&lifetime_def.lifetime); + visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name); for bound in lifetime_def.bounds.iter() { visitor.visit_lifetime_ref(bound); } diff --git a/src/test/compile-fail/bad-lit-suffixes.rs b/src/test/compile-fail/bad-lit-suffixes.rs index e142365a8ca07..d10337e768c71 100644 --- a/src/test/compile-fail/bad-lit-suffixes.rs +++ b/src/test/compile-fail/bad-lit-suffixes.rs @@ -36,6 +36,6 @@ fn main() { 1234suffix; //~ ERROR illegal suffix `suffix` for numeric literal 0b101suffix; //~ ERROR illegal suffix `suffix` for numeric literal - 1.0suffix; //~ ERROR illegal suffix `suffix` for numeric literal - 1.0e10suffix; //~ ERROR illegal suffix `suffix` for numeric literal + 1.0suffix; //~ ERROR illegal suffix `suffix` for float literal + 1.0e10suffix; //~ ERROR illegal suffix `suffix` for float literal } diff --git a/src/test/compile-fail/issue-19086.rs b/src/test/compile-fail/issue-19086.rs index 9fd1f228984bb..692018594571e 100644 --- a/src/test/compile-fail/issue-19086.rs +++ b/src/test/compile-fail/issue-19086.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main() { - enum Foo { - FooB { x: i32, y: i32 } - } +use Foo::FooB; +enum Foo { + FooB { x: i32, y: i32 } +} + +fn main() { let f = FooB { x: 3, y: 4 }; match f { FooB(a, b) => println!("{} {}", a, b),