# Buggy code
def _add_symbols(self, nestedName, templateDecls, declaration, docname):
    # This condition should be checked at the parser level.
    # Each template argument list must have a template parameter list.
    # But to declare a template there must be an additional template parameter list.
    assert nestedName.num_templates() == len(
        templateDecls
    ) or nestedName.num_templates() + 1 == len(templateDecls)

    parentSymbol = self
    if nestedName.rooted:
        while parentSymbol.parent:
            parentSymbol = parentSymbol.parent
    names = nestedName.names
    iTemplateDecl = 0
    for name in names[:-1]:
        # there shouldn't be anything inside an operator
        # (other than template parameters, which are not added this way, right?)
        assert not name.is_operator()
        identifier = name.identifier
        templateArgs = name.templateArgs
        if templateArgs:
            assert iTemplateDecl < len(templateDecls)
            templateParams = templateDecls[iTemplateDecl]
            iTemplateDecl += 1
        else:
            templateParams = None
        symbol = parentSymbol._find_named_symbol(
            identifier,
            templateParams,
            templateArgs,
            operator=None,
            templateShorthand=False,
            matchSelf=False,
        )
        if symbol is None:
            symbol = Symbol(
                parent=parentSymbol,
                identifier=identifier,
                templateParams=templateParams,
                templateArgs=templateArgs,
                declaration=None,
                docname=None,
            )
        parentSymbol = symbol
    name = names[-1]
    if name.is_operator():
        identifier = None
        templateArgs = None
        operator = name
    else:
        identifier = name.identifier
        templateArgs = name.templateArgs
        operator = None
    if iTemplateDecl < len(templateDecls):
        if iTemplateDecl + 1 != len(templateDecls):
            print(text_type(templateDecls))
            print(text_type(nestedName))
        assert iTemplateDecl + 1 == len(templateDecls)
        templateParams = templateDecls[iTemplateDecl]
    else:
        assert iTemplateDecl == len(templateDecls)
        templateParams = None
    symbol = parentSymbol._find_named_symbol(
        identifier,
        templateParams,
        templateArgs,
        operator,
        templateShorthand=False,
        matchSelf=False,
    )
    if symbol:
        if not declaration:
            # good, just a scope creation
            return symbol
        if not symbol.declaration:
            # If someone first opened the scope, and then later
            # declares it, e.g,
            # .. namespace:: Test
            # .. namespace:: nullptr
            # .. class:: Test
            symbol._fill_empty(declaration, docname)
            return symbol
        # it may simply be a functin overload
        # TODO: it could be a duplicate but let's just insert anyway
        # the id generation will warn about it
        symbol = Symbol(
            parent=parentSymbol,
            identifier=identifier,
            templateParams=templateParams,
            templateArgs=templateArgs,
            declaration=declaration,
            docname=docname,
        )
    else:
        symbol = Symbol(
            parent=parentSymbol,
            identifier=identifier,
            templateParams=templateParams,
            templateArgs=templateArgs,
            declaration=declaration,
            docname=docname,
        )
    return symbol


# Traceback (AssertionError)
$ sudo make install
sphinx-build -c ./src/build-data/sphinx -b html ./doc/manual build/docs/manual
Running Sphinx v1.4
WARNING: The config value `latex_show_urls' has type `bool', defaults to `str.'
loading pickled environment... not yet created
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 26 source files that are out of date
updating environment: 26 added, 0 changed, 0 removed
reading sources... [100%] x509
/Users/uri/src/botan/doc/manual/tls.rst:2: SEVERE: Duplicate ID: "TLS::Session".
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
/Users/uri/src/botan/doc/manual/building.rst:17: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:27: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:80: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:102: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:109: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:113: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:123: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:140: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:159: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:196: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:202: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:208: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
/Users/uri/src/botan/doc/manual/building.rst:215: WARNING: Could not lex literal_block as "cpp". Highlighting skipped.
('Target: ', u'std')92%] tls
('ParentKey: ', [(<ASTNestedNameElement TLS>, None), (<ASTNestedNameElement Session>, None), (<ASTNestedNameElement encrypt>, None)])

