From 3fb1a849ddd162444e2894bce52f7bb2dbc53d69 Mon Sep 17 00:00:00 2001
From: Josh Stone
Date: Mon, 3 Apr 2017 13:46:50 -0700
Subject: [PATCH 01/18] Add a common Build::src_is_git flag
---
src/bootstrap/lib.rs | 8 ++++----
src/bootstrap/sanity.rs | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 84254d7d6ae51..f80ba017f0774 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").is_dir();
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());
}
From e9cfc300a3a5b5a6f6f27df3305338f4b451366d Mon Sep 17 00:00:00 2001
From: Josh Stone
Date: Mon, 3 Apr 2017 13:46:53 -0700
Subject: [PATCH 02/18] Only use cargo-vendor if building from git sources
---
src/bootstrap/dist.rs | 41 ++++++++++++++++++++++-------------------
1 file changed, 22 insertions(+), 19 deletions(-)
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")))
From 4d32ff4e498c391d65b44d26cfb453651dc3da7b Mon Sep 17 00:00:00 2001
From: Josh Stone
Date: Mon, 3 Apr 2017 15:28:06 -0700
Subject: [PATCH 03/18] Loosen src_is_git to just check exists()
---
src/bootstrap/lib.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index f80ba017f0774..8303a40bb6965 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -234,7 +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").is_dir();
+ let src_is_git = src.join(".git").exists();
Build {
flags: flags,
From 631f761f18d6e4e8d1d4eccaa622ee7defbb8ca4 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Wed, 5 Apr 2017 10:39:02 -0700
Subject: [PATCH 04/18] travis: Update musl for i686/x86_64
This is a random stab towards #38618, no idea if it'll work. But hey more
up-to-date software is better, right?
---
src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh | 9 ++++++---
src/ci/docker/dist-x86_64-musl/build-musl.sh | 2 +-
2 files changed, 7 insertions(+), 4 deletions(-)
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-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
From 4c7e27734031d8b57cb51ad498d7f5111032468d Mon Sep 17 00:00:00 2001
From: Jorge Aparicio
Date: Mon, 20 Feb 2017 14:42:47 -0500
Subject: [PATCH 05/18] add an #[used] attribute
similar to GCC's __attribute((used))__. This attribute prevents LLVM from
optimizing away a non-exported symbol, within a compilation unit (object file),
when there are no references to it.
This is better explained with an example:
```
#[used]
static LIVE: i32 = 0;
static REFERENCED: i32 = 0;
static DEAD: i32 = 0;
fn internal() {}
pub fn exported() -> &'static i32 {
&REFERENCED
}
```
Without optimizations, LLVM pretty much preserves all the static variables and
functions within the compilation unit.
```
$ rustc --crate-type=lib --emit=obj symbols.rs && nm -C symbols.o
0000000000000000 t drop::h1be0f8f27a2ba94a
0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c
0000000000000000 r symbols::DEAD::hc2ea8f9bd06f380b
0000000000000000 r symbols::LIVE::h0970cf9889edb56e
0000000000000000 T symbols::exported::h6f096c2b1fc292b2
0000000000000000 t symbols::internal::h0ac1aadbc1e3a494
```
With optimizations, LLVM will drop dead code. Here `internal` is dropped because
it's not a exported function/symbol (i.e. not `pub`lic). `DEAD` is dropped for
the same reason. `REFERENCED` is preserved, even though it's not exported,
because it's referenced by the `exported` function. Finally, `LIVE` survives
because of the `#[used]` attribute even though it's not exported or referenced.
```
$ rustc --crate-type=lib -C opt-level=3 --emit=obj symbols.rs && nm -C symbols.o
0000000000000000 r symbols::REFERENCED::hb3bdfd46050bc84c
0000000000000000 r symbols::LIVE::h0970cf9889edb56e
0000000000000000 T symbols::exported::h6f096c2b1fc292b2
```
Note that the linker knows nothing about `#[used]` and will drop `LIVE`
because no other object references to it.
```
$ echo 'fn main() {}' >> symbols.rs
$ rustc symbols.rs && nm -C symbols | grep LIVE
```
At this time, `#[used]` only works on `static` variables.
---
src/librustc_trans/base.rs | 20 +++++++++++++++++++-
src/librustc_trans/consts.rs | 4 ++++
src/librustc_trans/context.rs | 7 +++++++
src/libsyntax/feature_gate.rs | 8 ++++++++
4 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index ec45c5593632e..63258b7453317 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -50,7 +50,7 @@ use builder::Builder;
use callee;
use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
use collector::{self, TransItemCollectionMode};
-use common::{C_struct_in_context, C_u64, C_undef};
+use common::{C_struct_in_context, C_u64, C_undef, C_array};
use common::CrateContext;
use common::{type_is_zero_size, val_ty};
use common;
@@ -1187,6 +1187,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
+ // Create llvm.used variable
+ if !ccx.used_statics().borrow().is_empty() {
+ debug!("llvm.used");
+
+ let name = CString::new("llvm.used").unwrap();
+ let section = CString::new("llvm.metadata").unwrap();
+ let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
+
+ unsafe {
+ let g = llvm::LLVMAddGlobal(ccx.llmod(),
+ val_ty(array).to_ref(),
+ name.as_ptr());
+ llvm::LLVMSetInitializer(g, array);
+ llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+ llvm::LLVMSetSection(g, section.as_ptr());
+ }
+ }
+
// Finalize debuginfo
if ccx.sess().opts.debuginfo != NoDebugInfo {
debuginfo::finalize(&ccx);
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 0c3d211912add..9974155f7c07d 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -276,6 +276,10 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
base::set_link_section(ccx, g, attrs);
+ if attr::contains_name(attrs, "used") {
+ ccx.used_statics().borrow_mut().push(g);
+ }
+
Ok(g)
}
}
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 73602dc420b3f..2eca0a18e2b38 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -132,6 +132,8 @@ pub struct LocalCrateContext<'tcx> {
/// to constants.)
statics_to_rauw: RefCell>,
+ used_statics: RefCell>,
+
lltypes: RefCell, Type>>,
llsizingtypes: RefCell, Type>>,
type_hashcodes: RefCell, String>>,
@@ -587,6 +589,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
impl_method_cache: RefCell::new(FxHashMap()),
closure_bare_wrapper_cache: RefCell::new(FxHashMap()),
statics_to_rauw: RefCell::new(Vec::new()),
+ used_statics: RefCell::new(Vec::new()),
lltypes: RefCell::new(FxHashMap()),
llsizingtypes: RefCell::new(FxHashMap()),
type_hashcodes: RefCell::new(FxHashMap()),
@@ -754,6 +757,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local().statics_to_rauw
}
+ pub fn used_statics<'a>(&'a self) -> &'a RefCell> {
+ &self.local().used_statics
+ }
+
pub fn lltypes<'a>(&'a self) -> &'a RefCell, Type>> {
&self.local().lltypes
}
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 12d25ca4274fe..66a813025c437 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -337,11 +337,15 @@ declare_features! (
// `extern "x86-interrupt" fn()`
(active, abi_x86_interrupt, "1.17.0", Some(40180)),
+
// Allows the `catch {...}` expression
(active, catch_expr, "1.17.0", Some(31436)),
// See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
(active, rvalue_static_promotion, "1.15.1", Some(38865)),
+
+ // Used to preserve symbols
+ (active, used, "1.18.0", None),
);
declare_features! (
@@ -748,6 +752,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
"unwind_attributes",
"#[unwind] is experimental",
cfg_fn!(unwind_attributes))),
+ ("used", Whitelisted, Gated(
+ Stability::Unstable, "used",
+ "the `#[used]` attribute is an experimental feature",
+ cfg_fn!(used))),
// used in resolve
("prelude_import", Whitelisted, Gated(Stability::Unstable,
From 4e1147f3406bcd368c50c89242bbba6a6fec5127 Mon Sep 17 00:00:00 2001
From: raph
Date: Wed, 5 Apr 2017 20:41:43 +0200
Subject: [PATCH 06/18] Add example to std::process::abort
This is a second (2/3?) step in order to complete this issue: https://github.com/rust-lang/rust/issues/29370
I submitted this PR with the help of @steveklabnik again. Thanks to him! More info here: https://github.com/rust-lang/rust/issues/29370#issuecomment-290653877
---
src/libstd/process.rs | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 7f1a00c707c20..95e625888ccee 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1070,6 +1070,28 @@ pub fn exit(code: i32) -> ! {
/// // execution never gets here
/// }
/// ```
+///
+/// The abort function terminates the process, so the destructor will not get
+/// run on the example below:
+///
+/// ```no_run
+/// use std::process;
+///
+/// struct HasDrop;
+///
+/// impl Drop for HasDrop {
+/// fn drop(&mut self) {
+/// println!("This will never be printed!");
+/// }
+/// }
+///
+/// fn main() {
+/// let _x = HasDrop;
+/// process::abort();
+/// // the destructor implemented for HasDrop will never get run
+/// }
+/// ```
+///
#[stable(feature = "process_abort", since = "1.17.0")]
pub fn abort() -> ! {
unsafe { ::sys::abort_internal() };
From bc1bd8a609823814079996ca3ca0b05774e07a74 Mon Sep 17 00:00:00 2001
From: Jorge Aparicio
Date: Sun, 5 Mar 2017 23:03:42 -0500
Subject: [PATCH 07/18] add tracking issue and feature-gate and run-make tests
---
src/test/compile-fail/feature-gate-used.rs | 15 +++++++++++++++
src/test/run-make/used/Makefile | 12 ++++++++++++
src/test/run-make/used/used.rs | 17 +++++++++++++++++
3 files changed, 44 insertions(+)
create mode 100644 src/test/compile-fail/feature-gate-used.rs
create mode 100644 src/test/run-make/used/Makefile
create mode 100644 src/test/run-make/used/used.rs
diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs
new file mode 100644
index 0000000000000..68679d7dac896
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-used.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[used]
+fn foo() {}
+//~^^ ERROR the `#[used]` attribute is an experimental feature
+
+fn main() {}
diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile
new file mode 100644
index 0000000000000..70ac2e3802b81
--- /dev/null
+++ b/src/test/run-make/used/Makefile
@@ -0,0 +1,12 @@
+-include ../tools.mk
+
+ifdef IS_WINDOWS
+# Do nothing on MSVC.
+all:
+ exit 0
+else
+all:
+ $(RUSTC) -C opt-level=3 --emit=obj used.rs
+ nm -C used.o | grep FOO
+ nm -C used.o | grep -v BAR
+endif
diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs
new file mode 100644
index 0000000000000..186cd0fdf5e35
--- /dev/null
+++ b/src/test/run-make/used/used.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+#![feature(used)]
+
+#[used]
+static FOO: u32 = 0;
+
+static BAR: u32 = 0;
From c759eea7a60941f28e7e7a370ba95eeae06ea013 Mon Sep 17 00:00:00 2001
From: Jorge Aparicio
Date: Mon, 6 Mar 2017 11:18:56 -0500
Subject: [PATCH 08/18] fix location of the emitted object file
---
src/test/run-make/used/Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile
index 70ac2e3802b81..650464e4d8454 100644
--- a/src/test/run-make/used/Makefile
+++ b/src/test/run-make/used/Makefile
@@ -7,6 +7,6 @@ all:
else
all:
$(RUSTC) -C opt-level=3 --emit=obj used.rs
- nm -C used.o | grep FOO
- nm -C used.o | grep -v BAR
+ nm -C $(TMPDIR)/used.o | grep FOO
+ nm -C $(TMPDIR)/used.o | grep -v BAR
endif
From c1635d7e61533550d6c58d4f92a01d1e6acd28e6 Mon Sep 17 00:00:00 2001
From: Jorge Aparicio
Date: Wed, 5 Apr 2017 21:02:52 -0500
Subject: [PATCH 09/18] cast the #[used] static to *i8
to match the type signature of the llvm.used variable
---
src/librustc_trans/base.rs | 2 --
src/librustc_trans/consts.rs | 3 ++-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 63258b7453317..378e1d7fc63f0 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1189,8 +1189,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Create llvm.used variable
if !ccx.used_statics().borrow().is_empty() {
- debug!("llvm.used");
-
let name = CString::new("llvm.used").unwrap();
let section = CString::new("llvm.metadata").unwrap();
let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 9974155f7c07d..ae8c2433fed75 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -277,7 +277,8 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
base::set_link_section(ccx, g, attrs);
if attr::contains_name(attrs, "used") {
- ccx.used_statics().borrow_mut().push(g);
+ let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref());
+ ccx.used_statics().borrow_mut().push(cast);
}
Ok(g)
From ecddad6920b7640ff0398a52a808703db3d4e62a Mon Sep 17 00:00:00 2001
From: Jorge Aparicio
Date: Wed, 5 Apr 2017 21:06:53 -0500
Subject: [PATCH 10/18] don't test for the absence of BAR in the rmake test
it's not related to this feature
---
src/test/run-make/used/Makefile | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile
index 650464e4d8454..5fe09e95a828d 100644
--- a/src/test/run-make/used/Makefile
+++ b/src/test/run-make/used/Makefile
@@ -8,5 +8,4 @@ else
all:
$(RUSTC) -C opt-level=3 --emit=obj used.rs
nm -C $(TMPDIR)/used.o | grep FOO
- nm -C $(TMPDIR)/used.o | grep -v BAR
endif
From bbe54115873eca9d9a889be3d9eff0c01d2ba8be Mon Sep 17 00:00:00 2001
From: Jorge Aparicio
Date: Wed, 5 Apr 2017 21:11:22 -0500
Subject: [PATCH 11/18] document the implementation a bit more
---
src/librustc_trans/base.rs | 3 ++-
src/librustc_trans/consts.rs | 1 +
src/librustc_trans/context.rs | 2 ++
src/libsyntax/feature_gate.rs | 4 ++--
4 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 378e1d7fc63f0..d204703b77598 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1187,7 +1187,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
- // Create llvm.used variable
+ // Create the llvm.used variable
+ // This variable has type [N x i8*] and is stored in the llvm.metadata section
if !ccx.used_statics().borrow().is_empty() {
let name = CString::new("llvm.used").unwrap();
let section = CString::new("llvm.metadata").unwrap();
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index ae8c2433fed75..daf1a1ba95f9a 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -277,6 +277,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
base::set_link_section(ccx, g, attrs);
if attr::contains_name(attrs, "used") {
+ // This static will be stored in the llvm.used variable which is an array of i8*
let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref());
ccx.used_statics().borrow_mut().push(cast);
}
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 2eca0a18e2b38..afb94f546abe8 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -132,6 +132,8 @@ pub struct LocalCrateContext<'tcx> {
/// to constants.)
statics_to_rauw: RefCell>,
+ /// Statics that will be placed in the llvm.used variable
+ /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details
used_statics: RefCell>,
lltypes: RefCell, Type>>,
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 66a813025c437..5f71900120386 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -344,8 +344,8 @@ 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)),
- // Used to preserve symbols
- (active, used, "1.18.0", None),
+ // Used to preserve symbols (see llvm.used)
+ (active, used, "1.18.0", Some(40289)),
);
declare_features! (
From 763beff5d1bcfb74d2930decd731a43a7d3ad080 Mon Sep 17 00:00:00 2001
From: Jorge Aparicio
Date: Thu, 6 Apr 2017 00:04:33 -0500
Subject: [PATCH 12/18] add documentation to the unstable book
---
src/doc/unstable-book/src/SUMMARY.md | 1 +
src/doc/unstable-book/src/used.md | 152 +++++++++++++++++++++++++++
2 files changed, 153 insertions(+)
create mode 100644 src/doc/unstable-book/src/used.md
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
index 292f5a1ec816a..0459c6a251995 100644
--- a/src/doc/unstable-book/src/SUMMARY.md
+++ b/src/doc/unstable-book/src/SUMMARY.md
@@ -203,6 +203,7 @@
- [unwind_attributes](unwind-attributes.md)
- [update_panic_count](update-panic-count.md)
- [use_extern_macros](use-extern-macros.md)
+- [used](used.md)
- [utf8_error_error_len](utf8-error-error-len.md)
- [vec_remove_item](vec-remove-item.md)
- [windows_c](windows-c.md)
diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md
new file mode 100644
index 0000000000000..749c9a8ec288c
--- /dev/null
+++ b/src/doc/unstable-book/src/used.md
@@ -0,0 +1,152 @@
+# `used`
+
+The tracking issue for this feature is: 40289.
+
+------------------------
+
+The `#[used]` attribute can be applied to `static` variables to prevent the Rust
+compiler from optimizing them away even if they appear to be unused by the crate
+(appear to be "dead code").
+
+``` rust
+#![feature(used)]
+
+#[used]
+static FOO: i32 = 1;
+
+static BAR: i32 = 2;
+
+fn main() {}
+```
+
+If you compile this program into an object file, you'll see that `FOO` makes it
+to the object file but `BAR` doesn't. Neither static variable is used by the
+program.
+
+``` text
+$ rustc -C opt-level=3 --emit=obj used.rs
+
+$ nm -C used.o
+0000000000000000 T main
+ U std::rt::lang_start
+0000000000000000 r used::FOO
+0000000000000000 t used::main
+```
+
+Note that the *linker* knows nothing about the `#[used]` attribute and will
+remove `#[used]` symbols if they are not referenced by other parts of the
+program:
+
+``` text
+$ rustc -C opt-level=3 used.rs
+
+$ nm -C used | grep FOO
+```
+
+"This doesn't sound too useful then!" you may think but keep reading.
+
+To preserve the symbols all the way to the final binary, you'll need the
+cooperation of the linker. Here's one example:
+
+The ELF standard defines two special sections, `.init_array` and
+`.pre_init_array`, that may contain function pointers which will be executed
+*before* the `main` function is invoked. The linker will preserve symbols placed
+in these sections (at least when linking programs that target the `*-*-linux-*`
+targets).
+
+``` rust
+#![feature(used)]
+
+extern "C" fn before_main() {
+ println!("Hello, world!");
+}
+
+#[link_section = ".init_array"]
+#[used]
+static INIT_ARRAY: [extern "C" fn(); 1] = [before_main];
+
+fn main() {}
+```
+
+So, `#[used]` and `#[link_section]` can be combined to obtain "life before
+main".
+
+``` text
+$ rustc -C opt-level=3 before-main.rs
+
+$ ./before-main
+Hello, world!
+```
+
+Another example: ARM Cortex-M microcontrollers need their reset handler, a
+pointer to the function that will executed right after the microcontroller is
+turned on, to be placed near the start of their FLASH memory to boot properly.
+
+This condition can be met using `#[used]` and `#[link_section]` plus a linker
+script.
+
+``` rust
+#![feature(lang_items)]
+#![feature(used)]
+#![no_main]
+#![no_std]
+
+extern "C" fn reset_handler() -> ! {
+ loop {}
+}
+
+#[link_section = ".reset_handler"]
+#[used]
+static RESET_HANDLER: extern "C" fn() -> ! = reset_handler;
+
+#[lang = "panic_fmt"]
+fn panic_fmt() {}
+```
+
+``` text
+MEMORY
+{
+ FLASH : ORIGIN = 0x08000000, LENGTH = 128K
+ RAM : ORIGIN = 0x20000000, LENGTH = 20K
+}
+
+SECTIONS
+{
+ .text ORIGIN(FLASH) :
+ {
+ /* Vector table */
+ LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */
+ KEEP(*(.reset_handler));
+
+ /* Omitted: The rest of the vector table */
+
+ *(.text.*);
+ } > FLASH
+
+ /DISCARD/ :
+ {
+ /* Unused unwinding stuff */
+ *(.ARM.exidx.*)
+ }
+}
+```
+
+``` text
+$ xargo rustc --target thumbv7m-none-eabi --release -- \
+ -C link-arg=-Tlink.x -C link-arg=-nostartfiles
+
+$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app
+./target/thumbv7m-none-eabi/release/app: file format elf32-littlearm
+
+
+Disassembly of section .text:
+
+08000000 :
+ 8000000: 20005000 .word 0x20005000
+
+08000004 :
+ 8000004: 08000009 ....
+
+08000008 :
+ 8000008: e7fe b.n 8000008
+```
From 16c77d7da1d1707a90d94d9eb77e0752f974a0db Mon Sep 17 00:00:00 2001
From: raph
Date: Thu, 6 Apr 2017 10:17:32 +0200
Subject: [PATCH 13/18] Update process.rs
---
src/libstd/process.rs | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 95e625888ccee..8cfd8fcd8c680 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1071,8 +1071,8 @@ pub fn exit(code: i32) -> ! {
/// }
/// ```
///
-/// The abort function terminates the process, so the destructor will not get
-/// run on the example below:
+/// The [`abort`] function terminates the process, so the destructor will not
+/// get run on the example below:
///
/// ```no_run
/// use std::process;
@@ -1091,7 +1091,6 @@ pub fn exit(code: i32) -> ! {
/// // the destructor implemented for HasDrop will never get run
/// }
/// ```
-///
#[stable(feature = "process_abort", since = "1.17.0")]
pub fn abort() -> ! {
unsafe { ::sys::abort_internal() };
From b4be4758361bf1b03410a523e8672b1c1fa7d385 Mon Sep 17 00:00:00 2001
From: Oliver Middleton
Date: Thu, 6 Apr 2017 12:57:40 +0100
Subject: [PATCH 14/18] Fix Markdown issues in the docs
* Since the switch to pulldown-cmark reference links need a blank line
before the URLs.
* Reference link references are not case sensitive.
* Doc comments need to be indented uniformly otherwise rustdoc gets
confused.
---
src/libcollections/vec.rs | 2 +-
src/libcore/sync/atomic.rs | 5 +++--
src/libstd/fs.rs | 14 ++++++++++++++
src/libstd/io/buffered.rs | 17 +++++++++--------
src/libstd/io/mod.rs | 9 +++++----
src/libstd/net/tcp.rs | 4 ++--
src/libstd/prelude/mod.rs | 12 ++++++------
src/libstd/sys/windows/ext/fs.rs | 2 +-
src/libstd/sys/windows/ext/process.rs | 1 +
src/libstd/thread/mod.rs | 4 ++--
10 files changed, 44 insertions(+), 26 deletions(-)
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/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
From f9fb381b2a13260c3fcdae2f6d9546ab2c87e717 Mon Sep 17 00:00:00 2001
From: Oliver Middleton
Date: Thu, 6 Apr 2017 13:09:20 +0100
Subject: [PATCH 15/18] rustdoc: Use pulldown-cmark for Markdown HTML rendering
Instead of rendering all of the HTML in rustdoc this relies on
pulldown-cmark's `push_html` to do most of the work. A few iterator
adapters are used to make rustdoc specific modifications to the output.
This also fixes MarkdownHtml and link titles in plain_summary_line.
---
src/librustdoc/html/markdown.rs | 728 +++++++-----------
src/librustdoc/html/render.rs | 12 +-
src/librustdoc/markdown.rs | 4 +-
src/test/rustdoc/check-hard-break.rs | 3 +-
src/test/rustdoc/check-rule-image-footnote.rs | 14 +-
src/test/rustdoc/test-lists.rs | 14 +-
src/tools/error_index_generator/main.rs | 4 +-
7 files changed, 296 insertions(+), 483 deletions(-)
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 245a3946a3709..1e687d63f5875 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -16,10 +16,10 @@
//! of `fmt::Display`. Example usage:
//!
//! ```rust,ignore
-//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle};
+//! use rustdoc::html::markdown::Markdown;
//!
//! let s = "My *markdown* _text_";
-//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy));
+//! let html = format!("{}", Markdown(s));
//! // ... something using html
//! ```
@@ -27,7 +27,7 @@
use std::ascii::AsciiExt;
use std::cell::RefCell;
-use std::collections::HashMap;
+use std::collections::{HashMap, VecDeque};
use std::default::Default;
use std::fmt::{self, Write};
use std::str;
@@ -37,43 +37,23 @@ use syntax::codemap::Span;
use html::render::derive_id;
use html::toc::TocBuilder;
use html::highlight;
-use html::escape::Escape;
use test;
-use pulldown_cmark::{self, Event, Parser, Tag};
-
-#[derive(Copy, Clone)]
-pub enum MarkdownOutputStyle {
- Compact,
- Fancy,
-}
-
-impl MarkdownOutputStyle {
- pub fn is_compact(&self) -> bool {
- match *self {
- MarkdownOutputStyle::Compact => true,
- _ => false,
- }
- }
-
- pub fn is_fancy(&self) -> bool {
- match *self {
- MarkdownOutputStyle::Fancy => true,
- _ => false,
- }
- }
-}
+use pulldown_cmark::{html, Event, Tag, Parser};
+use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
/// A unit struct which has the `fmt::Display` trait implemented. When
/// formatted, this struct will emit the HTML corresponding to the rendered
/// version of the contained markdown string.
// The second parameter is whether we need a shorter version or not.
-pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle);
+pub struct Markdown<'a>(pub &'a str);
/// A unit struct like `Markdown`, that renders the markdown with a
/// table of contents.
pub struct MarkdownWithToc<'a>(pub &'a str);
/// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
pub struct MarkdownHtml<'a>(pub &'a str);
+/// A unit struct like `Markdown`, that renders only the first paragraph.
+pub struct MarkdownSummaryLine<'a>(pub &'a str);
/// Returns Some(code) if `s` is a line that should be stripped from
/// documentation but used in example code. `code` is the portion of
@@ -90,12 +70,21 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
}
}
-/// Returns a new string with all consecutive whitespace collapsed into
-/// single spaces.
+/// Convert chars from a title for an id.
///
-/// Any leading or trailing whitespace will be trimmed.
-fn collapse_whitespace(s: &str) -> String {
- s.split_whitespace().collect::>().join(" ")
+/// "Hello, world!" -> "hello-world"
+fn slugify(c: char) -> Option {
+ if c.is_alphanumeric() || c == '-' || c == '_' {
+ if c.is_ascii() {
+ Some(c.to_ascii_lowercase())
+ } else {
+ Some(c)
+ }
+ } else if c.is_whitespace() && c.is_ascii() {
+ Some('-')
+ } else {
+ None
+ }
}
// Information about the playground if a URL has been specified, containing an
@@ -104,103 +93,50 @@ thread_local!(pub static PLAYGROUND: RefCell
",
- cur_id,
- if content.ends_with("") {
- &content[..content.len() - 4]
- } else {
- &content
- }));
- }
- Event::FootnoteReference(ref reference) => {
- debug!("FootnoteReference");
- let entry = parser.get_entry(reference.as_ref());
- buffer.push_str(&format!("{0}\
- ",
- (*entry).1));
- }
- Event::HardBreak => {
- debug!("HardBreak");
- if shorter.is_fancy() {
- buffer.push_str(" ");
- } else if !buffer.is_empty() {
- buffer.push(' ');
+impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> {
+ type Item = Event<'a>;
+
+ fn next(&mut self) -> Option {
+ loop {
+ match self.inner.next() {
+ Some(Event::FootnoteReference(ref reference)) => {
+ let entry = self.get_entry(&reference);
+ let reference = format!("{0}\
+ ",
+ (*entry).1);
+ return Some(Event::Html(reference.into()));
+ }
+ Some(Event::Start(Tag::FootnoteDefinition(def))) => {
+ let mut content = Vec::new();
+ for event in &mut self.inner {
+ if let Event::End(Tag::FootnoteDefinition(..)) = event {
+ break;
+ }
+ content.push(event);
+ }
+ let entry = self.get_entry(&def);
+ (*entry).0 = content;
+ }
+ Some(e) => return Some(e),
+ None => {
+ if !self.footnotes.is_empty() {
+ let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect();
+ v.sort_by(|a, b| a.1.cmp(&b.1));
+ let mut ret = String::from("
");
+ for (mut content, id) in v {
+ write!(ret, "