[llvm-branch-commits] [llvm] [4/4]: [docs] Enforce unambiguous toctree in llvm/docs (PR #203967)

Scott Linder via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Tue Jun 23 10:10:30 PDT 2026


https://github.com/slinder1 updated https://github.com/llvm/llvm-project/pull/203967

>From fef10fe00c9476c5b5793c6a65eee918c33ffed5 Mon Sep 17 00:00:00 2001
From: Scott Linder <Scott.Linder at amd.com>
Date: Fri, 12 Jun 2026 20:44:17 +0000
Subject: [PATCH] [docs] Enforce unambiguous toctree in llvm/docs

It seems like using a non-`hidden` `toctree` for page navigation is a
bit of a trap, in that every doc must have a single unique path through
the global toctree to the root doc, and it is very easy to end up with
multiple.

This patch tries to address the warnings (actually infos, hence why it
does not fail the build) in llvm/docs/, namely:

  $ sphinx-build -b html -jauto llvm/docs/ /tmp/sphinx-out
  checking consistency...
  llvm/docs/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack.md: document is referenced in multiple toctrees: ['UserGuides', 'AMDGPUUsage'], selecting: UserGuides <- AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack
  llvm/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.rst: document is referenced in multiple toctrees: ['UserGuides', 'AMDGPUUsage'], selecting: UserGuides <- AMDGPUDwarfExtensionsForHeterogeneousDebugging
  llvm/docs/CommandGuide/llvm-reduce.rst: document is referenced in multiple toctrees: ['CommandGuide/index', 'CommandGuide/index', 'Reference'], selecting: Reference <- CommandGuide/llvm-reduce
  llvm/docs/GitHub.rst: document is referenced in multiple toctrees: ['GettingInvolved', 'UserGuides'], selecting: UserGuides <- GitHub
  llvm/docs/GlobalISel/IRTranslator.rst: document is referenced in multiple toctrees: ['GlobalISel/index', 'GlobalISel/Pipeline'], selecting: GlobalISel/index <- GlobalISel/IRTranslator
  llvm/docs/GlobalISel/InstructionSelect.rst: document is referenced in multiple toctrees: ['GlobalISel/index', 'GlobalISel/Pipeline'], selecting: GlobalISel/index <- GlobalISel/InstructionSelect
  llvm/docs/GlobalISel/Legalizer.rst: document is referenced in multiple toctrees: ['GlobalISel/index', 'GlobalISel/Pipeline'], selecting: GlobalISel/index <- GlobalISel/Legalizer
  llvm/docs/GlobalISel/MIRPatterns.rst: document is referenced in multiple toctrees: ['GlobalISel/index', 'UserGuides'], selecting: UserGuides <- GlobalISel/MIRPatterns
  llvm/docs/GlobalISel/RegBankSelect.rst: document is referenced in multiple toctrees: ['GlobalISel/index', 'GlobalISel/Pipeline'], selecting: GlobalISel/index <- GlobalISel/RegBankSelect
  llvm/docs/TestSuiteGuide.md: document is referenced in multiple toctrees: ['Reference', 'TestingGuide'], selecting: TestingGuide <- TestSuiteGuide
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl01
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl02
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl03.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl03
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl04.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl04
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl05.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl05
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl06.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl06
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl07.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl07
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl08.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl08
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl09.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl09
  llvm/docs/tutorial/MyFirstLanguageFrontend/LangImpl10.rst: document is referenced in multiple toctrees: ['tutorial/index', 'tutorial/MyFirstLanguageFrontend/index'], selecting: tutorial/index <- tutorial/MyFirstLanguageFrontend/LangImpl10

I tried to preserve the documents as-is, by hiding `toctree`s and
instead using lists of `{doc}` forms where the `toctree` was visible
before.

The only visual change in the resulting HTML is that the link is now
underlined where it wasn't before.

I also nested the `Tutorials` section in GISel Porting document, and
didn't link to it directly as the title is a bit ambiguous without the
context of the document it appears in.

I also saw warnings about a jump in heading level in
`llvm-debuginfo-analyzer/README.md` and assumed it was just a mistake,
so I collapsed the level-3 headings down to level-2.

Finally, I wrote a sphinx extension to make ambiguous toctree entries
into errors, so the docs do not regress. I hope to fix other sphinx
project in llvm-project and enable the checks for them too, assuming
this patch is accepted.

Change-Id: Icb11de69be1ea5489fba501aee4d767f5129e7e1
---
 llvm/docs/CommandGuide/index.md               | 159 +++++++++++-------
 llvm/docs/GettingInvolved.md                  |   1 -
 llvm/docs/GlobalISel/Pipeline.rst             |   8 -
 llvm/docs/GlobalISel/Porting.rst              |   2 +-
 llvm/docs/GlobalISel/index.rst                |  51 +++---
 llvm/docs/Reference.md                        |   3 -
 llvm/docs/UserGuides.md                       |   3 -
 llvm/docs/conf.py                             |   2 +-
 .../MyFirstLanguageFrontend/index.rst         |  14 --
 llvm/tools/llvm-debuginfo-analyzer/README.md  |  42 ++---
 utils/docs/llvm_sphinx/ext/checks.py          |  50 ++++++
 11 files changed, 205 insertions(+), 130 deletions(-)
 create mode 100644 utils/docs/llvm_sphinx/ext/checks.py

diff --git a/llvm/docs/CommandGuide/index.md b/llvm/docs/CommandGuide/index.md
index 6b126837343e2..ac90d9468b848 100644
--- a/llvm/docs/CommandGuide/index.md
+++ b/llvm/docs/CommandGuide/index.md
@@ -1,104 +1,149 @@
 # LLVM Command Guide
 
-The following documents are command descriptions for all of the LLVM tools.
-These pages describe how to use the LLVM commands and what their options are.
-Note that these pages do not describe all of the options available for all
-tools. To get a complete listing, pass the `--help` (general options) or
-`--help-hidden` (general and debugging options) arguments to the tool you are
-interested in.
-
-## Basic Commands
-
 ```{toctree}
-:maxdepth: 1
+:hidden:
 
+FileCheck
+clang-tblgen
 dsymutil
+lit
 llc
+lldb-tblgen
 lli
 llubi
+llvm-addr2line
+llvm-ar
 llvm-as
+llvm-bcanalyzer
 llvm-cgdata
 llvm-config
 llvm-cov
+llvm-cxxfilt
 llvm-cxxmap
 llvm-debuginfo-analyzer
 llvm-diff
 llvm-dis
 llvm-dwarfdump
 llvm-dwarfutil
+llvm-exegesis
+llvm-extract
 llvm-extract-bundle-entry
+llvm-ifs
+llvm-install-name-tool
 llvm-ir2vec
 llvm-lib
 llvm-libtool-darwin
 llvm-link
 llvm-lipo
+llvm-locstats
 llvm-mc
 llvm-mca
+llvm-nm
+llvm-objcopy
+llvm-objdump
+llvm-offload-binary
 llvm-opt-report
 llvm-otool
+llvm-pdbutil
 llvm-profdata
+llvm-profgen
+llvm-ranlib
+llvm-readelf
 llvm-readobj
 llvm-reduce
+llvm-remarkutil
+llvm-size
 llvm-stress
+llvm-strings
+llvm-strip
 llvm-symbolizer
+llvm-tblgen
+llvm-test-mustache-spec
+llvm-tli-checker
+mlir-tblgen
 opt
+tblgen
 ```
 
-## GNU binutils replacements
+The following documents are command descriptions for all of the LLVM tools.
+These pages describe how to use the LLVM commands and what their options are.
+Note that these pages do not describe all of the options available for all
+tools. To get a complete listing, pass the `--help` (general options) or
+`--help-hidden` (general and debugging options) arguments to the tool you are
+interested in.
 
-```{toctree}
-:maxdepth: 1
+## Basic Commands
 
-llvm-addr2line
-llvm-ar
-llvm-cxxfilt
-llvm-install-name-tool
-llvm-nm
-llvm-objcopy
-llvm-objdump
-llvm-ranlib
-llvm-readelf
-llvm-size
-llvm-strings
-llvm-strip
-```
+* {doc}`dsymutil`
+* {doc}`llc`
+* {doc}`lli`
+* {doc}`llubi`
+* {doc}`llvm-as`
+* {doc}`llvm-cgdata`
+* {doc}`llvm-config`
+* {doc}`llvm-cov`
+* {doc}`llvm-cxxmap`
+* {doc}`llvm-debuginfo-analyzer`
+* {doc}`llvm-diff`
+* {doc}`llvm-dis`
+* {doc}`llvm-dwarfdump`
+* {doc}`llvm-dwarfutil`
+* {doc}`llvm-extract-bundle-entry`
+* {doc}`llvm-ir2vec`
+* {doc}`llvm-lib`
+* {doc}`llvm-libtool-darwin`
+* {doc}`llvm-link`
+* {doc}`llvm-lipo`
+* {doc}`llvm-mc`
+* {doc}`llvm-mca`
+* {doc}`llvm-opt-report`
+* {doc}`llvm-otool`
+* {doc}`llvm-profdata`
+* {doc}`llvm-readobj`
+* {doc}`llvm-reduce`
+* {doc}`llvm-stress`
+* {doc}`llvm-symbolizer`
+* {doc}`opt`
 
-## Debugging Tools
+## GNU binutils replacements
 
-```{toctree}
-:maxdepth: 1
+* {doc}`llvm-addr2line`
+* {doc}`llvm-ar`
+* {doc}`llvm-cxxfilt`
+* {doc}`llvm-install-name-tool`
+* {doc}`llvm-nm`
+* {doc}`llvm-objcopy`
+* {doc}`llvm-objdump`
+* {doc}`llvm-ranlib`
+* {doc}`llvm-readelf`
+* {doc}`llvm-size`
+* {doc}`llvm-strings`
+* {doc}`llvm-strip`
 
-llvm-extract
-llvm-bcanalyzer
-llvm-reduce
-```
+## Debugging Tools
+
+* {doc}`llvm-extract`
+* {doc}`llvm-bcanalyzer`
+* {doc}`llvm-reduce`
 
 ## Developer Tools
 
-```{toctree}
-:maxdepth: 1
-
-FileCheck
-tblgen
-clang-tblgen
-lldb-tblgen
-llvm-tblgen
-mlir-tblgen
-lit
-llvm-exegesis
-llvm-ifs
-llvm-locstats
-llvm-test-mustache-spec
-llvm-pdbutil
-llvm-profgen
-llvm-tli-checker
-llvm-offload-binary
-```
+* {doc}`FileCheck`
+* {doc}`tblgen`
+* {doc}`clang-tblgen`
+* {doc}`lldb-tblgen`
+* {doc}`llvm-tblgen`
+* {doc}`mlir-tblgen`
+* {doc}`lit`
+* {doc}`llvm-exegesis`
+* {doc}`llvm-ifs`
+* {doc}`llvm-locstats`
+* {doc}`llvm-test-mustache-spec`
+* {doc}`llvm-pdbutil`
+* {doc}`llvm-profgen`
+* {doc}`llvm-tli-checker`
+* {doc}`llvm-offload-binary`
 
 ## Remarks Tools
 
-```{toctree}
-:maxdepth: 1
-
-llvm-remarkutil
-```
+* {doc}`llvm-remarkutil`
diff --git a/llvm/docs/GettingInvolved.md b/llvm/docs/GettingInvolved.md
index a172481f81df9..c7d4584af4770 100644
--- a/llvm/docs/GettingInvolved.md
+++ b/llvm/docs/GettingInvolved.md
@@ -17,7 +17,6 @@ SphinxQuickstartTemplate
 HowToSubmitABug
 BugLifeCycle
 CodingStandards
-GitHub
 GitBisecting
 GitRepositoryPolicy
 ```
diff --git a/llvm/docs/GlobalISel/Pipeline.rst b/llvm/docs/GlobalISel/Pipeline.rst
index b9085e82f1428..8565c8c95178b 100644
--- a/llvm/docs/GlobalISel/Pipeline.rst
+++ b/llvm/docs/GlobalISel/Pipeline.rst
@@ -3,14 +3,6 @@
 Core Pipeline
 =============
 
-.. toctree::
-  :hidden:
-
-  IRTranslator
-  Legalizer
-  RegBankSelect
-  InstructionSelect
-
 The core pipeline of GlobalISel is:
 
 .. image:: pipeline-overview.png
diff --git a/llvm/docs/GlobalISel/Porting.rst b/llvm/docs/GlobalISel/Porting.rst
index 0bc5e7446b83f..89aeeb5f53fcb 100644
--- a/llvm/docs/GlobalISel/Porting.rst
+++ b/llvm/docs/GlobalISel/Porting.rst
@@ -21,7 +21,7 @@ Additionally:
   including additional passes not included in the :ref:`pipeline`.
 
 Tutorials
-=========
+---------
 
 We'd recommend watching `this tutorial
 <https://www.llvm.org/devmtg/2017-10/#tutorial2>`_ from the 2017 LLVM DevMeeting
diff --git a/llvm/docs/GlobalISel/index.rst b/llvm/docs/GlobalISel/index.rst
index 2b639706afdc2..4951e09c257fd 100644
--- a/llvm/docs/GlobalISel/index.rst
+++ b/llvm/docs/GlobalISel/index.rst
@@ -10,8 +10,23 @@ Global Instruction Selection
    :local:
    :depth: 1
 
+.. toctree::
+   :hidden:
+
+   GMIR
+   GenericOpcode
+   MIRPatterns
+   Pipeline
+   Porting
+   Resources
+   IRTranslator
+   Legalizer
+   RegBankSelect
+   InstructionSelect
+   KnownBits
+
 Introduction
-============
+------------
 
 GlobalISel is a framework that provides a set of reusable passes and utilities
 for instruction selection --- translation from LLVM IR to target-specific
@@ -41,36 +56,30 @@ solve three major problems:
   configure that pipeline to better suit their needs.
 
 Design and Implementation Reference
-===================================
+-----------------------------------
 
 More information on the design and implementation of GlobalISel can be found in
 the following sections.
 
-.. toctree::
-  :maxdepth: 1
-
-  GMIR
-  GenericOpcode
-  MIRPatterns
-  Pipeline
-  Porting
-  Resources
+* :doc:`GMIR`
+* :doc:`GenericOpcode`
+* :doc:`MIRPatterns`
+* :doc:`Pipeline`
+* :doc:`Porting`
+* :doc:`Resources`
 
 More information on specific passes can be found in the following sections:
 
-.. toctree::
-  :maxdepth: 1
-
-  IRTranslator
-  Legalizer
-  RegBankSelect
-  InstructionSelect
-  KnownBits
+* :doc:`IRTranslator`
+* :doc:`Legalizer`
+* :doc:`RegBankSelect`
+* :doc:`InstructionSelect`
+* :doc:`KnownBits`
 
 .. _progress:
 
 Progress and Future Work
-========================
+------------------------
 
 The initial goal is to replace FastISel on AArch64.  The next step will be to
 replace SelectionDAG as the optimized ISel.
@@ -84,7 +93,7 @@ that is destroyed after :ref:`instructionselect`.
 .. _progress-fastisel:
 
 FastISel Replacement
---------------------
+^^^^^^^^^^^^^^^^^^^^
 
 For the initial FastISel replacement, we intend to fallback to SelectionDAG on
 selection failures.
diff --git a/llvm/docs/Reference.md b/llvm/docs/Reference.md
index cddcc9056128d..1bbdc8f4582dd 100644
--- a/llvm/docs/Reference.md
+++ b/llvm/docs/Reference.md
@@ -11,7 +11,6 @@ LLVM and API reference documentation.
 
 HowToUseAttributes
 CommandGuide/index
-CommandGuide/llvm-reduce
 OptBisect
 SymbolizerMarkupFormat
 PDB/index
@@ -27,7 +26,6 @@ MIRLangRef
 GlobalISel/index
 ConvergentOperations
 TestingGuide
-TestSuiteGuide
 GwpAsan
 XRay
 XRayExample
@@ -148,7 +146,6 @@ XRayFDRFormat
 {doc}`TestSuiteGuide`
 :   Describes how to compile and run the test-suite benchmarks.
 
-
 {doc}`GwpAsan`
 :   A sampled heap memory error detection toolkit designed for production use.
 
diff --git a/llvm/docs/UserGuides.md b/llvm/docs/UserGuides.md
index 72ebd3b9cedce..e91cdd8975115 100644
--- a/llvm/docs/UserGuides.md
+++ b/llvm/docs/UserGuides.md
@@ -48,7 +48,6 @@ InstCombineContributorGuide
 WritingAnLLVMBackend
 CodeGenerator
 TableGen/index
-GlobalISel/MIRPatterns
 MCJITDesignAndImplementation
 ORCv2
 JITLink
@@ -64,8 +63,6 @@ CompileCudaWithLLVM
 NVPTXUsage
 AMDGPUUsage
 AMDGPUAsyncOperations
-AMDGPUDwarfExtensionsForHeterogeneousDebugging
-AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack/AMDGPUDwarfExtensionAllowLocationDescriptionOnTheDwarfExpressionStack
 AMDGPUExecutionSynchronization
 AMDGPUMemoryModel
 SPIRVUsage
diff --git a/llvm/docs/conf.py b/llvm/docs/conf.py
index 2727f2248e803..8a5d0186250fd 100644
--- a/llvm/docs/conf.py
+++ b/llvm/docs/conf.py
@@ -22,7 +22,7 @@
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions += ["sphinx.ext.intersphinx", "sphinx.ext.todo"]
+extensions += ["sphinx.ext.intersphinx", "sphinx.ext.todo", "llvm_sphinx.ext.checks"]
 
 myst_enable_extensions += ["deflist"]
 myst_url_schemes = {
diff --git a/llvm/docs/tutorial/MyFirstLanguageFrontend/index.rst b/llvm/docs/tutorial/MyFirstLanguageFrontend/index.rst
index 669df43111cc7..230313ddd21db 100644
--- a/llvm/docs/tutorial/MyFirstLanguageFrontend/index.rst
+++ b/llvm/docs/tutorial/MyFirstLanguageFrontend/index.rst
@@ -2,20 +2,6 @@
 My First Language Frontend with LLVM Tutorial
 =============================================
 
-.. toctree::
-   :hidden:
-
-   LangImpl01
-   LangImpl02
-   LangImpl03
-   LangImpl04
-   LangImpl05
-   LangImpl06
-   LangImpl07
-   LangImpl08
-   LangImpl09
-   LangImpl10
-
 **Requirements:** This tutorial assumes you know C++, but no previous
 compiler experience is necessary.
 
diff --git a/llvm/tools/llvm-debuginfo-analyzer/README.md b/llvm/tools/llvm-debuginfo-analyzer/README.md
index 28c4be6f73229..6b2d392c57d5d 100644
--- a/llvm/tools/llvm-debuginfo-analyzer/README.md
+++ b/llvm/tools/llvm-debuginfo-analyzer/README.md
@@ -3,14 +3,14 @@
 These are the notes collected during the development, review and test.
 They describe limitations, known issues and future work.
 
-### Remove the use of macros in ``LVReader.h`` that describe the ``bumpallocators``.
+## Remove the use of macros in ``LVReader.h`` that describe the ``bumpallocators``.
 **[D137933](https://reviews.llvm.org/D137933#inline-1389904)**
 
 Use a standard (or LLVM) ``map`` with ``typeinfo`` (would need a specialization
 to expose equality and hasher) for the allocators and the creation
 functions could be a function template.
 
-### Use a **lit test** instead of a **unit test** for the **logical readers**.
+## Use a **lit test** instead of a **unit test** for the **logical readers**.
 **[D125783](https://reviews.llvm.org/D125783#inline-1324376)**
 
 As the ``DebugInfoLogicalView`` library is sufficiently exposed via the
@@ -28,7 +28,7 @@ llvm-project/llvm/test/DebugInfo/LogicalView/CodeViewReader.test
 llvm-project/llvm/test/DebugInfo/LogicalView/DWARFReader.test
 ```
 
-### Eliminate calls to ``getInputFileDirectory()`` in the ``unittests``.
+## Eliminate calls to ``getInputFileDirectory()`` in the ``unittests``.
 **[D125783](https://reviews.llvm.org/D125783#inline-1324359)**
 
 Rewrite the unittests ``ReaderTest`` and ``CodeViewReaderTest`` to eliminate
@@ -38,37 +38,37 @@ the call:
 ```
 as use of that call is discouraged.
 
-### Fix mismatch between ``%d/%x`` format strings and ``uint64_t`` type.
+## Fix mismatch between ``%d/%x`` format strings and ``uint64_t`` type.
 **[D137400](https://reviews.llvm.org/D137400) / [58758](https://github.com/llvm/llvm-project/issues/58758)**
 
 Incorrect printing of ``uint64_t`` on ``32-bit`` platforms.
 Add the ``PRIx64`` specifier to the printing code (``format()``).
 
-### Remove ``LVScope::Children`` container.
+## Remove ``LVScope::Children`` container.
 **[D137933](https://reviews.llvm.org/D137933#inline-1373902)**
 
 Use a **chaining iterator** over the other containers rather than keep a
 separate container ``Children`` that mirrors their contents.
 
-### Use ``TableGen`` for command line options.
+## Use ``TableGen`` for command line options.
 **[D125777](https://reviews.llvm.org/D125777#inline-1291801)**
 
 The current trend is to use ``TableGen`` for command-line options in tools.
 Change command line options to use ``tablegen`` as many other LLVM tools.
 
-### ``LVDoubleMap`` to return ``optional<ValueType>`` instead of ``null pointer``.
+## ``LVDoubleMap`` to return ``optional<ValueType>`` instead of ``null pointer``.
 **[D125783](https://reviews.llvm.org/D125783#inline-1294164)**
 
 The more idiomatic LLVM way to handle this would be to have ``find``
 return ``Optional<ValueType>``.
 
-### Pass references instead of pointers (**Comparison functions**).
+## Pass references instead of pointers (**Comparison functions**).
 **[D125782](https://reviews.llvm.org/D125782#inline-1293920)**
 
 In the **comparison functions**, pass references instead of pointers (when
 pointers cannot be null).
 
-### Use ``StringMap`` where possible.
+## Use ``StringMap`` where possible.
 **[D125783](https://reviews.llvm.org/D125783#inline-1294211)**
 
 LLVM has a ``StringMap`` class that is advertised as more efficient than
@@ -78,7 +78,7 @@ because the key is not a ``std::string``.
 Replace the use of ``std::map<std::string, ValueType>`` with ``StringMap``.
 One specific case is the ``LVSymbolNames`` definitions.
 
-### Calculate unique offset for CodeView elements.
+## Calculate unique offset for CodeView elements.
 In order to have the same logical functionality as the DWARF reader, such
 as:
 
@@ -88,7 +88,7 @@ as:
 The logical elements must have an unique offset (similar like the DWARF
 ``DIE`` offset).
 
-### Move ``initializeFileAndStringTables`` to the CodeView Library.
+## Move ``initializeFileAndStringTables`` to the CodeView Library.
 There is some code in the CodeView reader that was extracted/adapted
 from ``tools/llvm-readobj/COFFDumper.cpp`` that can be moved to the CodeView
 library.
@@ -96,18 +96,18 @@ library.
 We had a similar case with code shared with ``llvm-pdbutil`` that was moved
 to the PDB library: **[D122226](https://reviews.llvm.org/D122226)**
 
-### Move ``getSymbolKindName`` and ``formatRegisterId`` to the CodeView Library.
+## Move ``getSymbolKindName`` and ``formatRegisterId`` to the CodeView Library.
 There is some code in the CodeView reader that was extracted/adapted
 from ``lib/DebugInfo/CodeView/SymbolDumper.cpp`` that can be used.
 
-### Use of ``std::unordered_set`` instead of ``std::set``.
+## Use of ``std::unordered_set`` instead of ``std::set``.
 **[D125784](https://reviews.llvm.org/D125784#inline-1221421)**
 
 Replace the ``std::set`` usage for ``DeducedScopes``, ``UnresolvedScopes`` and
 ``IdentifiedNamespaces`` with ``std::unordered_set`` and get the benefit
 of the O(1) while inserting/searching, as the order is not important.
 
-### Optimize ``LVNamespaceDeduction::find`` funtion.
+## Optimize ``LVNamespaceDeduction::find`` funtion.
 **[D125784](https://reviews.llvm.org/D125784#inline-1296195)**
 
 Optimize the ``find`` method to use the proposed code:
@@ -120,11 +120,11 @@ Optimize the ``find`` method to use the proposed code:
   LVStringRefs::size_type FirstNonNamespace = std::distance(Components.begin(), Iter);
 ```
 
-### Move all the printing support to a common module.
+## Move all the printing support to a common module.
 Factor out printing functionality from the logical elements into a
 common module.
 
-### Refactor ``LVBinaryReader::processLines``.
+## Refactor ``LVBinaryReader::processLines``.
 **[D125783](https://reviews.llvm.org/D125783#inline-1246155) /
 [D137156](https://reviews.llvm.org/D137156)**
 
@@ -137,13 +137,13 @@ we will allocate those logical lines to their logical scopes.
 Consider the case when any of those lines become orphans, causing
 incorrect scope parent for disassembly or line records.
 
-### Add support for ``-ffunction-sections``.
+## Add support for ``-ffunction-sections``.
 **[D125783](https://reviews.llvm.org/D125783#inline-1295012)**
 
 Only linked executables are handled. It does not support relocatable
 files compiled with ``-ffunction-sections``.
 
-### Add support for DWARF v5 `.debug_names` section / CodeView public symbols stream.
+## Add support for DWARF v5 `.debug_names` section / CodeView public symbols stream.
 **[D125783](https://reviews.llvm.org/D125783#inline-1294142)**
 
 The DWARF and CodeView readers use the public names information to create
@@ -155,16 +155,16 @@ the debug information.
 If the object file supports the above section names and stream, use them
 to create the public names.
 
-### Add support for some extra DWARF locations.
+## Add support for some extra DWARF locations.
 The following DWARF debug location operands are not supported:
 
 * `DW_OP_const_type`
 * `DW_OP_entry_value`
 * `DW_OP_implicit_value`
 
-### Add support for additional binary formats.
+## Add support for additional binary formats.
 * Extended COFF (`XCOFF`)
 
-### Add support for ``JSON`` or ``YAML``
+## Add support for ``JSON`` or ``YAML``
 The logical view uses its own and non-standard free form text when
 displaying information on logical elements.
diff --git a/utils/docs/llvm_sphinx/ext/checks.py b/utils/docs/llvm_sphinx/ext/checks.py
new file mode 100644
index 0000000000000..105cd571f44c9
--- /dev/null
+++ b/utils/docs/llvm_sphinx/ext/checks.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+
+"""Sphinx extension for llvm-project checks/lints.
+
+Enable by adding "llvm_sphinx.checks" to the sphinx `extensions` list.
+"""
+
+import sys
+from typing import Dict, List
+from llvm_sphinx.help import venv_help
+
+try:
+    from sphinx.application import Sphinx
+    from sphinx.environment import BuildEnvironment
+    from sphinx.util import logging
+    from sphinx.errors import ExtensionError
+except ImportError as err:
+    print(venv_help(err), file=sys.stderr)
+    raise
+
+__version__ = "1.0"
+
+logger = logging.getLogger("llvm_sphinx.ext.checks")
+
+
+def setup(app: Sphinx) -> Dict[str, object]:
+    app.connect("env-updated", check_env)
+    return {
+        "version": __version__,
+        "parallel_read_safe": True,
+        "parallel_write_safe": True,
+    }
+
+
+def check_env(app: Sphinx, env: BuildEnvironment) -> None:
+    toc_parents: Dict[str, List[str]] = {}
+    for parent, children in env.toctree_includes.items():
+        for child in children:
+            toc_parents.setdefault(child, []).append(parent)
+
+    for doc, parents in sorted(toc_parents.items()):
+        if len(parents) > 1:
+            # sphinx considers this an `info` only, and silently picks one
+            # parent arbitrarily. We upgrade this to an `error` to ensure
+            # we don't accumulate a growing list of offending toctrees.
+            logger.error(
+                "document is referenced in multiple toctrees: %s",
+                parents,
+                location=doc,
+            )



More information about the llvm-branch-commits mailing list