[cfe-dev] local submodule visibility, namespaces and Decl::getOwningModule()

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Wed Oct 24 13:36:15 PDT 2018

On Wed, 24 Oct 2018 at 12:51, Adrian Prantl via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> On Oct 23, 2018, at 6:17 PM, Richard Smith <richard at metafoo.co.uk> wrote:
> On Tue, 23 Oct 2018 at 17:29, Adrian Prantl via cfe-dev <
> cfe-dev at lists.llvm.org> wrote:
>> On Oct 23, 2018, at 5:10 PM, Richard Smith <richard at metafoo.co.uk> wrote:
>> On Mon, 15 Oct 2018 at 10:13, Adrian Prantl via cfe-dev <
>> cfe-dev at lists.llvm.org> wrote:
>>> I'm trying to fix a bug in the -gmodules debug info that appears when
>>> debugging Clang with local submodule visibility enabled. In my reduced
>>> testcase, I have a module A, defining a template
>>> "AlignedCharArray<unsigned, unsigned>", and two templates "SmallVector" and
>>> "Optional" that use it. In module B, I'm instantiating an Optional that
>>> instantiates an AlignedCharArray<4, 16>. In module C, I'm instantiating a
>>> SmallVector that also instantiates an AlignedCharArray<4, 16>.
>>> The -gmodules debug info format saves space by forward-declaring types
>>> that are defined in an already-imported module and specify which module
>>> they came from. To point to the module of the definition
>>> CGDebugInfo::getParentModuleOrNull(const Decl *D) uses
>>> Decl::getOwningModule(). This mechanism works as expected, but only if the
>>> TemplateDecl is not inside a namespace.
>>> When compiling the attached testcase with -U WITH_NAMESPACE, the owning
>>> module for the ClassTemplateSpecializationDecl (of AlignedCharArray<4, 16>)
>>> in module B is C. (B imports C, so the C specialization is instantiated
>>> first).
>>> When compiling the attached testcase with -D WITH_NAMESPACE, the owning
>>> module for the ClassTemplateSpecializationDecl (of AlignedCharArray<4, 16>)
>>> in module B is A. (A is where the TemplateDecl that is being specialized
>>> comes from).
>>> I'm sure that this discrepancy must be because a namespace can be spread
>>> out over many modules.
>> Sort of. In practice, what's happening is this:
>> When we create a declaration, we inherit its owning module from its
>> lexical parent by default. And we ensure that the lexical parent of the TU
>> declaration corresponds to the module we're currently "in". When a
>> declaration is injected into a lexical declaration context from a different
>> module, such as happens when adding a template specialization to an
>> imported template, that default behavior will pick up the current module at
>> global scope, but will pick up the owning module of the enclosing namespace
>> declaration at namespace scope, which will be the owning module of
>> whichever declaration of the template we picked. Now, this usually doesn't
>> matter, because a template specialization doesn't really *have* a
>> meaningful notion of "owning module". For visibility purposes, the
>> specialization should be visible wherever the corresponding template is
>> visible, and for linkage purposes, it should be considered owned by the
>> same module as the template pattern. So in some sense the bug is in the
>> global-scope case: we should always treat the specialization as being owned
>> by module A.
>> I think there's a chance that you're asking the wrong question -- perhaps
>> you should be trying to determine whether the declaration in question is
>> imported from a module *file*, not what its semantic owning module is. (As
>> an example, suppose we're tracking module ownership but not using PCM
>> files. If we textually enter a modular header of some other module, I think
>> you want to *not* treat declarations in that header as being owned by a
>> module for the purpose of -gmodules, because there is no reason to think
>> there's separate debug information for that header.) You can figure that
>> out by calling Decl::isFromASTFile(), and if you want to know *which* AST
>> file the declaration comes from (because you know that some AST files have
>> debug information and some don't), you can use
>> ASTReader::getOwningModuleFile to find out.
>> Thanks for the pointer! That interface sounds promising; I will try to
>> expose it as a
>>    virtual ASTSourceDescriptor getOwningModuleFile(Decl *);
>> in ExternalASTSource and see if that gets me further.
> A more general name might make sense at the ExternalASTSource level (eg,
> lldb might want to specify that its declarations come from a certain .dwo
> file), but that generally sounds reasonable to me.
> I experimented with this quite a bit today, and using
> getOwningModuleFile() solves 50% of my problem. Not bad :-)
> Using it, I can now correctly deduce the Module that contains the
> previously imported definition of the ClassTemplateSpecialization, and emit
> debug info as a  forward decl.
> But while emitting debug info for the PCM that contains the definition of
> ClassTemplateSpecializationDecl itself, getOwningModuleFile() errors out
> because Decl::isFromASTFile() is naturally false and the function only
> works for imported types; so the template specialization ends up nested in
> the module that contains the ClassTemplate, not the one that contains the
> specialization.
> Is there a way to determine the module ClassTemplateSpecializationDecl is
> in while compiling that module? The ClassTemplateSpecializationDecl's
> DeclContext and LexicalDeclContext both are the NamespaceDecl in the module
> containing the ClassTemplate. I suppose that while compiling a PCM, I could
> force every Decl that !isFromASTFile() to be inside that PCM's module, but
> it would be nice to have something more elegant.

I think the same approach should work, but maybe I'm not understanding
something about the problem? If getOwningModuleFile returns null, then the
declaration is not imported from a module file, so you should do with it
whatever you're doing with declarations that aren't from an imported module
file. (Eg, if you're building a module file with modular debug information,
then emit debug information for that declaration.)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20181024/0b5d8b29/attachment.html>

More information about the cfe-dev mailing list