7

Consider the following example provided by Aykhan Hagverdili:

#include <string>

using std::operator""s;

#define s foobar

auto s = "hello world"s;

Some compilers would substitute s and fail compilation. Some compilers would not substitute s.

See the result here: https://godbolt.org/z/jx4nhYczd gcc fails, clang compiles

Which is right?

Alex Guteniev
  • 12,039
  • 2
  • 34
  • 79
  • It would be easier if you gave examples of compilers that do the replacement or not. Also, identifier `_min` is [reserved](https://en.cppreference.com/w/cpp/language/identifiers) in global scope and you may not use it for macro (although using it for literal is fine) - that may or may not be the reason why some compilers do accept the code and others don't. – Yksisarvinen Aug 02 '23 at 20:19
  • 1
    The `""_min` is one token. It does not match the `_min` token. – Eljay Aug 02 '23 at 20:20
  • 2
    Operator names not starting with `_` are reserved. Macro names starting with `_` are reserved. Thus, you have undefined behavior either way. – Aykhan Hagverdili Aug 02 '23 at 20:24
  • @AyxanHaqverdili, good point. But operators are reserved for Standard Library. Assume it is a part of standard library implementation. – Alex Guteniev Aug 02 '23 at 20:25
  • 2
    @AlexGuteniev Standard library implementations are implementation defined. – Aykhan Hagverdili Aug 02 '23 at 20:26
  • 4
    @AlexGuteniev Maybe you could bring one of the standard library operators into the global namespace with `using std::operator""s` and also define the `s` as a macro *after that* to make the question more meaningful. – Aykhan Hagverdili Aug 02 '23 at 20:28
  • Here's an example with what Ayxan suggested: https://godbolt.org/z/hs7M9P9c5. It's actually interesting, I think clang is right to compile this code, but I'm not 100% sure. – Yksisarvinen Aug 02 '23 at 20:30
  • Having a whitespace after `""` is deprecated in C++23. https://cplusplus.github.io/CWG/issues/2521.html Implemenation status for this probably varies. – BoP Aug 02 '23 at 20:31
  • I say it all depends on the contents of ``. Much of the content is implementation defined. I would expect a *nice* compiler to issue a warning if `min` was already in the symbol table before the `#define` is processed. Remember that the preprocessor primarily builds a "new" version of the source code containing the substitution text. The compiler and linker will determine which version of `min` to use. – Thomas Matthews Aug 02 '23 at 20:35
  • @AlexGuteniev I would define the `s` macro *after* including the header. – Aykhan Hagverdili Aug 02 '23 at 20:40
  • @AyxanHaqverdili, in this case the issue both compiler compile it. Looks like there's no standard-compliant way to have this problem. – Alex Guteniev Aug 02 '23 at 20:42
  • @AyxanHaqverdili But then there's no ambiguity? `5s` is always interpreted as literal. On the other hand, if `""s` should compile with `#define s` beforehand is the question whether `""s` is one token or not. It seems that gcc treats it as two tokens. – Yksisarvinen Aug 02 '23 at 20:43
  • 1
    @AlexGuteniev here you go: https://godbolt.org/z/jx4nhYczd – Aykhan Hagverdili Aug 02 '23 at 20:45
  • 1
    @Yksisarvinen see my previous comment. – Aykhan Hagverdili Aug 02 '23 at 20:45
  • 1
    @AyxanHaqverdili, thanks, I pasted your example into the question – Alex Guteniev Aug 02 '23 at 20:48
  • @AyxanHaqverdili Names starting with an underscore are reserved to the implementation for use as a name in the global namespace. Macto names do not belong to any namespace. – n. m. could be an AI Aug 02 '23 at 20:51
  • 1
    @n.m.couldbeanAI In any case, you can't define a macro called `_min` because the implementation might have a global variable with that name and that variable might further be used in the definition of a standard macro, like `assert`. – Aykhan Hagverdili Aug 02 '23 at 20:55
  • @AyxanHaqverdili Then that implementation would have a bug I suppose. Why wouldn't it use a variable with a name that is reserved for all uses? – n. m. could be an AI Aug 02 '23 at 21:03
  • @n.m.couldbeanAI Well, it could have been used like `(::_min)`. Can you show me a case where this can go wrong? – Aykhan Hagverdili Aug 02 '23 at 21:04
  • 3
    Here's a follow up question about `#define _x`: https://stackoverflow.com/questions/76823547/are-you-allowed-to-define-min – Yksisarvinen Aug 02 '23 at 21:11

2 Answers2

10

"hello world"s is, since C++11, a single preprocessing token matching the user-defined-string-literal grammar production.

Macros substitute on the level of preprocessing tokens. Since there is no s preprocessing token, there can't be any substitution of your macro.

As a result your code is well-formed in C++14 or later. std::operator""s is chosen. In C++11 there was no std::operator""s.

However, before C++11 when user-defined literals were introduced, "hello world"s would have been two preprocessing tokens "hello" and s, so the latter one would have been substituted with your macro.

This is even explicitly mentioned in [diff.cpp03.lex]/2 as a backwards-incompatible change with C++11.

user17732522
  • 53,019
  • 2
  • 56
  • 105
3

GCC is wrong.

A user-defined string literal like "hello world"s is a preprocessing-token, not two preprocessing-tokens "hello world" and s. The preprocessor should not replace parts of a preprocessing-token.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243