<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Sep 3, 2015 at 6:46 PM, Jordan Rose <span dir="ltr"><<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word">Hi, Richard. One of our Swift tests recently hit an interesting edge case involving modules and redefinitions. Take the following code:<div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>// Module A</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>struct Foo {</div><div><span style="white-space:pre-wrap">        </span>int x;</div><div>};</div><div><br></div><div>// Module B</div><div>struct Foo {</div><div><span style="white-space:pre-wrap">    </span>int x;</div><div>};</div><div><br></div><div>// Module C</div><div>typedef struct Foo *FooPtr;</div><div><br></div><div>// main.m</div><div>@import A;</div><div>@import B;</div><div>@import C;</div></blockquote><br><div>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 <i>some</i> declaration of Foo. "C.Foo", on the other hand, should say "there's no 'Foo' in C" (because Swift doesn't have forward declarations).</div><div><br></div><div>I tried using isCompleteDefinition to distinguish the B case from the C case, but of course Clang doesn't consider the second definition to <i>be</i> a definition. Do you have any ideas?</div></div></blockquote><div><br></div><div>It depends whether this is Objective C or Objective C++.</div><div><br></div><div>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).</div><div><br></div><div>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).</div></div></div></div>