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

Jordan Rose via cfe-dev cfe-dev at lists.llvm.org
Thu Sep 3 20:02:08 PDT 2015


> On Sep 3, 2015, at 19:33 , Richard Smith <richard at metafoo.co.uk> wrote:
> 
> On Thu, Sep 3, 2015 at 6:46 PM, Jordan Rose <jordan_rose at apple.com <mailto: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).

Huh. No, we're not in Objective-C++ mode. I guess I need to dig in more carefully to what's actually happening—I was definitely seeing Swift treat the definition as not being part of that module even after walking the redeclaration chain for other complete definitions. Thanks.

Jordan

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150903/5f1b254d/attachment.html>


More information about the cfe-dev mailing list