C++ Logo

sg15

Advanced search

Re: [SG15] [isocpp-modules] Determining identity like #pragma once

From: Richard Smith <richardsmith_at_[hidden]>
Date: Wed, 10 Jul 2019 15:40:17 -0700
On Wed, Jul 10, 2019 at 3:15 PM Michael Spencer <bigcheesegs_at_[hidden]>
wrote:

> On Wed, Jul 10, 2019 at 2:51 PM Gabriel Dos Reis via SG15 <
> sg15_at_[hidden]> wrote:
>
>>
>>
>> | -----Original Message-----
>> | From: Bryce Adelstein Lelbach aka wash <brycelelbach_at_[hidden]>
>> | Sent: Wednesday, July 10, 2019 2:37 PM
>> | To: Gabriel Dos Reis <gdr_at_[hidden]>
>> | Cc: Tom Honermann <tom_at_[hidden]>; modules_at_[hidden];
>> | sg15_at_[hidden]
>> | Subject: Re: [isocpp-modules] [SG15] Determining identity like #pragma
>> once
>> |
>> | On Wed, Jul 10, 2019 at 11:02 AM Gabriel Dos Reis <gdr_at_[hidden]>
>> | wrote:
>> | >
>> | > You are implying that the include translation is mandatory. Is that
>> your
>> | argument?
>> |
>> | It is my belief that include translation is mandatory.
>> |
>> | "If the header identified by the header-name denotes an importable
>> | header ([module.import]), the preprocessing directive is instead
>> | replaced by the preprocessing-tokens: import header-name ;"
>> | https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Feel.is
>> | %2Fc%2B%2Bdraft%2Fcpp.include%237&amp;data=02%7C01%7Cgdr%40mic
>> | rosoft.com%7C57adb75b608743ebf6e208d7057ed5d4%7C72f988bf86f141af
>> | 91ab2d7cd011db47%7C1%7C0%7C636983914618863287&amp;sdata=JsvGf
>> | 0RfvcjOSMF6q%2FfsW60hhKx5TI%2F1K42M8PdRbOU%3D&amp;reserved=0
>> |
>> | To me, that reads as "including an importable header must be
>> | translated to an import".
>> |
>> | Was that the original design intent?
>>
>> The original intent, as I understood it, was to *permit* include
>> translation.
>>
>> A mandatory include translation is practically unworkable for the MSVC
>> audience. I wouldn't be surprised at all if that is the case of other
>> compilers too.
>>
>> A permission, as opposed to a requirement, would allow adoption of header
>> import as better and principled replacement of PCH. Otherwise, it would
>> create more problems than it solves.
>>
>> -- Gaby
>>
>>
> I was there for most of the LEWG discussion on D1502R0 (Standard library
> header units for C++20), and I can not say with confidence that the room
> understood the implication that this would require include translation.
> There don't seem to be any minutes of the discussion on the wiki.
>
> However, the paper does explicitly point this out:
>
> > This has a number of consequences, such as:
> > * ...
> > * Existing #includes of standard library headers transparently turn
> into module imports in C++20
>
> It also in the wording explicitly adds the headers to the set of
> implementation-defined importable headers.
>
> > An importable header is a member of an implementation-defined set of
> headers that includes all importable C++ library headers (16.5.1.2
> [headers])
>
> So I believe the author's intent was to require that include translation
> occurs.
>
> + Richard so we can ask them :)
>

Yes, my intent was to (effectively) require include translation for these
parts of the standard library. In practice, an implementation could satisfy
that requirement by instead providing standard library wrapper headers that
simply contain a relevant import declaration -- this does not strictly
require an implementation to actually do include translation during
preprocessing.

An implementation that doesn't actually do include translation at all is
still permissible using this technique. Such an implementation would need
to document that its implementation-defined set of importable headers is
empty other than the standard library headers. If they did so, then any
"import header-name;" construct that didn't name a standard library header
would violate [module.import]/5's "H shall identify an importable header."
Such an implementation could still choose to accept such an import as a
language extension. I would not encourage such an approach, but I think
it's consistent with the wording we have.

If we want to permit "import header-name;" without requiring include
translation, and we want to allow re-exporting of imported header units,
we'll need to fix the robustness issues that arise when a legacy
header's macros (particularly include guards) are divorced from its
semantic contents. (Nathan pointed this out during prior EWG discussion,
and this non-robustness is the reason we require include translation for
importable headers.) For example:

// foo.h
#fndef FOO_H
#define FOO_H
struct X {};
#endif

// TU A
export module M;
export import "foo.h";

// TU B
import M;
// suppose we make a language change that allows this #include to be
textually included rather than subject to include translation
// then because the FOO_H macro is not visible here (because modules can't
export macros), we get...
#include "foo.h" // error, redefinition of X

The same issue arises with the global module fragment:

// TU C
module;
#include "foo.h"
export module M;
export X f(); // definition of X is reachable through this TU

// TU D
import M;
#include "foo.h" // error, redefinition of X

I think there's a reasonable fix to both of these; instead of rejecting a
redefinition when a prior definition is reachable, we should only reject a
redefinition of an entity attached to the global module when there's a
prior definition in the same translation unit. The ODR would apply as
normal to such global-module-owned redefinitions. (I think I've suggested
this on either the evolution or modules reflector before.)

If we make that change, both the global module fragment and header units
would become more robust, and we would no longer need to require include
translation for all importable headers. (I think we should still require
include translation for the standard library, though as noted above, an
implementation can model that by providing header files that contain
imports.)

Received on 2019-07-10 17:42:25