From 57009caabd2a45a6efa4d36149feec39ab0a0658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Mar 2017 23:00:21 -0700 Subject: [PATCH 01/21] Identify missing item category in `impl`s ```rust struct S; impl S { pub hello_method(&self) { println!("Hello"); } } fn main() { S.hello_method(); } ``` ```rust error: can't qualify macro invocation with `pub` --> file.rs:3:4 | 3 | pub hello_method(&self) { | ^^^- - expected `!` here for a macro invocation | | | did you mean to write `fn` here for a method declaration? | = help: try adjusting the macro to put `pub` inside the invocation ``` --- src/libsyntax/parse/parser.rs | 62 ++++++++++++++++----- src/test/ui/did_you_mean/issue-40006.rs | 21 +++++++ src/test/ui/did_you_mean/issue-40006.stderr | 12 ++++ 3 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/did_you_mean/issue-40006.rs create mode 100644 src/test/ui/did_you_mean/issue-40006.stderr diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index df4ccc94c0421..a19339f8cc1c1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4660,25 +4660,30 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) { - match *visa { - Visibility::Inherited => (), + fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { + err.emit(); + } + } + + fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + match *vis { + Visibility::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), _ => false, }; if is_macro_rules { - self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ - invocation with `pub`") - .help("did you mean #[macro_export]?") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.help("did you mean #[macro_export]?"); + Err(err) } else { - self.diagnostic().struct_span_err(span, "can't qualify macro \ - invocation with `pub`") - .help("try adjusting the macro to put `pub` \ - inside the invocation") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + Err(err) } } } @@ -4689,14 +4694,41 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { - // method macro. + // Method macro. let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis, prev_span); + // Before complaining about trying to set a macro as `pub`, + // check if `!` comes after the path. + let err = self.complain_if_pub_macro_diag(&vis, prev_span); let lo = self.span.lo; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + let bang_err = self.expect(&token::Not); + if let Err(mut err) = err { + if let Err(mut bang_err) = bang_err { + // Given this code `pub path(`, it seems like this is not setting the + // visibility of a macro invocation, but rather a mistyped method declaration. + // Keep the macro diagnostic, but also provide a hint that `fn` might be + // missing. Don't complain about the missing `!` as a separate diagnostic, add + // label in the appropriate place as part of one unified diagnostic. + // + // x | pub path(&self) { + // | ^^^- - expected `!` here for a macro invocation + // | | + // | did you mean to write `fn` here for a method declaration? + + bang_err.cancel(); + err.span_label(self.span, &"expected `!` here for a macro invocation"); + // pub path( + // ^^ `sp` below will point to this + let sp = mk_sp(prev_span.hi, self.prev_span.lo); + err.span_label(sp, + &"did you mean to write `fn` here for a method declaration?"); + } + return Err(err); + } else if let Err(bang_err) = bang_err { + return Err(bang_err); + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs new file mode 100644 index 0000000000000..cf75929bae20c --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.rs @@ -0,0 +1,21 @@ +// Copyright 2017 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. + +struct S; + +impl S { + pub hello_method(&self) { + println!("Hello"); + } +} + +fn main() { + S.hello_method(); +} diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr new file mode 100644 index 0000000000000..93a0c58f91a57 --- /dev/null +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -0,0 +1,12 @@ +error: can't qualify macro invocation with `pub` + --> $DIR/issue-40006.rs:14:5 + | +14 | pub hello_method(&self) { + | ^^^- - expected `!` here for a macro invocation + | | + | did you mean to write `fn` here for a method declaration? + | + = help: try adjusting the macro to put `pub` inside the invocation + +error: aborting due to previous error + From c963d613a2275d5c9b31cd7124dda2f2af61deb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 27 Mar 2017 17:15:16 -0700 Subject: [PATCH 02/21] Simplify error output --- src/libsyntax/parse/parser.rs | 17 ++++++----------- src/test/ui/did_you_mean/issue-40006.stderr | 10 +++------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a19339f8cc1c1..2603b3302c610 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4708,26 +4708,21 @@ impl<'a> Parser<'a> { if let Err(mut bang_err) = bang_err { // Given this code `pub path(`, it seems like this is not setting the // visibility of a macro invocation, but rather a mistyped method declaration. - // Keep the macro diagnostic, but also provide a hint that `fn` might be - // missing. Don't complain about the missing `!` as a separate diagnostic, add - // label in the appropriate place as part of one unified diagnostic. + // Create a diagnostic pointing out that `fn` is missing. // // x | pub path(&self) { - // | ^^^- - expected `!` here for a macro invocation - // | | - // | did you mean to write `fn` here for a method declaration? + // | ^ missing `fn` for method declaration + err.cancel(); bang_err.cancel(); - err.span_label(self.span, &"expected `!` here for a macro invocation"); // pub path( // ^^ `sp` below will point to this let sp = mk_sp(prev_span.hi, self.prev_span.lo); - err.span_label(sp, - &"did you mean to write `fn` here for a method declaration?"); + err = self.diagnostic() + .struct_span_err(sp, "missing `fn` for method declaration"); + err.span_label(sp, &"missing `fn`"); } return Err(err); - } else if let Err(bang_err) = bang_err { - return Err(bang_err); } // eat a matched-delimiter token tree: diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index 93a0c58f91a57..460958027ad0f 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -1,12 +1,8 @@ -error: can't qualify macro invocation with `pub` - --> $DIR/issue-40006.rs:14:5 +error: missing `fn` for method declaration + --> $DIR/issue-40006.rs:14:8 | 14 | pub hello_method(&self) { - | ^^^- - expected `!` here for a macro invocation - | | - | did you mean to write `fn` here for a method declaration? - | - = help: try adjusting the macro to put `pub` inside the invocation + | ^ missing `fn` error: aborting due to previous error From 68d17817d02e829bf38c12cc552c28c711aa7db4 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 15 Mar 2017 21:27:40 -0500 Subject: [PATCH 03/21] First attempt at global_asm! macro --- src/librustc/hir/def.rs | 6 +- src/librustc/hir/intravisit.rs | 1 + src/librustc/hir/lowering.rs | 9 +++ src/librustc/hir/map/def_collector.rs | 1 + src/librustc/hir/map/mod.rs | 1 + src/librustc/hir/mod.rs | 10 +++ src/librustc/hir/print.rs | 5 ++ src/librustc/middle/reachable.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 3 +- .../calculate_svh/svh_visitor.rs | 5 +- src/librustc_metadata/decoder.rs | 1 + src/librustc_metadata/encoder.rs | 2 + src/librustc_metadata/schema.rs | 1 + src/librustc_privacy/lib.rs | 13 +++- src/librustc_resolve/build_reduced_graph.rs | 2 + src/librustc_resolve/lib.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 1 + src/librustc_save_analysis/lib.rs | 1 + src/librustc_trans/collector.rs | 1 + src/librustc_typeck/collect.rs | 1 + src/librustc_typeck/variance/constraints.rs | 1 + src/librustc_typeck/variance/terms.rs | 1 + src/librustdoc/visit_ast.rs | 1 + src/libsyntax/ast.rs | 13 ++++ src/libsyntax/ext/expand.rs | 1 + src/libsyntax/feature_gate.rs | 6 ++ src/libsyntax/fold.rs | 10 +++ src/libsyntax/print/pprust.rs | 5 ++ src/libsyntax/visit.rs | 6 ++ src/libsyntax_ext/global_asm.rs | 76 +++++++++++++++++++ src/libsyntax_ext/lib.rs | 2 + 31 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/libsyntax_ext/global_asm.rs diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 7bab4a8d725dc..771031db0c045 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -57,6 +57,8 @@ pub enum Def { // Macro namespace Macro(DefId, MacroKind), + GlobalAsm(DefId), + // Both namespaces Err, } @@ -144,7 +146,8 @@ impl Def { Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | - Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => { + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) | + Def::GlobalAsm(id) => { id } @@ -185,6 +188,7 @@ impl Def { Def::Label(..) => "label", Def::SelfTy(..) => "self type", Def::Macro(..) => "macro", + Def::GlobalAsm(..) => "global asm", Def::Err => "unresolved item", } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f59b8b757f5cc..259cb7e781fe7 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -474,6 +474,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } + ItemGlobalAsm(_) => {} ItemTy(ref typ, ref type_parameters) => { visitor.visit_id(item.id); visitor.visit_ty(typ); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f9b740235f49e..fb25e76b8ab57 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -642,6 +642,14 @@ impl<'a> LoweringContext<'a> { } } + fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P { + P(hir::GlobalAsm { + asm: ga.asm, + asm_str_style: ga.asm_str_style, + expn_id: ga.expn_id, + }) + } + fn lower_variant(&mut self, v: &Variant) -> hir::Variant { Spanned { node: hir::Variant_ { @@ -1284,6 +1292,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), + ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)), ItemKind::Ty(ref t, ref generics) => { hir::ItemTy(self.lower_ty(t), self.lower_generics(generics)) } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cae358a303e02..baf9aef49f163 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -120,6 +120,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { DefPathData::ValueNs(i.ident.name.as_str()), ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), + ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(ref view_path) => { match view_path.node { ViewPathGlob(..) => {} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index d7aa36b24f942..2287b525df75f 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1056,6 +1056,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemFn(..) => "fn", ItemMod(..) => "mod", ItemForeignMod(..) => "foreign mod", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "ty", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 27fa748727088..7c830d0d15a9d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1490,6 +1490,13 @@ pub struct ForeignMod { pub items: HirVec, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct GlobalAsm { + pub asm: Symbol, + pub asm_str_style: StrStyle, + pub expn_id: ExpnId +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: HirVec, @@ -1681,6 +1688,8 @@ pub enum Item_ { ItemMod(Mod), /// An external module ItemForeignMod(ForeignMod), + /// Module-level inline assembly (from global_asm!) + ItemGlobalAsm(P), /// A type alias, e.g. `type Foo = Bar` ItemTy(P, Generics), /// An enum definition, e.g. `enum Foo {C, D}` @@ -1715,6 +1724,7 @@ impl Item_ { ItemFn(..) => "function", ItemMod(..) => "module", ItemForeignMod(..) => "foreign module", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "type alias", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 3411de9bb5df1..057d02ef1b804 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -630,6 +630,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + hir::ItemGlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global asm"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()? + } hir::ItemTy(ref ty, ref params) => { self.ibox(indent_unit)?; self.ibox(0)?; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index b0e39442af98c..30c60fb902010 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -267,7 +267,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {} + hir::ItemUnion(..) | hir::ItemDefaultImpl(..) | + hir::ItemGlobalAsm(..) => {} } } hir_map::NodeTraitItem(trait_method) => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 5094e28475b26..f209cdb650d97 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -314,7 +314,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemUse(..) | hir::ItemMod(..) | hir::ItemDefaultImpl(..) | - hir::ItemForeignMod(..) => { + hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 210803c3f329c..88fbc71eea18e 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -354,6 +354,7 @@ enum SawItemComponent { SawItemFn(Unsafety, Constness, Abi), SawItemMod, SawItemForeignMod(Abi), + SawItemGlobalAsm, SawItemTy, SawItemEnum, SawItemStruct, @@ -372,6 +373,7 @@ fn saw_item(node: &Item_) -> SawItemComponent { ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), ItemMod(..) => SawItemMod, ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi), + ItemGlobalAsm(..) => SawItemGlobalAsm, ItemTy(..) => SawItemTy, ItemEnum(..) => SawItemEnum, ItemStruct(..) => SawItemStruct, @@ -921,7 +923,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | - Def::Macro(..) => { + Def::Macro(..) | + Def::GlobalAsm(..) => { DefHash::SawDefId.hash(self.st); self.hash_def_id(def.def_id()); } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 3de1e3442c69d..badbb0be89d0f 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -429,6 +429,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Trait(_) => Def::Trait(did), EntryKind::Enum(..) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), + EntryKind::GlobalAsm => Def::GlobalAsm(did), EntryKind::ForeignMod | EntryKind::Impl(_) | diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 38d774992a551..6b4c13439f72f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -655,6 +655,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis))); } hir::ItemForeignMod(_) => EntryKind::ForeignMod, + hir::ItemGlobalAsm(..) => EntryKind::GlobalAsm, hir::ItemTy(..) => EntryKind::Type, hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)), hir::ItemStruct(ref struct_def, _) => { @@ -895,6 +896,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemDefaultImpl(..) | diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index abb482a50ebc2..bd50c1a3c97d3 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -227,6 +227,7 @@ pub enum EntryKind<'tcx> { ForeignImmStatic, ForeignMutStatic, ForeignMod, + GlobalAsm, Type, Enum(ReprOptions), Field, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 64821f5d44bf4..6167e9ddd337c 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -161,7 +161,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { self.prev_level } // Other `pub` items inherit levels from parents - _ => { + hir::ItemConst(..) | hir::ItemEnum(..) | hir::ItemExternCrate(..) | + hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) | + hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemTrait(..) | + hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => { if item.vis == hir::Public { self.prev_level } else { None } } }; @@ -213,7 +216,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } } - _ => {} + hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | + hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemDefaultImpl(..) => {} } // Mark all items in interfaces of reachable items as reachable @@ -226,6 +231,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemUse(..) => {} // The interface is empty hir::ItemDefaultImpl(..) => {} + // The interface is empty + hir::ItemGlobalAsm(..) => {} // Visit everything hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { @@ -1093,6 +1100,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> hir::ItemMod(..) => {} // Checked in resolve hir::ItemUse(..) => {} + // No subitems + hir::ItemGlobalAsm(..) => {} // Subitems of these items have inherited publicity hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 86e0d0039d1a7..c603fd33548fd 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -268,6 +268,8 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, imported_binding); } + ItemKind::GlobalAsm(..) => {} + ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root ItemKind::Mod(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da3..5cbced9738f70 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1707,7 +1707,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> { // do nothing, these are just around to be encoded } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f2aa89ba4b66e..b75dd311dfe88 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | + Def::GlobalAsm(_) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index e5c04f6b61ec2..cd9434dc8f0fd 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -657,6 +657,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::SelfTy(..) | Def::Label(..) | Def::Macro(..) | + Def::GlobalAsm(..) | Def::Err => None, } } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 500802a4135d0..479c5b5a1d94d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -811,6 +811,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemDefaultImpl(..) | hir::ItemTrait(..) | diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1ed42b842c6fa..a4e92b961fd57 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1074,6 +1074,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemTrait(..) | ItemMod(..) | ItemForeignMod(..) | + ItemGlobalAsm(..) | ItemExternCrate(..) | ItemUse(..) => { span_bug!( diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f0f543fa6f23b..1bde1eea37c39 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -113,6 +113,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => {} diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 36352f50e4406..890414e317c62 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -251,6 +251,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => {} } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2793307697852..ea2fe8bc67c90 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -355,6 +355,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } // If we're inlining, skip private items. _ if self.inlining && item.vis != hir::Public => {} + hir::ItemGlobalAsm(..) => {} hir::ItemExternCrate(ref p) => { let cstore = &self.cx.sess().cstore; om.extern_crates.push(ExternCrate { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3dd4bdbd14ddb..838ad587dd747 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1624,6 +1624,16 @@ pub struct ForeignMod { pub items: Vec, } +/// Global inline assembly +/// +/// aka module-level assembly or file-scoped assembly +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub struct GlobalAsm { + pub asm: Symbol, + pub asm_str_style: StrStyle, + pub expn_id: ExpnId, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec, @@ -1851,6 +1861,8 @@ pub enum ItemKind { /// /// E.g. `extern {}` or `extern "C" {}` ForeignMod(ForeignMod), + /// Module-level inline assembly (from `global_asm!()`) + GlobalAsm(P), /// A type alias (`type` or `pub type`). /// /// E.g. `type Foo = Bar;` @@ -1903,6 +1915,7 @@ impl ItemKind { ItemKind::Fn(..) => "function", ItemKind::Mod(..) => "module", ItemKind::ForeignMod(..) => "foreign module", + ItemKind::GlobalAsm(..) => "global asm", ItemKind::Ty(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 6abeb4b0b2805..df284d9c168ae 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1056,6 +1056,7 @@ impl<'feat> ExpansionConfig<'feat> { feature_tests! { fn enable_quotes = quote, fn enable_asm = asm, + fn enable_global_asm = global_asm, fn enable_log_syntax = log_syntax, fn enable_concat_idents = concat_idents, fn enable_trace_macros = trace_macros, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9d280a413e666..807e767ecc0cb 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -342,6 +342,9 @@ declare_features! ( // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Allows module-level inline assembly by way of global_asm!() + (active, global_asm, "1.17.0", Some(35119)), ); declare_features! ( @@ -982,6 +985,9 @@ pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; +pub const EXPLAIN_GLOBAL_ASM: &'static str = + "module-level inline assembly is experimental and subject to change"; + pub const EXPLAIN_LOG_SYNTAX: &'static str = "`log_syntax!` is not stable enough for use and is subject to change"; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a4e196ac5577..06b8e071b7975 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -140,6 +140,10 @@ pub trait Folder : Sized { noop_fold_foreign_mod(nm, self) } + fn fold_global_asm(&mut self, ga: P) -> P { + noop_fold_global_asm(ga, self) + } + fn fold_variant(&mut self, v: Variant) -> Variant { noop_fold_variant(v, self) } @@ -412,6 +416,11 @@ pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, } } +pub fn noop_fold_global_asm(ga: P, + _: &mut T) -> P { + ga +} + pub fn noop_fold_variant(v: Variant, fld: &mut T) -> Variant { Spanned { node: Variant_ { @@ -867,6 +876,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), + ItemKind::GlobalAsm(ga) => ItemKind::GlobalAsm(folder.fold_global_asm(ga)), ItemKind::Ty(t, generics) => { ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics)) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f042a18d61036..3c6254c442e22 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1264,6 +1264,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + ast::ItemKind::GlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global_asm!"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()?; + } ast::ItemKind::Ty(ref ty, ref params) => { self.ibox(INDENT_UNIT)?; self.ibox(0)?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a5333f3bb6a6e..36ed29f911cd1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -58,6 +58,7 @@ pub trait Visitor<'ast>: Sized { } fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) { walk_foreign_item(self, i) } + fn visit_global_asm(&mut self, ga: &'ast GlobalAsm) { walk_global_asm(self, ga) } fn visit_item(&mut self, i: &'ast Item) { walk_item(self, i) } fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } @@ -253,6 +254,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::ForeignMod(ref foreign_module) => { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } + ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga), ItemKind::Ty(ref typ, ref type_parameters) => { visitor.visit_ty(typ); visitor.visit_generics(type_parameters) @@ -464,6 +466,10 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a walk_list!(visitor, visit_attribute, &foreign_item.attrs); } +pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { + // Empty! +} + pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyParamBound) { match *bound { TraitTyParamBound(ref typ, ref modifier) => { diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs new file mode 100644 index 0000000000000..7f41d84fb4a41 --- /dev/null +++ b/src/libsyntax_ext/global_asm.rs @@ -0,0 +1,76 @@ +// Copyright 2012-2013 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. + +/// Module-level assembly support. +/// +/// The macro defined here allows you to specify "top-level", +/// "file-scoped", or "module-level" assembly. These synonyms +/// all correspond to LLVM's module-level inline assembly instruction. +/// +/// For example, `global_asm!("some assembly here")` translates to +/// LLVM's `module asm "some assembly here"`. All of LLVM's caveats +/// therefore apply. + +use syntax::ast; +use syntax::ext::base; +use syntax::ext::base::*; +use syntax::codemap; +use syntax::feature_gate; +use syntax::ptr::P; +use syntax::symbol::Symbol; +use syntax_pos::Span; +use syntax::tokenstream; + +use syntax::util::small_vector::SmallVector; + +pub const MACRO: &'static str = "global_asm"; + +pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) -> Box { + if !cx.ecfg.enable_global_asm() { + feature_gate::emit_feature_err(&cx.parse_sess, + MACRO, + sp, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_GLOBAL_ASM); + return DummyResult::any(sp); + } + + let mut p = cx.new_parser_from_tts(tts); + let (asm, asm_str_style) = match expr_to_string(cx, + panictry!(p.parse_expr()), + "inline assembly must be a string literal") { + Some((s, st)) => (s, st), + None => return DummyResult::any(sp), + }; + + let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: sp, + callee: codemap::NameAndSpan { + format: codemap::MacroBang(Symbol::intern(MACRO)), + allow_internal_unstable: false, + span: None, + }, + }); + + MacEager::items(SmallVector::one(P(ast::Item { + ident: ast::Ident::with_empty_ctxt(Symbol::intern("")), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::GlobalAsm(P(ast::GlobalAsm { + asm: asm, + asm_str_style: asm_str_style, + expn_id: expn_id, + })), + vis: ast::Visibility::Inherited, + span: sp, + }))) +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 1e9b112b6df56..e35e79df58520 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -38,6 +38,7 @@ mod concat_idents; mod env; mod format; mod format_foreign; +mod global_asm; mod log_syntax; mod trace_macros; @@ -99,6 +100,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, module_path: expand_mod, asm: asm::expand_asm, + global_asm: global_asm::expand_global_asm, cfg: cfg::expand_cfg, concat: concat::expand_syntax_ext, concat_idents: concat_idents::expand_syntax_ext, From c54f935fa51de917caf990c1b8850bc47806345e Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Thu, 16 Mar 2017 22:16:40 -0500 Subject: [PATCH 04/21] Expand _ into explicit variants in match --- src/librustc_typeck/collect.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index a4e92b961fd57..1b5d1ee945307 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -490,8 +490,10 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. - hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { - } + hir::ItemExternCrate(_) | + hir::ItemUse(..) | + hir::ItemMod(_) | + hir::ItemGlobalAsm(_) => {} hir::ItemForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { let def_id = tcx.hir.local_def_id(item.id); @@ -543,12 +545,12 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, - _ => { + } + hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, + } } } From 4ed08b5fc14fbb3b4531a244558b30e983c1374e Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 10:03:52 -0500 Subject: [PATCH 05/21] Add new TransItem for global_asm trans --- src/librustc_trans/asm.rs | 8 ++++++++ src/librustc_trans/collector.rs | 10 +++++++++- src/librustc_trans/partitioning.rs | 25 +++++++++++++++---------- src/librustc_trans/symbol_map.rs | 5 ++++- src/librustc_trans/trans_item.rs | 28 ++++++++++++++++++++++++++-- 5 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index b6195765b27c2..9437430802c1a 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -124,3 +124,11 @@ pub fn trans_inline_asm<'a, 'tcx>( llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1)); } } + +pub fn trans_global_asm<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ga: &hir::GlobalAsm) { + let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); + unsafe { + llvm::LLVMSetModuleInlineAsm(ccx.llmod(), asm.as_ptr()); + } +} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 479c5b5a1d94d..ba2b807d5a01c 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -349,6 +349,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, collect_neighbours(scx, instance, &mut neighbors); } + TransItem::GlobalAsm(..) => { + recursion_depth_reset = None; + } } record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map); @@ -811,7 +814,6 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemForeignMod(..) | - hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemDefaultImpl(..) | hir::ItemTrait(..) | @@ -841,6 +843,12 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { } } } + hir::ItemGlobalAsm(..) => { + debug!("RootCollector: ItemGlobalAsm({})", + def_id_to_string(self.scx.tcx(), + self.scx.tcx().hir.local_def_id(item.id))); + self.output.push(TransItem::GlobalAsm(item.id)); + } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", def_id_to_string(self.scx.tcx(), diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 90ce40cfbcf8f..4973181202eed 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -185,15 +185,16 @@ impl<'tcx> CodegenUnit<'tcx> { symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); let exported = match item { - TransItem::Fn(ref instance) => { - let node_id = - scx.tcx().hir.as_local_node_id(instance.def_id()); + TransItem::Fn(ref instance) => { + let node_id = + scx.tcx().hir.as_local_node_id(instance.def_id()); node_id.map(|node_id| exported_symbols.contains(&node_id)) - .unwrap_or(false) - } - TransItem::Static(node_id) => { + .unwrap_or(false) + } + TransItem::Static(node_id) => { exported_symbols.contains(&node_id) - } + } + TransItem::GlobalAsm(..) => true, }; exported.hash(&mut state); } @@ -243,7 +244,9 @@ impl<'tcx> CodegenUnit<'tcx> { TransItem::Fn(instance) => { tcx.hir.as_local_node_id(instance.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { + Some(node_id) + } } } } @@ -338,7 +341,8 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, None => { match trans_item { TransItem::Fn(..) | - TransItem::Static(..) => llvm::ExternalLinkage, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => llvm::ExternalLinkage, } } }; @@ -483,7 +487,8 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't Some(def_id) } - TransItem::Static(node_id) => Some(tcx.hir.local_def_id(node_id)), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 1b48e131b720a..36c3981e3a6f2 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -99,7 +99,10 @@ impl<'tcx> SymbolMap<'tcx> { TransItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => { + Some(node_id) + } }.map(|node_id| { tcx.hir.span(node_id) }) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 410e3f30be731..f5556bb8382f6 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -14,6 +14,7 @@ //! item-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. +use asm; use attributes; use base; use consts; @@ -38,7 +39,8 @@ use std::iter; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { Fn(Instance<'tcx>), - Static(NodeId) + Static(NodeId), + GlobalAsm(NodeId), } /// Describes how a translation item will be instantiated in object files. @@ -89,6 +91,14 @@ impl<'a, 'tcx> TransItem<'tcx> { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") } } + TransItem::GlobalAsm(node_id) => { + let item = ccx.tcx().hir.expect_item(node_id); + if let hir::ItemGlobalAsm(ref ga) = item.node { + asm::trans_global_asm(ccx, ga); + } else { + span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") + } + } TransItem::Fn(instance) => { let _task = ccx.tcx().dep_graph.in_task( DepNode::TransCrateItem(instance.def_id())); // (*) @@ -123,6 +133,7 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(instance) => { TransItem::predefine_fn(ccx, instance, linkage, &symbol_name); } + TransItem::GlobalAsm(..) => {} } debug!("END PREDEFINING '{} ({})' in cgu {}", @@ -185,6 +196,10 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = scx.tcx().hir.local_def_id(node_id); symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) } + TransItem::GlobalAsm(node_id) => { + let def_id = scx.tcx().hir.local_def_id(node_id); + format!("global_asm_{:?}", def_id) + } } } @@ -202,6 +217,7 @@ impl<'a, 'tcx> TransItem<'tcx> { } } TransItem::Static(..) => InstantiationMode::GloballyShared, + TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared, } } @@ -210,7 +226,8 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(ref instance) => { instance.substs.types().next().is_some() } - TransItem::Static(..) => false, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => false, } } @@ -218,6 +235,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = match *self { TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), + TransItem::GlobalAsm(..) => return None, }; let attributes = tcx.get_attrs(def_id); @@ -249,6 +267,9 @@ impl<'a, 'tcx> TransItem<'tcx> { let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, + TransItem::GlobalAsm(..) => { + "global_asm".to_string() + } }; fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -273,6 +294,9 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Static(id) => { format!("Static({:?})", id) } + TransItem::GlobalAsm(id) => { + format!("GlobalAsm({:?})", id) + } } } } From 60cde930fe66ed8f6a95082858dd3189f6413ae2 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Fri, 24 Mar 2017 18:33:49 -0500 Subject: [PATCH 06/21] Remove unused str_style field --- src/librustc/hir/lowering.rs | 1 - src/librustc/hir/mod.rs | 1 - src/libsyntax/ast.rs | 1 - src/libsyntax_ext/global_asm.rs | 3 +-- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index fb25e76b8ab57..821a09fa5789a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -645,7 +645,6 @@ impl<'a> LoweringContext<'a> { fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P { P(hir::GlobalAsm { asm: ga.asm, - asm_str_style: ga.asm_str_style, expn_id: ga.expn_id, }) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 7c830d0d15a9d..a7aff5cd09414 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1493,7 +1493,6 @@ pub struct ForeignMod { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct GlobalAsm { pub asm: Symbol, - pub asm_str_style: StrStyle, pub expn_id: ExpnId } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 838ad587dd747..7a868d54dc3cd 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1630,7 +1630,6 @@ pub struct ForeignMod { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub struct GlobalAsm { pub asm: Symbol, - pub asm_str_style: StrStyle, pub expn_id: ExpnId, } diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 7f41d84fb4a41..aa8548d17919a 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -45,7 +45,7 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, } let mut p = cx.new_parser_from_tts(tts); - let (asm, asm_str_style) = match expr_to_string(cx, + let (asm, _) = match expr_to_string(cx, panictry!(p.parse_expr()), "inline assembly must be a string literal") { Some((s, st)) => (s, st), @@ -67,7 +67,6 @@ pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, id: ast::DUMMY_NODE_ID, node: ast::ItemKind::GlobalAsm(P(ast::GlobalAsm { asm: asm, - asm_str_style: asm_str_style, expn_id: expn_id, })), vis: ast::Visibility::Inherited, From b068d38fba064901a7dcf3f6a424a7afbf018f6a Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 29 Mar 2017 23:32:20 -0500 Subject: [PATCH 07/21] Ensure walk_item visits GlobalAsm NodeId Travis failures indicated the OuterVisitor#visit_item method caused a panic. The Visitor's inner visitor actually relies on the visitor visiting every item's NodeId. I forgot to perform that call in the ItemGlobalAsm match arm, leading to build breakage. The fix is simple: call visit_id(...) for ItemGlobalAsm --- src/librustc/hir/intravisit.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 259cb7e781fe7..f9a8eb89b9744 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -474,7 +474,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } - ItemGlobalAsm(_) => {} + ItemGlobalAsm(_) => { + visitor.visit_id(item.id); + } ItemTy(ref typ, ref type_parameters) => { visitor.visit_id(item.id); visitor.visit_ty(typ); From f44a689626097f5ee306aad24ee9dfc77e97ec07 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 19:50:23 -0500 Subject: [PATCH 08/21] Expose LLVM appendModuleInlineAsm --- src/librustc_llvm/ffi.rs | 1 + src/librustc_trans/asm.rs | 2 +- src/rustllvm/RustWrapper.cpp | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 26c7a9166e68e..d6b85340cc095 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -507,6 +507,7 @@ extern "C" { /// See Module::setModuleInlineAsm. pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); + pub fn LLVMRustAppendModuleInlineAsm(M: ModuleRef, Asm: *const c_char); /// See llvm::LLVMTypeKind::getTypeID. pub fn LLVMRustGetTypeKind(Ty: TypeRef) -> TypeKind; diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 9437430802c1a..495b530c3d3ce 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -129,6 +129,6 @@ pub fn trans_global_asm<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ga: &hir::GlobalAsm) { let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); unsafe { - llvm::LLVMSetModuleInlineAsm(ccx.llmod(), asm.as_ptr()); + llvm::LLVMRustAppendModuleInlineAsm(ccx.llmod(), asm.as_ptr()); } } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5ab786f40b933..c24867224ea86 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -312,6 +312,10 @@ extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, HasSideEffects, IsAlignStack, fromRust(Dialect))); } +extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) { + unwrap(M)->appendModuleInlineAsm(StringRef(Asm)); +} + typedef DIBuilder *LLVMRustDIBuilderRef; typedef struct LLVMOpaqueMetadata *LLVMRustMetadataRef; From 4d46f546fdf3173f20857a8230e6641c92136d31 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 10:02:14 -0500 Subject: [PATCH 09/21] Update unstable book with global_asm feature --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/asm.md | 2 + src/doc/unstable-book/src/global_asm.md | 78 +++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/doc/unstable-book/src/global_asm.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index fe491d7f9018e..1e6d9c5710af8 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -81,6 +81,7 @@ - [future_atomic_orderings](future-atomic-orderings.md) - [generic_param_attrs](generic-param-attrs.md) - [get_type_id](get-type-id.md) +- [global_asm](global_asm.md) - [heap_api](heap-api.md) - [i128](i128.md) - [i128_type](i128-type.md) diff --git a/src/doc/unstable-book/src/asm.md b/src/doc/unstable-book/src/asm.md index 032d9d8124026..5e68be633e7ab 100644 --- a/src/doc/unstable-book/src/asm.md +++ b/src/doc/unstable-book/src/asm.md @@ -189,3 +189,5 @@ constraints, etc. [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions +If you need more power and don't mind losing some of the niceties of +`asm!`, check out [global_asm](global_asm.html). diff --git a/src/doc/unstable-book/src/global_asm.md b/src/doc/unstable-book/src/global_asm.md new file mode 100644 index 0000000000000..f092a4ad6640c --- /dev/null +++ b/src/doc/unstable-book/src/global_asm.md @@ -0,0 +1,78 @@ +# `global_asm` + +The tracking issue for this feature is: [#35119] + +[#35119]: https://github.com/rust-lang/rust/issues/35119 + +------------------------ + +The `global_asm!` macro allows the programmer to write arbitrary +assembly outside the scope of a function body, passing it through +`rustc` and `llvm` to the assembler. The macro is a no-frills +interface to LLVM's concept of [module-level inline assembly]. That is, +all caveats applicable to LLVM's module-level inline assembly apply +to `global_asm!`. + +[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly + +`global_asm!` fills a role not currently satisfied by either `asm!` +or `#[naked]` functions. The programmer has _all_ features of the +assembler at their disposal. The linker will expect to resolve any +symbols defined in the inline assembly, modulo any symbols marked as +external. It also means syntax for directives and assembly follow the +conventions of the assembler in your toolchain. + +A simple usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# you also need relevant target_arch cfgs +global_asm!(include_str("something_neato.s")); +``` + +And a more complicated usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + +pub mod sally { + global_asm!(r#" + .global foo + foo: + jmp baz + "#); + + #[no_mangle] + pub unsafe extern "C" fn baz() {} +} + +// the symbols `foo` and `bar` are global, no matter where +// `global_asm!` was used. +extern "C" { + fn foo(); + fn bar(); +} + +pub mod harry { + global_asm!(r#" + .global bar + bar: + jmp quux + "#); + + #[no_mangle] + pub unsafe extern "C" fn quux() {} +} +``` + +You may use `global_asm!` multiple times, anywhere in your crate, in +whatever way suits you. The effect is as if you concatenated all +usages and placed the larger, single usage in the crate root. + +------------------------ + +If you don't need quite as much power and flexibility as +`global_asm!` provides, and you don't mind restricting your inline +assembly to `fn` bodies only, you might try the [asm](asm.html) +feature instead. From 907ba1b9b2168547214169131a686a6185944eac Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 23:47:25 -0500 Subject: [PATCH 10/21] Add global_asm tests --- src/doc/unstable-book/src/global_asm.md | 2 +- src/librustc_driver/test.rs | 1 + src/libsyntax/feature_gate.rs | 2 +- src/test/codegen/foo.s | 3 + src/test/codegen/global_asm.rs | 73 +++++++++++++++ src/test/codegen/global_asm_include.rs | 68 ++++++++++++++ src/test/codegen/global_asm_x2.rs | 90 +++++++++++++++++++ .../compile-fail/feature-gate-global_asm.rs | 15 ++++ src/test/run-pass/empty_global_asm.rs | 28 ++++++ src/test/run-pass/simple_global_asm.rs | 27 ++++++ 10 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 src/test/codegen/foo.s create mode 100644 src/test/codegen/global_asm.rs create mode 100644 src/test/codegen/global_asm_include.rs create mode 100644 src/test/codegen/global_asm_x2.rs create mode 100644 src/test/compile-fail/feature-gate-global_asm.rs create mode 100644 src/test/run-pass/empty_global_asm.rs create mode 100644 src/test/run-pass/simple_global_asm.rs diff --git a/src/doc/unstable-book/src/global_asm.md b/src/doc/unstable-book/src/global_asm.md index f092a4ad6640c..44921aa309f84 100644 --- a/src/doc/unstable-book/src/global_asm.md +++ b/src/doc/unstable-book/src/global_asm.md @@ -27,7 +27,7 @@ A simple usage looks like this: ```rust,ignore # #![feature(global_asm)] # you also need relevant target_arch cfgs -global_asm!(include_str("something_neato.s")); +global_asm!(include_str!("something_neato.s")); ``` And a more complicated usage looks like this: diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index af2416f787ea4..44e291a44c777 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -233,6 +233,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => None, hir::ItemEnum(..) | diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 807e767ecc0cb..a9f1eb937c587 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -986,7 +986,7 @@ pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; pub const EXPLAIN_GLOBAL_ASM: &'static str = - "module-level inline assembly is experimental and subject to change"; + "`global_asm!` is not stable enough for use and is subject to change"; pub const EXPLAIN_LOG_SYNTAX: &'static str = "`log_syntax!` is not stable enough for use and is subject to change"; diff --git a/src/test/codegen/foo.s b/src/test/codegen/foo.s new file mode 100644 index 0000000000000..304d82aa0c653 --- /dev/null +++ b/src/test/codegen/foo.s @@ -0,0 +1,3 @@ +.global foo +foo: + jmp baz diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs new file mode 100644 index 0000000000000..5bd0c1b4076ee --- /dev/null +++ b/src/test/codegen/global_asm.rs @@ -0,0 +1,73 @@ +// Copyright 2017 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-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// this regex will capture the correct unconditional branch inst. +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs new file mode 100644 index 0000000000000..401b1fad566d5 --- /dev/null +++ b/src/test/codegen/global_asm_include.rs @@ -0,0 +1,68 @@ +// Copyright 2017 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-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(include_str!("foo.s")); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs new file mode 100644 index 0000000000000..8b59165e9e61b --- /dev/null +++ b/src/test/codegen/global_asm_x2.rs @@ -0,0 +1,90 @@ +// Copyright 2017 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-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] +#[no_std] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +// any other global_asm will be appended to this first block, so: +// CHECK-LABEL: bar +// CHECK: module asm "{{[[:space:]]+}}jmp quux" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} + +// no checks here; this has been appended to the first occurrence +global_asm!(r#" + .global bar +bar: + jmp quux +"#); + +extern "C" { + fn bar(); +} + +#[no_mangle] +pub unsafe extern "C" fn quux() {} diff --git a/src/test/compile-fail/feature-gate-global_asm.rs b/src/test/compile-fail/feature-gate-global_asm.rs new file mode 100644 index 0000000000000..0560abb6af498 --- /dev/null +++ b/src/test/compile-fail/feature-gate-global_asm.rs @@ -0,0 +1,15 @@ +// 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. + +// gate-test-global_asm + +global_asm!(""); //~ ERROR `global_asm!` is not stable + +fn main() {} diff --git a/src/test/run-pass/empty_global_asm.rs b/src/test/run-pass/empty_global_asm.rs new file mode 100644 index 0000000000000..db73da2747f9c --- /dev/null +++ b/src/test/run-pass/empty_global_asm.rs @@ -0,0 +1,28 @@ +// Copyright 2017 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(global_asm)] + +#[cfg(target_arch = "x86")] +global_asm!(""); + +#[cfg(target_arch = "x86_64")] +global_asm!(""); + +#[cfg(target_arch = "arm")] +global_asm!(""); + +#[cfg(target_arch = "aarch64")] +global_asm!(""); + +#[cfg(target_arch = "mips")] +global_asm!(""); + +fn main() {} diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs new file mode 100644 index 0000000000000..a5ffe607fdf84 --- /dev/null +++ b/src/test/run-pass/simple_global_asm.rs @@ -0,0 +1,27 @@ +// Copyright 2017 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(global_asm)] + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern { + fn foo(); +} + +#[no_mangle] +pub extern fn baz() {} + +fn main() {} From 8ad8ba619426d76b041905258cd571538e7d4ca8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 1 Apr 2017 06:58:11 -0700 Subject: [PATCH 11/21] Update cargo submodule Pulls in a fix for rust-lang/rust#40956 --- cargo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo b/cargo index 4e95c6b41eca3..4729175045b41 160000 --- a/cargo +++ b/cargo @@ -1 +1 @@ -Subproject commit 4e95c6b41eca3388f54dd5f7787366ad2df637b5 +Subproject commit 4729175045b41b688ab903120860866ce7a22ba9 From b946ecd02018d1671c990057d7136176df60da35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 23 Mar 2017 15:14:45 -0700 Subject: [PATCH 12/21] Suggest using enum when a variant is used as a type Given a file: ```rust enum Fruit { Apple(i64), Orange(i64), } fn should_return_fruit() -> Apple { Apple(5) } ``` Provide the following output: ```rust error[E0412]: cannot find type `Apple` in this scope --> file.rs:16:29 | 16 | fn should_return_fruit() -> Apple { | ^^^^^ not found in this scope | help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? --> file.rs:12:5 | 12 | Apple(i64), | ^^^^^^^^^^ error[E0425]: cannot find function `Apple` in this scope --> file.rs:17:5 | 17 | Apple(5) | ^^^^^ not found in this scope | = help: possible candidate is found in another module, you can import it into scope: `use Fruit::Apple;` ``` --- src/librustc_resolve/lib.rs | 30 +++++++++ src/test/ui/did_you_mean/issue-35675.rs | 44 ++++++++++++ src/test/ui/did_you_mean/issue-35675.stderr | 74 +++++++++++++++++++++ 3 files changed, 148 insertions(+) create mode 100644 src/test/ui/did_you_mean/issue-35675.rs create mode 100644 src/test/ui/did_you_mean/issue-35675.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da3..a39cd3b0d551c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2220,6 +2220,7 @@ impl<'a> Resolver<'a> { -> PathResolution { let ns = source.namespace(); let is_expected = &|def| source.is_expected(def); + let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false }; // Base error is amended with one short label and possibly some longer helps/notes. let report_errors = |this: &mut Self, def: Option| { @@ -2270,6 +2271,19 @@ impl<'a> Resolver<'a> { if !candidates.is_empty() { // Report import candidates as help and proceed searching for labels. show_candidates(&mut err, &candidates, def.is_some()); + } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { + let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); + for suggestion in enum_candidates { + let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", + variant_path, + enum_path); + if suggestion.path.span == DUMMY_SP { + err.help(&msg); + } else { + err.span_help(suggestion.path.span, &msg); + } + } } if path.len() == 1 && this.self_type_is_available() { if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) { @@ -3422,6 +3436,22 @@ fn path_names_to_string(path: &Path) -> String { names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::>()) } +/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { + let variant_path = &suggestion.path; + let variant_path_string = path_names_to_string(variant_path); + + let path_len = suggestion.path.segments.len(); + let enum_path = ast::Path { + span: suggestion.path.span, + segments: suggestion.path.segments[0..path_len - 1].to_vec(), + }; + let enum_path_string = path_names_to_string(&enum_path); + + (variant_path_string, enum_path_string) +} + + /// When an entity with a given name is not available in scope, we search for /// entities with that name in all crates. This method allows outputting the /// results of this search in a programmer-friendly way diff --git a/src/test/ui/did_you_mean/issue-35675.rs b/src/test/ui/did_you_mean/issue-35675.rs new file mode 100644 index 0000000000000..ff29f3ad4078b --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.rs @@ -0,0 +1,44 @@ +// Copyright 2017 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. + +enum Fruit { + Apple(i64), + Orange(i64), +} + +fn should_return_fruit() -> Apple { + Apple(5) +} + +fn should_return_fruit_too() -> Fruit::Apple { + Apple(5) +} + +fn foo() -> Ok { + Ok(()) +} + +fn bar() -> Variant3 { +} + +fn qux() -> Some { + Some(1) +} + +fn main() {} + +mod x { + enum Enum { + Variant1, + Variant2(), + Variant3(usize), + Variant4 {}, + } +} diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr new file mode 100644 index 0000000000000..43851d76029df --- /dev/null +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -0,0 +1,74 @@ +error[E0412]: cannot find type `Apple` in this scope + --> $DIR/issue-35675.rs:16:29 + | +16 | fn should_return_fruit() -> Apple { + | ^^^^^ not found in this scope + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:17:5 + | +17 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Fruit::Apple` + --> $DIR/issue-35675.rs:20:33 + | +20 | fn should_return_fruit_too() -> Fruit::Apple { + | ^^^^^^^^^^^^ not a type + | +help: there is an enum variant `Fruit::Apple`, did you mean to use `Fruit`? + --> $DIR/issue-35675.rs:12:5 + | +12 | Apple(i64), + | ^^^^^^^^^^ + +error[E0425]: cannot find function `Apple` in this scope + --> $DIR/issue-35675.rs:21:5 + | +21 | Apple(5) + | ^^^^^ not found in this scope + | + = help: possible candidate is found in another module, you can import it into scope: + `use Fruit::Apple;` + +error[E0573]: expected type, found variant `Ok` + --> $DIR/issue-35675.rs:24:13 + | +24 | fn foo() -> Ok { + | ^^ not a type + | + = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? + = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + +error[E0412]: cannot find type `Variant3` in this scope + --> $DIR/issue-35675.rs:28:13 + | +28 | fn bar() -> Variant3 { + | ^^^^^^^^ not found in this scope + | +help: there is an enum variant `x::Enum::Variant3`, did you mean to use `x::Enum`? + --> $DIR/issue-35675.rs:41:9 + | +41 | Variant3(usize), + | ^^^^^^^^^^^^^^^ + +error[E0573]: expected type, found variant `Some` + --> $DIR/issue-35675.rs:31:13 + | +31 | fn qux() -> Some { + | ^^^^ not a type + | + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + +error: aborting due to 7 previous errors + From 7b89bd7ccacd0908d7e22a5cf383c8cc147bc3d5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 31 Mar 2017 13:52:46 +0100 Subject: [PATCH 13/21] Add ptr::offset_to --- src/doc/unstable-book/src/SUMMARY.md | 1 + src/doc/unstable-book/src/offset-to.md | 7 +++ src/libcollections/lib.rs | 1 + src/libcollections/vec.rs | 12 ++-- src/libcore/ptr.rs | 76 ++++++++++++++++++++++++++ src/libcore/slice/mod.rs | 7 ++- 6 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 src/doc/unstable-book/src/offset-to.md diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index fe491d7f9018e..0c3b7990c93b8 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -123,6 +123,7 @@ - [no_debug](no-debug.md) - [non_ascii_idents](non-ascii-idents.md) - [nonzero](nonzero.md) +- [offset_to](offset-to.md) - [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md) - [on_unimplemented](on-unimplemented.md) - [once_poison](once-poison.md) diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md new file mode 100644 index 0000000000000..376f3ff5d2199 --- /dev/null +++ b/src/doc/unstable-book/src/offset-to.md @@ -0,0 +1,7 @@ +# `offset_to` + +The tracking issue for this feature is: [#0] + +[#0]: https://github.com/rust-lang/rust/issues/0 + +------------------------ diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 72e950bc91fa9..2b345e3d0a59f 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -61,6 +61,7 @@ #![feature(unique)] #![feature(untagged_unions)] #![cfg_attr(test, feature(rand, test))] +#![feature(offset_to)] #![no_std] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 56b60a3e00341..f12380a9ea535 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -2073,14 +2073,10 @@ impl Iterator for IntoIter { #[inline] fn size_hint(&self) -> (usize, Option) { - let diff = (self.end as usize) - (self.ptr as usize); - let size = mem::size_of::(); - let exact = diff / - (if size == 0 { - 1 - } else { - size - }); + let exact = match self.ptr.offset_to(self.end) { + Some(x) => x as usize, + None => (self.end as usize).wrapping_sub(self.ptr as usize), + }; (exact, Some(exact)) } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d2830a6d00cec..6bcce76af04e3 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -500,6 +500,44 @@ impl *const T { intrinsics::arith_offset(self, count) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "0")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option where T: Sized { + let size = mem::size_of::(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } #[lang = "mut_ptr"] @@ -653,6 +691,44 @@ impl *mut T { Some(&mut *self) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "0")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option where T: Sized { + let size = mem::size_of::(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } // Equality for pointers diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index af492b3c63976..5a978ccc74153 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1502,9 +1502,10 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} // Return the arithmetic difference if `T` is zero size. #[inline(always)] fn ptrdistance(start: *const T, end: *const T) -> usize { - let diff = (end as usize).wrapping_sub(start as usize); - let size = mem::size_of::(); - diff / (if size == 0 { 1 } else { size }) + match start.offset_to(end) { + Some(x) => x as usize, + None => (end as usize).wrapping_sub(start as usize), + } } // Extension methods for raw pointers, used by the iterators From 73f6f5e0968ebe032a0730e2e3dfccea5a61c384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 3 Apr 2017 07:46:35 -0700 Subject: [PATCH 14/21] Sort enum suggestions --- src/librustc_resolve/lib.rs | 14 ++++++++------ src/test/ui/did_you_mean/issue-35675.stderr | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a39cd3b0d551c..e191fadc01beb 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2273,15 +2273,17 @@ impl<'a> Resolver<'a> { show_candidates(&mut err, &candidates, def.is_some()); } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) { let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant); - for suggestion in enum_candidates { - let (variant_path, enum_path) = import_candidate_to_paths(&suggestion); + let mut enum_candidates = enum_candidates.iter() + .map(|suggestion| import_candidate_to_paths(&suggestion)).collect::>(); + enum_candidates.sort(); + for (sp, variant_path, enum_path) in enum_candidates { let msg = format!("there is an enum variant `{}`, did you mean to use `{}`?", variant_path, enum_path); - if suggestion.path.span == DUMMY_SP { + if sp == DUMMY_SP { err.help(&msg); } else { - err.span_help(suggestion.path.span, &msg); + err.span_help(sp, &msg); } } } @@ -3437,7 +3439,7 @@ fn path_names_to_string(path: &Path) -> String { } /// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant. -fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) { +fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (Span, String, String) { let variant_path = &suggestion.path; let variant_path_string = path_names_to_string(variant_path); @@ -3448,7 +3450,7 @@ fn import_candidate_to_paths(suggestion: &ImportSuggestion) -> (String, String) }; let enum_path_string = path_names_to_string(&enum_path); - (variant_path_string, enum_path_string) + (suggestion.path.span, variant_path_string, enum_path_string) } diff --git a/src/test/ui/did_you_mean/issue-35675.stderr b/src/test/ui/did_you_mean/issue-35675.stderr index 43851d76029df..3d615785b25fa 100644 --- a/src/test/ui/did_you_mean/issue-35675.stderr +++ b/src/test/ui/did_you_mean/issue-35675.stderr @@ -46,8 +46,8 @@ error[E0573]: expected type, found variant `Ok` 24 | fn foo() -> Ok { | ^^ not a type | - = help: there is an enum variant `std::result::Result::Ok`, did you mean to use `std::result::Result`? = help: there is an enum variant `std::prelude::v1::Ok`, did you mean to use `std::prelude::v1`? + = help: there is an enum variant `std::prelude::v1::Result::Ok`, did you mean to use `std::prelude::v1::Result`? error[E0412]: cannot find type `Variant3` in this scope --> $DIR/issue-35675.rs:28:13 @@ -67,8 +67,8 @@ error[E0573]: expected type, found variant `Some` 31 | fn qux() -> Some { | ^^^^ not a type | - = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? = help: there is an enum variant `std::prelude::v1::Option::Some`, did you mean to use `std::prelude::v1::Option`? + = help: there is an enum variant `std::prelude::v1::Some`, did you mean to use `std::prelude::v1`? error: aborting due to 7 previous errors From 4143d409eed1393a830fcc089dc68d94a20a223f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 16:30:31 +1300 Subject: [PATCH 15/21] save-analysis: only index path references once --- src/librustc_save_analysis/dump_visitor.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 7a7fa4eda05a6..491618f7952d8 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1401,15 +1401,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, debug!("visit_expr {:?}", ex.node); self.process_macro_use(ex.span, ex.id); match ex.node { - ast::ExprKind::Call(ref _f, ref _args) => { - // Don't need to do anything for function calls, - // because just walking the callee path does what we want. - visit::walk_expr(self, ex); - } - ast::ExprKind::Path(_, ref path) => { - self.process_path(ex.id, path, None); - visit::walk_expr(self, ex); - } ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id); let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) { @@ -1507,6 +1498,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, self.visit_expr(element); self.nest_tables(count.id, |v| v.visit_expr(count)); } + // In particular, we take this branch for call and path expressions, + // where we'll index the idents involved just by continuing to walk. _ => { visit::walk_expr(self, ex) } From ccdbb31a4773fcb44d046f02a822e54dfe132970 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 8 Mar 2017 18:04:30 +1300 Subject: [PATCH 16/21] save-analysis: index extern blocks --- src/librustc_save_analysis/dump_visitor.rs | 35 +++++++++++++ src/librustc_save_analysis/lib.rs | 55 +++++++++++++++++++++ src/test/run-make/save-analysis-fail/foo.rs | 5 ++ 3 files changed, 95 insertions(+) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 491618f7952d8..3fd0ce45e3610 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1599,4 +1599,39 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, walk_list!(self, visit_ty, &l.ty); walk_list!(self, visit_expr, &l.init); } + + fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) { + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(fn_data, FunctionData, item.span); + if !self.span.filter_generated(Some(fn_data.span), item.span) { + self.dumper.function(fn_data.clone().lower(self.tcx)); + } + + self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, + &fn_data.qualname)); + self.process_generic_params(generics, item.span, &fn_data.qualname, item.id); + } + + for arg in &decl.inputs { + self.visit_ty(&arg.ty); + } + + if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output { + self.visit_ty(&ret_ty); + } + } + ast::ForeignItemKind::Static(ref ty, _) => { + if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { + down_cast_data!(var_data, VariableData, item.span); + if !self.span.filter_generated(Some(var_data.span), item.span) { + self.dumper.variable(var_data.lower(self.tcx)); + } + } + + self.visit_ty(ty); + } + } + } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1de9fbc8e4941..b34cffd2d15bd 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -120,6 +120,46 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result } + pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option { + let qualname = format!("::{}", self.tcx.node_path_str(item.id)); + match item.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); + Some(Data::FunctionData(FunctionData { + id: item.id, + name: item.ident.to_string(), + qualname: qualname, + declaration: None, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + value: make_signature(decl, generics), + visibility: From::from(&item.vis), + parent: None, + docs: docs_for_attrs(&item.attrs), + sig: self.sig_base_extern(item), + })) + } + ast::ForeignItemKind::Static(ref ty, m) => { + let keyword = if m { keywords::Mut } else { keywords::Static }; + let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); + Some(Data::VariableData(VariableData { + id: item.id, + kind: VariableKind::Static, + name: item.ident.to_string(), + qualname: qualname, + span: sub_span.unwrap(), + scope: self.enclosing_scope(item.id), + parent: None, + value: String::new(), + type_value: ty_to_string(ty), + visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), + sig: Some(self.sig_base_extern(item)), + })) + } + } + } + pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.node { ast::ItemKind::Fn(ref decl, .., ref generics, _) => { @@ -751,6 +791,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } + fn sig_base_extern(&self, item: &ast::ForeignItem) -> Signature { + let text = self.span_utils.signature_string_for_span(item.span); + let name = item.ident.to_string(); + let ident_start = text.find(&name).expect("Name not in signature?"); + let ident_end = ident_start + name.len(); + Signature { + span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + text: text, + ident_start: ident_start, + ident_end: ident_end, + defs: vec![], + refs: vec![], + } + } + #[inline] pub fn enclosing_scope(&self, id: NodeId) -> NodeId { self.tcx.hir.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID) diff --git a/src/test/run-make/save-analysis-fail/foo.rs b/src/test/run-make/save-analysis-fail/foo.rs index e331f65abb7b3..a996aa4fad5a7 100644 --- a/src/test/run-make/save-analysis-fail/foo.rs +++ b/src/test/run-make/save-analysis-fail/foo.rs @@ -448,3 +448,8 @@ fn test_format_args() { print!("{0} + {} = {}", x, y); print!("x is {}, y is {1}, name is {n}", x, y, n = name); } + +extern { + static EXTERN_FOO: u8; + fn extern_foo(a: u8, b: i32) -> String; +} From d76daf5c616f7969752e5370287f4495b95fe00c Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Mar 2017 10:43:11 +1300 Subject: [PATCH 17/21] rebased --- src/librustc_save_analysis/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b34cffd2d15bd..44615071a56a7 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -125,6 +125,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); + filter!(self.span_utils, sub_span, item.span, None); Some(Data::FunctionData(FunctionData { id: item.id, name: item.ident.to_string(), @@ -137,11 +138,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { parent: None, docs: docs_for_attrs(&item.attrs), sig: self.sig_base_extern(item), + attributes: item.attrs.clone(), })) } ast::ForeignItemKind::Static(ref ty, m) => { let keyword = if m { keywords::Mut } else { keywords::Static }; let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); + filter!(self.span_utils, sub_span, item.span, None); Some(Data::VariableData(VariableData { id: item.id, kind: VariableKind::Static, @@ -155,6 +158,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), sig: Some(self.sig_base_extern(item)), + attributes: item.attrs.clone(), })) } } @@ -797,7 +801,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ident_start = text.find(&name).expect("Name not in signature?"); let ident_end = ident_start + name.len(); Signature { - span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)), + span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, text: text, ident_start: ident_start, ident_end: ident_end, From f07ebd609796226e672737e502525fbbf5e27940 Mon Sep 17 00:00:00 2001 From: arthurprs Date: Wed, 15 Mar 2017 23:26:27 +0100 Subject: [PATCH 18/21] Simplify HashMap Bucket interface * Store capacity_mask instead of capacity * Move bucket index into RawBucket * Bucket index is now always within [0..table_capacity) * Clone RawTable using RawBucket * Simplify iterators by moving logic into RawBuckets * Make retain aware of the number of elements --- src/libstd/collections/hash/map.rs | 32 ++- src/libstd/collections/hash/table.rs | 324 +++++++++++++-------------- 2 files changed, 165 insertions(+), 191 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 5733217008146..a06299eaefe0a 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -472,7 +472,7 @@ fn pop_internal(starting_bucket: FullBucketMut) } // Now we've done all our shifting. Return the value we grabbed earlier. - (retkey, retval, gap.into_bucket().into_table()) + (retkey, retval, gap.into_table()) } /// Perform robin hood bucket stealing at the given `bucket`. You must @@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>, mut key: K, mut val: V) -> FullBucketMut<'a, K, V> { - let start_index = bucket.index(); let size = bucket.table().size(); - // Save the *starting point*. - let mut bucket = bucket.stash(); + let raw_capacity = bucket.table().capacity(); // There can be at most `size - dib` buckets to displace, because // in the worst case, there are `size` elements and we already are // `displacement` buckets away from the initial one. - let idx_end = start_index + size - bucket.displacement(); + let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity; + // Save the *starting point*. + let mut bucket = bucket.stash(); loop { let (old_hash, old_key, old_val) = bucket.replace(hash, key, val); @@ -568,11 +568,8 @@ impl HashMap // The caller should ensure that invariants by Robin Hood Hashing hold // and that there's space in the underlying table. fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { - let raw_cap = self.raw_capacity(); let mut buckets = Bucket::new(&mut self.table, hash); - // note that buckets.index() keeps increasing - // even if the pointer wraps back to the first bucket. - let limit_bucket = buckets.index() + raw_cap; + let start_index = buckets.index(); loop { // We don't need to compare hashes for value swap. @@ -585,7 +582,7 @@ impl HashMap Full(b) => b.into_bucket(), }; buckets.next(); - debug_assert!(buckets.index() < limit_bucket); + debug_assert!(buckets.index() != start_index); } } } @@ -1244,24 +1241,25 @@ impl HashMap pub fn retain(&mut self, mut f: F) where F: FnMut(&K, &mut V) -> bool { - if self.table.capacity() == 0 || self.table.size() == 0 { + if self.table.size() == 0 { return; } + let mut elems_left = self.table.size(); let mut bucket = Bucket::head_bucket(&mut self.table); bucket.prev(); - let tail = bucket.index(); - loop { + let start_index = bucket.index(); + while elems_left != 0 { bucket = match bucket.peek() { Full(mut full) => { + elems_left -= 1; let should_remove = { let (k, v) = full.read_mut(); !f(k, v) }; if should_remove { - let prev_idx = full.index(); let prev_raw = full.raw(); let (_, _, t) = pop_internal(full); - Bucket::new_from(prev_raw, prev_idx, t) + Bucket::new_from(prev_raw, t) } else { full.into_bucket() } @@ -1271,9 +1269,7 @@ impl HashMap } }; bucket.prev(); // reverse iteration - if bucket.index() == tail { - break; - } + debug_assert!(elems_left == 0 || bucket.index() != start_index); } } } diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index da5fb1a47333e..9623706548b32 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -113,7 +113,7 @@ impl TaggedHashUintPtr { /// when the RawTable is created and is accessible with the `tag` and `set_tag` /// functions. pub struct RawTable { - capacity: usize, + capacity_mask: usize, size: usize, hashes: TaggedHashUintPtr, @@ -125,10 +125,13 @@ pub struct RawTable { unsafe impl Send for RawTable {} unsafe impl Sync for RawTable {} +// An unsafe view of a RawTable bucket +// Valid indexes are within [0..table_capacity) pub struct RawBucket { - hash: *mut HashUint, + hash_start: *mut HashUint, // We use *const to ensure covariance with respect to K and V - pair: *const (K, V), + pair_start: *const (K, V), + idx: usize, _marker: marker::PhantomData<(K, V)>, } @@ -141,7 +144,6 @@ impl Clone for RawBucket { pub struct Bucket { raw: RawBucket, - idx: usize, table: M, } @@ -154,13 +156,11 @@ impl Clone for Bucket { pub struct EmptyBucket { raw: RawBucket, - idx: usize, table: M, } pub struct FullBucket { raw: RawBucket, - idx: usize, table: M, } @@ -232,13 +232,17 @@ fn can_alias_safehash_as_hash() { assert_eq!(size_of::(), size_of::()) } +// RawBucket methods are unsafe as it's possible to +// make a RawBucket point to invalid memory using safe code. impl RawBucket { - unsafe fn offset(self, count: isize) -> RawBucket { - RawBucket { - hash: self.hash.offset(count), - pair: self.pair.offset(count), - _marker: marker::PhantomData, - } + unsafe fn hash(&self) -> *mut HashUint { + self.hash_start.offset(self.idx as isize) + } + unsafe fn pair(&self) -> *mut (K, V) { + self.pair_start.offset(self.idx as isize) as *mut (K, V) + } + unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) { + (self.hash(), self.pair()) } } @@ -258,7 +262,7 @@ impl FullBucket { } /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// Get the raw bucket. pub fn raw(&self) -> RawBucket { @@ -280,7 +284,7 @@ impl EmptyBucket { impl Bucket { /// Get the raw index. pub fn index(&self) -> usize { - self.idx + self.raw.idx } /// get the table. pub fn into_table(self) -> M { @@ -331,12 +335,11 @@ impl>> Bucket { Bucket::at_index(table, hash.inspect() as usize) } - pub fn new_from(r: RawBucket, i: usize, t: M) + pub fn new_from(r: RawBucket, t: M) -> Bucket { Bucket { raw: r, - idx: i, table: t, } } @@ -346,18 +349,16 @@ impl>> Bucket { // This is an uncommon case though, so avoid it in release builds. debug_assert!(table.capacity() > 0, "Table should have capacity at this point"); - let ib_index = ib_index & (table.capacity() - 1); + let ib_index = ib_index & table.capacity_mask; Bucket { - raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) }, - idx: ib_index, + raw: table.raw_bucket_at(ib_index), table: table, } } pub fn first(table: M) -> Bucket { Bucket { - raw: table.first_bucket_raw(), - idx: 0, + raw: table.raw_bucket_at(0), table: table, } } @@ -401,48 +402,30 @@ impl>> Bucket { /// the appropriate types to call most of the other functions in /// this module. pub fn peek(self) -> BucketState { - match unsafe { *self.raw.hash } { + match unsafe { *self.raw.hash() } { EMPTY_BUCKET => { Empty(EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } _ => { Full(FullBucket { raw: self.raw, - idx: self.idx, table: self.table, }) } } } - /// Modifies the bucket pointer in place to make it point to the next slot. + /// Modifies the bucket in place to make it point to the next slot. pub fn next(&mut self) { - self.idx += 1; - let range = self.table.capacity(); - // This code is branchless thanks to a conditional move. - let dist = if self.idx & (range - 1) == 0 { - 1 - range as isize - } else { - 1 - }; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask; } - /// Modifies the bucket pointer in place to make it point to the previous slot. + /// Modifies the bucket in place to make it point to the previous slot. pub fn prev(&mut self) { - let range = self.table.capacity(); - let new_idx = self.idx.wrapping_sub(1) & (range - 1); - let dist = (new_idx as isize).wrapping_sub(self.idx as isize); - self.idx = new_idx; - unsafe { - self.raw = self.raw.offset(dist); - } + self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask; } } @@ -458,7 +441,6 @@ impl>> EmptyBucket { pub fn into_bucket(self) -> Bucket { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -466,7 +448,6 @@ impl>> EmptyBucket { pub fn gap_peek(self) -> Result, Bucket> { let gap = EmptyBucket { raw: self.raw, - idx: self.idx, table: (), }; @@ -494,15 +475,14 @@ impl EmptyBucket /// Use `make_hash` to construct a `SafeHash` to pass to this function. pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket { unsafe { - *self.raw.hash = hash.inspect(); - ptr::write(self.raw.pair as *mut (K, V), (key, value)); + *self.raw.hash() = hash.inspect(); + ptr::write(self.raw.pair(), (key, value)); self.table.borrow_table_mut().size += 1; } FullBucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -510,15 +490,14 @@ impl EmptyBucket /// Puts given key, remain value uninitialized. /// It is only used for inplacement insertion. pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket { - *self.raw.hash = hash.inspect(); - let pair_mut = self.raw.pair as *mut (K, V); - ptr::write(&mut (*pair_mut).0, key); + *self.raw.hash() = hash.inspect(); + let pair_ptr = self.raw.pair(); + ptr::write(&mut (*pair_ptr).0, key); self.table.borrow_table_mut().size += 1; FullBucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -536,7 +515,6 @@ impl>> FullBucket { pub fn into_bucket(self) -> Bucket { Bucket { raw: self.raw, - idx: self.idx, table: self.table, } } @@ -546,7 +524,6 @@ impl>> FullBucket { pub fn stash(self) -> FullBucket { FullBucket { raw: self.raw, - idx: self.idx, table: self, } } @@ -560,17 +537,20 @@ impl>> FullBucket { // Calculates the distance one has to travel when going from // `hash mod capacity` onwards to `idx mod capacity`, wrapping around // if the destination is not reached before the end of the table. - (self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1) + (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask } #[inline] pub fn hash(&self) -> SafeHash { - unsafe { SafeHash { hash: *self.raw.hash } } + unsafe { SafeHash { hash: *self.raw.hash() } } } /// Gets references to the key and value at a given index. pub fn read(&self) -> (&K, &V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -586,11 +566,10 @@ impl<'t, K, V> FullBucket> { self.table.size -= 1; unsafe { - *self.raw.hash = EMPTY_BUCKET; - let (k, v) = ptr::read(self.raw.pair); + *self.raw.hash() = EMPTY_BUCKET; + let (k, v) = ptr::read(self.raw.pair()); (EmptyBucket { raw: self.raw, - idx: self.idx, table: self.table, }, k, @@ -604,9 +583,9 @@ impl<'t, K, V> FullBucket> { pub unsafe fn remove_key(&mut self) { self.table.size -= 1; - *self.raw.hash = EMPTY_BUCKET; - let pair_mut = self.raw.pair as *mut (K, V); - ptr::drop_in_place(&mut (*pair_mut).0); // only drop key + *self.raw.hash() = EMPTY_BUCKET; + let pair_ptr = self.raw.pair(); + ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key } } @@ -617,8 +596,8 @@ impl FullBucket { pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unsafe { - let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h); - let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v)); + let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h); + let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v)); (old_hash, old_key, old_val) } @@ -630,8 +609,10 @@ impl FullBucket { /// Gets mutable references to the key and value at a given index. pub fn read_mut(&mut self) -> (&mut K, &mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -644,7 +625,10 @@ impl<'t, K, V, M> FullBucket /// in exchange for this, the returned references have a longer lifetime /// than the references returned by `read()`. pub fn into_refs(self) -> (&'t K, &'t V) { - unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) + } } } @@ -654,8 +638,10 @@ impl<'t, K, V, M> FullBucket /// This works similarly to `into_refs`, exchanging a bucket state /// for mutable references into the table. pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { - let pair_mut = self.raw.pair as *mut (K, V); - unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) } + unsafe { + let pair_ptr = self.raw.pair(); + (&mut (*pair_ptr).0, &mut (*pair_ptr).1) + } } } @@ -667,22 +653,23 @@ impl GapThenFull &self.full } - pub fn into_bucket(self) -> Bucket { - self.full.into_bucket() + pub fn into_table(self) -> M { + self.full.into_table() } pub fn shift(mut self) -> Result, Bucket> { unsafe { - *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET); - ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1); + let (gap_hash, gap_pair) = self.gap.raw.hash_pair(); + let (full_hash, full_pair) = self.full.raw.hash_pair(); + *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET); + ptr::copy_nonoverlapping(full_pair, gap_pair, 1); } - let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full; + let FullBucket { raw: prev_raw, .. } = self.full; match self.full.next().peek() { Full(bucket) => { self.gap.raw = prev_raw; - self.gap.idx = prev_idx; self.full = bucket; @@ -761,7 +748,7 @@ impl RawTable { if capacity == 0 { return RawTable { size: 0, - capacity: 0, + capacity_mask: capacity.wrapping_sub(1), hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint), marker: marker::PhantomData, }; @@ -801,25 +788,27 @@ impl RawTable { let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; RawTable { - capacity: capacity, + capacity_mask: capacity.wrapping_sub(1), size: 0, hashes: TaggedHashUintPtr::new(hashes), marker: marker::PhantomData, } } - fn first_bucket_raw(&self) -> RawBucket { - let hashes_size = self.capacity * size_of::(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + fn raw_bucket_at(&self, index: usize) -> RawBucket { + let hashes_size = self.capacity() * size_of::(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); - let buffer = self.hashes.ptr() as *mut u8; let (pairs_offset, _, oflo) = calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>()); debug_assert!(!oflo, "capacity overflow"); + + let buffer = self.hashes.ptr() as *mut u8; unsafe { RawBucket { - hash: self.hashes.ptr(), - pair: buffer.offset(pairs_offset as isize) as *const _, + hash_start: buffer as *mut HashUint, + pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), + idx: index, _marker: marker::PhantomData, } } @@ -837,7 +826,7 @@ impl RawTable { /// The hashtable's capacity, similar to a vector's. pub fn capacity(&self) -> usize { - self.capacity + self.capacity_mask.wrapping_add(1) } /// The number of elements ever `put` in the hashtable, minus the number @@ -848,8 +837,8 @@ impl RawTable { fn raw_buckets(&self) -> RawBuckets { RawBuckets { - raw: self.first_bucket_raw(), - hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) }, + raw: self.raw_bucket_at(0), + elems_left: self.size, marker: marker::PhantomData, } } @@ -857,25 +846,23 @@ impl RawTable { pub fn iter(&self) -> Iter { Iter { iter: self.raw_buckets(), - elems_left: self.size(), } } pub fn iter_mut(&mut self) -> IterMut { IterMut { iter: self.raw_buckets(), - elems_left: self.size(), _marker: marker::PhantomData, } } pub fn into_iter(self) -> IntoIter { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. IntoIter { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: self, @@ -883,12 +870,12 @@ impl RawTable { } pub fn drain(&mut self) -> Drain { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { raw, elems_left, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. Drain { iter: RawBuckets { raw: raw, - hashes_end: hashes_end, + elems_left: elems_left, marker: marker::PhantomData, }, table: unsafe { Shared::new(self) }, @@ -900,18 +887,16 @@ impl RawTable { /// state and should only be used for dropping the table's remaining /// entries. It's used in the implementation of Drop. unsafe fn rev_drop_buckets(&mut self) { - let first_raw = self.first_bucket_raw(); - let mut raw = first_raw.offset(self.capacity as isize); + // initialize the raw bucket past the end of the table + let mut raw = self.raw_bucket_at(self.capacity()); let mut elems_left = self.size; while elems_left != 0 { - debug_assert!(raw.hash != first_raw.hash); + raw.idx -= 1; - raw = raw.offset(-1); - - if *raw.hash != EMPTY_BUCKET { + if *raw.hash() != EMPTY_BUCKET { elems_left -= 1; - ptr::drop_in_place(raw.pair as *mut (K, V)); + ptr::drop_in_place(raw.pair()); } } } @@ -931,7 +916,7 @@ impl RawTable { /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { raw: RawBucket, - hashes_end: *mut HashUint, + elems_left: usize, // Strictly speaking, this should be &'a (K,V), but that would // require that K:'a, and we often use RawBuckets<'static...> for @@ -946,7 +931,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> { fn clone(&self) -> RawBuckets<'a, K, V> { RawBuckets { raw: self.raw, - hashes_end: self.hashes_end, + elems_left: self.elems_left, marker: marker::PhantomData, } } @@ -957,25 +942,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { type Item = RawBucket; fn next(&mut self) -> Option> { - while self.raw.hash != self.hashes_end { + if self.elems_left == 0 { + return None; + } + + loop { unsafe { - // We are swapping out the pointer to a bucket and replacing - // it with the pointer to the next one. - let prev = ptr::replace(&mut self.raw, self.raw.offset(1)); - if *prev.hash != EMPTY_BUCKET { - return Some(prev); + let item = self.raw; + self.raw.idx += 1; + if *item.hash() != EMPTY_BUCKET { + self.elems_left -= 1; + return Some(item); } } } + } + + fn size_hint(&self) -> (usize, Option) { + (self.elems_left, Some(self.elems_left)) + } +} - None +impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> { + fn len(&self) -> usize { + self.elems_left } } /// Iterator over shared references to entries in a table. pub struct Iter<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, } unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {} @@ -986,16 +982,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { fn clone(&self) -> Iter<'a, K, V> { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } - /// Iterator over mutable references to entries in a table. pub struct IterMut<'a, K: 'a, V: 'a> { iter: RawBuckets<'a, K, V>, - elems_left: usize, // To ensure invariance with respect to V _marker: marker::PhantomData<&'a mut V>, } @@ -1009,7 +1002,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> { pub fn iter(&self) -> Iter { Iter { iter: self.iter.clone(), - elems_left: self.elems_left, } } } @@ -1027,7 +1019,6 @@ impl IntoIter { pub fn iter(&self) -> Iter { Iter { iter: self.iter.clone(), - elems_left: self.table.size, } } } @@ -1044,11 +1035,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {} impl<'a, K, V> Drain<'a, K, V> { pub fn iter(&self) -> Iter { - unsafe { - Iter { - iter: self.iter.clone(), - elems_left: (**self.table).size, - } + Iter { + iter: self.iter.clone(), } } } @@ -1057,19 +1045,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &(*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1077,20 +1066,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); fn next(&mut self) -> Option<(&'a K, &'a mut V)> { - self.iter.next().map(|bucket| { - self.elems_left -= 1; - let pair_mut = bucket.pair as *mut (K, V); - unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) } + self.iter.next().map(|raw| unsafe { + let pair_ptr = raw.pair(); + (&(*pair_ptr).0, &mut (*pair_ptr).1) }) } fn size_hint(&self) -> (usize, Option) { - (self.elems_left, Some(self.elems_left)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { fn len(&self) -> usize { - self.elems_left + self.iter.len() } } @@ -1098,23 +1087,23 @@ impl Iterator for IntoIter { type Item = (SafeHash, K, V); fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { + self.iter.next().map(|raw| { self.table.size -= 1; unsafe { - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: *bucket.hash }, k, v) + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: *raw.hash() }, k, v) } }) } fn size_hint(&self) -> (usize, Option) { - let size = self.table.size(); - (size, Some(size)) + self.iter.size_hint() } } + impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { - self.table.size() + self.iter().len() } } @@ -1123,23 +1112,21 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { #[inline] fn next(&mut self) -> Option<(SafeHash, K, V)> { - self.iter.next().map(|bucket| { - unsafe { - (*self.table.as_mut_ptr()).size -= 1; - let (k, v) = ptr::read(bucket.pair); - (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v) - } + self.iter.next().map(|raw| unsafe { + (*self.table.as_mut_ptr()).size -= 1; + let (k, v) = ptr::read(raw.pair()); + (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v) }) } fn size_hint(&self) -> (usize, Option) { - let size = unsafe { (**self.table).size() }; - (size, Some(size)) + self.iter.size_hint() } } + impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { fn len(&self) -> usize { - unsafe { (**self.table).size() } + self.iter.len() } } @@ -1152,30 +1139,21 @@ impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> { impl Clone for RawTable { fn clone(&self) -> RawTable { unsafe { - let mut new_ht = RawTable::new_uninitialized(self.capacity()); - - { - let cap = self.capacity(); - let mut new_buckets = Bucket::first(&mut new_ht); - let mut buckets = Bucket::first(self); - while buckets.index() != cap { - match buckets.peek() { - Full(full) => { - let (h, k, v) = { - let (k, v) = full.read(); - (full.hash(), k.clone(), v.clone()) - }; - *new_buckets.raw.hash = h.inspect(); - ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v)); - } - Empty(..) => { - *new_buckets.raw.hash = EMPTY_BUCKET; - } - } - new_buckets.next(); - buckets.next(); + let cap = self.capacity(); + let mut new_ht = RawTable::new_uninitialized(cap); + + let mut new_buckets = new_ht.raw_bucket_at(0); + let mut buckets = self.raw_bucket_at(0); + while buckets.idx < cap { + *new_buckets.hash() = *buckets.hash(); + if *new_buckets.hash() != EMPTY_BUCKET { + let pair_ptr = buckets.pair(); + let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone()); + ptr::write(new_buckets.pair(), kv); } - }; + buckets.idx += 1; + new_buckets.idx += 1; + } new_ht.size = self.size(); @@ -1186,7 +1164,7 @@ impl Clone for RawTable { unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { fn drop(&mut self) { - if self.capacity == 0 { + if self.capacity() == 0 { return; } @@ -1202,8 +1180,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { } } - let hashes_size = self.capacity * size_of::(); - let pairs_size = self.capacity * size_of::<(K, V)>(); + let hashes_size = self.capacity() * size_of::(); + let pairs_size = self.capacity() * size_of::<(K, V)>(); let (align, _, size, oflo) = calculate_allocation(hashes_size, align_of::(), pairs_size, From 56902fbe71b9b0a9b327972412fca085a8770e61 Mon Sep 17 00:00:00 2001 From: GitLab Date: Mon, 13 Mar 2017 14:44:54 -0300 Subject: [PATCH 19/21] Fixes other targets rustlibs installation When the user select more than one target to generate rustlibs for, rustbuild will only install the host one. This patch fixes it, more info in https://github.com/rust-lang/rust/issues/39235#issuecomment-285878858 --- src/bootstrap/install.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 249f241a151bb..25082e3a9d095 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -49,12 +49,17 @@ pub fn install(build: &Build, stage: u32, host: &str) { install_sh(&build, "docs", "rust-docs", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } + + for target in build.config.target.iter() { + install_sh(&build, "std", "rust-std", stage, target, &prefix, + &docdir, &libdir, &mandir, &empty_dir); + } + if build.config.rust_save_analysis { install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } - install_sh(&build, "std", "rust-std", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + install_sh(&build, "rustc", "rustc", stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); t!(fs::remove_dir_all(&empty_dir)); From 1f70247446914a8b58bd088f32bcca792d30d75f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 5 Apr 2017 07:45:44 +0100 Subject: [PATCH 20/21] Add tracking issue for offset_to --- src/doc/unstable-book/src/offset-to.md | 4 ++-- src/libcore/ptr.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md index 376f3ff5d2199..03d990eb4ae97 100644 --- a/src/doc/unstable-book/src/offset-to.md +++ b/src/doc/unstable-book/src/offset-to.md @@ -1,7 +1,7 @@ # `offset_to` -The tracking issue for this feature is: [#0] +The tracking issue for this feature is: [#41079] -[#0]: https://github.com/rust-lang/rust/issues/0 +[#41079]: https://github.com/rust-lang/rust/issues/41079 ------------------------ diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6bcce76af04e3..04480fc5d31da 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -527,7 +527,7 @@ impl *const T { /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); /// } /// ``` - #[unstable(feature = "offset_to", issue = "0")] + #[unstable(feature = "offset_to", issue = "41079")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); @@ -718,7 +718,7 @@ impl *mut T { /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); /// } /// ``` - #[unstable(feature = "offset_to", issue = "0")] + #[unstable(feature = "offset_to", issue = "41079")] #[inline] pub fn offset_to(self, other: *const T) -> Option where T: Sized { let size = mem::size_of::(); From 44bcd261a7fa2a4ad873a77b67ac88b0cf09f111 Mon Sep 17 00:00:00 2001 From: Kang Seonghoon Date: Wed, 22 Mar 2017 03:27:06 +0900 Subject: [PATCH 21/21] Reduce a table used for `Debug` impl of `str`. This commit shrinks the size of the aforementioned table from 2,102 bytes to 1,197 bytes. This is achieved by an observation that most u16 entries are common in its upper byte. Specifically: - SINGLETONS now uses two tables, one for (upper byte, lower count) and another for a series of lower bytes. For each upper byte given number of lower bytes are read and compared. - NORMAL now uses a variable length format for the count of "true" codepoints and "false" codepoints (one byte with MSB unset, or two big-endian bytes with the first MSB set). The code size and relative performance roughly remains same as this commit tries to optimize for both. The new table and algorithm has been verified for the equivalence to older ones. --- src/etc/char_private.py | 132 +++- src/libcore/char_private.rs | 1238 +++++++++++++---------------------- 2 files changed, 565 insertions(+), 805 deletions(-) diff --git a/src/etc/char_private.py b/src/etc/char_private.py index 9d15f98e06709..75ab3f1a17be4 100644 --- a/src/etc/char_private.py +++ b/src/etc/char_private.py @@ -76,6 +76,66 @@ def get_codepoints(f): for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) +def compress_singletons(singletons): + uppers = [] # (upper, # items in lowers) + lowers = [] + + for i in singletons: + upper = i >> 8 + lower = i & 0xff + if len(uppers) == 0 or uppers[-1][0] != upper: + uppers.append((upper, 1)) + else: + upper, count = uppers[-1] + uppers[-1] = upper, count + 1 + lowers.append(lower) + + return uppers, lowers + +def compress_normal(normal): + # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f + # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + + prev_start = 0 + for start, count in normal: + truelen = start - prev_start + falselen = count + prev_start = start + count + + assert truelen < 0x8000 and falselen < 0x8000 + entry = [] + if truelen > 0x7f: + entry.append(0x80 | (truelen >> 8)) + entry.append(truelen & 0xff) + else: + entry.append(truelen & 0x7f) + if falselen > 0x7f: + entry.append(0x80 | (falselen >> 8)) + entry.append(falselen & 0xff) + else: + entry.append(falselen & 0x7f) + + compressed.append(entry) + + return compressed + +def print_singletons(uppers, lowers, uppersname, lowersname): + print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) + for u, c in uppers: + print(" ({:#04x}, {}),".format(u, c)) + print("];") + print("const {}: &'static [u8] = &[".format(lowersname)) + for i in range(0, len(lowers), 8): + print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print("];") + +def print_normal(normal, normalname): + print("const {}: &'static [u8] = &[".format(normalname)) + for v in normal: + print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) + print("];") + def main(): file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") @@ -111,6 +171,11 @@ def main(): else: normal0.append((a, b - a)) + singletons0u, singletons0l = compress_singletons(singletons0) + singletons1u, singletons1l = compress_singletons(singletons1) + normal0 = compress_normal(normal0) + normal1 = compress_normal(normal1) + print("""\ // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -125,38 +190,49 @@ def main(): // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { break; } + lowerstart = lowerend; } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; - } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 } else { + v as i32 + }; + x -= len; + if x < 0 { break; } + current = !current; } - true + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else {\ """) for a, b in extra: @@ -169,22 +245,10 @@ def main(): }\ """) print() - print("const SINGLETONS0: &'static [u16] = &[") - for s in singletons0: - print(" 0x{:x},".format(s)) - print("];") - print("const SINGLETONS1: &'static [u16] = &[") - for s in singletons1: - print(" 0x{:x},".format(s)) - print("];") - print("const NORMAL0: &'static [u16] = &[") - for a, b in normal0: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") - print("const NORMAL1: &'static [u16] = &[") - for a, b in normal1: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") + print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') + print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') + print_normal(normal0, 'NORMAL0') + print_normal(normal1, 'NORMAL1') if __name__ == '__main__': main() diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs index ddc473592a260..2c0f449b27601 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/char_private.rs @@ -11,38 +11,49 @@ // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } + } + } else if xupper < upper { break; } + lowerstart = lowerend; } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; - } + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 } else { + v as i32 + }; + x -= len; + if x < 0 { break; } + current = !current; } - true + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else { if 0x2a6d7 <= x && x < 0x2a700 { return false; @@ -66,761 +77,446 @@ pub fn is_printable(x: char) -> bool { } } -const SINGLETONS0: &'static [u16] = &[ - 0xad, - 0x378, - 0x379, - 0x38b, - 0x38d, - 0x3a2, - 0x530, - 0x557, - 0x558, - 0x560, - 0x588, - 0x58b, - 0x58c, - 0x590, - 0x61c, - 0x61d, - 0x6dd, - 0x70e, - 0x70f, - 0x74b, - 0x74c, - 0x82e, - 0x82f, - 0x83f, - 0x85c, - 0x85d, - 0x8b5, - 0x8e2, - 0x984, - 0x98d, - 0x98e, - 0x991, - 0x992, - 0x9a9, - 0x9b1, - 0x9ba, - 0x9bb, - 0x9c5, - 0x9c6, - 0x9c9, - 0x9ca, - 0x9de, - 0x9e4, - 0x9e5, - 0xa04, - 0xa11, - 0xa12, - 0xa29, - 0xa31, - 0xa34, - 0xa37, - 0xa3a, - 0xa3b, - 0xa3d, - 0xa49, - 0xa4a, - 0xa5d, - 0xa84, - 0xa8e, - 0xa92, - 0xaa9, - 0xab1, - 0xab4, - 0xaba, - 0xabb, - 0xac6, - 0xaca, - 0xace, - 0xacf, - 0xae4, - 0xae5, - 0xb04, - 0xb0d, - 0xb0e, - 0xb11, - 0xb12, - 0xb29, - 0xb31, - 0xb34, - 0xb3a, - 0xb3b, - 0xb45, - 0xb46, - 0xb49, - 0xb4a, - 0xb5e, - 0xb64, - 0xb65, - 0xb84, - 0xb91, - 0xb9b, - 0xb9d, - 0xbc9, - 0xbce, - 0xbcf, - 0xc04, - 0xc0d, - 0xc11, - 0xc29, - 0xc45, - 0xc49, - 0xc57, - 0xc64, - 0xc65, - 0xc84, - 0xc8d, - 0xc91, - 0xca9, - 0xcb4, - 0xcba, - 0xcbb, - 0xcc5, - 0xcc9, - 0xcdf, - 0xce4, - 0xce5, - 0xcf0, - 0xd04, - 0xd0d, - 0xd11, - 0xd3b, - 0xd3c, - 0xd45, - 0xd49, - 0xd64, - 0xd65, - 0xd80, - 0xd81, - 0xd84, - 0xdb2, - 0xdbc, - 0xdbe, - 0xdbf, - 0xdd5, - 0xdd7, - 0xdf0, - 0xdf1, - 0xe83, - 0xe85, - 0xe86, - 0xe89, - 0xe8b, - 0xe8c, - 0xe98, - 0xea0, - 0xea4, - 0xea6, - 0xea8, - 0xea9, - 0xeac, - 0xeba, - 0xebe, - 0xebf, - 0xec5, - 0xec7, - 0xece, - 0xecf, - 0xeda, - 0xedb, - 0xf48, - 0xf98, - 0xfbd, - 0xfcd, - 0x10c6, - 0x10ce, - 0x10cf, - 0x1249, - 0x124e, - 0x124f, - 0x1257, - 0x1259, - 0x125e, - 0x125f, - 0x1289, - 0x128e, - 0x128f, - 0x12b1, - 0x12b6, - 0x12b7, - 0x12bf, - 0x12c1, - 0x12c6, - 0x12c7, - 0x12d7, - 0x1311, - 0x1316, - 0x1317, - 0x135b, - 0x135c, - 0x13f6, - 0x13f7, - 0x13fe, - 0x13ff, - 0x1680, - 0x170d, - 0x176d, - 0x1771, - 0x17de, - 0x17df, - 0x180e, - 0x180f, - 0x191f, - 0x196e, - 0x196f, - 0x1a1c, - 0x1a1d, - 0x1a5f, - 0x1a7d, - 0x1a7e, - 0x1aae, - 0x1aaf, - 0x1cf7, - 0x1f16, - 0x1f17, - 0x1f1e, - 0x1f1f, - 0x1f46, - 0x1f47, - 0x1f4e, - 0x1f4f, - 0x1f58, - 0x1f5a, - 0x1f5c, - 0x1f5e, - 0x1f7e, - 0x1f7f, - 0x1fb5, - 0x1fc5, - 0x1fd4, - 0x1fd5, - 0x1fdc, - 0x1ff0, - 0x1ff1, - 0x1ff5, - 0x2072, - 0x2073, - 0x208f, - 0x23ff, - 0x2b74, - 0x2b75, - 0x2b96, - 0x2b97, - 0x2bc9, - 0x2c2f, - 0x2c5f, - 0x2d26, - 0x2d2e, - 0x2d2f, - 0x2da7, - 0x2daf, - 0x2db7, - 0x2dbf, - 0x2dc7, - 0x2dcf, - 0x2dd7, - 0x2ddf, - 0x2e9a, - 0x3040, - 0x3097, - 0x3098, - 0x318f, - 0x321f, - 0x32ff, - 0xa7af, - 0xa8fe, - 0xa8ff, - 0xa9ce, - 0xa9ff, - 0xaa4e, - 0xaa4f, - 0xaa5a, - 0xaa5b, - 0xab07, - 0xab08, - 0xab0f, - 0xab10, - 0xab27, - 0xab2f, - 0xabee, - 0xabef, - 0xfa6e, - 0xfa6f, - 0xfb37, - 0xfb3d, - 0xfb3f, - 0xfb42, - 0xfb45, - 0xfd90, - 0xfd91, - 0xfdfe, - 0xfdff, - 0xfe53, - 0xfe67, - 0xfe75, - 0xffc8, - 0xffc9, - 0xffd0, - 0xffd1, - 0xffd8, - 0xffd9, - 0xffe7, - 0xfffe, - 0xffff, +const SINGLETONS0U: &'static [(u8, u8)] = &[ + (0x00, 1), + (0x03, 5), + (0x05, 8), + (0x06, 3), + (0x07, 4), + (0x08, 7), + (0x09, 16), + (0x0a, 27), + (0x0b, 24), + (0x0c, 22), + (0x0d, 20), + (0x0e, 22), + (0x0f, 4), + (0x10, 3), + (0x12, 18), + (0x13, 9), + (0x16, 1), + (0x17, 5), + (0x18, 2), + (0x19, 3), + (0x1a, 7), + (0x1c, 1), + (0x1f, 22), + (0x20, 3), + (0x23, 1), + (0x2b, 5), + (0x2c, 2), + (0x2d, 11), + (0x2e, 1), + (0x30, 3), + (0x31, 1), + (0x32, 2), + (0xa7, 1), + (0xa8, 2), + (0xa9, 2), + (0xaa, 4), + (0xab, 8), + (0xfa, 2), + (0xfb, 5), + (0xfd, 4), + (0xfe, 3), + (0xff, 9), ]; -const SINGLETONS1: &'static [u16] = &[ - 0xc, - 0x27, - 0x3b, - 0x3e, - 0x4e, - 0x4f, - 0x18f, - 0x39e, - 0x49e, - 0x49f, - 0x806, - 0x807, - 0x809, - 0x836, - 0x83d, - 0x83e, - 0x856, - 0x8f3, - 0x9d0, - 0x9d1, - 0xa04, - 0xa14, - 0xa18, - 0xb56, - 0xb57, - 0x10bd, - 0x1135, - 0x11ce, - 0x11cf, - 0x11e0, - 0x1212, - 0x1287, - 0x1289, - 0x128e, - 0x129e, - 0x1304, - 0x130d, - 0x130e, - 0x1311, - 0x1312, - 0x1329, - 0x1331, - 0x1334, - 0x133a, - 0x133b, - 0x1345, - 0x1346, - 0x1349, - 0x134a, - 0x134e, - 0x134f, - 0x1364, - 0x1365, - 0x145a, - 0x145c, - 0x15b6, - 0x15b7, - 0x1c09, - 0x1c37, - 0x1c90, - 0x1c91, - 0x1ca8, - 0x246f, - 0x6a5f, - 0x6aee, - 0x6aef, - 0x6b5a, - 0x6b62, - 0xbc9a, - 0xbc9b, - 0xd127, - 0xd128, - 0xd455, - 0xd49d, - 0xd4a0, - 0xd4a1, - 0xd4a3, - 0xd4a4, - 0xd4a7, - 0xd4a8, - 0xd4ad, - 0xd4ba, - 0xd4bc, - 0xd4c4, - 0xd506, - 0xd50b, - 0xd50c, - 0xd515, - 0xd51d, - 0xd53a, - 0xd53f, - 0xd545, - 0xd551, - 0xd6a6, - 0xd6a7, - 0xd7cc, - 0xd7cd, - 0xdaa0, - 0xe007, - 0xe019, - 0xe01a, - 0xe022, - 0xe025, - 0xe8c5, - 0xe8c6, - 0xee04, - 0xee20, - 0xee23, - 0xee25, - 0xee26, - 0xee28, - 0xee33, - 0xee38, - 0xee3a, - 0xee48, - 0xee4a, - 0xee4c, - 0xee50, - 0xee53, - 0xee55, - 0xee56, - 0xee58, - 0xee5a, - 0xee5c, - 0xee5e, - 0xee60, - 0xee63, - 0xee65, - 0xee66, - 0xee6b, - 0xee73, - 0xee78, - 0xee7d, - 0xee7f, - 0xee8a, - 0xeea4, - 0xeeaa, - 0xf0af, - 0xf0b0, - 0xf0c0, - 0xf0d0, - 0xf12f, - 0xf91f, - 0xf931, - 0xf932, - 0xf93f, +const SINGLETONS0L: &'static [u8] = &[ + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, + 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, + 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, + 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, 0xc9, + 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, 0x29, + 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, + 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, + 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, 0x04, + 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, + 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, 0xcf, 0x04, + 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, + 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, + 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11, + 0x3b, 0x3c, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, + 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, + 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, + 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, + 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, + 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, + 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, + 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, + 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, + 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, + 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, + 0x7e, 0xae, 0xaf, 0xf7, 0x16, 0x17, 0x1e, 0x1f, + 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, + 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, + 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0xff, 0x74, 0x75, + 0x96, 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, + 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, + 0x9a, 0x40, 0x97, 0x98, 0x8f, 0x1f, 0xff, 0xaf, + 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, + 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, + 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, + 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, + 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; -const NORMAL0: &'static [u16] = &[ - 0x0, 0x20, - 0x7f, 0x22, - 0x380, 0x4, - 0x5c8, 0x8, - 0x5eb, 0x5, - 0x5f5, 0x11, - 0x7b2, 0xe, - 0x7fb, 0x5, - 0x85f, 0x41, - 0x8be, 0x16, - 0x9b3, 0x3, - 0x9cf, 0x8, - 0x9d8, 0x4, - 0x9fc, 0x5, - 0xa0b, 0x4, - 0xa43, 0x4, - 0xa4e, 0x3, - 0xa52, 0x7, - 0xa5f, 0x7, - 0xa76, 0xb, - 0xad1, 0xf, - 0xaf2, 0x7, - 0xafa, 0x7, - 0xb4e, 0x8, - 0xb58, 0x4, - 0xb78, 0xa, - 0xb8b, 0x3, - 0xb96, 0x3, - 0xba0, 0x3, - 0xba5, 0x3, - 0xbab, 0x3, - 0xbba, 0x4, - 0xbc3, 0x3, - 0xbd1, 0x6, - 0xbd8, 0xe, - 0xbfb, 0x5, - 0xc3a, 0x3, - 0xc4e, 0x7, - 0xc5b, 0x5, - 0xc70, 0x8, - 0xcce, 0x7, - 0xcd7, 0x7, - 0xcf3, 0xe, - 0xd50, 0x4, - 0xd97, 0x3, - 0xdc7, 0x3, - 0xdcb, 0x4, - 0xde0, 0x6, - 0xdf5, 0xc, - 0xe3b, 0x4, - 0xe5c, 0x25, - 0xe8e, 0x6, - 0xee0, 0x20, - 0xf6d, 0x4, - 0xfdb, 0x25, - 0x10c8, 0x5, - 0x137d, 0x3, - 0x139a, 0x6, - 0x169d, 0x3, - 0x16f9, 0x7, - 0x1715, 0xb, - 0x1737, 0x9, - 0x1754, 0xc, - 0x1774, 0xc, - 0x17ea, 0x6, - 0x17fa, 0x6, - 0x181a, 0x6, - 0x1878, 0x8, - 0x18ab, 0x5, - 0x18f6, 0xa, - 0x192c, 0x4, - 0x193c, 0x4, - 0x1941, 0x3, - 0x1975, 0xb, - 0x19ac, 0x4, - 0x19ca, 0x6, - 0x19db, 0x3, - 0x1a8a, 0x6, - 0x1a9a, 0x6, - 0x1abf, 0x41, - 0x1b4c, 0x4, - 0x1b7d, 0x3, - 0x1bf4, 0x8, - 0x1c38, 0x3, - 0x1c4a, 0x3, - 0x1c89, 0x37, - 0x1cc8, 0x8, - 0x1cfa, 0x6, - 0x1df6, 0x5, - 0x1fff, 0x11, - 0x2028, 0x8, - 0x205f, 0x11, - 0x209d, 0x3, - 0x20bf, 0x11, - 0x20f1, 0xf, - 0x218c, 0x4, - 0x2427, 0x19, - 0x244b, 0x15, - 0x2bba, 0x3, - 0x2bd2, 0x1a, - 0x2bf0, 0x10, - 0x2cf4, 0x5, - 0x2d28, 0x5, - 0x2d68, 0x7, - 0x2d71, 0xe, - 0x2d97, 0x9, - 0x2e45, 0x3b, - 0x2ef4, 0xc, - 0x2fd6, 0x1a, - 0x2ffc, 0x5, - 0x3100, 0x5, - 0x312e, 0x3, - 0x31bb, 0x5, - 0x31e4, 0xc, - 0x4db6, 0xa, - 0x9fd6, 0x2a, - 0xa48d, 0x3, - 0xa4c7, 0x9, - 0xa62c, 0x14, - 0xa6f8, 0x8, - 0xa7b8, 0x3f, - 0xa82c, 0x4, - 0xa83a, 0x6, - 0xa878, 0x8, - 0xa8c6, 0x8, - 0xa8da, 0x6, - 0xa954, 0xb, - 0xa97d, 0x3, - 0xa9da, 0x4, - 0xaa37, 0x9, - 0xaac3, 0x18, - 0xaaf7, 0xa, - 0xab17, 0x9, - 0xab66, 0xa, - 0xabfa, 0x6, - 0xd7a4, 0xc, - 0xd7c7, 0x4, - 0xd7fc, 0x2104, - 0xfada, 0x26, - 0xfb07, 0xc, - 0xfb18, 0x5, - 0xfbc2, 0x11, - 0xfd40, 0x10, - 0xfdc8, 0x28, - 0xfe1a, 0x6, - 0xfe6c, 0x4, - 0xfefd, 0x4, - 0xffbf, 0x3, - 0xffdd, 0x3, - 0xffef, 0xd, +const SINGLETONS1U: &'static [(u8, u8)] = &[ + (0x00, 6), + (0x01, 1), + (0x03, 1), + (0x04, 2), + (0x08, 8), + (0x09, 2), + (0x0a, 3), + (0x0b, 2), + (0x10, 1), + (0x11, 4), + (0x12, 5), + (0x13, 18), + (0x14, 2), + (0x15, 2), + (0x1c, 5), + (0x24, 1), + (0x6a, 3), + (0x6b, 2), + (0xbc, 2), + (0xd1, 2), + (0xd4, 12), + (0xd5, 9), + (0xd6, 2), + (0xd7, 2), + (0xda, 1), + (0xe0, 5), + (0xe8, 2), + (0xee, 32), + (0xf0, 4), + (0xf1, 1), + (0xf9, 4), ]; -const NORMAL1: &'static [u16] = &[ +const SINGLETONS1L: &'static [u8] = &[ + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, + 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, + 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, + 0xb7, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x6f, 0x5f, + 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, + 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, + 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, + 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, + 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, + 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, + 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, + 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, + 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, + 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x1f, 0x31, + 0x32, 0x3f, +]; +const NORMAL0: &'static [u8] = &[ + 0x00, 0x20, + 0x5f, 0x22, + 0x82, 0xdf, 0x04, + 0x82, 0x44, 0x08, + 0x1b, 0x05, + 0x05, 0x11, + 0x81, 0xac, 0x0e, + 0x3b, 0x05, + 0x5f, 0x41, + 0x1e, 0x16, + 0x80, 0xdf, 0x03, + 0x19, 0x08, + 0x01, 0x04, + 0x20, 0x05, + 0x0a, 0x04, + 0x34, 0x04, + 0x07, 0x03, + 0x01, 0x07, + 0x06, 0x07, + 0x10, 0x0b, + 0x50, 0x0f, + 0x12, 0x07, + 0x01, 0x07, + 0x4d, 0x08, + 0x02, 0x04, + 0x1c, 0x0a, + 0x09, 0x03, + 0x08, 0x03, + 0x07, 0x03, + 0x02, 0x03, + 0x03, 0x03, + 0x0c, 0x04, + 0x05, 0x03, + 0x0b, 0x06, + 0x01, 0x0e, + 0x15, 0x05, + 0x3a, 0x03, + 0x11, 0x07, + 0x06, 0x05, + 0x10, 0x08, + 0x56, 0x07, + 0x02, 0x07, + 0x15, 0x0e, + 0x4f, 0x04, + 0x43, 0x03, + 0x2d, 0x03, + 0x01, 0x04, + 0x11, 0x06, + 0x0f, 0x0c, + 0x3a, 0x04, + 0x1d, 0x25, + 0x0d, 0x06, + 0x4c, 0x20, + 0x6d, 0x04, + 0x6a, 0x25, + 0x80, 0xc8, 0x05, + 0x82, 0xb0, 0x03, + 0x1a, 0x06, + 0x82, 0xfd, 0x03, + 0x59, 0x07, + 0x15, 0x0b, + 0x17, 0x09, + 0x14, 0x0c, + 0x14, 0x0c, + 0x6a, 0x06, + 0x0a, 0x06, + 0x1a, 0x06, + 0x58, 0x08, + 0x2b, 0x05, + 0x46, 0x0a, + 0x2c, 0x04, + 0x0c, 0x04, + 0x01, 0x03, + 0x31, 0x0b, + 0x2c, 0x04, + 0x1a, 0x06, + 0x0b, 0x03, + 0x80, 0xac, 0x06, + 0x0a, 0x06, + 0x1f, 0x41, + 0x4c, 0x04, + 0x2d, 0x03, + 0x74, 0x08, + 0x3c, 0x03, + 0x0f, 0x03, + 0x3c, 0x37, + 0x08, 0x08, + 0x2a, 0x06, + 0x80, 0xf6, 0x05, + 0x82, 0x04, 0x11, + 0x18, 0x08, + 0x2f, 0x11, + 0x2d, 0x03, + 0x1f, 0x11, + 0x21, 0x0f, + 0x80, 0x8c, 0x04, + 0x82, 0x97, 0x19, + 0x0b, 0x15, + 0x87, 0x5a, 0x03, + 0x15, 0x1a, + 0x04, 0x10, + 0x80, 0xf4, 0x05, + 0x2f, 0x05, + 0x3b, 0x07, + 0x02, 0x0e, + 0x18, 0x09, + 0x80, 0xa5, 0x3b, + 0x74, 0x0c, + 0x80, 0xd6, 0x1a, + 0x0c, 0x05, + 0x80, 0xff, 0x05, + 0x29, 0x03, + 0x80, 0x8a, 0x05, + 0x24, 0x0c, + 0x9b, 0xc6, 0x0a, + 0xd2, 0x16, 0x2a, + 0x84, 0x8d, 0x03, + 0x37, 0x09, + 0x81, 0x5c, 0x14, + 0x80, 0xb8, 0x08, + 0x80, 0xb8, 0x3f, + 0x35, 0x04, + 0x0a, 0x06, + 0x38, 0x08, + 0x46, 0x08, + 0x0c, 0x06, + 0x74, 0x0b, + 0x1e, 0x03, + 0x5a, 0x04, + 0x59, 0x09, + 0x80, 0x83, 0x18, + 0x1c, 0x0a, + 0x16, 0x09, + 0x46, 0x0a, + 0x80, 0x8a, 0x06, + 0xab, 0xa4, 0x0c, + 0x17, 0x04, + 0x31, 0xa1, 0x04, + 0x81, 0xda, 0x26, + 0x07, 0x0c, + 0x05, 0x05, + 0x80, 0xa5, 0x11, + 0x81, 0x6d, 0x10, + 0x78, 0x28, + 0x2a, 0x06, + 0x4c, 0x04, + 0x80, 0x8d, 0x04, + 0x80, 0xbe, 0x03, + 0x1b, 0x03, + 0x0f, 0x0d, +]; +const NORMAL1: &'static [u8] = &[ + 0x5e, 0x22, + 0x7b, 0x05, + 0x03, 0x04, + 0x2d, 0x03, + 0x65, 0x04, + 0x01, 0x2f, + 0x2e, 0x80, 0x82, + 0x1d, 0x03, + 0x31, 0x0f, + 0x1c, 0x04, + 0x24, 0x0c, + 0x1b, 0x05, + 0x2b, 0x05, + 0x44, 0x04, + 0x0e, 0x2a, + 0x80, 0xaa, 0x06, + 0x24, 0x04, + 0x24, 0x04, + 0x28, 0x08, + 0x34, 0x0b, + 0x01, 0x80, 0x90, + 0x81, 0x37, 0x09, + 0x16, 0x0a, + 0x08, 0x80, 0x98, + 0x39, 0x03, + 0x63, 0x08, + 0x09, 0x30, + 0x16, 0x05, + 0x21, 0x03, + 0x1b, 0x05, + 0x01, 0x40, + 0x38, 0x04, + 0x4b, 0x05, + 0x28, 0x04, + 0x03, 0x04, + 0x09, 0x08, + 0x09, 0x07, + 0x40, 0x20, + 0x27, 0x04, + 0x0c, 0x09, + 0x36, 0x03, + 0x3a, 0x05, + 0x1a, 0x07, + 0x04, 0x0c, + 0x07, 0x50, + 0x49, 0x37, + 0x33, 0x0d, + 0x33, 0x07, + 0x06, 0x81, 0x60, + 0x1f, 0x81, 0x81, + 0x4e, 0x04, + 0x1e, 0x0f, + 0x43, 0x0e, + 0x19, 0x07, + 0x0a, 0x06, + 0x44, 0x0c, + 0x27, 0x09, + 0x75, 0x0b, + 0x3f, 0x41, + 0x2a, 0x06, + 0x3b, 0x05, + 0x0a, 0x06, + 0x51, 0x06, + 0x01, 0x05, + 0x10, 0x03, + 0x05, 0x80, 0x8b, + 0x5e, 0x22, + 0x48, 0x08, + 0x0a, 0x80, 0xa6, 0x5e, 0x22, - 0xfb, 0x5, - 0x103, 0x4, - 0x134, 0x3, - 0x19c, 0x4, - 0x1a1, 0x2f, - 0x1fe, 0x82, - 0x29d, 0x3, - 0x2d1, 0xf, - 0x2fc, 0x4, - 0x324, 0xc, - 0x34b, 0x5, - 0x37b, 0x5, - 0x3c4, 0x4, - 0x3d6, 0x2a, - 0x4aa, 0x6, - 0x4d4, 0x4, - 0x4fc, 0x4, - 0x528, 0x8, - 0x564, 0xb, - 0x570, 0x90, - 0x737, 0x9, - 0x756, 0xa, - 0x768, 0x98, - 0x839, 0x3, - 0x89f, 0x8, - 0x8b0, 0x30, - 0x8f6, 0x5, - 0x91c, 0x3, - 0x93a, 0x5, - 0x940, 0x40, - 0x9b8, 0x4, - 0xa07, 0x5, - 0xa34, 0x4, - 0xa3b, 0x4, - 0xa48, 0x8, - 0xa59, 0x7, - 0xaa0, 0x20, - 0xae7, 0x4, - 0xaf7, 0x9, - 0xb36, 0x3, - 0xb73, 0x5, - 0xb92, 0x7, - 0xb9d, 0xc, - 0xbb0, 0x50, - 0xc49, 0x37, - 0xcb3, 0xd, - 0xcf3, 0x7, - 0xd00, 0x160, - 0xe7f, 0x181, - 0x104e, 0x4, - 0x1070, 0xf, - 0x10c2, 0xe, - 0x10e9, 0x7, - 0x10fa, 0x6, - 0x1144, 0xc, - 0x1177, 0x9, - 0x11f5, 0xb, - 0x123f, 0x41, - 0x12aa, 0x6, - 0x12eb, 0x5, - 0x12fa, 0x6, - 0x1351, 0x6, - 0x1358, 0x5, - 0x136d, 0x3, - 0x1375, 0x8b, - 0x145e, 0x22, - 0x14c8, 0x8, - 0x14da, 0xa6, - 0x15de, 0x22, - 0x1645, 0xb, - 0x165a, 0x6, - 0x166d, 0x13, - 0x16b8, 0x8, - 0x16ca, 0x36, - 0x171a, 0x3, - 0x172c, 0x4, - 0x1740, 0x160, - 0x18f3, 0xc, - 0x1900, 0x1c0, - 0x1af9, 0x107, - 0x1c46, 0xa, - 0x1c6d, 0x3, - 0x1cb7, 0x349, - 0x239a, 0x66, - 0x2475, 0xb, - 0x2544, 0xabc, - 0x342f, 0xfd1, - 0x4647, 0x21b9, - 0x6a39, 0x7, - 0x6a6a, 0x4, - 0x6a70, 0x60, - 0x6af6, 0xa, - 0x6b46, 0xa, - 0x6b78, 0x5, - 0x6b90, 0x370, - 0x6f45, 0xb, - 0x6f7f, 0x10, - 0x6fa0, 0x40, - 0x6fe1, 0x1f, - 0x87ed, 0x13, - 0x8af3, 0x250d, - 0xb002, 0xbfe, - 0xbc6b, 0x5, - 0xbc7d, 0x3, - 0xbc89, 0x7, - 0xbca0, 0x1360, - 0xd0f6, 0xa, - 0xd173, 0x8, - 0xd1e9, 0x17, - 0xd246, 0xba, - 0xd357, 0x9, - 0xd372, 0x8e, - 0xd547, 0x3, - 0xda8c, 0xf, - 0xdab0, 0x550, - 0xe02b, 0x7d5, - 0xe8d7, 0x29, - 0xe94b, 0x5, - 0xe95a, 0x4, - 0xe960, 0x4a0, - 0xee3c, 0x6, - 0xee43, 0x4, - 0xee9c, 0x5, - 0xeebc, 0x34, - 0xeef2, 0x10e, - 0xf02c, 0x4, - 0xf094, 0xc, - 0xf0f6, 0xa, - 0xf10d, 0x3, - 0xf16c, 0x4, - 0xf1ad, 0x39, - 0xf203, 0xd, - 0xf23c, 0x4, - 0xf249, 0x7, - 0xf252, 0xae, - 0xf6d3, 0xd, - 0xf6ed, 0x3, - 0xf6f7, 0x9, - 0xf774, 0xc, - 0xf7d5, 0x2b, - 0xf80c, 0x4, - 0xf848, 0x8, - 0xf85a, 0x6, - 0xf888, 0x8, - 0xf8ae, 0x62, - 0xf928, 0x8, - 0xf94c, 0x4, - 0xf95f, 0x21, - 0xf992, 0x2e, - 0xf9c1, 0x63f, + 0x45, 0x0b, + 0x0a, 0x06, + 0x0d, 0x13, + 0x38, 0x08, + 0x0a, 0x36, + 0x1a, 0x03, + 0x0f, 0x04, + 0x10, 0x81, 0x60, + 0x53, 0x0c, + 0x01, 0x81, 0xc0, + 0x39, 0x81, 0x07, + 0x46, 0x0a, + 0x1d, 0x03, + 0x47, 0x83, 0x49, + 0x83, 0x9a, 0x66, + 0x75, 0x0b, + 0x80, 0xc4, 0x8a, 0xbc, + 0x84, 0x2f, 0x8f, 0xd1, + 0x82, 0x47, 0xa1, 0xb9, + 0x82, 0x39, 0x07, + 0x2a, 0x04, + 0x02, 0x60, + 0x26, 0x0a, + 0x46, 0x0a, + 0x28, 0x05, + 0x13, 0x83, 0x70, + 0x45, 0x0b, + 0x2f, 0x10, + 0x11, 0x40, + 0x01, 0x1f, + 0x97, 0xed, 0x13, + 0x82, 0xf3, 0xa5, 0x0d, + 0x02, 0x8b, 0xfe, + 0x6b, 0x05, + 0x0d, 0x03, + 0x09, 0x07, + 0x10, 0x93, 0x60, + 0x80, 0xf6, 0x0a, + 0x73, 0x08, + 0x6e, 0x17, + 0x46, 0x80, 0xba, + 0x57, 0x09, + 0x12, 0x80, 0x8e, + 0x81, 0x47, 0x03, + 0x85, 0x42, 0x0f, + 0x15, 0x85, 0x50, + 0x2b, 0x87, 0xd5, + 0x80, 0xd7, 0x29, + 0x4b, 0x05, + 0x0a, 0x04, + 0x02, 0x84, 0xa0, + 0x3c, 0x06, + 0x01, 0x04, + 0x55, 0x05, + 0x1b, 0x34, + 0x02, 0x81, 0x0e, + 0x2c, 0x04, + 0x64, 0x0c, + 0x56, 0x0a, + 0x0d, 0x03, + 0x5c, 0x04, + 0x3d, 0x39, + 0x1d, 0x0d, + 0x2c, 0x04, + 0x09, 0x07, + 0x02, 0x80, 0xae, + 0x83, 0xd3, 0x0d, + 0x0d, 0x03, + 0x07, 0x09, + 0x74, 0x0c, + 0x55, 0x2b, + 0x0c, 0x04, + 0x38, 0x08, + 0x0a, 0x06, + 0x28, 0x08, + 0x1e, 0x62, + 0x18, 0x08, + 0x1c, 0x04, + 0x0f, 0x21, + 0x12, 0x2e, + 0x01, 0x86, 0x3f, ];