]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #41303 - CryZe:patch-5, r=japaric
authorCorey Farwell <coreyf@rwell.org>
Fri, 14 Apr 2017 21:41:06 +0000 (17:41 -0400)
committerGitHub <noreply@github.com>
Fri, 14 Apr 2017 21:41:06 +0000 (17:41 -0400)
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.

56 files changed:
src/doc/unstable-book/src/SUMMARY.md
src/doc/unstable-book/src/asm.md
src/doc/unstable-book/src/global_asm.md [new file with mode: 0644]
src/librustc/hir/def.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/map/def_collector.rs
src/librustc/hir/map/mod.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/ich/impls_hir.rs
src/librustc/middle/reachable.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc_borrowck/borrowck/move_data.rs
src/librustc_driver/test.rs
src/librustc_llvm/ffi.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/schema.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_trans/asm.rs
src/librustc_trans/collector.rs
src/librustc_trans/partitioning.rs
src/librustc_trans/symbol_map.rs
src/librustc_trans/trans_item.rs
src/librustc_typeck/collect.rs
src/librustc_typeck/variance/constraints.rs
src/librustc_typeck/variance/terms.rs
src/librustdoc/clean/mod.rs
src/librustdoc/html/format.rs
src/librustdoc/visit_ast.rs
src/librustdoc/visit_lib.rs
src/libsyntax/ast.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/libsyntax_ext/global_asm.rs [new file with mode: 0644]
src/libsyntax_ext/lib.rs
src/rustllvm/RustWrapper.cpp
src/test/codegen/foo.s [new file with mode: 0644]
src/test/codegen/global_asm.rs [new file with mode: 0644]
src/test/codegen/global_asm_include.rs [new file with mode: 0644]
src/test/codegen/global_asm_x2.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-global_asm.rs [new file with mode: 0644]
src/test/compile-fail/union/union-borrow-move-parent-sibling.rs [new file with mode: 0644]
src/test/run-pass/empty_global_asm.rs [new file with mode: 0644]
src/test/run-pass/simple_global_asm.rs [new file with mode: 0644]
src/test/rustdoc/assoc-item-cast.rs [new file with mode: 0644]
src/test/rustdoc/auxiliary/issue-40936.rs [new file with mode: 0644]
src/test/rustdoc/issue-40936.rs [new file with mode: 0644]

index 14774e2d2293ce9ece91b24b99c69c8ceab0d163..a5599395f796564928da250b10bf7abfa4bdc453 100644 (file)
@@ -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)
index 032d9d81240266ec346bcf03dceaf1ac46de3fb6..5e68be633e7ab2d69aa066853c888b7ccf5c3467 100644 (file)
@@ -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 (file)
index 0000000..44921aa
--- /dev/null
@@ -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.
index 7bab4a8d725dc2bcdfd87fdde54c44d639c3973c..771031db0c045f99e985f96b2e7caf05332c55da 100644 (file)
@@ -57,6 +57,8 @@ pub enum Def {
     // Macro namespace
     Macro(DefId, MacroKind),
 
+    GlobalAsm(DefId),
+
     // Both namespaces
     Err,
 }
@@ -144,7 +146,8 @@ pub fn def_id(&self) -> DefId {
             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 @@ pub fn kind_name(&self) -> &'static str {
             Def::Label(..) => "label",
             Def::SelfTy(..) => "self type",
             Def::Macro(..) => "macro",
+            Def::GlobalAsm(..) => "global asm",
             Def::Err => "unresolved item",
         }
     }
index 2c8b145f126cd17ffb05ddd7c805dc4dc9c21132..2b0d53b2bc35645403aed989624f577e69c3abd1 100644 (file)
@@ -474,6 +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(_) => {
+            visitor.visit_id(item.id);
+        }
         ItemTy(ref typ, ref type_parameters) => {
             visitor.visit_id(item.id);
             visitor.visit_ty(typ);
index 30fec50d4eb6fef66ea3cc62a28353977f6bf9be..c86aaa7bf672745a9fd74bababce0979e59bcd20 100644 (file)
@@ -646,6 +646,13 @@ fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod {
         }
     }
 
