On Oct 28, 2013, at 1:13 PM, Richard Smith <[email protected]> wrote:

> On Mon, Oct 28, 2013 at 12:15 PM, Richard Smith <[email protected]> wrote:
> On Sat, Oct 26, 2013 at 10:14 AM, Argyrios Kyrtzidis <[email protected]> 
> wrote:
> As I said above, I think there's a misunderstanding here; to reiterate: when 
> you say "I want to use the interface provided by M1. If I've not imported M2" 
> this is case 1) I mentioned and I agree with what you said should happen. If 
> this does not happen currently then it should be fixed.
> 
> Should we focus on what should happen when importing both M1 and M2 ?
> 
> Yes, I think refocusing will help. In particular, I think this is the key 
> question on which we have different views:
>  
> How do I know that two modules are *related* ? One module may have imported 
> the other but if it doesn't re-export it it might as well be an *unrelated* 
> one from my perspective; why do I need to care what modules it imported 
> internally ?
> 
> There are (I think) two different ways that two modules can have a conflict 
> on what a macro name means:
> 
> 1) Both modules want the name to mean something (which be mean "it's a macro 
> expanding to X" or might be "it's not a macro").
> 2) One module wants to *override* what another module meant the name to mean 
> (M2 says "it expands to FOO BAR", and M1 says "actually, I override M2 and 
> say it expands to BAZ")
> 
> There are also two different ways that a module can express its intent for a 
> macro name to mean something:
> 
> A) It can #define the name to something
> B) It can #undef the name
> 
> I think we agree that:
> 
> 1A: If two modules want the same macro name to be defined to different 
> things, and that macro name is used, that is clearly ambiguous and should be 
> diagnosed.
> 
> I'm on the fence about this one:
> 
> 1B: If one module wants the macro name to be #defined to something, and 
> another module wants it to be undefined, currently Clang silently picks the 
> definition. I am not entirely convinced that's appropriate -- if my module 
> explicitly #undef's a macro, that's a statement of intent: in my interface, 
> I'm using that name to mean something that's not a macro. I don't think it's 
> obvious that:
> 
>   #undef X
>   #define X X
> 
> and 
> 
>   #undef X
> 
> should mean fundamentally different things here. Either way, I'm saying "I 
> own the macro name X and it produces the token sequence X."
> 
> Hmm, I think it's actually rather important that we diagnose this: on the 
> upgrade path from #includes to modules, we'll get a silent change of behavior 
> without this.
> 
> If we do diagnose this case (where two imported modules disagree on a macro: 
> one says it should be defined and the other says it should not), then I care 
> a lot less about case 2. (It's enough for me that we diagnose this; we don't 
> need to preserve the existing behavior.)
> 
> That said, I think we should take as a guiding rule that modules and 
> submodules should behave the same, and we currently violate that in the case 
> of macros.
>  
> Case 2 is where we really seem to disagree. It's also a weird case for 
> modules, since we rarely have cases in which the interface of one module 
> includes "modify the interface of another module". Which brings me to your 
> next point:
>  
> I'm suggesting that If I explicitly import 2 modules, and the modules' 
> interfaces disagree on what an identifier means, then there is ambiguity.
> One module may or may not have imported the other module internally, but that 
> doesn't change the fact that the modules' interfaces disagree on the meaning 
> of an identifier.
> 
> The key thing for me is, if one module imports another module, undefines some 
> part of it, then re-exports it, it seems pretty clear that it intends to 
> *modify* the interface of that first module. This happens in other guises 
> too: extending overload sets, specializing templates, shadowing a tag name 
> with a non-tag name, and so on. In all other cases, importing both modules 
> gives you the modified interface *with no ambiguity*. The ambiguity has 
> already been resolved by the dominating module saying how to resolve it. And 
> if I import a module that says that it modifies another module's interface, I 
> expect to get that modified interface.
> 
> So: 2A) if M2 defines our macro, and M1 imports M2 and undefines and 
> redefines that macro, and either I import M1 or I import *both* M1 and M2, 
> I've expressed my intent to use M1's resolution to the conflict, and I think 
> I should get M1's definition.
> 2B) if M2 defines our macro, and M1 imports M2 and undefines the macro, and 
> either I import M1 or I import both M1 and M2, I think the macro should not 
> be defined.
> 
> By exporting a macro undefinition that undefines M2's macro, M1 is saying 
> "importing me undefines M2's macro definition". There's no ambiguity in that, 
> and if I import both modules, that's what I expect to happen. This would 
> behave in (largely) the same way we behave across submodules in the same 
> module, which makes the intuitive model simpler. If M1 didn't want this 
> behavior, it should not export the macro.
> 
> 
> Let me make my proposal a bit more concrete, since I think I've been vague up 
> until now.
> 
> Instead of storing a single flat list of macro definitions and undefines, we 
> store a DAG. The predecessors of each directive are the set of directives 
> that were visible at the point of the directive. (For a #define, these must 
> all be either #undefs or #defines to the same value.) When we see a macro 
> name being used, we take the set of visible leaves of this graph, check they 
> are consistent[1], and use that consistent value as the value of the macro. 
> Otherwise, we diagnose.
> 
> [1] I'm not certain whether consistency should allow a mixture of #undefs and 
> #defines, but I'm inclined to think it should not.
> 

Richard, thanks for the detailed explanation, I'm convinced that if a module 
undefines a macro of another module and re-exports it, the macro should be 
considered undefined even if I import both modules.
I have another question, what if the module doesn't re-export the imported 
module ? Specifically, M1 imports M2, undefines a macro from M2, but then it 
doesn't re-export module M2 ? That seems like a sufficiently different case, to 
be considered separately.

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to