# Buggy code
def add_target_and_index(self, ast, sig, signode):
    ids = [  # the newest should be first
        ast.get_id_v2(),
        ast.get_id_v1(),
    ]
    theid = ids[0]
    ast.newestId = theid
    assert theid  # shouldn't be None
    name = text_type(ast.prefixedName)
    if theid not in self.state.document.ids:
        # if the name is not unique, the first one will win
        objects = self.env.domaindata["cpp"]["objects"]
        if name not in objects:
            signode["names"].append(name)
        else:
            pass
            # print("[CPP] non-unique name:", name)
        for id in ids:
            if id:  # is None when the element didn't exist in that version
                signode["ids"].append(id)
        signode["first"] = not self.names
        self.state.document.note_explicit_target(signode)
        if not name in objects:
            objects.setdefault(name, (self.env.docname, ast))
            if ast.objectType == "enumerator":
                # find the parent, if it exists && is an enum
                #                     && it's unscoped,
                #                  then add the name to the parent scope
                assert len(ast.prefixedName.names) > 0
                parentPrefixedAstName = ASTNestedName(ast.prefixedName.names[:-1])
                parentPrefixedName = text_type(parentPrefixedAstName)
                if parentPrefixedName in objects:
                    docname, parentAst = objects[parentPrefixedName]
                    if parentAst.objectType == "enum" and not parentAst.scoped:
                        enumeratorName = ASTNestedName([ast.prefixedName.names[-1]])
                        assert len(parentAst.prefixedName.names) > 0
                        enumScope = ASTNestedName(parentAst.prefixedName.names[:-1])
                        unscopedName = enumeratorName.prefix_nested_name(enumScope)
                        txtUnscopedName = text_type(unscopedName)
                        if not txtUnscopedName in objects:
                            objects.setdefault(txtUnscopedName, (self.env.docname, ast))
            # add the uninstantiated template if it doesn't exist
            uninstantiated = ast.prefixedName.get_name_no_last_template()
            if uninstantiated != name and uninstantiated not in objects:
                signode["names"].append(uninstantiated)
                objects.setdefault(uninstantiated, (self.env.docname, ast))
        self.env.ref_context["cpp:lastname"] = ast.prefixedName

    indextext = self.get_index_text(name)
    if not re.compile(r"^[a-zA-Z0-9_]*$").match(theid):
        self.state_machine.reporter.warning(
            'Index id generation for C++ object "%s" failed, please '
            "report as bug (id=%s)." % (text_type(ast), theid),
            line=self.lineno,
        )
    self.indexnode["entries"].append(("single", indextext, theid, ""))


