- [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)
[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).
--- /dev/null
+# `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.
// Macro namespace
Macro(DefId, MacroKind),
+ GlobalAsm(DefId),
+
// Both namespaces
Err,
}
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
}
Def::Label(..) => "label",
Def::SelfTy(..) => "self type",
Def::Macro(..) => "macro",
+ Def::GlobalAsm(..) => "global asm",
Def::Err => "unresolved 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);
}
}
+ 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_ {
}
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))
}
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(..) => {}
ItemFn(..) => "fn",
ItemMod(..) => "mod",
ItemForeignMod(..) => "foreign mod",
+ ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "ty",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
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>,
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>}`
ItemFn(..) => "function",
ItemMod(..) => "module",
ItemForeignMod(..) => "foreign module",
+ ItemGlobalAsm(..) => "global asm",
ItemTy(..) => "type alias",
ItemEnum(..) => "enum",
ItemStruct(..) => "struct",
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)?;
hir::ItemFn(..) |
hir::ItemMod(..) |
hir::ItemForeignMod(..) |
+ hir::ItemGlobalAsm(..) |
hir::ItemTy(..) |
hir::ItemEnum(..) |
hir::ItemStruct(..) |
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),
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>,
Upvar(def_id, index, expr_id),
Label(node_id),
Macro(def_id, macro_kind),
+ GlobalAsm(def_id),
Err
});
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) => {
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);
}
/// 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>,
hir::ItemStatic(..) |
hir::ItemFn(..) |
hir::ItemForeignMod(..) |
+ hir::ItemGlobalAsm(..) |
hir::ItemTy(..) => None,
hir::ItemEnum(..) |
/// 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;
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(_) |
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, _) => {
hir::ItemFn(..) |
hir::ItemMod(..) |
hir::ItemForeignMod(..) |
+ hir::ItemGlobalAsm(..) |
hir::ItemExternCrate(..) |
hir::ItemUse(..) |
hir::ItemDefaultImpl(..) |
ForeignImmStatic,
ForeignMutStatic,
ForeignMod,
+ GlobalAsm,
Type,
Enum(ReprOptions),
Field,
EntryKind::ForeignImmStatic |
EntryKind::ForeignMutStatic |
EntryKind::ForeignMod |
+ EntryKind::GlobalAsm |
EntryKind::Field |
EntryKind::Type => {
// Nothing else to hash here.
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 }
}
};
}
}
}
- _ => {}
+ 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
hir::ItemUse(..) => {}
// The interface is empty
hir::ItemDefaultImpl(..) => {}
+ // The interface is empty
+ hir::ItemGlobalAsm(..) => {}
// Visit everything
hir::ItemConst(..) | hir::ItemStatic(..) |
hir::ItemFn(..) | hir::ItemTy(..) => {
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(..) => {
self.define(parent, ident, TypeNS, imported_binding);
}
+ ItemKind::GlobalAsm(..) => {}
+
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
ItemKind::Mod(..) => {
}
}
- ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => {
+ ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> {
// do nothing, these are just around to be encoded
}
Def::AssociatedTy(..) |
Def::AssociatedConst(..) |
Def::PrimTy(_) |
+ Def::GlobalAsm(_) |
Def::Err => {
span_bug!(span,
"process_def_kind for unexpected item: {:?}",
Def::SelfTy(..) |
Def::Label(..) |
Def::Macro(..) |
+ Def::GlobalAsm(..) |
Def::Err => None,
}
}
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());
+ }
+}
collect_neighbours(scx, instance, &mut neighbors);
}
+ TransItem::GlobalAsm(..) => {
+ recursion_depth_reset = None;
+ }
}
record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map);
}
}
}
+ 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(),
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);
}
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)
+ }
}
}
}
None => {
match trans_item {
TransItem::Fn(..) |
- TransItem::Static(..) => llvm::ExternalLinkage,
+ TransItem::Static(..) |
+ TransItem::GlobalAsm(..) => llvm::ExternalLinkage,
}
}
};
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)),
}
}
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)
})
//! 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;
#[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.
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())); // (*)
TransItem::Fn(instance) => {
TransItem::predefine_fn(ccx, instance, linkage, &symbol_name);
}
+ TransItem::GlobalAsm(..) => {}
}
debug!("END PREDEFINING '{} ({})' in cgu {}",
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)
+ }
}
}
}
}
TransItem::Static(..) => InstantiationMode::GloballyShared,
+ TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared,
}
}
TransItem::Fn(ref instance) => {
instance.substs.types().next().is_some()
}
- TransItem::Static(..) => false,
+ TransItem::Static(..) |
+ TransItem::GlobalAsm(..) => false,
}
}
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);
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>,
TransItem::Static(id) => {
format!("Static({:?})", id)
}
+ TransItem::GlobalAsm(id) => {
+ format!("GlobalAsm({:?})", id)
+ }
}
}
}
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);
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);
- },
+ }
}
}
ItemTrait(..) |
ItemMod(..) |
ItemForeignMod(..) |
+ ItemGlobalAsm(..) |
ItemExternCrate(..) |
ItemUse(..) => {
span_bug!(
hir::ItemFn(..) |
hir::ItemMod(..) |
hir::ItemForeignMod(..) |
+ hir::ItemGlobalAsm(..) |
hir::ItemTy(..) |
hir::ItemImpl(..) |
hir::ItemDefaultImpl(..) => {}
hir::ItemFn(..) |
hir::ItemMod(..) |
hir::ItemForeignMod(..) |
+ hir::ItemGlobalAsm(..) |
hir::ItemTy(..) => {}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub struct PathSegment {
pub name: String,
- pub params: PathParameters
+ pub params: PathParameters,
}
impl Clean<PathSegment> for hir::PathSegment {
/// 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 {
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)?;
}
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 {
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 {
}
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, "<{} 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 `<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)
}
}
}
}
// 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 {
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;
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> {
cstore: &*cx.sess().cstore,
access_levels: cx.access_levels.borrow_mut(),
prev_level: Some(AccessLevel::Public),
+ visited_mods: FxHashSet()
}
}
}
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);
}
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>,
///
/// 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>;`
ItemKind::Fn(..) => "function",
ItemKind::Mod(..) => "module",
ItemKind::ForeignMod(..) => "foreign module",
+ ItemKind::GlobalAsm(..) => "global asm",
ItemKind::Ty(..) => "type alias",
ItemKind::Enum(..) => "enum",
ItemKind::Struct(..) => "struct",
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,
// 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! (
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";
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)
}
}
}
+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_ {
}
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))
}
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)?;
}
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) }
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)
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) => {
--- /dev/null
+// 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,
+ })))
+}
mod env;
mod format;
mod format_foreign;
+mod global_asm;
mod log_syntax;
mod trace_macros;
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,
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;
--- /dev/null
+.global foo
+foo:
+ jmp baz
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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;
--- /dev/null
+// 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::*;
+ }
+}
--- /dev/null
+// 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;