diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 70c7acccd3638..0dc81378e05b2 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -197,7 +197,11 @@ in software.
## prefer-dynamic
By default, `rustc` prefers to statically link dependencies. This option will
-make it use dynamic linking instead.
+indicate that dynamic linking should be used if possible if both a static and
+dynamic versions of a library are available. There is an internal algorithm
+for determining whether or not it is possible to statically or dynamically
+link with a dependency. For example, `cdylib` crate types may only use static
+linkage.
## no-integrated-as
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 79b4f7542f9b0..577d03d1038f8 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -21,8 +21,7 @@ to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively.
## `-L`: add a directory to the library search path
-When looking for external crates or libraries, a directory passed to this flag
-will be searched.
+The `-L` flag adds a path to search for external crates and libraries.
The kind of search path can optionally be specified with the form `-L
KIND=PATH` where `KIND` may be one of:
@@ -262,9 +261,30 @@ This flag, when combined with other flags, makes them produce extra output.
## `--extern`: specify where an external library is located
-This flag allows you to pass the name and location of an external crate that
-will be linked into the crate you are building. This flag may be specified
-multiple times. The format of the value should be `CRATENAME=PATH`.
+This flag allows you to pass the name and location for an external crate of a
+direct dependency. Indirect dependencies (dependencies of dependencies) are
+located using the [`-L` flag](#option-l-search-path). The given crate name is
+added to the [extern prelude], which is the same as specifying `extern crate`
+within the root module. The given crate name does not need to match the name
+the library was built with.
+
+This flag may be specified multiple times. This flag takes an argument with
+either of the following formats:
+
+* `CRATENAME=PATH` — Indicates the given crate is found at the given path.
+* `CRATENAME` — Indicates the given crate may be found in the search path,
+ such as within the sysroot or via the `-L` flag.
+
+The same crate name may be specified multiple times for different crate types.
+If both an `rlib` and `dylib` are found, an internal algorithm is used to
+decide which to use for linking. The [`-C prefer-dynamic`
+flag][prefer-dynamic] may be used to influence which is used.
+
+If the same crate name is specified with and without a path, the one with the
+path is used and the pathless flag has no effect.
+
+[extern prelude]: ../reference/items/extern-crates.html#extern-prelude
+[prefer-dynamic]: codegen-options/index.md#prefer-dynamic
## `--sysroot`: Override the system root
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 2bcddeaf1962d..eb5654e80a82c 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1800,7 +1800,7 @@ pub fn rustc_optgroups() -> Vec {
"",
"extern",
"Specify where an external rust library is located",
- "NAME=PATH",
+ "NAME[=PATH]",
),
opt::multi_s(
"",
@@ -2164,7 +2164,6 @@ fn collect_print_requests(
cg: &mut CodegenOptions,
dopts: &mut DebuggingOptions,
matches: &getopts::Matches,
- is_unstable_enabled: bool,
error_format: ErrorOutputType,
) -> Vec {
let mut prints = Vec::::new();
@@ -2206,7 +2205,7 @@ fn collect_print_requests(
"tls-models" => PrintRequest::TlsModels,
"native-static-libs" => PrintRequest::NativeStaticLibs,
"target-spec-json" => {
- if is_unstable_enabled {
+ if dopts.unstable_options {
PrintRequest::TargetSpec
} else {
early_error(
@@ -2370,7 +2369,6 @@ fn parse_externs(
matches: &getopts::Matches,
debugging_opts: &DebuggingOptions,
error_format: ErrorOutputType,
- is_unstable_enabled: bool,
) -> Externs {
if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
early_error(
@@ -2392,13 +2390,6 @@ fn parse_externs(
let name = parts.next().unwrap_or_else(||
early_error(error_format, "--extern value must not be empty"));
let location = parts.next().map(|s| s.to_string());
- if location.is_none() && !is_unstable_enabled {
- early_error(
- error_format,
- "the `-Z unstable-options` flag must also be passed to \
- enable `--extern crate_name` without `=path`",
- );
- };
let entry = externs
.entry(name.to_owned())
@@ -2483,12 +2474,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
);
}
- let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
let prints = collect_print_requests(
&mut cg,
&mut debugging_opts,
matches,
- is_unstable_enabled,
error_format,
);
@@ -2521,7 +2510,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
);
}
- let externs = parse_externs(matches, &debugging_opts, error_format, is_unstable_enabled);
+ let externs = parse_externs(matches, &debugging_opts, error_format);
let crate_name = matches.opt_str("crate-name");
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 0b8d4d6c302f1..255d5f9f35dbf 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -615,10 +615,6 @@ fn parse_externs(matches: &getopts::Matches) -> Result {
let mut parts = arg.splitn(2, '=');
let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
let location = parts.next().map(|s| s.to_string());
- if location.is_none() && !nightly_options::is_unstable_enabled(matches) {
- return Err("the `-Z unstable-options` flag must also be passed to \
- enable `--extern crate_name` without `=path`".to_string());
- }
let name = name.to_string();
// For Rustdoc purposes, we can treat all externs as public
externs.entry(name)
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 8cd32a3d1b508..13b8809e23e40 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -140,7 +140,7 @@ fn opts() -> Vec {
}),
stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")),
stable("extern", |o| {
- o.optmulti("", "extern", "pass an --extern to rustc", "NAME=PATH")
+ o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")
}),
unstable("extern-html-root-url", |o| {
o.optmulti("", "extern-html-root-url",
diff --git a/src/test/run-make-fulldeps/extern-flag-fun/Makefile b/src/test/run-make-fulldeps/extern-flag-fun/Makefile
index a9f2585335003..38d1d5bb8488a 100644
--- a/src/test/run-make-fulldeps/extern-flag-fun/Makefile
+++ b/src/test/run-make-fulldeps/extern-flag-fun/Makefile
@@ -4,7 +4,6 @@ all:
$(RUSTC) bar.rs --crate-type=rlib
$(RUSTC) bar.rs --crate-type=rlib -C extra-filename=-a
$(RUSTC) bar-alt.rs --crate-type=rlib
- $(RUSTC) foo.rs --extern hello && exit 1 || exit 0
$(RUSTC) foo.rs --extern bar=no-exist && exit 1 || exit 0
$(RUSTC) foo.rs --extern bar=foo.rs && exit 1 || exit 0
$(RUSTC) foo.rs \
@@ -15,3 +14,6 @@ all:
--extern bar=$(TMPDIR)/libbar.rlib \
--extern bar=$(TMPDIR)/libbar-a.rlib
$(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib
+ # Try to be sneaky and load a private crate from with a non-private name.
+ $(RUSTC) rustc.rs -Zforce-unstable-if-unmarked --crate-type=rlib
+ $(RUSTC) gated_unstable.rs --extern alloc=$(TMPDIR)/librustc.rlib 2>&1 | $(CGREP) 'rustc_private'
diff --git a/src/test/run-make-fulldeps/extern-flag-fun/gated_unstable.rs b/src/test/run-make-fulldeps/extern-flag-fun/gated_unstable.rs
new file mode 100644
index 0000000000000..03600c830fff6
--- /dev/null
+++ b/src/test/run-make-fulldeps/extern-flag-fun/gated_unstable.rs
@@ -0,0 +1,3 @@
+extern crate alloc;
+
+fn main() {}
diff --git a/src/test/run-make-fulldeps/extern-flag-fun/rustc.rs b/src/test/run-make-fulldeps/extern-flag-fun/rustc.rs
new file mode 100644
index 0000000000000..b76b4321d62aa
--- /dev/null
+++ b/src/test/run-make-fulldeps/extern-flag-fun/rustc.rs
@@ -0,0 +1 @@
+pub fn foo() {}
diff --git a/src/test/run-make-fulldeps/extern-flag-pathless/Makefile b/src/test/run-make-fulldeps/extern-flag-pathless/Makefile
new file mode 100644
index 0000000000000..4849fc62f4a95
--- /dev/null
+++ b/src/test/run-make-fulldeps/extern-flag-pathless/Makefile
@@ -0,0 +1,18 @@
+-include ../tools.mk
+
+# Test mixing pathless --extern with paths.
+
+all:
+ $(RUSTC) bar-static.rs --crate-name=bar --crate-type=rlib
+ $(RUSTC) bar-dynamic.rs --crate-name=bar --crate-type=dylib -C prefer-dynamic
+ # rlib preferred over dylib
+ $(RUSTC) foo.rs --extern bar
+ $(call RUN,foo) | $(CGREP) 'static'
+ $(RUSTC) foo.rs --extern bar=$(TMPDIR)/libbar.rlib --extern bar
+ $(call RUN,foo) | $(CGREP) 'static'
+ # explicit --extern overrides pathless
+ $(RUSTC) foo.rs --extern bar=$(call DYLIB,bar) --extern bar
+ $(call RUN,foo) | $(CGREP) 'dynamic'
+ # prefer-dynamic does what it says
+ $(RUSTC) foo.rs --extern bar -C prefer-dynamic
+ $(call RUN,foo) | $(CGREP) 'dynamic'
diff --git a/src/test/run-make-fulldeps/extern-flag-pathless/bar-dynamic.rs b/src/test/run-make-fulldeps/extern-flag-pathless/bar-dynamic.rs
new file mode 100644
index 0000000000000..e2d68d517ff97
--- /dev/null
+++ b/src/test/run-make-fulldeps/extern-flag-pathless/bar-dynamic.rs
@@ -0,0 +1,3 @@
+pub fn f() {
+ println!("dynamic");
+}
diff --git a/src/test/run-make-fulldeps/extern-flag-pathless/bar-static.rs b/src/test/run-make-fulldeps/extern-flag-pathless/bar-static.rs
new file mode 100644
index 0000000000000..240d8bde4d186
--- /dev/null
+++ b/src/test/run-make-fulldeps/extern-flag-pathless/bar-static.rs
@@ -0,0 +1,3 @@
+pub fn f() {
+ println!("static");
+}
diff --git a/src/test/run-make-fulldeps/extern-flag-pathless/foo.rs b/src/test/run-make-fulldeps/extern-flag-pathless/foo.rs
new file mode 100644
index 0000000000000..1ea64da7dad26
--- /dev/null
+++ b/src/test/run-make-fulldeps/extern-flag-pathless/foo.rs
@@ -0,0 +1,3 @@
+fn main() {
+ bar::f();
+}
diff --git a/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile b/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile
index bf98fcd10cfde..36288c4b870e7 100644
--- a/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile
+++ b/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile
@@ -1,8 +1,7 @@
-include ../tools.mk
all: extern_absolute_paths.rs krate2
- $(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018 \
- -Z unstable-options --extern krate2
+ $(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018 --extern krate2
cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py
krate2: krate2.rs
diff --git a/src/test/rustdoc/inline_cross/use_crate.rs b/src/test/rustdoc/inline_cross/use_crate.rs
index f678ba0a46c0d..00e0f041c56fe 100644
--- a/src/test/rustdoc/inline_cross/use_crate.rs
+++ b/src/test/rustdoc/inline_cross/use_crate.rs
@@ -2,7 +2,7 @@
// aux-build:use_crate_2.rs
// build-aux-docs
// edition:2018
-// compile-flags:--extern use_crate --extern use_crate_2 -Z unstable-options
+// compile-flags:--extern use_crate --extern use_crate_2
// During the buildup to Rust 2018, rustdoc would eagerly inline `pub use some_crate;` as if it
// were a module, so we changed it to make `pub use`ing crate roots remain as a `pub use` statement
diff --git a/src/test/ui-fulldeps/pathless-extern-unstable.rs b/src/test/ui-fulldeps/pathless-extern-unstable.rs
new file mode 100644
index 0000000000000..00b3ec5409ff0
--- /dev/null
+++ b/src/test/ui-fulldeps/pathless-extern-unstable.rs
@@ -0,0 +1,10 @@
+// ignore-stage1
+// edition:2018
+// compile-flags:--extern rustc
+
+// Test that `--extern rustc` fails with `rustc_private`.
+
+pub use rustc;
+//~^ ERROR use of unstable library feature 'rustc_private'
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/pathless-extern-unstable.stderr b/src/test/ui-fulldeps/pathless-extern-unstable.stderr
new file mode 100644
index 0000000000000..edc3b1c58be22
--- /dev/null
+++ b/src/test/ui-fulldeps/pathless-extern-unstable.stderr
@@ -0,0 +1,12 @@
+error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
+ --> $DIR/pathless-extern-unstable.rs:7:9
+ |
+LL | pub use rustc;
+ | ^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/27812
+ = help: add `#![feature(rustc_private)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/pathless-extern-ok.rs b/src/test/ui/pathless-extern-ok.rs
new file mode 100644
index 0000000000000..0ffa5eb894040
--- /dev/null
+++ b/src/test/ui/pathless-extern-ok.rs
@@ -0,0 +1,9 @@
+// edition:2018
+// compile-flags:--extern alloc
+// build-pass
+
+// Test that `--extern alloc` will load from the sysroot without error.
+
+fn main() {
+ let _: Vec = alloc::vec::Vec::new();
+}