# Traceback (KeyError)
# Sphinx version: 1.3b3
# Python version: 2.7.6
# Docutils version: 0.11 release
# Jinja2 version: 2.7.2
# Last messages:
#   Running Sphinx v1.3b3
#   loading pickled environment...
#   done
#   WARNING: 'default' html theme has been renamed to 'classic'. Please rename it to 'alabaster' new theme or 'classic'.
#   building [mo]: targets for 0 po files that are out of date
#   building [html]: targets for 1 source files that are out of date
#   updating environment:
#   [extensions changed] 1 added, 0 changed, 0 removed
#   reading sources... [100%] index
# Loaded extensions:
#   alabaster (unknown version) from /usr/local/lib/python2.7/dist-packages/alabaster-0.6.3-py2.7.egg/alabaster/__init__.pyc
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/cmdline.py", line 246, in main
app.build(opts.force_all, filenames)
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/application.py", line 263, in build
self.builder.build_update()
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/builders/__init__.py", line 237, in build_update
'out of date' % len(to_build))
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/builders/__init__.py", line 251, in build
self.doctreedir, self.app))
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/environment.py", line 586, in update
self._read_serial(docnames, app)
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/environment.py", line 606, in _read_serial
self.read_doc(docname, app)
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/environment.py", line 758, in read_doc
pub.publish()
File "/usr/lib/python2.7/dist-packages/docutils/core.py", line 217, in publish
self.settings)
File "/usr/lib/python2.7/dist-packages/docutils/readers/__init__.py", line 72, in read
self.parse()
File "/usr/lib/python2.7/dist-packages/docutils/readers/__init__.py", line 78, in parse
self.parser.parse(self.input, document)
File "/usr/lib/python2.7/dist-packages/docutils/parsers/rst/__init__.py", line 172, in parse
self.statemachine.run(inputlines, document, inliner=self.inliner)
File "/usr/lib/python2.7/dist-packages/docutils/parsers/rst/states.py", line 171, in run
input_source=document['source'])
File "/usr/lib/python2.7/dist-packages/docutils/statemachine.py", line 239, in run
context, state, transitions)
File "/usr/lib/python2.7/dist-packages/docutils/statemachine.py", line 460, in check_line
return method(match, context, next_state)
File "/usr/lib/python2.7/dist-packages/docutils/parsers/rst/states.py", line 2300, in explicit_markup
nodelist, blank_finish = self.explicit_construct(match)
File "/usr/lib/python2.7/dist-packages/docutils/parsers/rst/states.py", line 2312, in explicit_construct
return method(self, expmatch)
File "/usr/lib/python2.7/dist-packages/docutils/parsers/rst/states.py", line 2055, in directive
directive_class, match, type_name, option_presets)
File "/usr/lib/python2.7/dist-packages/docutils/parsers/rst/states.py", line 2104, in run_directive
result = directive_instance.run()
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/domains/__init__.py", line 195, in run
return BaseDirective.run(self)
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/directives/__init__.py", line 159, in run
self.after_content()
File "/usr/local/lib/python2.7/dist-packages/Sphinx-1.3b3dev_20150223-py2.7.egg/sphinx/domains/cpp.py", line 2228, in after_content
self.env.ref_context['cpp:parent'].pop()
KeyError: 'cpp:parent'

# Fixed code
def add_target_and_index(self, ast, sig, signode):
    ids = [  # the newest should be first
        ast.get_id_v2(),
        ast.get_id_v1(),
    ]
    theid = ids[0]
    ast.newestId = theid
    assert theid  # shouldn't be None
    name = text_type(ast.prefixedName)
    if theid not in self.state.document.ids:
        # if the name is not unique, the first one will win
        objects = self.env.domaindata["cpp"]["objects"]
        if name not in objects:
            signode["names"].append(name)
        else:
            pass
            # print("[CPP] non-unique name:", name)
        for id in ids:
            if id:  # is None when the element didn't exist in that version
                signode["ids"].append(id)
        signode["first"] = not self.names
        self.state.document.note_explicit_target(signode)
        if not name in objects:
            objects.setdefault(name, (self.env.docname, ast))
            if ast.objectType == "enumerator":
                # find the parent, if it exists && is an enum
                #                     && it's unscoped,
                #                  then add the name to the parent scope
                assert len(ast.prefixedName.names) > 0
                parentPrefixedAstName = ASTNestedName(ast.prefixedName.names[:-1])
                parentPrefixedName = text_type(parentPrefixedAstName)
                if parentPrefixedName in objects:
                    docname, parentAst = objects[parentPrefixedName]
                    if parentAst.objectType == "enum" and not parentAst.scoped:
                        enumeratorName = ASTNestedName([ast.prefixedName.names[-1]])
                        assert len(parentAst.prefixedName.names) > 0
                        enumScope = ASTNestedName(parentAst.prefixedName.names[:-1])
                        unscopedName = enumeratorName.prefix_nested_name(enumScope)
                        txtUnscopedName = text_type(unscopedName)
                        if not txtUnscopedName in objects:
                            objects.setdefault(txtUnscopedName, (self.env.docname, ast))
            # add the uninstantiated template if it doesn't exist
            uninstantiated = ast.prefixedName.get_name_no_last_template()
            if uninstantiated != name and uninstantiated not in objects:
                signode["names"].append(uninstantiated)
                objects.setdefault(uninstantiated, (self.env.docname, ast))

    indextext = self.get_index_text(name)
    if not re.compile(r"^[a-zA-Z0-9_]*$").match(theid):
        self.state_machine.reporter.warning(
            'Index id generation for C++ object "%s" failed, please '
            "report as bug (id=%s)." % (text_type(ast), theid),
            line=self.lineno,
        )
    self.indexnode["entries"].append(("single", indextext, theid, ""))