This patch addresses https://bugs.llvm.org/show_bug.cgi?id=39287.
Clang creates a 'std' namespace in one of two ways: either it parses a
namespace std { ... } declaration, or it creates one implicitly. For the
implicit case clang::Sema maintains a pointer StdNamespace and either
gets an existing namespace decl, lazily deserializes one from an external
AST, or lazily creates a 'std' namespace decl.
When using modules, however, a different instance of Sema is used, with a
different StdNamespace pointer. So a new instance of the 'std' namespace may
be created when compiling a module.
Normally, multiple definitions of the same namespace would be merged across
modules. However, finding multiple definitions is done using the standard
lookup machinery in Clang, which ignores the implicit 'std' namespaces lazily
created by Sema. This results in bugs in which members of one module's 'std'
namespace are not visible to another's.
One case in which issues may arise is when Clang creates an implicit 'std'
namespace when it encounters a virtual destructor in C++17. This results in
the implicit definition of operator new and delete overloads that take a
std::align_val_t argument (this behavior was added in rL282800). The tests
in this patch demonstrate two existing bugs that are fixed by this patch:
- mod-virtual-destructor-bug defines std::type_info within the main translation unit. When it does so, there are two 'std' namespaces available: the implicitly defined one that is returned by Sema::getStdNamespace, and the explicit one defined in the a.h module. The std::type_info definition ends up being attached to the module's std namespace, and so the subsequent lookup of getStdNamespace's type_info member fails.
- mod-virtual-destructor-bug-two defines std::type_info within a module. Later, the lookup of std::type_info finds the implicitly created getStdNamespace, which only defines std::align_val_t, not std::type_info.
To fix, this patch modifies ASTDeclReader::findExisting such that an
explicit check is made: "are we trying to merge multiple definitions of a
namespace named 'std'?" If so, it explicitly grabs Sema::StdNamespace
(taking care not to trigger its lazy deserialization) to merge the
definitions.
Don't we also have to check New's context is the global namespace? What happens for something like 'namespace evil::std {};'?