10

Follow up to discussion in comments of Do preprocessor defines substitute in `operator""_name`

According to cppreference, reserved identifiers include

in the global namespace, identifiers that begin with an underscore.

To my knowledge, macros are not part of a namespace, so according to that #define _min should not make my program ill-formed, no diagnostic required. But is it really okay to do so? Do I have guarantee that compliant compiler will never use this identifier in a way that could be broken by this macro?

Yksisarvinen
  • 18,008
  • 2
  • 24
  • 52
  • 2
    *Macros are not part of namespace* This is false. All macros belong to the global namespace. – NathanOliver Aug 02 '23 at 21:11
  • You may want to consider adding `#undef _min` to your question as well. – Thomas Matthews Aug 02 '23 at 21:13
  • 2
    @NathanOliver-IsonStrike Hmm, but namespaces are not a thing at preprocessing time. – HolyBlackCat Aug 02 '23 at 21:13
  • macro with reserved-name probably is even more disasterous than a global namespace variable.If tere is anywhere some local variable named _min used in code, or any other identifier, they would be replaced with.. what? – Swift - Friday Pie Aug 02 '23 at 21:14
  • @NathanOliver-IsonStrike I couldn't find a definite information on that (cppreference doesn't mention macros on [namespaces](https://en.cppreference.com/w/cpp/language/namespace) nor namespace in [macros](https://en.cppreference.com/w/cpp/preprocessor/replace)), I guess defining that would make for an answer. – Yksisarvinen Aug 02 '23 at 21:14
  • @Yksisarvinen undefained behaviour means exactly that.. noone knows what may happen. The rule goes back to cfront an other early variants of C++ where creating those names would mess with internal naming convention used by compiler for some intermediate symbols (e.g. vtable and vtable pointers). Macroses cannot be hidden by symbols in nested namespaces. And only functional macroses can be worked around. – Swift - Friday Pie Aug 02 '23 at 21:17
  • @HolyBlackCat Sure, but the macro was still defined in the global namespace, so it should be violating the rules. – NathanOliver Aug 02 '23 at 21:18
  • In fact, even `#define min` is an UB, because there is `std::min` – Swift - Friday Pie Aug 02 '23 at 21:18
  • I have found *The global scope is the namespace scope of the global namespace* from [here](https://timsong-cpp.github.io/cppwp/basic.scope.namespace) which I think supports my conclusion – NathanOliver Aug 02 '23 at 21:19
  • @Swift-FridayPie `#define min` is not UB if you define it *after* including the standard headers. – Aykhan Hagverdili Aug 02 '23 at 21:19
  • @AyxanHaqverdili not exactly. if you start using it . Or you would ODR-use something that in one implemenetations refers to `std::min`, in another it doesn't. – Swift - Friday Pie Aug 02 '23 at 21:20
  • 2
    @AyxanHaqverdili Not according to [cppreference](https://en.cppreference.com/w/cpp/preprocessor/replace#Reserved_macro_names) - if translation unit includes any standard header, you are not allowed to `#define` or `#undef` any name declared in any standard library. Now whether this applies also to names that are hidden as implementation detail, I'm not sure. – Yksisarvinen Aug 02 '23 at 21:21
  • @Yksisarvinen Are you able to figure out what part of the spec that is referring to? I assumed that's about the names in the global namespace. If it's also about every other identifier in the standard library, that makes use of macros pretty difficult. – Aykhan Hagverdili Aug 02 '23 at 21:30
  • @NathanOliver-IsonStrike "All macros belong to the global namespace" -- A namespace is an optionally-named entity whose scope can contain declarations of any kind of entity. A macro is not an entity though. Unless there is a special rule somewhere that a namespace can contain macros, it cannot. – n. m. could be an AI Aug 02 '23 at 21:32
  • @AyxanHaqverdili Relevant , I suppose: https://stackoverflow.com/questions/52367490/whats-the-meaning-of-reserved-for-any-use – Swift - Friday Pie Aug 02 '23 at 21:39
  • 2
    @AyxanHaqverdili The standard does not consider order of include/defines for the purpose of library-reserved names: https://timsong-cpp.github.io/cppwp/n4868/macro.names#1.sentence-1 – user17732522 Aug 02 '23 at 21:39
  • @user17732522 Appears to be even stricter than UB. "shall not" suggests that doing otherwise produces ill-formed code. Even if it compiles. Not all instances of "ill-formed" required to produce diagnostics (clang does, afaik) – Swift - Friday Pie Aug 02 '23 at 21:41
  • Clang seems to think it's not UB: https://godbolt.org/z/45ffTqjvx – Artyer Aug 02 '23 at 21:52
  • 1
    @Artyer clang thinks `#define _reserved__` is also OK, which definitely isn't. – Aykhan Hagverdili Aug 02 '23 at 21:55
  • @AykhanHagverdili `_reserved__`, `_Reserved` and few others similar are something used internally by compiler's headers in case of GCC or clang, you might accidently step on a warning-supression mine. – Swift - Friday Pie Aug 03 '23 at 06:37
  • @Swift-FridayPie `_foo_bar___` doesn't warn either in Clang. – Aykhan Hagverdili Aug 03 '23 at 07:40
  • 1
    [Related](https://stackoverflow.com/q/76195920/16217248) – user16217248 Aug 30 '23 at 03:17

2 Answers2

8

[lex.name]/3.2 says that an identifier like _min, i.e. starting with an underscore,

[...] is reserved to the implementation for use as a name in the global namespace.

The wording doesn't say that you can't use the identifier in the global namespace scope, but that you must ensure that the implementation can do so. If you #define it as a macro and then include a standard library header, then the implementation can't reliably use the name in the global namespace scope.

So it seems clearly UB to me if you include (transitively) a standard library header after the #define and before a corresponding #undef. It doesn't seem however to be the intention to generally make these #define UB. As long as no standard library header is affected during preprocessing, it seems to be fine. See also comments under the answer.

An interpretation along the lines above, i.e. UB if a standard library header would see the macro definition, is also given by Richard Smith (C++ standard editor) in a comment on Clang's -Wreserved-identifier warning here, although qualified with "I think".

There is indeed a code example using #define _x in [diff.cpp03.lex]/2 of the standard which is implied to be (at least by itself) well-defined, although it is in a non-normative section of the standard.

user17732522
  • 53,019
  • 2
  • 56
  • 105
  • @EricPostpischil: But if you define a macro, then the implementation cannot use a global namespace name with the same name. That's the point; the standard prohibits you from doing *anything* which would interfere with that. – Nicol Bolas Aug 02 '23 at 21:36
  • @EricPostpischil Could C++ keywords be implemented as pre-defined macros that end up referring to `(::_min)`? For example, I can imagine `new` actually calling `::_new()` or something like that. Is that forbidden? – Aykhan Hagverdili Aug 02 '23 at 21:44
  • "..cannot use a global namespace name with the same name" It very much can, it just cannot do so carelessly. If it never mentions that name in any user-accessible header, it is free to use such name (as a name of a global function or variable for example, usable from other standard functions that are exposed to the user. For example `sin` and `cos` could call `_sincos`, the user never sees this name, but cannot define a global function with this name ). It also can push and pop user-defined macros by means of an extension if it so desperately needs to bring `_sincos` to a user-visible header. – n. m. could be an AI Aug 02 '23 at 21:48
  • @n.m.couldbeanAI Well, it doesn't say "reserved to the implementation for use **with care**". – Aykhan Hagverdili Aug 02 '23 at 21:51
  • @AyxanHaqverdili An implementation must exercise enough care so that the standard requirements are met, not just here but everywhere. If it needs a lot of care, then so be it. – n. m. could be an AI Aug 02 '23 at 21:55
  • @n.m.couldbeanAI Yes, but then the rule is pointless and I can't imagine committee (which also consists of compiler implementers) to agree on such phrasing. If you need extra care to use identifier, you would either only use identifiers that are reserved in every context or change the rule in standard. – Yksisarvinen Aug 02 '23 at 22:01
  • @n.m.couldbeanAI but imagine that name was used with `extern "C"` and what it would do with popular implementations. it would become `__sincos`, which may match with other built-in name. – Swift - Friday Pie Aug 02 '23 at 22:10
  • @EricPostpischil Sorry, my last comment didn't really make sense. I think I am now convinced that the `#define` is fine as long as the implementation's headers aren't affected by it during preprocessing. I think my answer now reflects that. – user17732522 Aug 02 '23 at 22:14
  • 1
    @Yksisarvinen Good point. I completely missed that. Added to the answer. – user17732522 Aug 02 '23 at 22:28
  • It would be legal for an implementation to use a freestanding `_min` in the global namespace from a macro that is expanded from user code. – Simon Richter Aug 03 '23 at 06:28
0

There is note about what is considered identifier:

[Note 3: In translation phase 4, identifier also includes those preprocessing-tokens ([lex.pptoken]) differentiated as keywords ([lex.key]) in the later translation phase 7 ([lex.token]). — end note] https://timsong-cpp.github.io/cppwp/lex.name#3

Phase 4 is preprocessing phase. Phase 7 is syntax analysis and translation.

Then there is infamous reserved names clause (emphasis mine):

  1. In addition, some identifiers appearing as a token or preprocessing-token are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.

(3.1) - Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.

(3.2) - Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

To wit, if you do use reserved identifier, you formally have ill-formed code. In addition, standard library identifiers are off-limits:

16.4.5.3.3 Macro names

[macro.names]

  1. A translation unit that includes a standard library header shall not #define or #undef names declared in any standard library header.

  2. A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 4, or to the attribute-tokens described in [dcl.attr], except that the names likely and unlikely may be defined as function-like macros ([cpp.replace]).

Table 4 lists

final import module override

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42