From 63a291febac3ba2cb48787fed24388c2817ef4a2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 9 Apr 2017 12:00:34 -0400 Subject: [PATCH 01/13] Fix rustdoc infinitely recursing when an external crate reexports itself Previously, rustdoc's LibEmbargoVisitor unconditionally visited the child modules of an external crate. If a module re-exported its parent via 'pub use super::*', rustdoc would re-walk the parent, leading to infinite recursion. This commit makes LibEmbargoVisitor store already visited modules in an FxHashSet, ensuring that each module is only walked once. Fixes #40936 --- src/librustdoc/visit_lib.rs | 8 ++++++++ src/test/rustdoc/auxiliary/issue-40936.rs | 15 +++++++++++++++ src/test/rustdoc/issue-40936.rs | 16 ++++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/test/rustdoc/auxiliary/issue-40936.rs create mode 100644 src/test/rustdoc/issue-40936.rs diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 852c98eb2fd52..40a6ffe9505fd 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -13,6 +13,7 @@ use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty::Visibility; +use rustc::util::nodemap::FxHashSet; use std::cell::RefMut; @@ -29,6 +30,8 @@ pub struct LibEmbargoVisitor<'a, 'b: 'a, 'tcx: 'b> { access_levels: RefMut<'a, AccessLevels>, // Previous accessibility level, None means unreachable prev_level: Option, + // Keeps track of already visited modules, in case a module re-exports its parent + visited_mods: FxHashSet, } impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { @@ -38,6 +41,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { cstore: &*cx.sess().cstore, access_levels: cx.access_levels.borrow_mut(), prev_level: Some(AccessLevel::Public), + visited_mods: FxHashSet() } } @@ -62,6 +66,10 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { } pub fn visit_mod(&mut self, def_id: DefId) { + if !self.visited_mods.insert(def_id) { + return; + } + for item in self.cstore.item_children(def_id) { self.visit_item(item.def); } diff --git a/src/test/rustdoc/auxiliary/issue-40936.rs b/src/test/rustdoc/auxiliary/issue-40936.rs new file mode 100644 index 0000000000000..54cc18cca23ac --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-40936.rs @@ -0,0 +1,15 @@ +// 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. + +pub mod outermod { + pub mod innermod { + pub use super::*; + } +} diff --git a/src/test/rustdoc/issue-40936.rs b/src/test/rustdoc/issue-40936.rs new file mode 100644 index 0000000000000..3e02eec1b9c30 --- /dev/null +++ b/src/test/rustdoc/issue-40936.rs @@ -0,0 +1,16 @@ +// 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. + +// aux-build:issue-40936.rs +// build-aux-docs + +#![crate_name = "foo"] + +extern crate issue_40936; From dd7dfe56a9e0d095c670a84f9e827fa9689aad97 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 12 Apr 2017 18:14:54 +0200 Subject: [PATCH 02/13] Fix invalid associated type rendering in rustdoc --- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/html/format.rs | 115 ++++++++++++++++++---------- src/test/rustdoc/assoc-item-cast.rs | 26 +++++++ 3 files changed, 101 insertions(+), 42 deletions(-) create mode 100644 src/test/rustdoc/assoc-item-cast.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ac72d7d29a24c..2511560e87261 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2277,7 +2277,7 @@ impl Clean for hir::PathParameters { #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct PathSegment { pub name: String, - pub params: PathParameters + pub params: PathParameters, } impl Clean for hir::PathSegment { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index ffef42bc3d27c..0f47265a1aa66 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -470,10 +470,22 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { /// rendering function with the necessary arguments for linking to a local path. fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, print_all: bool, use_absolute: bool, is_not_debug: bool) -> fmt::Result { - let last = path.segments.last().unwrap(); - let rel_root = match &*path.segments[0].name { - "self" => Some("./".to_string()), - _ => None, + let empty = clean::PathSegment { + name: String::new(), + params: clean::PathParameters::Parenthesized { + inputs: Vec::new(), + output: None, + } + }; + let last = path.segments.last() + .unwrap_or(&empty); + let rel_root = if path.segments.is_empty() { + None + } else { + match &*path.segments[0].name { + "self" => Some("./".to_string()), + _ => None, + } }; if print_all { @@ -487,10 +499,9 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, root.push_str(&seg.name); root.push_str("/"); if is_not_debug { - write!(w, "{}::", - root, - seg.name)?; + write!(w, "{}::", + root, + seg.name)?; } else { write!(w, "{}::", seg.name)?; } @@ -516,7 +527,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, match href(did) { Some((_, _, fqp)) => format!("{}::{}", fqp[..fqp.len()-1].join("::"), - HRef::new(did, fqp.last().unwrap())), + HRef::new(did, fqp.last() + .unwrap_or(&String::new()))), None => format!("{}", HRef::new(did, &last.name)), } } else { @@ -528,7 +540,8 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, match href(did) { Some((_, _, fqp)) => format!("{:?}::{:?}", fqp[..fqp.len()-1].join("::"), - HRef::new(did, fqp.last().unwrap())), + HRef::new(did, fqp.last() + .unwrap_or(&String::new()))), None => format!("{:?}", HRef::new(did, &last.name)), } } else { @@ -801,45 +814,65 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool, } Ok(()) } - // It's pretty unsightly to look at `::C` in output, and - // we've got hyperlinking on our side, so try to avoid longer - // notation as much as possible by making `C` a hyperlink to trait - // `B` to disambiguate. - // - // FIXME: this is still a lossy conversion and there should probably - // be a better way of representing this in general? Most of - // the ugliness comes from inlining across crates where - // everything comes in as a fully resolved QPath (hard to - // look at). - clean::QPath { - ref name, - ref self_type, - trait_: box clean::ResolvedPath { did, ref typarams, .. }, - } => { - if f.alternate() { - write!(f, "{:#}::", self_type)?; - } else { - write!(f, "{}::", self_type)?; - } - let path = clean::Path::singleton(name.clone()); - resolved_path(f, did, &path, true, use_absolute, is_not_debug)?; - - // FIXME: `typarams` are not rendered, and this seems bad? - drop(typarams); - Ok(()) - } clean::QPath { ref name, ref self_type, ref trait_ } => { + let should_show_cast = match *trait_ { + box clean::ResolvedPath { .. } => { + let path = clean::Path::singleton(name.clone()); + !path.segments.is_empty() && &format!("{:#}", trait_) != "()" && + &format!("{:#}", self_type) != "Self" + } + _ => true, + }; if f.alternate() { if is_not_debug { - write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{:#} as {:#}>::", self_type, trait_)? + } else { + write!(f, "{:#}::", self_type)? + } } else { - write!(f, "<{:#?} as {:#?}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{:#?} as {:#?}>::", self_type, trait_)? + } else { + write!(f, "{:#?}::", self_type)? + } } } else { if is_not_debug { - write!(f, "<{} as {}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{} as {}>::", self_type, trait_)? + } else { + write!(f, "{}::", self_type)? + } } else { - write!(f, "<{:?} as {:?}>::{}", self_type, trait_, name) + if should_show_cast { + write!(f, "<{:?} as {:?}>::", self_type, trait_)? + } else { + write!(f, "{:?}::", self_type)? + } + } + }; + match *trait_ { + // It's pretty unsightly to look at `::C` in output, and + // we've got hyperlinking on our side, so try to avoid longer + // notation as much as possible by making `C` a hyperlink to trait + // `B` to disambiguate. + // + // FIXME: this is still a lossy conversion and there should probably + // be a better way of representing this in general? Most of + // the ugliness comes from inlining across crates where + // everything comes in as a fully resolved QPath (hard to + // look at). + box clean::ResolvedPath { did, ref typarams, .. } => { + let path = clean::Path::singleton(name.clone()); + resolved_path(f, did, &path, true, use_absolute, is_not_debug)?; + + // FIXME: `typarams` are not rendered, and this seems bad? + drop(typarams); + Ok(()) + } + _ => { + write!(f, "{}", name) } } } diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs new file mode 100644 index 0000000000000..24f31b5b1040b --- /dev/null +++ b/src/test/rustdoc/assoc-item-cast.rs @@ -0,0 +1,26 @@ +// 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. + +#![crate_name = "foo"] + +// ignore-tidy-linelength + +pub trait Expression { + type SqlType; +} + +pub trait AsExpression { + type Expression: Expression; + fn as_expression(self) -> Self::Expression; +} + +// @has foo/type.AsExprOf.html +// @has - '//*[@class="rust typedef"]' 'type AsExprOf = >::Expression;' +pub type AsExprOf = >::Expression; From 768e9029413c6fa3857cf8ba7d943bb297a58ee3 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 15 Mar 2017 21:27:40 -0500 Subject: [PATCH 03/13] First attempt at global_asm! macro --- src/librustc/hir/def.rs | 6 +- src/librustc/hir/intravisit.rs | 1 + src/librustc/hir/lowering.rs | 8 +++ src/librustc/hir/map/def_collector.rs | 1 + src/librustc/hir/map/mod.rs | 1 + src/librustc/hir/mod.rs | 9 +++ src/librustc/hir/print.rs | 5 ++ src/librustc/ich/impls_hir.rs | 13 ++++ src/librustc/middle/reachable.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 3 +- 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 | 12 ++++ 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 | 66 +++++++++++++++++++++ src/libsyntax_ext/lib.rs | 2 + 31 files changed, 180 insertions(+), 6 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 2c8b145f126cd..9615ed4af0692 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 30fec50d4eb6f..c86aaa7bf6727 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -646,6 +646,13 @@ impl<'a> LoweringContext<'a> { } } + fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P { + P(hir::GlobalAsm { + asm: ga.asm, + ctxt: ga.ctxt, + }) + } + fn lower_variant(&mut self, v: &Variant) -> hir::Variant { Spanned { node: hir::Variant_ { @@ -1288,6 +1295,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 c1417f718b27a..7ff5152c71a2c 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -109,6 +109,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 cfafec00ae20d..48b8a819fff03 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1077,6 +1077,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 0da405d1821d3..562b58844409d 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1495,6 +1495,12 @@ pub struct ForeignMod { pub items: HirVec, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct GlobalAsm { + pub asm: Symbol, + pub ctxt: SyntaxContext, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: HirVec, @@ -1686,6 +1692,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}` @@ -1720,6 +1728,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 4a5a35aa82ca0..5144f75b1a363 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -633,6 +633,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/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 9cf8a0693d363..5b8dc96f013c2 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -1014,6 +1014,19 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput { is_indirect }); +impl<'a, 'tcx> HashStable> for hir::GlobalAsm { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::GlobalAsm { + asm, + ctxt: _ + } = *self; + + asm.hash_stable(hcx, hasher); + } +} + impl<'a, 'tcx> HashStable> for hir::InlineAsm { fn hash_stable(&self, hcx: &mut StableHashingContext<'a, 'tcx>, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index e5dd48534a6a1..63455f94cedff 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 8037570d24a80..b9938a04047c9 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_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index cdbecb3ae2e42..3498be9dfdf32 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 ffe68094c6afc..50ebf6737a8d7 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -677,6 +677,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> EntryBuilder<'a, 'b, '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, _) => { @@ -917,6 +918,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 53d6a9ec10df2..ae20dd1a554ba 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -267,6 +267,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 300848fe8f25e..92f7e48b6be48 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -160,7 +160,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 } } }; @@ -212,7 +215,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 @@ -225,6 +230,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(..) => { @@ -1092,6 +1099,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 a15431afc164b..80f853778c744 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 c94f63329d1ff..6ba214f20f98d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1709,7 +1709,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 3fd0ce45e3610..3e8f7e11b6b43 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 44615071a56a7..d822f7bea3a30 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -701,6 +701,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 77ab076eba386..a7f9b66f659cb 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 c89ec5bbe15bd..4252f2981ed61 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -373,6 +373,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 c6a3e8a2dedc4..131adfe47afda 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1585,6 +1585,15 @@ 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 ctxt: SyntaxContext, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec, @@ -1812,6 +1821,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;` @@ -1864,6 +1875,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 1b3352f73ade7..48bfc050223ab 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1039,6 +1039,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 08762ccf04bde..70e4f7a42b68d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -346,6 +346,9 @@ declare_features! ( // Hack to document `-Z linker-flavor` in The Unstable Book (active, linker_flavor, "1.18.0", Some(41142)), + + // Allows module-level inline assembly by way of global_asm!() + (active, global_asm, "1.18.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 92e25b00e0ac1..a6ab8e10d9f91 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 e7feff2b79fce..433ba3d3693f1 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1267,6 +1267,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 b5e9a1892acc9..bae1c56db007c 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..d322d138f04cf --- /dev/null +++ b/src/libsyntax_ext/global_asm.rs @@ -0,0 +1,66 @@ +// 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, _) = 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), + }; + + 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, + ctxt: cx.backtrace(), + })), + 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 6bcd5b0980921a90367a3f8c4fbcd5b15fc4b3a5 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Thu, 16 Mar 2017 22:16:40 -0500 Subject: [PATCH 04/13] 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 a7f9b66f659cb..649353d52f6aa 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 70fcff631821c4225d38315d7d85de92dbc477be Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 10:03:52 -0500 Subject: [PATCH 05/13] 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 3e270b7928ebc..577d6798ec3fe 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 7be5043fd99308135bcd0443f8af6d7e012e4148 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 29 Mar 2017 23:32:20 -0500 Subject: [PATCH 06/13] 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 9615ed4af0692..2b0d53b2bc356 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 9240054b3ee5690b6c75bebdb6316a14bdd46340 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 19:50:23 -0500 Subject: [PATCH 07/13] 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 32c9183ece999..402166cc13fd9 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 577d6798ec3fe..92cbd004206e7 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 4b9de4cc6327b8c72716b1102a7db4f0858a76db Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 10:02:14 -0500 Subject: [PATCH 08/13] 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 54e602a81db73..8221d22eaac7b 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -83,6 +83,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 da0742c0707225c796c1710d5f97b58a5bc5a864 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Tue, 21 Mar 2017 23:47:25 -0500 Subject: [PATCH 09/13] 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 70e4f7a42b68d..8b62416dcbdbd 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 24a89a015e93afb473c267dbddc5c856d62a639c Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Wed, 5 Apr 2017 22:12:02 -0500 Subject: [PATCH 10/13] Replace ExpnId with SyntaxContext --- src/libsyntax_ext/global_asm.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index d322d138f04cf..dc67e1c45f6e7 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -21,7 +21,6 @@ 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; From 63a074791e587fa2cbb9d1b2bfdd08e08a001d9f Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Fri, 7 Apr 2017 09:46:34 -0500 Subject: [PATCH 11/13] Make simple_global_asm even simpler Windows builder croaked. This change tries to fix that by actually calling the global_asm-defined function so the symbol doesn't get optimized away, if that is in fact what was happening. Additionally, we provide an empty main() for non-x86 arches. --- src/librustc/ich/impls_hir.rs | 3 +++ src/librustc_metadata/schema.rs | 1 + src/test/run-pass/simple_global_asm.rs | 8 +++++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 5b8dc96f013c2..82e03a9fddc35 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -881,6 +881,7 @@ impl<'a, 'tcx> HashStable> for hir::Item { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemEnum(..) | hir::ItemStruct(..) | @@ -925,6 +926,7 @@ impl_stable_hash_for!(enum hir::Item_ { ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), ItemMod(module), ItemForeignMod(foreign_mod), + ItemGlobalAsm(global_asm), ItemTy(ty, generics), ItemEnum(enum_def, generics), ItemStruct(variant_data, generics), @@ -1083,6 +1085,7 @@ impl_stable_hash_for!(enum hir::def::Def { Upvar(def_id, index, expr_id), Label(node_id), Macro(def_id, macro_kind), + GlobalAsm(def_id), Err }); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index ae20dd1a554ba..6cd35f1335ed7 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -298,6 +298,7 @@ impl<'a, 'tcx> HashStable> for EntryKind<'tcx> { EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignMod | + EntryKind::GlobalAsm | EntryKind::Field | EntryKind::Type => { // Nothing else to hash here. diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs index a5ffe607fdf84..ac2cacf3db21d 100644 --- a/src/test/run-pass/simple_global_asm.rs +++ b/src/test/run-pass/simple_global_asm.rs @@ -9,19 +9,21 @@ // except according to those terms. #![feature(global_asm)] +#![feature(naked_functions)] #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] global_asm!(r#" .global foo foo: - jmp baz + ret "#); extern { fn foo(); } -#[no_mangle] -pub extern fn baz() {} +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +fn main() { unsafe { foo(); } } +#[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] fn main() {} From a35c4e354a65fdbbb61741db3a9dd1c190f2f146 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Thu, 13 Apr 2017 23:41:03 -0500 Subject: [PATCH 12/13] Comply with windows symbol name conventions --- src/test/run-pass/simple_global_asm.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs index ac2cacf3db21d..cd8273c6bc2b8 100644 --- a/src/test/run-pass/simple_global_asm.rs +++ b/src/test/run-pass/simple_global_asm.rs @@ -14,7 +14,9 @@ #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] global_asm!(r#" .global foo + .global _foo foo: +_foo: ret "#); From ec27aa97b921957711b96e578c7c197ff28553ac Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Fri, 14 Apr 2017 19:17:03 +0200 Subject: [PATCH 13/13] Compile WASM as WASM instead of asm.js Looks like the LinkerFlavor change introduced in #40018 accidentally uses GCC for the WebAssembly target, causing Rust to never actually pass the post link args to emscripten. This then causes the code to be compiled as asm.js instead of WebAssembly, because the Binaryen tools never run due to the missing linker argument. --- src/librustc_back/target/wasm32_unknown_emscripten.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs index a51f59d6ff192..f5fb63038e917 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -14,7 +14,7 @@ use super::emscripten_base::{cmd}; pub fn target() -> Result { let mut post_link_args = LinkArgs::new(); - post_link_args.insert(LinkerFlavor::Gcc, + post_link_args.insert(LinkerFlavor::Em, vec!["-s".to_string(), "BINARYEN=1".to_string(), "-s".to_string(),