+    fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P<hir::GlobalAsm> {
+        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 @@ fn lower_item_kind(&mut self,
             }
             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))
             }
index c1417f718b27abbecf88081040cf9a25adaab858..7ff5152c71a2cd6f29e306f01502dc68ed775a0b 100644 (file)
@@ -109,6 +109,7 @@ fn visit_item(&mut self, i: &'a Item) {
                 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(..) => {}
index cfafec00ae20def83507206f4855bc71b0a4cc53..48b8a819fff03eb53d018baebac65a13f04db6de 100644 (file)
@@ -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",
index 0da405d1821d360d8d804ae6463a7f42af706e86..562b58844409dc495da711300e5cd3aae63f3af1 100644 (file)
@@ -1495,6 +1495,12 @@ pub struct ForeignMod {
     pub items: HirVec<ForeignItem>,
 }
 
+#[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<Variant>,
@@ -1686,6 +1692,8 @@ pub enum Item_ {
     ItemMod(Mod),
     /// An external module
     ItemForeignMod(ForeignMod),
+    /// Module-level inline assembly (from global_asm!)
+    ItemGlobalAsm(P<GlobalAsm>),
     /// A type alias, e.g. `type Foo = Bar<u8>`
     ItemTy(P<Ty>, Generics),
     /// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
@@ -1720,6 +1728,7 @@ pub fn descriptive_variant(&self) -> &str {
             ItemFn(..) => "function",
             ItemMod(..) => "module",
             ItemForeignMod(..) => "foreign module",
+            ItemGlobalAsm(..) => "global asm",
             ItemTy(..) => "type alias",
             ItemEnum(..) => "enum",
             ItemStruct(..) => "struct",
index 4a5a35aa82ca0ef5799733d4021f2c4d86e49c50..5144f75b1a3634d8449f82d8ca5d6b073ce05ab8 100644 (file)
@@ -633,6 +633,11 @@ pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
                 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)?;
index 9cf8a0693d3636383133b2cbf0198e7bdb6141e0..82e03a9fddc35a94564c2fae13cc815cfdd78541 100644 (file)
@@ -881,6 +881,7 @@ fn hash_stable<W: StableHasherResult>(&self,
             hir::ItemFn(..)          |
             hir::ItemMod(..)         |
             hir::ItemForeignMod(..)  |
+            hir::ItemGlobalAsm(..)   |
             hir::ItemTy(..)          |
             hir::ItemEnum(..)        |
             hir::ItemStruct(..)      |
@@ -925,6 +926,7 @@ fn hash_stable<W: StableHasherResult>(&self,
     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),
@@ -1014,6 +1016,19 @@ fn hash_stable<W: StableHasherResult>(&self,
     is_indirect
 });
 
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::GlobalAsm {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::GlobalAsm {
+            asm,
+            ctxt: _
+        } = *self;
+
+        asm.hash_stable(hcx, hasher);
+    }
+}
+
 impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::InlineAsm {
     fn hash_stable<W: StableHasherResult>(&self,
                                           hcx: &mut StableHashingContext<'a, 'tcx>,
@@ -1070,6 +1085,7 @@ fn hash_stable<W: StableHasherResult>(&self,
     Upvar(def_id, index, expr_id),
     Label(node_id),
     Macro(def_id, macro_kind),
+    GlobalAsm(def_id),
     Err
 });
 
index e5dd48534a6a136ad452e09c9a01226dd1f7196e..63455f94cedff32370213bbaf6f1e200fc8db518 100644 (file)
@@ -267,7 +267,8 @@ fn propagate_node(&mut self, node: &hir_map::Node<'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) => {
index 8037570d24a808bb6ab7983d85d4ae7c4686d400..b9938a04047c96b141fc5a47b7484dcffe5d1c87 100644 (file)
@@ -314,7 +314,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
             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);
             }
index 2047a58f8ed85a24da6f28fd2ae7ae9d64c65d0b..5012969eef9058c4fe298e2ee0dc579bbadd0c47 100644 (file)
@@ -362,31 +362,31 @@ fn add_existing_base_paths(&self, lp: &Rc<LoanPath<'tcx>>,
 
     /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`.
     pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                    lp: Rc<LoanPath<'tcx>>,
+                    orig_lp: Rc<LoanPath<'tcx>>,
                     id: ast::NodeId,
                     kind: MoveKind) {
-        // Moving one union field automatically moves all its fields.
-        if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
-            if let ty::TyAdt(adt_def, _) = base_lp.ty.sty {
+        // Moving one union field automatically moves all its fields. Also move siblings of
+        // all parent union fields, moves do not propagate upwards automatically.
+        let mut lp = orig_lp.clone();
+        while let LpExtend(ref base_lp, mutbl, lp_elem) = lp.clone().kind {
+            if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior))
+                    = (&base_lp.ty.sty, lp_elem) {
                 if adt_def.is_union() {
                     for field in &adt_def.struct_variant().fields {
                         let field = InteriorKind::InteriorField(mc::NamedField(field.name));
-                        let field_ty = if field == interior {
-                            lp.ty
-                        } else {
-                            tcx.types.err // Doesn't matter
-                        };
-                        let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
-                                                    LpInterior(opt_variant_id, field));
-                        let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
-                        self.add_move_helper(tcx, sibling_lp, id, kind);
+                        if field != interior {
+                            let sibling_lp_kind =
+                                LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field));
+                            let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err));
+                            self.add_move_helper(tcx, sibling_lp, id, kind);
+                        }
                     }
-                    return;
                 }
             }
+            lp = base_lp.clone();
         }
 
-        self.add_move_helper(tcx, lp.clone(), id, kind);
+        self.add_move_helper(tcx, orig_lp.clone(), id, kind);
     }
 
     fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
index af2416f787ea4669e693fa0162bca977c6ac7ece..44e291a44c7779e4ba1ae72b27514ee610647bfb 100644 (file)
@@ -233,6 +233,7 @@ fn search(this: &Env, it: &hir::Item, idx: usize, names: &[String]) -> Option<as
                 hir::ItemStatic(..) |
                 hir::ItemFn(..) |
                 hir::ItemForeignMod(..) |
+                hir::ItemGlobalAsm(..) |
                 hir::ItemTy(..) => None,
 
                 hir::ItemEnum(..) |
index 32c9183ece999ff742f7d33f1dd9b0b92fddda20..402166cc13fd933853955fa504921cbc238a62ae 100644 (file)
@@ -507,6 +507,7 @@ pub enum DIBuilder_opaque {}
 
     /// 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;
index cdbecb3ae2e428a2e8535dceafd73eef0d0db7f9..3498be9dfdf3205d9dd7b5e1583fe9c9f4077143 100644 (file)
@@ -429,6 +429,7 @@ fn to_def(&self, did: DefId) -> Option<Def> {
             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(_) |
index 3bf22f8a6c82729d70aa48f61f9d0d114f0d6852..0e204695e8f22660ef8c05afd4105a163c7116c5 100644 (file)
@@ -677,6 +677,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
                 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 @@ fn encode_addl_info_for_item(&mut self, item: &hir::Item) {
             hir::ItemFn(..) |
             hir::ItemMod(..) |
             hir::ItemForeignMod(..) |
+            hir::ItemGlobalAsm(..) |
             hir::ItemExternCrate(..) |
             hir::ItemUse(..) |
             hir::ItemDefaultImpl(..) |
index 53d6a9ec10df2fca11c8cef3f8a0b5ffe89379b0..6cd35f1335ed79ef423a7a25c95efcc284a47de1 100644 (file)
@@ -267,6 +267,7 @@ pub enum EntryKind<'tcx> {
     ForeignImmStatic,
     ForeignMutStatic,
     ForeignMod,
+    GlobalAsm,
     Type,
     Enum(ReprOptions),
     Field,
@@ -297,6 +298,7 @@ fn hash_stable<W: StableHasherResult>(&self,
             EntryKind::ForeignImmStatic |
             EntryKind::ForeignMutStatic |
             EntryKind::ForeignMod       |
+            EntryKind::GlobalAsm        |
             EntryKind::Field |
             EntryKind::Type => {
                 // Nothing else to hash here.
index 300848fe8f25e1eb58ce214863b7c51e5d127bc7..92f7e48b6be4853f23321529f98156d4be2cfe4d 100644 (file)
@@ -160,7 +160,10 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
                 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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
                     }
                 }
             }
-            _ => {}
+            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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
             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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
             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(..) => {
index a15431afc164b66e14a5cab7e2bd1a598263e3cd..80f853778c744b50c909f011a589802c7da969fd 100644 (file)
@@ -268,6 +268,8 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                 self.define(parent, ident, TypeNS, imported_binding);
             }
 
+            ItemKind::GlobalAsm(..) => {}
+
             ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
 
             ItemKind::Mod(..) => {
index c94f63329d1ff1ec3c104835d630fac5a8d06722..6ba214f20f98d3b15ad4d603894231f283c40dd8 100644 (file)
@@ -1709,7 +1709,7 @@ fn resolve_item(&mut self, item: &Item) {
                 }
             }
 
-            ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => {
+            ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> {
                 // do nothing, these are just around to be encoded
             }
 
index 3fd0ce45e3610af20760a82c093a76450a1f6e9d..3e8f7e11b6b432fe9635ab655059349bbe6fbe9f 100644 (file)
@@ -341,6 +341,7 @@ fn process_def_kind(&mut self,
             Def::AssociatedTy(..) |
             Def::AssociatedConst(..) |
             Def::PrimTy(_) |
+            Def::GlobalAsm(_) |
             Def::Err => {
                span_bug!(span,
                          "process_def_kind for unexpected item: {:?}",
index 44615071a56a71eb87e495b03b3907ddb91bcc30..d822f7bea3a30e57891bb1df04f4166bbbf82d0d 100644 (file)
@@ -701,6 +701,7 @@ pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
             Def::SelfTy(..) |
             Def::Label(..) |
             Def::Macro(..) |
+            Def::GlobalAsm(..) |
             Def::Err => None,
         }
     }
index 3e270b7928ebc28127af2ab9d8228ce937286fa3..92cbd004206e7c53fc066821a34cc6418f5b5c58 100644 (file)
@@ -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::LLVMRustAppendModuleInlineAsm(ccx.llmod(), asm.as_ptr());
+    }
+}
index 500802a4135d009894d5a6beec787122e910c211..ba2b807d5a01c9496fc7f1967faf00644576a28f 100644 (file)
@@ -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);
@@ -840,6 +843,12 @@ fn visit_item(&mut self, item: &'v hir::Item) {
                     }
                 }
             }
+            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(),
index 90ce40cfbcf8fa3f27f3f33cbeb781baca05ab39..4973181202eeddcea8a787e66e53b42cecaba165 100644 (file)
@@ -185,15 +185,16 @@ pub fn compute_symbol_name_hash(&self,
             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 @@ fn local_node_id(tcx: TyCtxt, trans_item: TransItem) -> Option<NodeId> {
                 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)),
     }
 }
 
index 1b48e131b720a2c5e5a3b01c5e7597cbd524c235..36c3981e3a6f240c2b78538f8a8e03a4ac8ed4c4 100644 (file)
@@ -99,7 +99,10 @@ fn get_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, '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)
             })
index 410e3f30be731eb0622e0a659030f04215094612..f5556bb8382f6540f58bea55168ad96429475e56 100644 (file)
@@ -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 @@
 #[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 @@ pub fn define(&self, ccx: &CrateContext<'a, '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 @@ pub fn predefine(&self,
             TransItem::Fn(instance) => {
                 TransItem::predefine_fn(ccx, instance, linkage, &symbol_name);
             }
+            TransItem::GlobalAsm(..) => {}
         }
 
         debug!("END PREDEFINING '{} ({})' in cgu {}",
@@ -185,6 +196,10 @@ pub fn compute_symbol_name(&self,
                 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 @@ pub fn instantiation_mode(&self,
                 }
             }
             TransItem::Static(..) => InstantiationMode::GloballyShared,
+            TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared,
         }
     }
 
@@ -210,7 +226,8 @@ pub fn is_generic_fn(&self) -> bool {
             TransItem::Fn(ref instance) => {
                 instance.substs.types().next().is_some()
             }
-            TransItem::Static(..)   => false,
+            TransItem::Static(..) |
+            TransItem::GlobalAsm(..) => false,
         }
     }
 
@@ -218,6 +235,7 @@ pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<llvm::Link
         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 @@ pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
                 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 @@ pub fn to_raw_string(&self) -> String {
             TransItem::Static(id) => {
                 format!("Static({:?})", id)
             }
+            TransItem::GlobalAsm(id) => {
+                format!("GlobalAsm({:?})", id)
+            }
         }
     }
 }
index 77ab076eba38604f89bc5dc3775ea204ead4ecc3..649353d52f6aaf29052d3b783a52d38c4c1682f1 100644 (file)
@@ -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);
-        },
+        }
     }
 }
 
@@ -1074,6 +1076,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 ItemTrait(..) |
                 ItemMod(..) |
                 ItemForeignMod(..) |
+                ItemGlobalAsm(..) |
                 ItemExternCrate(..) |
                 ItemUse(..) => {
                     span_bug!(
index f0f543fa6f23b7af8b774a5e5e8bbe72e0fd069d..1bde1eea37c39a0b16c7032a1a16b6fcabb3c628 100644 (file)
@@ -113,6 +113,7 @@ fn visit_item(&mut self, item: &hir::Item) {
             hir::ItemFn(..) |
             hir::ItemMod(..) |
             hir::ItemForeignMod(..) |
+            hir::ItemGlobalAsm(..) |
             hir::ItemTy(..) |
             hir::ItemImpl(..) |
             hir::ItemDefaultImpl(..) => {}
index 36352f50e4406237115aa36abf42d55a53438c38..890414e317c62f3bc522d7660cfef818a6ef4478 100644 (file)
@@ -251,6 +251,7 @@ fn visit_item(&mut self, item: &hir::Item) {
             hir::ItemFn(..) |
             hir::ItemMod(..) |
             hir::ItemForeignMod(..) |
+            hir::ItemGlobalAsm(..) |
             hir::ItemTy(..) => {}
         }
     }
index fb8ba51853fe8748ca0ef482d70844e46efbae51..3d233463bba3a0fda17570add29d2ec081ff3789 100644 (file)
@@ -2285,7 +2285,7 @@ fn clean(&self, cx: &DocContext) -> PathParameters {
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
 pub struct PathSegment {
     pub name: String,
-    pub params: PathParameters
+    pub params: PathParameters,
 }
 
 impl Clean<PathSegment> for hir::PathSegment {
index ffef42bc3d27ce1fe398c0d5dee6386c427a79d5..0f47265a1aa6630e3620a8da230aff5141b91e87 100644 (file)
@@ -470,10 +470,22 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
 /// 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, "<a class=\"mod\"
-                                           href=\"{}index.html\">{}</a>::",
-                                     root,
-                                     seg.name)?;
+                            write!(w, "<a class=\"mod\" href=\"{}index.html\">{}</a>::",
+                                   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 `<A as B>::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, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
+                    if should_show_cast {
+                        write!(f, "&lt;{} as {}&gt;::", 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 `<A as B>::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)
                 }
             }
         }
index c89ec5bbe15bd36a0b14a8fcfc13139c69c2937f..4252f2981ed6193e1ba5d59166c7c7eea0b037ab 100644 (file)
@@ -373,6 +373,7 @@ pub fn visit_item(&mut self, item: &hir::Item,
             }
             // 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 {
index 852c98eb2fd52fcfb37e4cab0131f3aa415b6338..40a6ffe9505fd1f834d2fce524e9171cdef07110 100644 (file)
@@ -13,6 +13,7 @@
 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<DefId>>,
     // Previous accessibility level, None means unreachable
     prev_level: Option<AccessLevel>,
+    // Keeps track of already visited modules, in case a module re-exports its parent
+    visited_mods: FxHashSet<DefId>,
 }
 
 impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
@@ -38,6 +41,7 @@ pub fn new(cx: &'a ::core::DocContext<'b, 'tcx>) -> LibEmbargoVisitor<'a, 'b, 't
             cstore: &*cx.sess().cstore,
             access_levels: cx.access_levels.borrow_mut(),
             prev_level: Some(AccessLevel::Public),
+            visited_mods: FxHashSet()
         }
     }
 
@@ -62,6 +66,10 @@ fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLev
     }
 
     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);
         }
index c6a3e8a2dedc4653985b20276673a99c3fa658b9..131adfe47afdac6646dbd31819235deb53b20e02 100644 (file)
@@ -1585,6 +1585,15 @@ pub struct ForeignMod {
     pub items: Vec<ForeignItem>,
 }
 
+/// 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<Variant>,
@@ -1812,6 +1821,8 @@ pub enum ItemKind {
     ///
     /// E.g. `extern {}` or `extern "C" {}`
     ForeignMod(ForeignMod),
+    /// Module-level inline assembly (from `global_asm!()`)
+    GlobalAsm(P<GlobalAsm>),
     /// A type alias (`type` or `pub type`).
     ///
     /// E.g. `type Foo = Bar<u8>;`
@@ -1864,6 +1875,7 @@ pub fn descriptive_variant(&self) -> &str {
             ItemKind::Fn(..) => "function",
             ItemKind::Mod(..) => "module",
             ItemKind::ForeignMod(..) => "foreign module",
+            ItemKind::GlobalAsm(..) => "global asm",
             ItemKind::Ty(..) => "type alias",
             ItemKind::Enum(..) => "enum",
             ItemKind::Struct(..) => "struct",
index 1b3352f73ade794e9ee9da45730a72f5df9475b8..48bfc050223ab82ab60fe6581280c16fe70410a0 100644 (file)
@@ -1039,6 +1039,7 @@ pub fn default(crate_name: String) -> ExpansionConfig<'static> {
     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,
index 08762ccf04bde8d0dbaaf6a638402384cbe10262..8b62416dcbdbd6e541f68b055ac8f8933dfc3a95 100644 (file)
@@ -346,6 +346,9 @@ pub fn new() -> 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 fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: Ga
 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 =
+    "`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";
 
index 92e25b00e0ac108cfd41d90b06e1773f45b21d38..a6ab8e10d9f91aef1cff7fe1944be51965869e5c 100644 (file)
@@ -140,6 +140,10 @@ fn fold_foreign_mod(&mut self, nm: ForeignMod) -> ForeignMod {
         noop_fold_foreign_mod(nm, self)
     }
 
+    fn fold_global_asm(&mut self, ga: P<GlobalAsm>) -> P<GlobalAsm> {
+        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<T: Folder>(ForeignMod {abi, items}: ForeignMod,
     }
 }
 
+pub fn noop_fold_global_asm<T: Folder>(ga: P<GlobalAsm>,
+                                       _: &mut T) -> P<GlobalAsm> {
+    ga
+}
+
 pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant {
     Spanned {
         node: Variant_ {
@@ -867,6 +876,7 @@ pub fn noop_fold_item_kind<T: Folder>(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))
         }
index e7feff2b79fceb9936a665f90923ee0f9fa490b1..433ba3d3693f1a396565ec486d2b2d4e53a5d1e5 100644 (file)
@@ -1267,6 +1267,11 @@ pub fn print_item(&mut self, item: &ast::Item) -> io::Result<()> {
                 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)?;
index b5e9a1892acc9927446c1cfffcd394cbbcd93094..bae1c56db007c66d137cca850179820e91b77eaa 100644 (file)
@@ -58,6 +58,7 @@ fn visit_ident(&mut self, span: Span, ident: Ident) {
     }
     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 (file)
index 0000000..dc67e1c
--- /dev/null
@@ -0,0 +1,65 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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::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<base::MacResult + 'cx> {
+    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,
+    })))
+}
index 1e9b112b6df564263738be5f058d2e4c1a54bed6..e35e79df5852066cea8c85a228e3c89b9a40aa65 100644 (file)
@@ -38,6 +38,7 @@
 mod env;
 mod format;
 mod format_foreign;
