diff --git a/.gitmodules b/.gitmodules index 53d1787492409..3533f0df5d1ce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,4 +25,4 @@ url = https://github.com/rust-lang-nursery/reference.git [submodule "book"] path = src/doc/book - url = https://github.com/rust-lang/book + url = https://github.com/rust-lang/book.git diff --git a/appveyor.yml b/appveyor.yml index 83cfea0dd834e..9070c5d9edf1e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -141,15 +141,18 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' + - if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc + - sh src/ci/init_repo.sh . /c/cache/rustsrc - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh on_failure: - - cat %CD%/sccache.log + - cat %CD%\sccache.log + - cat C:\Users\appveyor\AppData\Local\Temp\1\build-cache-logs\*.log cache: + - C:\cache\rustsrc - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index ec992b47a6e4b..6472b1a928caf 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -433,29 +433,32 @@ pub fn rust_src(build: &Build) { copy(&build.src.join(item), &dst_src.join(item)); } - // Get cargo-vendor installed, if it isn't already. - let mut has_cargo_vendor = false; - let mut cmd = Command::new(&build.cargo); - for line in output(cmd.arg("install").arg("--list")).lines() { - has_cargo_vendor |= line.starts_with("cargo-vendor "); - } - if !has_cargo_vendor { + // If we're building from git sources, we need to vendor a complete distribution. + if build.src_is_git { + // Get cargo-vendor installed, if it isn't already. + let mut has_cargo_vendor = false; + let mut cmd = Command::new(&build.cargo); + for line in output(cmd.arg("install").arg("--list")).lines() { + has_cargo_vendor |= line.starts_with("cargo-vendor "); + } + if !has_cargo_vendor { + let mut cmd = Command::new(&build.cargo); + cmd.arg("install") + .arg("--force") + .arg("--debug") + .arg("--vers").arg(CARGO_VENDOR_VERSION) + .arg("cargo-vendor") + .env("RUSTC", &build.rustc); + build.run(&mut cmd); + } + + // Vendor all Cargo dependencies let mut cmd = Command::new(&build.cargo); - cmd.arg("install") - .arg("--force") - .arg("--debug") - .arg("--vers").arg(CARGO_VENDOR_VERSION) - .arg("cargo-vendor") - .env("RUSTC", &build.rustc); + cmd.arg("vendor") + .current_dir(&dst_src.join("src")); build.run(&mut cmd); } - // Vendor all Cargo dependencies - let mut cmd = Command::new(&build.cargo); - cmd.arg("vendor") - .current_dir(&dst_src.join("src")); - build.run(&mut cmd); - // Create source tarball in rust-installer format let mut cmd = Command::new(SH_CMD); cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84254d7d6ae51..8303a40bb6965 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -162,6 +162,7 @@ pub struct Build { cxx: HashMap, crates: HashMap, is_sudo: bool, + src_is_git: bool, } #[derive(Debug)] @@ -233,6 +234,7 @@ impl Build { }; let rust_info = channel::GitInfo::new(&src); let cargo_info = channel::GitInfo::new(&src.join("cargo")); + let src_is_git = src.join(".git").exists(); Build { flags: flags, @@ -251,6 +253,7 @@ impl Build { lldb_version: None, lldb_python_dir: None, is_sudo: is_sudo, + src_is_git: src_is_git, } } @@ -307,10 +310,7 @@ impl Build { OutOfSync, } - if !self.config.submodules { - return - } - if fs::metadata(self.src.join(".git")).is_err() { + if !self.src_is_git || !self.config.submodules { return } let git = || { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 235ce9360eff4..d1b235f4691dc 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -65,7 +65,7 @@ pub fn check(build: &mut Build) { // If we've got a git directory we're gona need git to update // submodules and learn about various other aspects. - if fs::metadata(build.src.join(".git")).is_ok() { + if build.src_is_git { need_cmd("git".as_ref()); } diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 52f74ba90de6e..6f3a7e091e1ed 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -152,18 +152,13 @@ For targets: `powerpc-unknown-linux-gnu` - Path and misc options > Patches origin = Bundled, then local - Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = powerpc -- Target options > Emit assembly for CPU = power4 -- (+) -- Target options > Tune for CPU = power6 -- (+) +- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC - Operating System > Target OS = linux - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc - C compiler > gcc version = 4.9.3 -- C compiler > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) -- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) - C compiler > C++ = ENABLE -- to cross compile LLVM -(+) These CPU options match the configuration of the toolchains in RHEL6. - ## `powerpc64-linux-gnu.config` For targets: `powerpc64-unknown-linux-gnu` diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh index a50a25c791348..ad285a57a84a3 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh +++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh @@ -15,11 +15,14 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL -CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686 -make -j10 +CC=gcc \ + CFLAGS="$CFLAGS -m32" \ + ./configure --prefix=/musl-i686 --disable-shared \ + --target=i686 +make AR=ar RANLIB=ranlib -j10 make install cd .. diff --git a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config index 26e2de863a0f9..984a0a0304e47 100644 --- a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -101,8 +101,8 @@ CT_ARCH_SUPPORTS_WITH_FLOAT=y CT_ARCH_DEFAULT_BE=y CT_ARCH_DEFAULT_32=y CT_ARCH_ABI="" -CT_ARCH_CPU="power4" -CT_ARCH_TUNE="power6" +CT_ARCH_CPU="powerpc" +CT_ARCH_TUNE="" CT_ARCH_BE=y # CT_ARCH_LE is not set CT_ARCH_32=y @@ -391,8 +391,8 @@ CT_CC_GCC_HAS_LIBSANITIZER=y CT_CC_GCC_VERSION="4.9.3" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" -CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" -CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="" CT_CC_GCC_EXTRA_ENV_ARRAY="" CT_CC_GCC_STATIC_LIBSTDCXX=y # CT_CC_GCC_SYSTEM_ZLIB is not set diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh index 86bb259c8549a..776da0093974c 100644 --- a/src/ci/docker/dist-x86_64-musl/build-musl.sh +++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh @@ -15,7 +15,7 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL ./configure --prefix=/musl-x86_64 --disable-shared diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 4e22907d9794c..c235681cddd0c 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -38,9 +38,20 @@ fi # Wipe the cache if it's not valid, or mark it as invalid while we update it if [ ! -f "$cache_valid_file" ]; then - rm -rf "$CACHE_DIR" && mkdir "$CACHE_DIR" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" else - rm "$cache_valid_file" + stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) + stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1 && echo $?) + if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then + # Something is badly wrong - the cache valid file is here, but something + # about the git repo is fishy. Nuke it all, just in case + echo "WARNING: $cache_valid_file exists but bad repo: l:$stat_lines, ec:$stat_ec" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" + else + rm "$cache_valid_file" + fi fi # Update the cache (a pristine copy of the rust source master) diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 9ce097e78a4e5..0d68f3ca4a843 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -81,6 +81,7 @@ - [future_atomic_orderings](future-atomic-orderings.md) - [generic_param_attrs](generic-param-attrs.md) - [get_type_id](get-type-id.md) +- [global_asm](global_asm.md) - [heap_api](heap-api.md) - [i128](i128.md) - [i128_type](i128-type.md) diff --git a/src/doc/unstable-book/src/asm.md b/src/doc/unstable-book/src/asm.md index 032d9d8124026..5e68be633e7ab 100644 --- a/src/doc/unstable-book/src/asm.md +++ b/src/doc/unstable-book/src/asm.md @@ -189,3 +189,5 @@ constraints, etc. [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions +If you need more power and don't mind losing some of the niceties of +`asm!`, check out [global_asm](global_asm.html). diff --git a/src/doc/unstable-book/src/global_asm.md b/src/doc/unstable-book/src/global_asm.md new file mode 100644 index 0000000000000..44921aa309f84 --- /dev/null +++ b/src/doc/unstable-book/src/global_asm.md @@ -0,0 +1,78 @@ +# `global_asm` + +The tracking issue for this feature is: [#35119] + +[#35119]: https://github.com/rust-lang/rust/issues/35119 + +------------------------ + +The `global_asm!` macro allows the programmer to write arbitrary +assembly outside the scope of a function body, passing it through +`rustc` and `llvm` to the assembler. The macro is a no-frills +interface to LLVM's concept of [module-level inline assembly]. That is, +all caveats applicable to LLVM's module-level inline assembly apply +to `global_asm!`. + +[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly + +`global_asm!` fills a role not currently satisfied by either `asm!` +or `#[naked]` functions. The programmer has _all_ features of the +assembler at their disposal. The linker will expect to resolve any +symbols defined in the inline assembly, modulo any symbols marked as +external. It also means syntax for directives and assembly follow the +conventions of the assembler in your toolchain. + +A simple usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# you also need relevant target_arch cfgs +global_asm!(include_str!("something_neato.s")); +``` + +And a more complicated usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + +pub mod sally { + global_asm!(r#" + .global foo + foo: + jmp baz + "#); + + #[no_mangle] + pub unsafe extern "C" fn baz() {} +} + +// the symbols `foo` and `bar` are global, no matter where +// `global_asm!` was used. +extern "C" { + fn foo(); + fn bar(); +} + +pub mod harry { + global_asm!(r#" + .global bar + bar: + jmp quux + "#); + + #[no_mangle] + pub unsafe extern "C" fn quux() {} +} +``` + +You may use `global_asm!` multiple times, anywhere in your crate, in +whatever way suits you. The effect is as if you concatenated all +usages and placed the larger, single usage in the crate root. + +------------------------ + +If you don't need quite as much power and flexibility as +`global_asm!` provides, and you don't mind restricting your inline +assembly to `fn` bodies only, you might try the [asm](asm.html) +feature instead. diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index c258ac2bdea9b..35ecf411db4e0 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1346,7 +1346,7 @@ impl Vec { /// # Examples /// /// ``` - ///# #![feature(vec_remove_item)] + /// # #![feature(vec_remove_item)] /// let mut vec = vec![1, 2, 3, 1]; /// /// vec.remove_item(&1); diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 4e5ddfb541e89..2e1058bfc3413 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -153,8 +153,9 @@ unsafe impl Sync for AtomicPtr {} /// Rust's memory orderings are [the same as /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). /// -/// For more information see the [nomicon][1]. -/// [1]: ../../../nomicon/atomics.html +/// For more information see the [nomicon]. +/// +/// [nomicon]: ../../../nomicon/atomics.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug)] pub enum Ordering { diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 7bab4a8d725dc..771031db0c045 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -57,6 +57,8 @@ pub enum Def { // Macro namespace Macro(DefId, MacroKind), + GlobalAsm(DefId), + // Both namespaces Err, } @@ -144,7 +146,8 @@ impl Def { Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | - Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => { + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) | + Def::GlobalAsm(id) => { id } @@ -185,6 +188,7 @@ impl Def { Def::Label(..) => "label", Def::SelfTy(..) => "self type", Def::Macro(..) => "macro", + Def::GlobalAsm(..) => "global asm", Def::Err => "unresolved item", } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index c7ad143c94979..01f600bb1888f 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 17185a6ab69f4..7e1b0d6389d2e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -645,6 +645,13 @@ impl<'a> LoweringContext<'a> { } } + fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P { + P(hir::GlobalAsm { + asm: ga.asm, + ctxt: ga.ctxt, + }) + } + fn lower_variant(&mut self, v: &Variant) -> hir::Variant { Spanned { node: hir::Variant_ { @@ -1287,6 +1294,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), + ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)), ItemKind::Ty(ref t, ref generics) => { hir::ItemTy(self.lower_ty(t), self.lower_generics(generics)) } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index afdb9059ea7c0..9887f4560f312 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -120,6 +120,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { DefPathData::ValueNs(i.ident.name.as_str()), ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), + ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(ref view_path) => { match view_path.node { ViewPathGlob(..) => {} diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index d7aa36b24f942..2287b525df75f 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1056,6 +1056,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemFn(..) => "fn", ItemMod(..) => "mod", ItemForeignMod(..) => "foreign mod", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "ty", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index d5000ac9c1866..4d38b0eae1d5f 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1493,6 +1493,12 @@ pub struct ForeignMod { pub items: HirVec, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct GlobalAsm { + pub asm: Symbol, + pub ctxt: SyntaxContext +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: HirVec, @@ -1684,6 +1690,8 @@ pub enum Item_ { ItemMod(Mod), /// An external module ItemForeignMod(ForeignMod), + /// Module-level inline assembly (from global_asm!) + ItemGlobalAsm(P), /// A type alias, e.g. `type Foo = Bar` ItemTy(P, Generics), /// An enum definition, e.g. `enum Foo {C, D}` @@ -1718,6 +1726,7 @@ impl Item_ { ItemFn(..) => "function", ItemMod(..) => "module", ItemForeignMod(..) => "foreign module", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "type alias", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 04a65fd5e3aa4..48efe1ad58f34 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -630,6 +630,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + hir::ItemGlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global asm"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()? + } hir::ItemTy(ref ty, ref params) => { self.ibox(indent_unit)?; self.ibox(0)?; diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3b52e85e08e32..7d3c17a048917 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -202,11 +202,14 @@ pub enum ImmutabilityBlame<'tcx> { } impl<'tcx> cmt_<'tcx> { - fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef) + fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> { - let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| { - bug!("interior cmt {:?} is not an ADT", self) - }); + let adt_def = match self.ty.sty { + ty::TyAdt(def, _) => def, + ty::TyTuple(..) => return None, + // closures get `Categorization::Upvar` rather than `Categorization::Interior` + _ => bug!("interior cmt {:?} is not an ADT", self) + }; let variant_def = match self.cat { Categorization::Downcast(_, variant_did) => { adt_def.variant_with_id(variant_did) @@ -220,7 +223,7 @@ impl<'tcx> cmt_<'tcx> { NamedField(name) => variant_def.field_named(name), PositionalField(idx) => &variant_def.fields[idx] }; - (adt_def, field_def) + Some((adt_def, field_def)) } pub fn immutability_blame(&self) -> Option> { @@ -232,8 +235,9 @@ impl<'tcx> cmt_<'tcx> { Categorization::Local(node_id) => Some(ImmutabilityBlame::LocalDeref(node_id)), Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { - let (adt_def, field_def) = base_cmt.resolve_field(field_name); - Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)) + base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| { + ImmutabilityBlame::AdtFieldDeref(adt_def, field_def) + }) } Categorization::Upvar(Upvar { id, .. }) => { if let NoteClosureEnv(..) = self.note { diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index b0e39442af98c..63455f94cedff 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,11 +15,11 @@ // makes all other generics or inline functions that it references // reachable as well. -use dep_graph::DepNode; use hir::map as hir_map; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, CrateNum}; use ty::{self, TyCtxt}; +use ty::maps::Providers; use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; @@ -267,7 +267,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {} + hir::ItemUnion(..) | hir::ItemDefaultImpl(..) | + hir::ItemGlobalAsm(..) => {} } } hir_map::NodeTraitItem(trait_method) => { @@ -362,7 +363,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { - let _task = tcx.dep_graph.in_task(DepNode::Reachability); + ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE) +} + +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet { + debug_assert!(crate_num == LOCAL_CRATE); let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE); @@ -408,3 +413,10 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet { // Return the set of reachable symbols. reachable_context.reachable_symbols } + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + reachable_set, + ..*providers + }; +} diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8037570d24a80..b9938a04047c9 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -314,7 +314,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemUse(..) | hir::ItemMod(..) | hir::ItemDefaultImpl(..) | - hir::ItemForeignMod(..) => { + hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 4a183191cef29..823bdc9e092ac 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -15,6 +15,7 @@ use middle::privacy::AccessLevels; use mir; use session::CompileResult; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use util::nodemap::NodeSet; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; @@ -209,6 +210,11 @@ impl<'tcx> QueryDescription for queries::typeck_item_bodies<'tcx> { } } +impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("reachability") + } +} macro_rules! define_maps { (<$tcx:tt> @@ -440,6 +446,8 @@ define_maps! { <'tcx> /// Performs the privacy check and computes "access levels". pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, + pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet, + pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> } @@ -451,6 +459,10 @@ fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { DepNode::Coherence } +fn reachability_dep_node(_: CrateNum) -> DepNode { + DepNode::Reachability +} + fn mir_shim(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 96eb5dd602f51..0fb386341a9f3 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -889,6 +889,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, rustc_privacy::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); + reachable::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index af2416f787ea4..44e291a44c777 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -233,6 +233,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => None, hir::ItemEnum(..) | diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 5401b371888e9..182fabed5cda3 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -354,6 +354,7 @@ enum SawItemComponent { SawItemFn(Unsafety, Constness, Abi), SawItemMod, SawItemForeignMod(Abi), + SawItemGlobalAsm, SawItemTy, SawItemEnum, SawItemStruct, @@ -372,6 +373,7 @@ fn saw_item(node: &Item_) -> SawItemComponent { ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi), ItemMod(..) => SawItemMod, ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi), + ItemGlobalAsm(..) => SawItemGlobalAsm, ItemTy(..) => SawItemTy, ItemEnum(..) => SawItemEnum, ItemStruct(..) => SawItemStruct, @@ -920,7 +922,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | - Def::Macro(..) => { + Def::Macro(..) | + Def::GlobalAsm(..) => { DefHash::SawDefId.hash(self.st); self.hash_def_id(def.def_id()); } diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 32c9183ece999..402166cc13fd9 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -507,6 +507,7 @@ extern "C" { /// See Module::setModuleInlineAsm. pub fn LLVMSetModuleInlineAsm(M: ModuleRef, Asm: *const c_char); + pub fn LLVMRustAppendModuleInlineAsm(M: ModuleRef, Asm: *const c_char); /// See llvm::LLVMTypeKind::getTypeID. pub fn LLVMRustGetTypeKind(Ty: TypeRef) -> TypeKind; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 43e076e799b3d..b893cccf8978b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -429,6 +429,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Trait(_) => Def::Trait(did), EntryKind::Enum(..) => Def::Enum(did), EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang), + EntryKind::GlobalAsm => Def::GlobalAsm(did), EntryKind::ForeignMod | EntryKind::Impl(_) | diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 38d774992a551..6b4c13439f72f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -655,6 +655,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis))); } hir::ItemForeignMod(_) => EntryKind::ForeignMod, + hir::ItemGlobalAsm(..) => EntryKind::GlobalAsm, hir::ItemTy(..) => EntryKind::Type, hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)), hir::ItemStruct(ref struct_def, _) => { @@ -895,6 +896,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemDefaultImpl(..) | diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index abb482a50ebc2..bd50c1a3c97d3 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -227,6 +227,7 @@ pub enum EntryKind<'tcx> { ForeignImmStatic, ForeignMutStatic, ForeignMod, + GlobalAsm, Type, Enum(ReprOptions), Field, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 300848fe8f25e..92f7e48b6be48 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -160,7 +160,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { self.prev_level } // Other `pub` items inherit levels from parents - _ => { + hir::ItemConst(..) | hir::ItemEnum(..) | hir::ItemExternCrate(..) | + hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) | + hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemTrait(..) | + hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => { if item.vis == hir::Public { self.prev_level } else { None } } }; @@ -212,7 +215,9 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { } } } - _ => {} + hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) | + hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemDefaultImpl(..) => {} } // Mark all items in interfaces of reachable items as reachable @@ -225,6 +230,8 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { hir::ItemUse(..) => {} // The interface is empty hir::ItemDefaultImpl(..) => {} + // The interface is empty + hir::ItemGlobalAsm(..) => {} // Visit everything hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { @@ -1092,6 +1099,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> hir::ItemMod(..) => {} // Checked in resolve hir::ItemUse(..) => {} + // No subitems + hir::ItemGlobalAsm(..) => {} // Subitems of these items have inherited publicity hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemTy(..) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index a15431afc164b..80f853778c744 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -268,6 +268,8 @@ impl<'a> Resolver<'a> { self.define(parent, ident, TypeNS, imported_binding); } + ItemKind::GlobalAsm(..) => {} + ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root ItemKind::Mod(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0466e76475da3..5cbced9738f70 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1707,7 +1707,7 @@ impl<'a> Resolver<'a> { } } - ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) => { + ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_)=> { // do nothing, these are just around to be encoded } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 3fd0ce45e3610..3e8f7e11b6b43 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -341,6 +341,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::AssociatedTy(..) | Def::AssociatedConst(..) | Def::PrimTy(_) | + Def::GlobalAsm(_) | Def::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 44615071a56a7..d822f7bea3a30 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -701,6 +701,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Def::SelfTy(..) | Def::Label(..) | Def::Macro(..) | + Def::GlobalAsm(..) | Def::Err => None, } } diff --git a/src/librustc_trans/asm.rs b/src/librustc_trans/asm.rs index 3e270b7928ebc..92cbd004206e7 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_trans/asm.rs @@ -124,3 +124,11 @@ pub fn trans_inline_asm<'a, 'tcx>( llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1)); } } + +pub fn trans_global_asm<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ga: &hir::GlobalAsm) { + let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); + unsafe { + llvm::LLVMRustAppendModuleInlineAsm(ccx.llmod(), asm.as_ptr()); + } +} diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 500802a4135d0..ba2b807d5a01c 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -349,6 +349,9 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, collect_neighbours(scx, instance, &mut neighbors); } + TransItem::GlobalAsm(..) => { + recursion_depth_reset = None; + } } record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map); @@ -840,6 +843,12 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { } } } + hir::ItemGlobalAsm(..) => { + debug!("RootCollector: ItemGlobalAsm({})", + def_id_to_string(self.scx.tcx(), + self.scx.tcx().hir.local_def_id(item.id))); + self.output.push(TransItem::GlobalAsm(item.id)); + } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", def_id_to_string(self.scx.tcx(), diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 90ce40cfbcf8f..4973181202eed 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -185,15 +185,16 @@ impl<'tcx> CodegenUnit<'tcx> { symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); let exported = match item { - TransItem::Fn(ref instance) => { - let node_id = - scx.tcx().hir.as_local_node_id(instance.def_id()); + TransItem::Fn(ref instance) => { + let node_id = + scx.tcx().hir.as_local_node_id(instance.def_id()); node_id.map(|node_id| exported_symbols.contains(&node_id)) - .unwrap_or(false) - } - TransItem::Static(node_id) => { + .unwrap_or(false) + } + TransItem::Static(node_id) => { exported_symbols.contains(&node_id) - } + } + TransItem::GlobalAsm(..) => true, }; exported.hash(&mut state); } @@ -243,7 +244,9 @@ impl<'tcx> CodegenUnit<'tcx> { TransItem::Fn(instance) => { tcx.hir.as_local_node_id(instance.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { + Some(node_id) + } } } } @@ -338,7 +341,8 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, None => { match trans_item { TransItem::Fn(..) | - TransItem::Static(..) => llvm::ExternalLinkage, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => llvm::ExternalLinkage, } } }; @@ -483,7 +487,8 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't Some(def_id) } - TransItem::Static(node_id) => Some(tcx.hir.local_def_id(node_id)), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => Some(tcx.hir.local_def_id(node_id)), } } diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs index 1b48e131b720a..36c3981e3a6f2 100644 --- a/src/librustc_trans/symbol_map.rs +++ b/src/librustc_trans/symbol_map.rs @@ -99,7 +99,10 @@ impl<'tcx> SymbolMap<'tcx> { TransItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } - TransItem::Static(node_id) => Some(node_id), + TransItem::Static(node_id) | + TransItem::GlobalAsm(node_id) => { + Some(node_id) + } }.map(|node_id| { tcx.hir.span(node_id) }) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 410e3f30be731..f5556bb8382f6 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -14,6 +14,7 @@ //! item-path. This is used for unit testing the code that generates //! paths etc in all kinds of annoying scenarios. +use asm; use attributes; use base; use consts; @@ -38,7 +39,8 @@ use std::iter; #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] pub enum TransItem<'tcx> { Fn(Instance<'tcx>), - Static(NodeId) + Static(NodeId), + GlobalAsm(NodeId), } /// Describes how a translation item will be instantiated in object files. @@ -89,6 +91,14 @@ impl<'a, 'tcx> TransItem<'tcx> { span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") } } + TransItem::GlobalAsm(node_id) => { + let item = ccx.tcx().hir.expect_item(node_id); + if let hir::ItemGlobalAsm(ref ga) = item.node { + asm::trans_global_asm(ccx, ga); + } else { + span_bug!(item.span, "Mismatch between hir::Item type and TransItem type") + } + } TransItem::Fn(instance) => { let _task = ccx.tcx().dep_graph.in_task( DepNode::TransCrateItem(instance.def_id())); // (*) @@ -123,6 +133,7 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(instance) => { TransItem::predefine_fn(ccx, instance, linkage, &symbol_name); } + TransItem::GlobalAsm(..) => {} } debug!("END PREDEFINING '{} ({})' in cgu {}", @@ -185,6 +196,10 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = scx.tcx().hir.local_def_id(node_id); symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx) } + TransItem::GlobalAsm(node_id) => { + let def_id = scx.tcx().hir.local_def_id(node_id); + format!("global_asm_{:?}", def_id) + } } } @@ -202,6 +217,7 @@ impl<'a, 'tcx> TransItem<'tcx> { } } TransItem::Static(..) => InstantiationMode::GloballyShared, + TransItem::GlobalAsm(..) => InstantiationMode::GloballyShared, } } @@ -210,7 +226,8 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Fn(ref instance) => { instance.substs.types().next().is_some() } - TransItem::Static(..) => false, + TransItem::Static(..) | + TransItem::GlobalAsm(..) => false, } } @@ -218,6 +235,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let def_id = match *self { TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), + TransItem::GlobalAsm(..) => return None, }; let attributes = tcx.get_attrs(def_id); @@ -249,6 +267,9 @@ impl<'a, 'tcx> TransItem<'tcx> { let instance = Instance::new(def_id, tcx.intern_substs(&[])); to_string_internal(tcx, "static ", instance) }, + TransItem::GlobalAsm(..) => { + "global_asm".to_string() + } }; fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -273,6 +294,9 @@ impl<'a, 'tcx> TransItem<'tcx> { TransItem::Static(id) => { format!("Static({:?})", id) } + TransItem::GlobalAsm(id) => { + format!("GlobalAsm({:?})", id) + } } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 1ed42b842c6fa..1b5d1ee945307 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -490,8 +490,10 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { let def_id = tcx.hir.local_def_id(item_id); match it.node { // These don't define types. - hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => { - } + hir::ItemExternCrate(_) | + hir::ItemUse(..) | + hir::ItemMod(_) | + hir::ItemGlobalAsm(_) => {} hir::ItemForeignMod(ref foreign_mod) => { for item in &foreign_mod.items { let def_id = tcx.hir.local_def_id(item.id); @@ -543,12 +545,12 @@ fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId) { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, - _ => { + } + hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => { tcx.item_generics(def_id); tcx.item_type(def_id); tcx.item_predicates(def_id); - }, + } } } @@ -1074,6 +1076,7 @@ fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ItemTrait(..) | ItemMod(..) | ItemForeignMod(..) | + ItemGlobalAsm(..) | ItemExternCrate(..) | ItemUse(..) => { span_bug!( diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index f0f543fa6f23b..1bde1eea37c39 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -113,6 +113,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => {} diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index 36352f50e4406..890414e317c62 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -251,6 +251,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> { hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => {} } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c89ec5bbe15bd..4252f2981ed61 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -373,6 +373,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } // If we're inlining, skip private items. _ if self.inlining && item.vis != hir::Public => {} + hir::ItemGlobalAsm(..) => {} hir::ItemExternCrate(ref p) => { let cstore = &self.cx.sess().cstore; om.extern_crates.push(ExternCrate { diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 1b00eb95de2bc..6b1267d89b6d5 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1176,6 +1176,7 @@ impl AsInner for DirEntry { /// This function currently corresponds to the `unlink` function on Unix /// and the `DeleteFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1212,6 +1213,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// This function currently corresponds to the `stat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1245,6 +1247,7 @@ pub fn metadata>(path: P) -> io::Result { /// This function currently corresponds to the `lstat` function on Unix /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1287,6 +1290,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// on Windows, `from` can be anything, but `to` must *not* be a directory. /// /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1330,6 +1334,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// `O_CLOEXEC` is set for returned file descriptors. /// On Windows, this function currently corresponds to `CopyFileEx`. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1366,6 +1371,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// This function currently corresponds to the `link` function on Unix /// and the `CreateHardLink` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1424,6 +1430,7 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1457,6 +1464,7 @@ pub fn read_link>(path: P) -> io::Result { /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1489,6 +1497,7 @@ pub fn canonicalize>(path: P) -> io::Result { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1522,6 +1531,7 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// This function currently corresponds to the `mkdir` function on Unix /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1562,6 +1572,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// This function currently corresponds to the `rmdir` function on Unix /// and the `RemoveDirectory` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1599,6 +1610,7 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions /// on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1633,6 +1645,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// This function currently corresponds to the `opendir` function on Unix /// and the `FindFirstFile` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors @@ -1679,6 +1692,7 @@ pub fn read_dir>(path: P) -> io::Result { /// This function currently corresponds to the `chmod` function on Unix /// and the `SetFileAttributes` function on Windows. /// Note that, this [may change in the future][changes]. +/// /// [changes]: ../io/index.html#platform-specific-behavior /// /// # Errors diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index f98a3a87b018f..3b82412716e54 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -21,12 +21,12 @@ use memchr; /// The `BufReader` struct adds buffering to any reader. /// /// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`] on [`TcpStream`] results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying [`Read`] -/// and maintains an in-memory buffer of the results. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. /// /// [`Read`]: ../../std/io/trait.Read.html -/// [`read`]: ../../std/net/struct.TcpStream.html#method.read +/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read /// [`TcpStream`]: ../../std/net/struct.TcpStream.html /// /// # Examples @@ -261,9 +261,10 @@ impl Seek for BufReader { /// Wraps a writer and buffers its output. /// /// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`] -/// results in a system call. A `BufWriter` keeps an in-memory buffer of data -/// and writes it to an underlying writer in large, infrequent batches. +/// implements [`Write`]. For example, every call to +/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. /// /// The buffer will be written out when the writer is dropped. /// @@ -303,7 +304,7 @@ impl Seek for BufReader { /// the `stream` is dropped. /// /// [`Write`]: ../../std/io/trait.Write.html -/// [`write`]: ../../std/net/struct.TcpStream.html#method.write +/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write /// [`TcpStream`]: ../../std/net/struct.TcpStream.html #[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 8ebc5c0a8fe2d..cd096c115ba5a 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -21,7 +21,8 @@ //! of other types, and you can implement them for your types too. As such, //! you'll see a few different types of I/O throughout the documentation in //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For -//! example, [`Read`] adds a [`read`] method, which we can use on `File`s: +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! `File`s: //! //! ``` //! use std::io; @@ -106,7 +107,7 @@ //! ``` //! //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call -//! to [`write`]: +//! to [`write`][`Write::write`]: //! //! ``` //! use std::io; @@ -257,13 +258,13 @@ //! [`Vec`]: ../vec/struct.Vec.html //! [`BufReader`]: struct.BufReader.html //! [`BufWriter`]: struct.BufWriter.html -//! [`write`]: trait.Write.html#tymethod.write +//! [`Write::write`]: trait.Write.html#tymethod.write //! [`io::stdout`]: fn.stdout.html //! [`println!`]: ../macro.println.html //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html //! [`?` operator]: ../../book/syntax-index.html -//! [`read`]: trait.Read.html#tymethod.read +//! [`Read::read`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index cf119720e5a17..bc315d54100e4 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -58,7 +58,7 @@ pub struct TcpStream(net_imp::TcpStream); /// /// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens /// for incoming TCP connections. These can be accepted by calling [`accept`] or by -/// iterating over the [`Incoming`] iterator returned by [`incoming`]. +/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`]. /// /// The socket will be closed when the value is dropped. /// @@ -68,7 +68,7 @@ pub struct TcpStream(net_imp::TcpStream); /// [`bind`]: #method.bind /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [`Incoming`]: ../../std/net/struct.Incoming.html -/// [`incoming`]: #method.incoming +/// [`TcpListener::incoming`]: #method.incoming /// /// # Examples /// diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index c71e0b2a7035a..86e661d7948f0 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -56,14 +56,14 @@ //! traits indicate fundamental properties of types. //! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various //! operations for both destructors and overloading `()`. -//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a -//! value. +//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly +//! dropping a value. //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap. //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a //! borrowed type. -//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone`], -//! the method for producing a copy of a value. +//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines +//! [`clone`][`Clone::clone`], the method for producing a copy of a value. //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The //! comparison traits, which implement the comparison operators and are often //! seen in trait bounds. @@ -117,8 +117,8 @@ //! [`ToOwned`]: ../borrow/trait.ToOwned.html //! [`ToString`]: ../string/trait.ToString.html //! [`Vec`]: ../vec/struct.Vec.html -//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone -//! [`drop`]: ../mem/fn.drop.html +//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone +//! [`mem::drop`]: ../mem/fn.drop.html //! [`std::borrow`]: ../borrow/index.html //! [`std::boxed`]: ../boxed/index.html //! [`std::clone`]: ../clone/index.html diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index c63dd8a47ca4f..d6e2fed56be96 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -144,7 +144,7 @@ pub trait OpenOptionsExt { /// `CreateFile`). /// /// If a _new_ file is created because it does not yet exist and - ///`.create(true)` or `.create_new(true)` are specified, the new file is + /// `.create(true)` or `.create_new(true)` are specified, the new file is /// given the attributes declared with `.attributes()`. /// /// If an _existing_ file is opened with `.create(true).truncate(true)`, its diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 1419a4af42738..759f055c4b123 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -104,6 +104,7 @@ pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 18c00e7c5f1b6..7ab6b82ada344 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -90,7 +90,7 @@ //! two ways: //! //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] -//! function, and calling [`thread`] on the [`JoinHandle`]. +//! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. //! * By requesting the current thread, using the [`thread::current`] function. //! //! The [`thread::current`] function is available even for threads not spawned @@ -151,7 +151,7 @@ //! [`Arc`]: ../../std/sync/struct.Arc.html //! [`spawn`]: ../../std/thread/fn.spawn.html //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html -//! [`thread`]: ../../std/thread/struct.JoinHandle.html#method.thread +//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join //! [`Result`]: ../../std/result/enum.Result.html //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9eb86aa006d17..08ea278df0ecb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1583,6 +1583,15 @@ pub struct ForeignMod { pub items: Vec, } +/// Global inline assembly +/// +/// aka module-level assembly or file-scoped assembly +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub struct GlobalAsm { + pub asm: Symbol, + pub ctxt: SyntaxContext, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: Vec, @@ -1810,6 +1819,8 @@ pub enum ItemKind { /// /// E.g. `extern {}` or `extern "C" {}` ForeignMod(ForeignMod), + /// Module-level inline assembly (from `global_asm!()`) + GlobalAsm(P), /// A type alias (`type` or `pub type`). /// /// E.g. `type Foo = Bar;` @@ -1862,6 +1873,7 @@ impl ItemKind { ItemKind::Fn(..) => "function", ItemKind::Mod(..) => "module", ItemKind::ForeignMod(..) => "foreign module", + ItemKind::GlobalAsm(..) => "global asm", ItemKind::Ty(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1b3352f73ade7..48bfc050223ab 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1039,6 +1039,7 @@ impl<'feat> ExpansionConfig<'feat> { feature_tests! { fn enable_quotes = quote, fn enable_asm = asm, + fn enable_global_asm = global_asm, fn enable_log_syntax = log_syntax, fn enable_concat_idents = concat_idents, fn enable_trace_macros = trace_macros, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 412803ddcd5a3..631fe0cc1d89e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -339,6 +339,9 @@ declare_features! ( // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Allows module-level inline assembly by way of global_asm!() + (active, global_asm, "1.17.0", Some(35119)), ); declare_features! ( @@ -971,6 +974,9 @@ pub const EXPLAIN_STMT_ATTR_SYNTAX: &'static str = pub const EXPLAIN_ASM: &'static str = "inline assembly is not stable enough for use and is subject to change"; +pub const EXPLAIN_GLOBAL_ASM: &'static str = + "`global_asm!` is not stable enough for use and is subject to change"; + pub const EXPLAIN_LOG_SYNTAX: &'static str = "`log_syntax!` is not stable enough for use and is subject to change"; diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1a4e196ac5577..06b8e071b7975 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -140,6 +140,10 @@ pub trait Folder : Sized { noop_fold_foreign_mod(nm, self) } + fn fold_global_asm(&mut self, ga: P) -> P { + noop_fold_global_asm(ga, self) + } + fn fold_variant(&mut self, v: Variant) -> Variant { noop_fold_variant(v, self) } @@ -412,6 +416,11 @@ pub fn noop_fold_foreign_mod(ForeignMod {abi, items}: ForeignMod, } } +pub fn noop_fold_global_asm(ga: P, + _: &mut T) -> P { + ga +} + pub fn noop_fold_variant(v: Variant, fld: &mut T) -> Variant { Spanned { node: Variant_ { @@ -867,6 +876,7 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), + ItemKind::GlobalAsm(ga) => ItemKind::GlobalAsm(folder.fold_global_asm(ga)), ItemKind::Ty(t, generics) => { ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics)) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f042a18d61036..3c6254c442e22 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1264,6 +1264,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + ast::ItemKind::GlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global_asm!"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()?; + } ast::ItemKind::Ty(ref ty, ref params) => { self.ibox(INDENT_UNIT)?; self.ibox(0)?; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a5333f3bb6a6e..36ed29f911cd1 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -58,6 +58,7 @@ pub trait Visitor<'ast>: Sized { } fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _n: NodeId) { walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'ast ForeignItem) { walk_foreign_item(self, i) } + fn visit_global_asm(&mut self, ga: &'ast GlobalAsm) { walk_global_asm(self, ga) } fn visit_item(&mut self, i: &'ast Item) { walk_item(self, i) } fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) } fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) } @@ -253,6 +254,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::ForeignMod(ref foreign_module) => { walk_list!(visitor, visit_foreign_item, &foreign_module.items); } + ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga), ItemKind::Ty(ref typ, ref type_parameters) => { visitor.visit_ty(typ); visitor.visit_generics(type_parameters) @@ -464,6 +466,10 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, foreign_item: &'a walk_list!(visitor, visit_attribute, &foreign_item.attrs); } +pub fn walk_global_asm<'a, V: Visitor<'a>>(_: &mut V, _: &'a GlobalAsm) { + // Empty! +} + pub fn walk_ty_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a TyParamBound) { match *bound { TraitTyParamBound(ref typ, ref modifier) => { diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs new file mode 100644 index 0000000000000..dc67e1c45f6e7 --- /dev/null +++ b/src/libsyntax_ext/global_asm.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Module-level assembly support. +/// +/// The macro defined here allows you to specify "top-level", +/// "file-scoped", or "module-level" assembly. These synonyms +/// all correspond to LLVM's module-level inline assembly instruction. +/// +/// For example, `global_asm!("some assembly here")` translates to +/// LLVM's `module asm "some assembly here"`. All of LLVM's caveats +/// therefore apply. + +use syntax::ast; +use syntax::ext::base; +use syntax::ext::base::*; +use syntax::feature_gate; +use syntax::ptr::P; +use syntax::symbol::Symbol; +use syntax_pos::Span; +use syntax::tokenstream; + +use syntax::util::small_vector::SmallVector; + +pub const MACRO: &'static str = "global_asm"; + +pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt, + sp: Span, + tts: &[tokenstream::TokenTree]) -> Box { + if !cx.ecfg.enable_global_asm() { + feature_gate::emit_feature_err(&cx.parse_sess, + MACRO, + sp, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_GLOBAL_ASM); + return DummyResult::any(sp); + } + + let mut p = cx.new_parser_from_tts(tts); + let (asm, _) = match expr_to_string(cx, + panictry!(p.parse_expr()), + "inline assembly must be a string literal") { + Some((s, st)) => (s, st), + None => return DummyResult::any(sp), + }; + + MacEager::items(SmallVector::one(P(ast::Item { + ident: ast::Ident::with_empty_ctxt(Symbol::intern("")), + attrs: Vec::new(), + id: ast::DUMMY_NODE_ID, + node: ast::ItemKind::GlobalAsm(P(ast::GlobalAsm { + asm: asm, + ctxt: cx.backtrace(), + })), + vis: ast::Visibility::Inherited, + span: sp, + }))) +} diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 1e9b112b6df56..e35e79df58520 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -38,6 +38,7 @@ mod concat_idents; mod env; mod format; mod format_foreign; +mod global_asm; mod log_syntax; mod trace_macros; @@ -99,6 +100,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, module_path: expand_mod, asm: asm::expand_asm, + global_asm: global_asm::expand_global_asm, cfg: cfg::expand_cfg, concat: concat::expand_syntax_ext, concat_idents: concat_idents::expand_syntax_ext, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 5ab786f40b933..c24867224ea86 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -312,6 +312,10 @@ extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, HasSideEffects, IsAlignStack, fromRust(Dialect))); } +extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) { + unwrap(M)->appendModuleInlineAsm(StringRef(Asm)); +} + typedef DIBuilder *LLVMRustDIBuilderRef; typedef struct LLVMOpaqueMetadata *LLVMRustMetadataRef; diff --git a/src/test/codegen/foo.s b/src/test/codegen/foo.s new file mode 100644 index 0000000000000..304d82aa0c653 --- /dev/null +++ b/src/test/codegen/foo.s @@ -0,0 +1,3 @@ +.global foo +foo: + jmp baz diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs new file mode 100644 index 0000000000000..5bd0c1b4076ee --- /dev/null +++ b/src/test/codegen/global_asm.rs @@ -0,0 +1,73 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// this regex will capture the correct unconditional branch inst. +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs new file mode 100644 index 0000000000000..401b1fad566d5 --- /dev/null +++ b/src/test/codegen/global_asm_include.rs @@ -0,0 +1,68 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +global_asm!(include_str!("foo.s")); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs new file mode 100644 index 0000000000000..8b59165e9e61b --- /dev/null +++ b/src/test/codegen/global_asm_x2.rs @@ -0,0 +1,90 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-aarch64 +// ignore-aarch64_be +// ignore-arm +// ignore-armeb +// ignore-avr +// ignore-bpfel +// ignore-bpfeb +// ignore-hexagon +// ignore-mips +// ignore-mipsel +// ignore-mips64 +// ignore-mips64el +// ignore-msp430 +// ignore-powerpc64 +// ignore-powerpc64le +// ignore-powerpc +// ignore-r600 +// ignore-amdgcn +// ignore-sparc +// ignore-sparcv9 +// ignore-sparcel +// ignore-s390x +// ignore-tce +// ignore-thumb +// ignore-thumbeb +// ignore-xcore +// ignore-nvptx +// ignore-nvptx64 +// ignore-le32 +// ignore-le64 +// ignore-amdil +// ignore-amdil64 +// ignore-hsail +// ignore-hsail64 +// ignore-spir +// ignore-spir64 +// ignore-kalimba +// ignore-shave +// ignore-wasm32 +// ignore-wasm64 +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +#![feature(global_asm)] +#![crate_type = "lib"] +#[no_std] + +// CHECK-LABEL: foo +// CHECK: module asm +// CHECK: module asm "{{[[:space:]]+}}jmp baz" +// any other global_asm will be appended to this first block, so: +// CHECK-LABEL: bar +// CHECK: module asm "{{[[:space:]]+}}jmp quux" +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern "C" { + fn foo(); +} + +// CHECK-LABEL: @baz +#[no_mangle] +pub unsafe extern "C" fn baz() {} + +// no checks here; this has been appended to the first occurrence +global_asm!(r#" + .global bar +bar: + jmp quux +"#); + +extern "C" { + fn bar(); +} + +#[no_mangle] +pub unsafe extern "C" fn quux() {} diff --git a/src/test/compile-fail/feature-gate-global_asm.rs b/src/test/compile-fail/feature-gate-global_asm.rs new file mode 100644 index 0000000000000..0560abb6af498 --- /dev/null +++ b/src/test/compile-fail/feature-gate-global_asm.rs @@ -0,0 +1,15 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// gate-test-global_asm + +global_asm!(""); //~ ERROR `global_asm!` is not stable + +fn main() {} diff --git a/src/test/run-pass/empty_global_asm.rs b/src/test/run-pass/empty_global_asm.rs new file mode 100644 index 0000000000000..db73da2747f9c --- /dev/null +++ b/src/test/run-pass/empty_global_asm.rs @@ -0,0 +1,28 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(global_asm)] + +#[cfg(target_arch = "x86")] +global_asm!(""); + +#[cfg(target_arch = "x86_64")] +global_asm!(""); + +#[cfg(target_arch = "arm")] +global_asm!(""); + +#[cfg(target_arch = "aarch64")] +global_asm!(""); + +#[cfg(target_arch = "mips")] +global_asm!(""); + +fn main() {} diff --git a/src/test/run-pass/simple_global_asm.rs b/src/test/run-pass/simple_global_asm.rs new file mode 100644 index 0000000000000..a5ffe607fdf84 --- /dev/null +++ b/src/test/run-pass/simple_global_asm.rs @@ -0,0 +1,27 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(global_asm)] + +#[cfg(any(target_arch = "x86_64", target_arch = "x86"))] +global_asm!(r#" + .global foo +foo: + jmp baz +"#); + +extern { + fn foo(); +} + +#[no_mangle] +pub extern fn baz() {} + +fn main() {} diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs index 6331fc5771fcb..d7c8935560623 100644 --- a/src/test/ui/did_you_mean/issue-39544.rs +++ b/src/test/ui/did_you_mean/issue-39544.rs @@ -51,3 +51,9 @@ pub fn with_arg(z: Z, w: &Z) { let _ = &mut z.x; let _ = &mut w.x; } + +pub fn with_tuple() { + let mut y = 0; + let x = (&y,); + *x.0 = 1; +} diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr index e1e229a8b0572..2e98bc65e9e9f 100644 --- a/src/test/ui/did_you_mean/issue-39544.stderr +++ b/src/test/ui/did_you_mean/issue-39544.stderr @@ -90,5 +90,11 @@ error: cannot borrow immutable field `w.x` as mutable 52 | let _ = &mut w.x; | ^^^ cannot mutably borrow immutable field -error: aborting due to 11 previous errors +error: cannot assign to immutable borrowed content `*x.0` + --> $DIR/issue-39544.rs:58:5 + | +58 | *x.0 = 1; + | ^^^^^^^^ cannot borrow as mutable + +error: aborting due to 12 previous errors