C++ Logo

sg15

Advanced search

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

From: Gabriel Dos Reis <gdr_at_[hidden]>
Date: Thu, 11 Jul 2019 12:36:46 +0000
  * Will the following code also propagate the macro into vector?

No.


  * It seem like a net-negative change to make #include <foo> and import <foo> mean different things in cases where both are well-formed.

I think that is an inevitable practical necessity.
Actually, I think it is a real net-positive: we can practically deploy it, enable incremental adoption, and update the toolchains to identify incoherent context settings.


  * 1) Allow users to opt/in out of having the std headers being importable. C

Any solution we adopt in this space should be applicable to non-std library headers; anything else is special casing that does not scale. Stdlib headers aren’t the only ones with this issue.

From: Modules <modules-bounces_at_[hidden]> On Behalf Of Mathias Stearn
Sent: Thursday, July 11, 2019 5:22 AM
To: sg15_at_[hidden]
Cc: modules_at_[hidden]; Bryce Adelstein Lelbach aka wash <brycelelbach_at_[hidden]>
Subject: Re: [isocpp-modules] [SG15] Determining identity like #pragma once

Will the following code also propagate the macro into vector?

#define _LIBCPP_NO_EXCEPTIONS
import <vector>;

It seem like a net-negative change to make #include <foo> and import <foo> mean different things in cases where both are well-formed. While it may not matter much for std headers, it will matter as soon as a single user header (or source file) becomes importable, since it will require boiling the oceans to get consistent semantics. If that header is ever transitively included, you are basically guaranteed to get a mix of import and #include of the header within a single TU until all code is converted to import, which may take a long time if ever. Even in those cases, we should still have order independence for importable header units.

If the goal is to allow this type of in-source (rather than cmdline) customization of stdlib via macros, I can think of a few other options that don't sacrifice that equivalence:

1) Allow users to opt/in out of having the std headers being importable. Can either be standards blessed (similar to contracts: "The mechanism for selecting [whether std headers are importable] is implementation-defined.") or a non-conforming extension for backwards compatibility with old extensions
2) Allow an implementation-defined set of macros to "flow into" imported std headers, regardless of whether import is spelled #include. This could be modeled as implicitly mangling the values of those macros into the name of the imported header-unit, so that different values import different TUs. Ideally this would error if the macros had different values for different imports in the same TU since that is almost certainly a bug.
3) Allow all macros to flow into importable std headers. This seems like a bad idea though because it would prevent de-uglifying modularized std code.

On Thu, Jul 11, 2019 at 10:36 AM Bryce Adelstein Lelbach aka wash via SG15 <sg15_at_[hidden]<mailto:sg15_at_[hidden]>> wrote:
IIUC, this proposed fix will give implementations freedom in how they
deal with this:

#define _LIBCPP_NO_EXCEPTIONS
#include <vector> // <vector> does not see our definition of
_LIBCPP_NO_EXCEPTIONS

With this change, implementations could select an approach where they
do not translate the above #include and the above code works as it
does in C++17 (e.g. <vector> sees _LIBCPP_NO_EXCEPTIONS).

Of course, then, if you have something like this, you have an ODR
violation if you do this (assuming that _LIBCPP_NO_EXCEPTIONS changes
how things are defined in <vector):

import <vector>;
#define _LIBCPP_NO_EXCEPTIONS
#include <vector>

On Thu, Jul 11, 2019 at 1:20 AM Richard Smith <richardsmith_at_[hidden]<mailto:richardsmith_at_[hidden]>> wrote:
>
> On Wed, Jul 10, 2019 at 4:03 PM Gabriel Dos Reis <gdr_at_[hidden]<mailto:gdr_at_[hidden]>> wrote:
>>
>> On Jul 10, 2019, at 3:40 PM, Richard Smith <richardsmith_at_[hidden]<mailto:richardsmith_at_[hidden]>> wrote:
>>
>> On Wed, Jul 10, 2019 at 3:15 PM Michael Spencer <bigcheesegs_at_[hidden]<mailto:bigcheesegs_at_[hidden]>> wrote:
>>>
>>> On Wed, Jul 10, 2019 at 2:51 PM Gabriel Dos Reis via SG15 <sg15_at_[hidden]<mailto:sg15_at_[hidden]>> wrote:
>>>>
>>>>
>>>>
>>>> | -----Original Message-----
>>>> | From: Bryce Adelstein Lelbach aka wash <brycelelbach_at_[hidden]<mailto:brycelelbach_at_[hidden]>>
>>>> | Sent: Wednesday, July 10, 2019 2:37 PM
>>>> | To: Gabriel Dos Reis <gdr_at_[hidden]<mailto:gdr_at_[hidden]>>
>>>> | Cc: Tom Honermann <tom_at_[hidden]<mailto:tom_at_[hidden]>>; modules_at_[hidden]<mailto:modules_at_[hidden]>;
>>>> | sg15_at_[hidden]<mailto: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]<mailto: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<http://eel.is>
>>>> | %2Fc%2B%2Bdraft%2Fcpp.include%237&amp;data=02%7C01%7Cgdr%40mic
>>>> | rosoft.com<https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Frosoft.com&data=02%7C01%7Cgdr%40microsoft.com%7Cf0b73ef1eb5348c4f0f408d705fa63aa%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636984445289953918&sdata=NCP7E3TfGS7WzkGY5pvgbx4P1Sm%2F2X4KGXwmf0YI5yw%3D&reserved=0>%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.
>>
>>
>> Thanks for clarifying the intent.
>>
>> 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.
>>
>>
>> That is indeed one possible conforming workaround. Another is what MSVC has been doing, but I would like to proceed differently with a more standards-blessed technique.
>>
>>
>> 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.
>>
>>
>> The problem with mandatory include translation is that it precludes existing conforming implementation techniques of headers where certain parts are driven from the outside by macros. Those techniques are necessary for incremental adoption.
>>
>>
>> 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.)
>>
>>
>> That roughly matches what MSVC has been doing for the last 3 years (in addition to fabricating a hash based on the content of the header for “include guard” purposes.)
>>
>> I am supportive of exploring this path of bugfix for C++20.
>
>
> OK! Shall we plan to coauthor a paper for the post-Cologne mailing, with the intent of filing an NB comment to make this change, or failing that, trying to resolve it as a DR? (We could also see if Ville is prepared to lend us some EWG time at Cologne, but I wouldn't bet on it.)
>>
>> 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.)
>>
>>
>> And that would help with adoption of header imports as better replacement of PCHs.
>>
>> — Gaby
>>


--
Bryce Adelstein Lelbach aka wash
CUDA Core C++ Libraries Lead @ NVIDIA
ISO C++ Library Evolution Incubator Chair
ISO C++ Tooling Chair
CppCon and C++Now Program Chair
CUDA Convert and Reformed AVX Junkie

Sleep is for the weak
--
_______________________________________________
SG15 mailing list
SG15_at_[hidden]<mailto:SG15_at_lists.isocpp.org>
http://lists.isocpp.org/mailman/listinfo.cgi/sg15<https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Flists.isocpp.org%2Fmailman%2Flistinfo.cgi%2Fsg15&data=02%7C01%7Cgdr%40microsoft.com%7Cf0b73ef1eb5348c4f0f408d705fa63aa%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636984445289963916&sdata=d%2FO92sOG0EtOBS0j9IAHFnspjVOmzZ1US6UIw9pJsqw%3D&reserved=0>

Received on 2019-07-11 07:38:42