+mod global_asm;
 mod log_syntax;
 mod trace_macros;
 
@@ -99,6 +100,7 @@ macro_rules! register {
         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,
index 5ab786f40b9335aca5b7a36d5e0af99c8869e995..c24867224ea864cd94733550001037fe7dee83fa 100644 (file)
@@ -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;
diff --git a/src/test/codegen/foo.s b/src/test/codegen/foo.s
new file mode 100644 (file)
index 0000000..304d82a
--- /dev/null
@@ -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 (file)
index 0000000..5bd0c1b
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 (file)
index 0000000..401b1fa
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 (file)
index 0000000..8b59165
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 (file)
index 0000000..0560abb
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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/compile-fail/union/union-borrow-move-parent-sibling.rs b/src/test/compile-fail/union/union-borrow-move-parent-sibling.rs
new file mode 100644 (file)
index 0000000..5f504fe
--- /dev/null
@@ -0,0 +1,57 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(untagged_unions)]
+#![allow(unused)]
+
+#[allow(unions_with_drop_fields)]
+union U {
+    x: ((Vec<u8>, Vec<u8>), Vec<u8>),
+    y: Box<Vec<u8>>,
+}
+
+unsafe fn parent_sibling_borrow() {
+    let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = &mut u.x.0;
+    let a = &u.y; //~ ERROR cannot borrow `u.y`
+}
+
+unsafe fn parent_sibling_move() {
+    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = u.x.0;
+    let a = u.y; //~ ERROR use of moved value: `u.y`
+}
+
+unsafe fn grandparent_sibling_borrow() {
+    let mut u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = &mut (u.x.0).0;
+    let a = &u.y; //~ ERROR cannot borrow `u.y`
+}
+
+unsafe fn grandparent_sibling_move() {
+    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = (u.x.0).0;
+    let a = u.y; //~ ERROR use of moved value: `u.y`
+}
+
+unsafe fn deref_sibling_borrow() {
+    let mut u = U { y: Box::default() };
+    let a = &mut *u.y;
+    let a = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
+}
+
+unsafe fn deref_sibling_move() {
+    let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+    let a = *u.y;
+    let a = u.x; //~ ERROR use of moved value: `u.x`
+}
+
+
+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 (file)
index 0000000..db73da2
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 (file)
index 0000000..cd8273c
--- /dev/null
@@ -0,0 +1,31 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// 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
+    .global _foo
+foo:
+_foo:
+    ret
+"#);
+
+extern {
+    fn foo();
+}
+
+#[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() {}
diff --git a/src/test/rustdoc/assoc-item-cast.rs b/src/test/rustdoc/assoc-item-cast.rs
new file mode 100644 (file)
index 0000000..24f31b5
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> {
+    type Expression: Expression<SqlType = T>;
+    fn as_expression(self) -> Self::Expression;
+}
+
+// @has foo/type.AsExprOf.html
+// @has - '//*[@class="rust typedef"]' 'type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;'
+pub type AsExprOf<Item, Type> = <Item as AsExpression<Type>>::Expression;
diff --git a/src/test/rustdoc/auxiliary/issue-40936.rs b/src/test/rustdoc/auxiliary/issue-40936.rs
new file mode 100644 (file)
index 0000000..54cc18c
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 (file)
index 0000000..3e02eec
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;