Date: Thu, 11 Jul 2019 12:09:38 +0000
+1.
| -----Original Message-----
| From: Bryce Adelstein Lelbach aka wash <brycelelbach_at_gmail.com>
| Sent: Thursday, July 11, 2019 1:36 AM
| To: Richard Smith <richardsmith_at_google.com>
| Cc: Gabriel Dos Reis <gdr_at_microsoft.com>; Michael Spencer
| <bigcheesegs_at_[hidden]>; sg15_at_lists.isocpp.org;
| modules_at_[hidden]
| Subject: Re: [SG15] [isocpp-modules] Determining identity like #pragma once
|
| 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_google.com>
| wrote:
| >
| > On Wed, Jul 10, 2019 at 4:03 PM Gabriel Dos Reis <gdr_at_microsoft.com>
| wrote:
| >>
| >> On Jul 10, 2019, at 3:40 PM, Richard Smith <richardsmith_at_google.com>
| wrote:
| >>
| >> 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_gmail.com>
| >>>> | Sent: Wednesday, July 10, 2019 2:37 PM
| >>>> | To: Gabriel Dos Reis <gdr_at_microsoft.com>
| >>>> | Cc: Tom Honermann <tom_at_honermann.net>;
| modules_at_[hidden]rg;
| >>>> | 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 ;"
| >>>> | http://eel.is
| >>>> |
| %2Fc%2B%2Bdraft%2Fcpp.include%237&data=02%7C01%7Cgdr%40mic
| >>>> |
| rosoft.com%7C57adb75b608743ebf6e208d7057ed5d4%7C72f988bf86f141af
| >>>> |
| 91ab2d7cd011db47%7C1%7C0%7C636983914618863287&sdata=JsvGf
| >>>> |
| 0RfvcjOSMF6q%2FfsW60hhKx5TI%2F1K42M8PdRbOU%3D&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
| --
| -----Original Message-----
| From: Bryce Adelstein Lelbach aka wash <brycelelbach_at_gmail.com>
| Sent: Thursday, July 11, 2019 1:36 AM
| To: Richard Smith <richardsmith_at_google.com>
| Cc: Gabriel Dos Reis <gdr_at_microsoft.com>; Michael Spencer
| <bigcheesegs_at_[hidden]>; sg15_at_lists.isocpp.org;
| modules_at_[hidden]
| Subject: Re: [SG15] [isocpp-modules] Determining identity like #pragma once
|
| 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_google.com>
| wrote:
| >
| > On Wed, Jul 10, 2019 at 4:03 PM Gabriel Dos Reis <gdr_at_microsoft.com>
| wrote:
| >>
| >> On Jul 10, 2019, at 3:40 PM, Richard Smith <richardsmith_at_google.com>
| wrote:
| >>
| >> 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_gmail.com>
| >>>> | Sent: Wednesday, July 10, 2019 2:37 PM
| >>>> | To: Gabriel Dos Reis <gdr_at_microsoft.com>
| >>>> | Cc: Tom Honermann <tom_at_honermann.net>;
| modules_at_[hidden]rg;
| >>>> | 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 ;"
| >>>> | http://eel.is
| >>>> |
| %2Fc%2B%2Bdraft%2Fcpp.include%237&data=02%7C01%7Cgdr%40mic
| >>>> |
| rosoft.com%7C57adb75b608743ebf6e208d7057ed5d4%7C72f988bf86f141af
| >>>> |
| 91ab2d7cd011db47%7C1%7C0%7C636983914618863287&sdata=JsvGf
| >>>> |
| 0RfvcjOSMF6q%2FfsW60hhKx5TI%2F1K42M8PdRbOU%3D&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
| --
Received on 2019-07-11 07:11:33