Exception occurred:
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/domains/cpp.py", line 4039, in _resolve_xref_inner
assert parentSymbol  # should be there
AssertionError
The full traceback has been saved in /tmp/sphinx-err-SPyA1q.log, if you want to report the issue to the developers.
Please also report this if it was a user error, so that a better error message can be provided next time.
A bug report can be filed in the tracker at <https://github.com/sphinx-doc/sphinx/issues>. Thanks!
make: *** [docs] Error 1
$ sudo cat /tmp/sphinx-err-SPyA1q.log
# Sphinx version: 1.4
# Python version: 2.7.11 (CPython)
# Docutils version: 0.12 release
# Jinja2 version: 2.8
# Last messages:
#   writing output... [ 57%] mceliece
#   writing output... [ 61%] ocsp
#   writing output... [ 65%] passhash
#   writing output... [ 69%] pbkdf
#   writing output... [ 73%] pubkey
#   writing output... [ 76%] python
#   writing output... [ 80%] rng
#   writing output... [ 84%] secmem
#   writing output... [ 88%] srp
#   writing output... [ 92%] tls
# Loaded extensions:
#   sphinx.ext.extlinks (1.4) from /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/ext/extlinks.pyc
#   alabaster (0.7.7) from /opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/alabaster/__init__.pyc
Traceback (most recent call last):
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/cmdline.py", line 244, in main
app.build(opts.force_all, filenames)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/application.py", line 287, in build
self.builder.build_update()
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/builders/__init__.py", line 251, in build_update
'out of date' % len(to_build))
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/builders/__init__.py", line 322, in build
self.write(docnames, list(updated_docnames), method)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/builders/__init__.py", line 360, in write
self._write_serial(sorted(docnames), warnings)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/builders/__init__.py", line 366, in _write_serial
doctree = self.env.get_and_resolve_doctree(docname, self)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/environment.py", line 1242, in get_and_resolve_doctree
self.resolve_references(doctree, docname, builder)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/environment.py", line 1497, in resolve_references
typ, target, node, contnode)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/domains/cpp.py", line 4070, in resolve_xref
target, node, contnode)[0]
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/Sphinx-1.4-py2.7.egg/sphinx/domains/cpp.py", line 4039, in _resolve_xref_inner
assert parentSymbol  # should be there
AssertionError
$

# Fixed code
def _add_symbols(self, nestedName, templateDecls, declaration, docname):
    # This condition should be checked at the parser level.
    # Each template argument list must have a template parameter list.
    # But to declare a template there must be an additional template parameter list.
    assert nestedName.num_templates() == len(
        templateDecls
    ) or nestedName.num_templates() + 1 == len(templateDecls)

    parentSymbol = self
    if nestedName.rooted:
        while parentSymbol.parent:
            parentSymbol = parentSymbol.parent
    names = nestedName.names
    iTemplateDecl = 0
    for name in names[:-1]:
        # there shouldn't be anything inside an operator
        # (other than template parameters, which are not added this way, right?)
        assert not name.is_operator()
        identifier = name.identifier
        templateArgs = name.templateArgs
        if templateArgs:
            assert iTemplateDecl < len(templateDecls)
            templateParams = templateDecls[iTemplateDecl]
            iTemplateDecl += 1
        else:
            templateParams = None
        symbol = parentSymbol._find_named_symbol(
            identifier,
            templateParams,
            templateArgs,
            operator=None,
            templateShorthand=False,
            matchSelf=False,
        )
        if symbol is None:
            symbol = Symbol(
                parent=parentSymbol,
                identifier=identifier,
                templateParams=templateParams,
                templateArgs=templateArgs,
                declaration=None,
                docname=None,
            )
        parentSymbol = symbol
    name = names[-1]
    if name.is_operator():
        identifier = None
        templateArgs = None
        operator = name
    else:
        identifier = name.identifier
        templateArgs = name.templateArgs
        operator = None
    if iTemplateDecl < len(templateDecls):
        if iTemplateDecl + 1 != len(templateDecls):
            print(text_type(templateDecls))
            print(text_type(nestedName))
        assert iTemplateDecl + 1 == len(templateDecls)
        templateParams = templateDecls[iTemplateDecl]
    else:
        assert iTemplateDecl == len(templateDecls)
        templateParams = None
    symbol = parentSymbol._find_named_symbol(
        identifier,
        templateParams,
        templateArgs,
        operator,
        templateShorthand=False,
        matchSelf=False,
    )
    if symbol:
        if not declaration:
            # good, just a scope creation
            return symbol
        if not symbol.declaration:
            # If someone first opened the scope, and then later
            # declares it, e.g,
            # .. namespace:: Test
            # .. namespace:: nullptr
            # .. class:: Test
            symbol._fill_empty(declaration, docname)
            return symbol
        # It may simply be a functin overload, so let's compare ids.
        candSymbol = Symbol(
            parent=parentSymbol,
            identifier=identifier,
            templateParams=templateParams,
            templateArgs=templateArgs,
            declaration=declaration,
            docname=docname,
        )
        newId = declaration.get_newest_id()
        oldId = symbol.declaration.get_newest_id()
        if newId != oldId:
            # we already inserted the symbol, so return the new one
            symbol = candSymbol
        else:
            # Redeclaration of the same symbol.
            # Let the new one be there, but raise an error to the client
            # so it can use the real symbol as subscope.
            # This will probably result in a duplicate id warning.
            raise _DuplicateSymbolError(symbol, candSymbol)
    else:
        symbol = Symbol(
            parent=parentSymbol,
            identifier=identifier,
            templateParams=templateParams,
            templateArgs=templateArgs,
            declaration=declaration,
            docname=docname,
        )
    return symbol