[cfe-dev] Redefinitions of a struct in different modules

Richard Smith via cfe-dev cfe-dev at lists.llvm.org
Thu Sep 3 19:33:50 PDT 2015


On Thu, Sep 3, 2015 at 6:46 PM, Jordan Rose <jordan_rose at apple.com> wrote:

> Hi, Richard. One of our Swift tests recently hit an interesting edge case
> involving modules and redefinitions. Take the following code:
>
> // Module A
>
> struct Foo {
> int x;
> };
>
> // Module B
> struct Foo {
> int x;
> };
>
> // Module C
> typedef struct Foo *FooPtr;
>
> // main.m
> @import A;
> @import B;
> @import C;
>
>
> If all of this was in one file, we'd have an invalid redefinition of Foo,
> but because A and B are separate modules (and supposedly self-contained)
> Clang just cheats and treat one of them as a mere declaration. Because
> Clang modules don't affect lookup, that's fine. In Swift, however, I can
> ask for "A.Foo" or "B.Foo", and ideally both would resolve to *some* declaration
> of Foo. "C.Foo", on the other hand, should say "there's no 'Foo' in C"
> (because Swift doesn't have forward declarations).
>
> I tried using isCompleteDefinition to distinguish the B case from the C
> case, but of course Clang doesn't consider the second definition to *be* a
> definition. Do you have any ideas?
>

It depends whether this is Objective C or Objective C++.

In C++, we take advantage of the ODR, which allows us to assume that those
two 'struct Foo's are defining the same struct. We mostly make it look like
one of the declarations was never a definition (so that AST consumers don't
need to treat this as a special case), but in practice you can infer
whether the declaration was once a definition by checking whether its decl
context lexically contains any declarations (it just so happens that a
current or former definition will always contain at least an injected class
name decl, and a "pure" declaration will always be empty).

In C, there is no ODR, and the same struct name is permitted to have
different definitions in different translation units in the same program.
What we /should/ do is to keep decl chains for types from distinct modules
separate, and implement C's "compatible type" structural typing rules to
determine whether two 'Foo's can be used interchangeably. What we
/actually/ do is to form a single redeclaration chain containing all the
definitions, all of which think they are still "the" definition, and each
use of the type will pick a semi-arbitrary definition. This case is easy
for you: just ask the decl whether it's a complete definition (but I'm
guessing you're in Objective C++ mode since you said that checking
IsCompleteDefinition isn't working).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150903/1230ce27/attachment.html>


More information about the cfe-dev mailing list