#include migration strategies

321 views
Skip to first unread message

James Widman

unread,
Mar 4, 2014, 2:14:28 PM3/4/14
to Richard Smith, Doug Gregor, Mark Hall (VC++), Daveed Vandevoorde, Gabriel Dos Reis, Bjarne.S...@morganstanley.com, mod...@isocpp.org, Gabriel Dos Reis
[No one’s name is on the “CC” line this time, because I’m posing this question directly to implementors in their capacity as implementors.]

[Also, Doug: I might have asked a question identical this one in the past, but forgot the answer. Apologies if so; at least this time I’ll have answers in writing.]

One thing I would like to write about in the near future is proposed strategies for migrating from:

#include <foo.h>

… to:

import foo;

… where foo.h is any arbitrary library header (standard or 3rd-party).

And here’s a straw-man proposal to implementors:

First, suppose that in the future we have normative wording that says that "import foo;" only imports a set of one-or-more “translated translation units” (as mentioned in the beginning of phase 8).

To clarify: suppose that, in this imaginary future core wording (and just for the sake of argument in this thread), your implementation behaves as if no #pragmas in foo have any effect on phases 1-through-end-of-phase-7 during translation of the importing TU.

Ditto for any other preprocessing directives in foo. (So, e.g., there’s no such thing as “exported macros”. In the import line above, the set of active #define directives after the import would be the same as before.)


Now, in real life, there are cases where that doesn’t work, because if a user put (say) “#pragma GCC poison X” inside foo.h, then they expect that to affect phase 3 in the TU that contains #include <foo.h>.

And when the user changes the #include to import, compile-time behavior is desired to be the same. Right?

We’ll come back to that in a moment.

Now just as a point of reference, let’s look at the effect of `gcc -E -dD`:

% cat u.cpp
#include <u.h>
% cat u.h

#pragma GCC poison X
#define Y 42
extern int n;
% gcc -E -dD u.cpp
// [omitting #line directives for brevity]
#define Y 42
extern int n;

The -dD switch means that the preprocessor additionally outputs directives, which is why #define Y appears in the output. (I think I know why #pragma poison is missing; we’ll come back to that.)

Next, suppose the preprocessor had a mode where it would output *only* directives and no other preprocessing tokens:

#pragma GCC poison X
#define Y 42
// (no declaration of variable n here)


And now, how about a mode where the compiler generates an alternative version of u.h:

// file new-u.h:
import u;
#pragma GCC poison X
#define Y 42
// end of file new-u.h

Now, if the library vendor renames u.h to old-u.h and new-u.h to u.h, the effect of client code:

#include <u.h>

… and the #include search finds the newly-generated header, the behavior after the #include should be exactly the same as it was before.

And now, the author of u.h is at liberty to selectively eliminate individual directives from the new u.h.

Simultaneously, the user would be at liberty to change:

#include <u.h>

… to:

import u;

… and the effect would be as described in the imaginary future wording mentioned earlier in this email (i.e., without any CPP effects from the directives in the new u.h).

So, if your library interface intentionally “exports” a macro, well… then tell your users to just include the header! You want CPP effects? We got CPP effects, and the syntax to get them should ideally be no different from the old syntax.

Example:

// primary source file a.cpp:
#include <new-u.h> // imports u and executes directives.
int f() { return n; } // ok, u’s n.
#define X 13 // Error (poisoned identifier X)

// primary source file b.cpp:
import u;
int f() { return n; } // ok, u’s n.
#define X 13 // ok

Again, I’m not (currently) proposing core wording that places restrictions on pragma effects; I’m just asking about the extent to which this migration approach can work in implementations that you know about (not just your own).

Thanks in advance!

—James

ps: about the disappearance of #pragma GCC poison: it’s because it causes a change to the behavior of phase 3, and is even documented as not affecting identifiers that result from a macro expansion (phase 4). Therefore, if tokens from a macro expansion appear in PP output mention X, users don’t want that to trigger an error when the PP output is read in again.

Csaba Csoma

unread,
Mar 6, 2014, 1:49:07 PM3/6/14
to mod...@isocpp.org
Somewhat tangential:

import foo;

does not scale. We will need

import category.group.foo;

or

import component/category/foo;

Csaba

Gabriel Dos Reis

unread,
Mar 6, 2014, 2:05:27 PM3/6/14
to mod...@isocpp.org

Indeed – if we have submodules, then we would need syntax to import them individually.

 

However, for the time being we can just talk about ‘import X’ knowing very well that in real life, module names are rarely one character long :-)

 

-- Gaby

 

--
You received this message because you are subscribed to the Google Groups "SG2 - Modules" group.
To unsubscribe from this group and stop receiving emails from it, send an email to modules+u...@isocpp.org.
To post to this group, send email to mod...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/modules/.

Andy Sawyer

unread,
Mar 6, 2014, 2:46:44 PM3/6/14
to mod...@isocpp.org
On Thursday, March 6, 2014 10:49 AM, Csaba Csoma wrote:

>
> Somewhat tangential:
>
> import foo;
>
> does not scale. We will need
>
> import category.group.foo;
>
> or
>
> import component/category/foo;

And maybe even:

import component/category/foo::type;

Regards,
Andy
Reply all
Reply to author
Forward
0 new messages