about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_codegen_cranelift/src/discriminant.rs2
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs12
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs8
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/mod.rs2
-rw-r--r--compiler/rustc_mir/src/transform/dest_prop.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/_match.rs4
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs2
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/crt_objects.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm32_wasi.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--library/core/src/future/mod.rs2
-rw-r--r--library/core/src/intrinsics.rs2
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/num/dec2flt/mod.rs2
-rw-r--r--library/core/src/slice/sort.rs2
-rw-r--r--library/panic_unwind/src/dwarf/eh.rs8
-rw-r--r--library/panic_unwind/src/gcc.rs6
-rw-r--r--src/bootstrap/toolstate.rs4
-rw-r--r--src/build_helper/lib.rs2
-rw-r--r--src/doc/rustdoc/src/lints.md38
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/core.rs4
-rw-r--r--src/librustdoc/passes/mod.rs5
-rw-r--r--src/librustdoc/passes/non_autolinks.rs139
-rw-r--r--src/test/rustdoc-ui/url-improvements.rs66
-rw-r--r--src/test/rustdoc-ui/url-improvements.stderr122
34 files changed, 425 insertions, 37 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e9ed2f16369..b992552a521 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4297,6 +4297,7 @@ dependencies = [
  "itertools 0.9.0",
  "minifier",
  "pulldown-cmark 0.8.0",
+ "regex",
  "rustc-rayon",
  "serde",
  "serde_json",
diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs
index 6c9fb8e051b..1e8e86add1a 100644
--- a/compiler/rustc_codegen_cranelift/src/discriminant.rs
+++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs
@@ -1,6 +1,6 @@
 //! Handling of enum discriminants
 //!
-//! Adapted from https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs
+//! Adapted from <https://github.com/rust-lang/rust/blob/d760df5aea483aae041c9a241e7acacf48f75035/src/librustc_codegen_ssa/mir/place.rs>
 
 use rustc_target::abi::{Int, TagEncoding, Variants};
 
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 7297a6de420..24bfdad970a 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -69,7 +69,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
     BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
     EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS,
-    MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
+    MISSING_DOC_CODE_EXAMPLES, NON_AUTOLINKS, PRIVATE_DOC_TESTS,
 };
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
@@ -313,6 +313,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
 
     add_lint_group!(
         "rustdoc",
+        NON_AUTOLINKS,
         BROKEN_INTRA_DOC_LINKS,
         PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a1b7c13e4c0..ff7a145c266 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1891,6 +1891,17 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `non_autolinks` lint detects when a URL could be written using
+    /// only angle brackets. This is a `rustdoc` only lint, see the
+    /// documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#non_autolinks
+    pub NON_AUTOLINKS,
+    Warn,
+    "detects URLs that could be written using only angle brackets"
+}
+
+declare_lint! {
     /// The `where_clauses_object_safety` lint detects for [object safety] of
     /// [where clauses].
     ///
@@ -2795,6 +2806,7 @@ declare_lint_pass! {
         MISSING_DOC_CODE_EXAMPLES,
         INVALID_HTML_TAGS,
         PRIVATE_DOC_TESTS,
+        NON_AUTOLINKS,
         WHERE_CLAUSES_OBJECT_SAFETY,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
         MACRO_USE_EXTERN_CRATE,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 25a7bfcabb7..af9926400ca 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -99,13 +99,13 @@ pub struct Lint {
     /// The name is written with underscores, e.g., "unused_imports".
     /// On the command line, underscores become dashes.
     ///
-    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming
+    /// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming>
     /// for naming guidelines.
     pub name: &'static str,
 
     /// Default level for the lint.
     ///
-    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels
+    /// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels>
     /// for guidelines on choosing a default level.
     pub default_level: Level,
 
@@ -330,8 +330,8 @@ impl LintBuffer {
 
 /// Declares a static item of type `&'static Lint`.
 ///
-/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation
-/// and guidelines on writing lints.
+/// See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for
+/// documentation and guidelines on writing lints.
 ///
 /// The macro call should start with a doc comment explaining the lint
 /// which will be embedded in the rustc user documentation book. It should
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 3a97e05a39f..6b46d7c497d 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -21,9 +21,9 @@ rustc_index::newtype_index! {
 impl ExpressionOperandId {
     /// An expression operand for a "zero counter", as described in the following references:
     ///
-    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter
-    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#tag
-    /// * https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter-expressions
+    /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter>
+    /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#tag>
+    /// * <https://github.com/rust-lang/llvm-project/blob/llvmorg-8.0.0/llvm/docs/CoverageMappingFormat.rst#counter-expressions>
     ///
     /// This operand can be used to count two or more separate code regions with a single counter,
     /// if they run sequentially with no branches, by injecting the `Counter` in a `BasicBlock` for
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 79e2c5aac23..1e70f760504 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -228,7 +228,7 @@ pub struct CodegenUnit<'tcx> {
 
 /// Specifies the linkage type for a `MonoItem`.
 ///
-/// See https://llvm.org/docs/LangRef.html#linkage-types for more details about these variants.
+/// See <https://llvm.org/docs/LangRef.html#linkage-types> for more details about these variants.
 #[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
 pub enum Linkage {
     External,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 216451f268f..1c6937e685c 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -368,7 +368,7 @@ pub struct TypeckResults<'tcx> {
     /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
     ///
     /// See:
-    /// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions
+    /// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
     pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
 
     /// Borrows
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 47726632727..ac8ab71a1dc 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -1364,7 +1364,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// terms that the "longer free region" `'a` outlived the "shorter free region" `'b`.
     ///
     /// More details can be found in this blog post by Niko:
-    /// http://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/
+    /// <http://smallcultfollowing.com/babysteps/blog/2019/01/17/polonius-and-region-errors/>
     ///
     /// In the canonical example
     ///
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
index 410f462ed46..46de5dba6e0 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir/src/transform/dest_prop.rs
@@ -8,7 +8,7 @@
 //! inside a single block to shuffle a value around unnecessarily.
 //!
 //! LLVM by itself is not good enough at eliminating these redundant copies (eg. see
-//! https://github.com/rust-lang/rust/issues/32966), so this leaves some performance on the table
+//! <https://github.com/rust-lang/rust/issues/32966>), so this leaves some performance on the table
 //! that we can regain by implementing an optimization for removing these assign statements in rustc
 //! itself. When this optimization runs fast enough, it can also speed up the constant evaluation
 //! and code generation phases of rustc due to the reduced number of statements and locals.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
index 9e096f9ad68..bc85d45d867 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs
@@ -8,7 +8,7 @@
 //! (b) each pattern is necessary (usefulness)
 //!
 //! The algorithm implemented here is a modified version of the one described in:
-//! http://moscova.inria.fr/~maranget/papers/warn/index.html
+//! <http://moscova.inria.fr/~maranget/papers/warn/index.html>
 //! However, to save future implementors from reading the original paper, we
 //! summarise the algorithm here to hopefully save time and be a little clearer
 //! (without being so rigorous).
@@ -2040,7 +2040,7 @@ impl<'tcx> MissingConstructors<'tcx> {
     }
 }
 
-/// Algorithm from http://moscova.inria.fr/~maranget/papers/warn/index.html.
+/// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
 /// The algorithm from the paper has been modified to correctly handle empty
 /// types. The changes are:
 ///   (0) We don't exit early if the pattern matrix has zero rows. We just
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 32b124970cf..0dfacd78908 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -511,7 +511,7 @@ impl<'a> StringReader<'a> {
     }
 
     /// Note: It was decided to not add a test case, because it would be to big.
-    /// https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180
+    /// <https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180>
     fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
         self.fatal_span_(
             start,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 4c0941120a6..75d75433f1b 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -38,7 +38,7 @@ use std::{cmp, fmt, mem};
 /// Implemented to visit all `DefId`s in a type.
 /// Visiting `DefId`s is useful because visibilities and reachabilities are attached to them.
 /// The idea is to visit "all components of a type", as documented in
-/// https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type.
+/// <https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type>.
 /// The default type visitor (`TypeVisitor`) does most of the job, but it has some shortcomings.
 /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s
 /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index 8991691a9a3..76c0bf419e8 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -3,7 +3,7 @@
 //!
 //! Table of CRT objects for popular toolchains.
 //! The `crtx` ones are generally distributed with libc and the `begin/end` ones with gcc.
-//! See https://dev.gentoo.org/~vapier/crt.txt for some more details.
+//! See <https://dev.gentoo.org/~vapier/crt.txt> for some more details.
 //!
 //! | Pre-link CRT objects | glibc                  | musl                   | bionic           | mingw             | wasi |
 //! |----------------------|------------------------|------------------------|------------------|-------------------|------|
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index ba9e2f7fa06..d3c5a9433d0 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -950,7 +950,7 @@ pub struct TargetOptions {
     /// The MergeFunctions pass is generally useful, but some targets may need
     /// to opt out. The default is "aliases".
     ///
-    /// Workaround for: https://github.com/rust-lang/rust/issues/57356
+    /// Workaround for: <https://github.com/rust-lang/rust/issues/57356>
     pub merge_functions: MergeFunctions,
 
     /// Use platform dependent mcount function
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 19609b0d496..1ef0a819378 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -8,7 +8,7 @@
 //! (e.g. trying to create a TCP stream or something like that).
 //!
 //! This target is more or less managed by the Rust and WebAssembly Working
-//! Group nowadays at https://github.com/rustwasm.
+//! Group nowadays at <https://github.com/rustwasm>.
 
 use super::wasm32_base;
 use super::{LinkerFlavor, LldFlavor, Target};
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index 26e0722fcf0..8c2bb920829 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -7,7 +7,7 @@
 //! intended to empower WebAssembly binaries with native capabilities such as
 //! filesystem access, network access, etc.
 //!
-//! You can see more about the proposal at https://wasi.dev
+//! You can see more about the proposal at <https://wasi.dev>.
 //!
 //! The Rust target definition here is interesting in a few ways. We want to
 //! serve two use cases here with this target:
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 50efbbbe0fd..32e0991733b 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -621,7 +621,7 @@ fn object_ty_for_trait<'tcx>(
 ///
 /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
 /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
-/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
+/// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>).
 /// Instead, we fudge a little by introducing a new type parameter `U` such that
 /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
 /// Written as a chalk-style query:
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index fa5655ca35f..cdde0941470 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -32,7 +32,7 @@ pub use poll_fn::{poll_fn, PollFn};
 /// This type is needed because:
 ///
 /// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass
-///    a raw pointer (see https://github.com/rust-lang/rust/issues/68923).
+///    a raw pointer (see <https://github.com/rust-lang/rust/issues/68923>).
 /// b) Raw pointers and `NonNull` aren't `Send` or `Sync`, so that would make every single future
 ///    non-Send/Sync as well, and we don't want that.
 ///
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 7d0ba97de6e..0e3129607a6 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -9,7 +9,7 @@
 //! This includes changes in the stability of the constness.
 //!
 //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation
-//! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to
+//! from <https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs> to
 //! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a
 //! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic.
 //!
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index b89ec93834f..069e6e7e718 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -287,6 +287,7 @@ pub mod primitive;
     unused_imports,
     unsafe_op_in_unsafe_fn
 )]
+#[cfg_attr(not(bootstrap), allow(non_autolinks))]
 // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
 // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
 #[allow(clashing_extern_declarations)]
diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs
index 6f3a3a86745..039112e9f34 100644
--- a/library/core/src/num/dec2flt/mod.rs
+++ b/library/core/src/num/dec2flt/mod.rs
@@ -33,7 +33,7 @@
 //!
 //! Primarily, this module and its children implement the algorithms described in:
 //! "How to Read Floating Point Numbers Accurately" by William D. Clinger,
-//! available online: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.45.4152
+//! available online: <http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.45.4152>
 //!
 //! In addition, there are numerous helper functions that are used in the paper but not available
 //! in Rust (or at least in core). Our version is additionally complicated by the need to handle
diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs
index 71d2c2c9b2f..2a7693d27ef 100644
--- a/library/core/src/slice/sort.rs
+++ b/library/core/src/slice/sort.rs
@@ -1,7 +1,7 @@
 //! Slice sorting
 //!
 //! This module contains a sorting algorithm based on Orson Peters' pattern-defeating quicksort,
-//! published at: https://github.com/orlp/pdqsort
+//! published at: <https://github.com/orlp/pdqsort>
 //!
 //! Unstable sorting is compatible with libcore because it doesn't allocate memory, unlike our
 //! stable sorting implementation.
diff --git a/library/panic_unwind/src/dwarf/eh.rs b/library/panic_unwind/src/dwarf/eh.rs
index 8ce4dcd2acd..6dbf7c11b4c 100644
--- a/library/panic_unwind/src/dwarf/eh.rs
+++ b/library/panic_unwind/src/dwarf/eh.rs
@@ -1,9 +1,9 @@
 //! Parsing of GCC-style Language-Specific Data Area (LSDA)
 //! For details see:
-//!   http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
-//!   http://mentorembedded.github.io/cxx-abi/exceptions.pdf
-//!   http://www.airs.com/blog/archives/460
-//!   http://www.airs.com/blog/archives/464
+//!  * <http://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html>
+//!  * <http://mentorembedded.github.io/cxx-abi/exceptions.pdf>
+//!  * <http://www.airs.com/blog/archives/460>
+//!  * <http://www.airs.com/blog/archives/464>
 //!
 //! A reference implementation may be found in the GCC source tree
 //! (`<root>/libgcc/unwind-c.c` as of this writing).
diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs
index 6b88bab8277..14f49bbf483 100644
--- a/library/panic_unwind/src/gcc.rs
+++ b/library/panic_unwind/src/gcc.rs
@@ -4,9 +4,9 @@
 //! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
 //! documents linked from it.
 //! These are also good reads:
-//!     https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html
-//!     http://monoinfinito.wordpress.com/series/exception-handling-in-c/
-//!     http://www.airs.com/blog/index.php?s=exception+frames
+//!  * <https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html>
+//!  * <http://monoinfinito.wordpress.com/series/exception-handling-in-c/>
+//!  * <http://www.airs.com/blog/index.php?s=exception+frames>
 //!
 //! ## A brief summary
 //!
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 8740393288c..205524ad84f 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -152,7 +152,7 @@ impl Step for ToolStateCheck {
     /// error if there are any.
     ///
     /// This also handles publishing the results to the `history` directory of
-    /// the toolstate repo https://github.com/rust-lang-nursery/rust-toolstate
+    /// the toolstate repo <https://github.com/rust-lang-nursery/rust-toolstate>
     /// if the env var `TOOLSTATE_PUBLISH` is set. Note that there is a
     /// *separate* step of updating the `latest.json` file and creating GitHub
     /// issues and comments in `src/ci/publish_toolstate.sh`, which is only
@@ -162,7 +162,7 @@ impl Step for ToolStateCheck {
     /// The rules for failure are:
     /// * If the PR modifies a tool, the status must be test-pass.
     ///   NOTE: There is intent to change this, see
-    ///   https://github.com/rust-lang/rust/issues/65000.
+    ///   <https://github.com/rust-lang/rust/issues/65000>.
     /// * All "stable" tools must be test-pass on the stable or beta branches.
     /// * During beta promotion week, a PR is not allowed to "regress" a
     ///   stable tool. That is, the status is not allowed to get worse
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index e30da8d56e1..80f804174ed 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -32,7 +32,7 @@ macro_rules! t {
 
 /// Reads an environment variable and adds it to dependencies.
 /// Supposed to be used for all variables except those set for build scripts by cargo
-/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
+/// <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
 pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
     println!("cargo:rerun-if-env-changed={}", key);
     env::var_os(key)
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index cb9099cd50b..41292b3d838 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -285,3 +285,41 @@ warning: unclosed HTML tag `h1`
 
 warning: 2 warnings emitted
 ```
+
+## non_autolinks
+
+This lint is **nightly-only** and **warns by default**. It detects links which
+could use the "automatic" link syntax. For example:
+
+```rust
+/// http://example.org
+/// [http://example.com](http://example.com)
+/// [http://example.net]
+///
+/// [http://example.com]: http://example.com
+pub fn foo() {}
+```
+
+Which will give:
+
+```text
+warning: this URL is not a hyperlink
+ --> foo.rs:1:5
+  |
+1 | /// http://example.org
+  |     ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.org>`
+  |
+  = note: `#[warn(non_autolinks)]` on by default
+
+warning: unneeded long form for URL
+ --> foo.rs:2:5
+  |
+2 | /// [http://example.com](http://example.com)
+  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.com>`
+
+warning: this URL is not a hyperlink
+ --> foo.rs:3:6
+  |
+3 | /// [http://example.net]
+  |      ^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://example.net>`
+```
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index a40a44fe27d..b0f5bac6abd 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -16,6 +16,7 @@ serde_json = "1.0"
 smallvec = "1.0"
 tempfile = "3"
 itertools = "0.9"
+regex = "1"
 
 [dev-dependencies]
 expect-test = "1.0"
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 45a84c4fb30..5eca54199d6 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -330,6 +330,7 @@ pub fn run_core(
     let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
     let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name;
     let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name;
+    let non_autolinks = rustc_lint::builtin::NON_AUTOLINKS.name;
     let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name;
 
     // In addition to those specific lints, we also need to allow those given through
@@ -344,6 +345,7 @@ pub fn run_core(
         invalid_html_tags.to_owned(),
         renamed_and_removed_lints.to_owned(),
         unknown_lints.to_owned(),
+        non_autolinks.to_owned(),
     ];
 
     let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
@@ -663,7 +665,7 @@ fn run_global_ctxt(
     (krate, ctxt.renderinfo.into_inner(), ctxt.render_options)
 }
 
-/// Due to https://github.com/rust-lang/rust/pull/73566,
+/// Due to <https://github.com/rust-lang/rust/pull/73566>,
 /// the name resolution pass may find errors that are never emitted.
 /// If typeck is called after this happens, then we'll get an ICE:
 /// 'Res::Error found but not reported'. To avoid this, emit the errors now.
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 2591650e3f9..047a73835c8 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -11,6 +11,9 @@ use crate::core::DocContext;
 mod stripper;
 pub use stripper::*;
 
+mod non_autolinks;
+pub use self::non_autolinks::CHECK_NON_AUTOLINKS;
+
 mod collapse_docs;
 pub use self::collapse_docs::COLLAPSE_DOCS;
 
@@ -90,6 +93,7 @@ pub const PASSES: &[Pass] = &[
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
     CHECK_INVALID_HTML_TAGS,
+    CHECK_NON_AUTOLINKS,
 ];
 
 /// The list of passes run by default.
@@ -105,6 +109,7 @@ pub const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
     ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
+    ConditionalPass::always(CHECK_NON_AUTOLINKS),
 ];
 
 /// The list of default passes run when `--doc-coverage` is passed to rustdoc.
diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/non_autolinks.rs
new file mode 100644
index 00000000000..4a8fc7fc618
--- /dev/null
+++ b/src/librustdoc/passes/non_autolinks.rs
@@ -0,0 +1,139 @@
+use super::{span_of_attrs, Pass};
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::html::markdown::opts;
+use core::ops::Range;
+use pulldown_cmark::{Event, LinkType, Parser, Tag};
+use regex::Regex;
+use rustc_errors::Applicability;
+use rustc_feature::UnstableFeatures;
+use rustc_session::lint;
+
+pub const CHECK_NON_AUTOLINKS: Pass = Pass {
+    name: "check-non-autolinks",
+    run: check_non_autolinks,
+    description: "detects URLS that could be written using angle brackets",
+};
+
+const URL_REGEX: &str = concat!(
+    r"https?://",                          // url scheme
+    r"([-a-zA-Z0-9@:%._\+~#=]{2,256}\.)+", // one or more subdomains
+    r"[a-zA-Z]{2,63}",                     // root domain
+    r"\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)"      // optional query or url fragments
+);
+
+struct NonAutolinksLinter<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
+    regex: Regex,
+}
+
+impl<'a, 'tcx> NonAutolinksLinter<'a, 'tcx> {
+    fn new(cx: &'a DocContext<'tcx>) -> Self {
+        Self { cx, regex: Regex::new(URL_REGEX).expect("failed to build regex") }
+    }
+
+    fn find_raw_urls(
+        &self,
+        text: &str,
+        range: Range<usize>,
+        f: &impl Fn(&DocContext<'_>, &str, &str, Range<usize>),
+    ) {
+        // For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
+        for match_ in self.regex.find_iter(&text) {
+            let url = match_.as_str();
+            let url_range = match_.range();
+            f(
+                self.cx,
+                "this URL is not a hyperlink",
+                url,
+                Range { start: range.start + url_range.start, end: range.start + url_range.end },
+            );
+        }
+    }
+}
+
+pub fn check_non_autolinks(krate: Crate, cx: &DocContext<'_>) -> Crate {
+    if !UnstableFeatures::from_environment().is_nightly_build() {
+        krate
+    } else {
+        let mut coll = NonAutolinksLinter::new(cx);
+
+        coll.fold_crate(krate)
+    }
+}
+
+impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> {
+    fn fold_item(&mut self, item: Item) -> Option<Item> {
+        let hir_id = match self.cx.as_local_hir_id(item.def_id) {
+            Some(hir_id) => hir_id,
+            None => {
+                // If non-local, no need to check anything.
+                return self.fold_item_recur(item);
+            }
+        };
+        let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
+        if !dox.is_empty() {
+            let report_diag = |cx: &DocContext<'_>, msg: &str, url: &str, range: Range<usize>| {
+                let sp = super::source_span_for_markdown_range(cx, &dox, &range, &item.attrs)
+                    .or_else(|| span_of_attrs(&item.attrs))
+                    .unwrap_or(item.source.span());
+                cx.tcx.struct_span_lint_hir(lint::builtin::NON_AUTOLINKS, hir_id, sp, |lint| {
+                    lint.build(msg)
+                        .span_suggestion(
+                            sp,
+                            "use an automatic link instead",
+                            format!("<{}>", url),
+                            Applicability::MachineApplicable,
+                        )
+                        .emit()
+                });
+            };
+
+            let mut p = Parser::new_ext(&dox, opts()).into_offset_iter();
+
+            while let Some((event, range)) = p.next() {
+                match event {
+                    Event::Start(Tag::Link(kind, _, _)) => {
+                        let ignore = matches!(kind, LinkType::Autolink | LinkType::Email);
+                        let mut title = String::new();
+
+                        while let Some((event, range)) = p.next() {
+                            match event {
+                                Event::End(Tag::Link(_, url, _)) => {
+                                    // NOTE: links cannot be nested, so we don't need to
+                                    // check `kind`
+                                    if url.as_ref() == title && !ignore && self.regex.is_match(&url)
+                                    {
+                                        report_diag(
+                                            self.cx,
+                                            "unneeded long form for URL",
+                                            &url,
+                                            range,
+                                        );
+                                    }
+                                    break;
+                                }
+                                Event::Text(s) if !ignore => title.push_str(&s),
+                                _ => {}
+                            }
+                        }
+                    }
+                    Event::Text(s) => self.find_raw_urls(&s, range, &report_diag),
+                    Event::Start(Tag::CodeBlock(_)) => {
+                        // We don't want to check the text inside the code blocks.
+                        while let Some((event, _)) = p.next() {
+                            match event {
+                                Event::End(Tag::CodeBlock(_)) => break,
+                                _ => {}
+                            }
+                        }
+                    }
+                    _ => {}
+                }
+            }
+        }
+
+        self.fold_item_recur(item)
+    }
+}
diff --git a/src/test/rustdoc-ui/url-improvements.rs b/src/test/rustdoc-ui/url-improvements.rs
new file mode 100644
index 00000000000..8531583d38a
--- /dev/null
+++ b/src/test/rustdoc-ui/url-improvements.rs
@@ -0,0 +1,66 @@
+#![deny(non_autolinks)]
+
+/// [http://aa.com](http://aa.com)
+//~^ ERROR unneeded long form for URL
+/// [http://bb.com]
+//~^ ERROR unneeded long form for URL
+///
+/// [http://bb.com]: http://bb.com
+///
+/// [http://c.com][http://c.com]
+pub fn a() {}
+
+/// https://somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com
+//~^ ERROR this URL is not a hyperlink
+/// https://www.somewhere.com/a
+//~^ ERROR this URL is not a hyperlink
+/// https://subdomain.example.com
+//~^ ERROR not a hyperlink
+/// https://somewhere.com?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a?hello=12#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://example.com/a#xyz
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com/a?hello=12&bye=11
+//~^ ERROR this URL is not a hyperlink
+/// https://somewhere.com?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+/// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+//~^ ERROR this URL is not a hyperlink
+pub fn c() {}
+
+/// <https://somewhere.com>
+/// [a](http://a.com)
+/// [b]
+///
+/// [b]: http://b.com
+///
+/// ```
+/// This link should not be linted: http://example.com
+/// ```
+///
+/// [should_not.lint](should_not.lint)
+pub fn everything_is_fine_here() {}
+
+#[allow(non_autolinks)]
+pub mod foo {
+    /// https://somewhere.com/a?hello=12&bye=11#xyz
+    pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/url-improvements.stderr b/src/test/rustdoc-ui/url-improvements.stderr
new file mode 100644
index 00000000000..70ad4b06a51
--- /dev/null
+++ b/src/test/rustdoc-ui/url-improvements.stderr
@@ -0,0 +1,122 @@
+error: unneeded long form for URL
+  --> $DIR/url-improvements.rs:3:5
+   |
+LL | /// [http://aa.com](http://aa.com)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://aa.com>`
+   |
+note: the lint level is defined here
+  --> $DIR/url-improvements.rs:1:9
+   |
+LL | #![deny(non_autolinks)]
+   |         ^^^^^^^^^^^^^
+
+error: unneeded long form for URL
+  --> $DIR/url-improvements.rs:5:5
+   |
+LL | /// [http://bb.com]
+   |     ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://bb.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:13:5
+   |
+LL | /// https://somewhere.com
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:15:5
+   |
+LL | /// https://somewhere.com/a
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:17:5
+   |
+LL | /// https://www.somewhere.com
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:19:5
+   |
+LL | /// https://www.somewhere.com/a
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://www.somewhere.com/a>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:21:5
+   |
+LL | /// https://subdomain.example.com
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://subdomain.example.com>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:23:5
+   |
+LL | /// https://somewhere.com?
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:25:5
+   |
+LL | /// https://somewhere.com/a?
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:27:5
+   |
+LL | /// https://somewhere.com?hello=12
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:29:5
+   |
+LL | /// https://somewhere.com/a?hello=12
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:31:5
+   |
+LL | /// https://example.com?hello=12#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:33:5
+   |
+LL | /// https://example.com/a?hello=12#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a?hello=12#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:35:5
+   |
+LL | /// https://example.com#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:37:5
+   |
+LL | /// https://example.com/a#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://example.com/a#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:39:5
+   |
+LL | /// https://somewhere.com?hello=12&bye=11
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:41:5
+   |
+LL | /// https://somewhere.com/a?hello=12&bye=11
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:43:5
+   |
+LL | /// https://somewhere.com?hello=12&bye=11#xyz
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com?hello=12&bye=11#xyz>`
+
+error: this URL is not a hyperlink
+  --> $DIR/url-improvements.rs:45:10
+   |
+LL | /// hey! https://somewhere.com/a?hello=12&bye=11#xyz
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use an automatic link instead: `<https://somewhere.com/a?hello=12&bye=11#xyz>`
+
+error: aborting due to 19 previous errors
+