This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115c. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-09-25


2521. User-defined literals and reserved identifiers

Section: 12.6  [over.literal]     Status: C++23     Submitter: Jim X     Date: 2022-01-07     Liaison: (EWG)

[Accepted as a DR at the February, 2023 meeting.]

The example in 12.6 [over.literal] paragraph 8 has the following lines:

  double operator""_Bq(long double);  // OK: does not use the reserved identifier _Bq (5.10)
  double operator"" _Bq(long double); // ill-formed, no diagnostic required:
                                      // uses the reserved identifier _Bq (5.10)

The referenced rule in 5.10 [lex.name] is in bullet 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.

The distinction being drawn in the user-defined literal example apparently relies on the grammar for literal-operator-id at the beginning of 12.6 [over.literal]:

The second production does not mention the syntactic non-terminal identifier, so the literal-operator-id operator""_Bq presumably does not run afoul of the restriction in 5.10 [lex.name]. However, the grammar for user-defined-string-literal in 5.13.9 [lex.ext] is:

There doesn't seem to be a rule that exempts the identifier that is the ud-suffix of a user-defined-string-literal from the restriction in 5.10 [lex.name]. Either the example is incorrect or there needs to be a refinement of the rule in 5.10 [lex.name].

CWG 2022-11-11

CWG feels that the ostensible significance of whitespace in this context is unfortunate. In addition, since the normative rule is not consistent with the example, CWG solicits EWG input on the handling of this issue via cplusplus/papers#1367.

EWG 2023-02-06

EWG had consensus on "The form of User Defined Literals that permits a space between the quotes and the name of the literal should be deprecated, and eventually removed. Additionally, the UDL name should be excluded from the restriction in 5.10 [lex.name] in the non-deprecated form (sans space)."

Proposed resolution (February, 2023) [SUPERSEDED]:

  1. Change in 5.10 [lex.name] paragraph 3 as follows:

    In addition, some identifiers appearing as a token or pp-token are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
  2. Change in 12.6 [over.literal] paragraph 1 as follows:

    The string-literal or user-defined-string-literal in a literal-operator-id shall have no encoding-prefix and shall contain no characters other than the implicit terminating '\0'. The ud-suffix of the user-defined-string-literal or the identifier in a literal-operator-id is called a literal suffix identifier. The first form of literal-operator-id is deprecated. Some literal suffix identifiers are reserved for future standardization; see 16.4.5.3.6 [usrlit.suffix]. A declaration whose literal-operator-id uses such a literal suffix identifier is ill-formed, no diagnostic required.
  3. Change in 12.6 [over.literal] paragraph 8 as follows:

      void operator "" _km(long double);         // OK
      string operator "" _i18n(const char*, std::size_t); // OK, deprecated
      template <char...> double operator "" _\u03C0();  // OK, UCN for lowercase pi
      float operator ""_e(const char*);          // OK
      float operator ""E(const char*);          // ill-formed, no diagnostic required:
    			    // reserved literal suffix ([usrlit.suffix], [lex.ext])
      double operator""_Bq(long double);         // OK, does not use the reserved identifier _Bq ([lex.name])
      double operator"" _Bq(long double);         // ill-formed, no diagnostic required:
    			    // uses the reserved identifier _Bq ([lex.name])
      float operator " " B(const char*);         // error: non-empty string-literal
      string operator "" 5X(const char*, std::size_t);  // error: invalid literal suffix identifier
      double operator "" _miles(double);         // error: invalid parameter-declaration-clause
      template <char...> int operator "" _j(const char*); // error: invalid parameter-declaration-clause
      extern "C" void operator "" _m(long double);    // error: C language linkage
    
  4. Add a new subclause after D.7 [depr.impldec]:

    D.9 Literal operator function declarations using an identifier [depr.lit]

    A literal-operator-id (12.6 [over.literal]) of the form

        operator string-literal identifier
    
    is deprecated.

CWG 2023-02-07

Some implementers are concerned about the lack of space for implementation extensions. The suggestion is to reserve literal suffix identifiers starting with two underscores for the implementation in 16.4.5.3.6 [usrlit.suffix]. EWG is invited to comment on that direction.

EWG / LEWG 2023-02-07

EWG and LEWG resolved to amend the proposed resolution for CWG2521 to reserve literal suffix identifiers with double underscores anywhere for implementation use.

Proposed resolution (approved by CWG 2023-02-09):

  1. Change in 5.10 [lex.name] paragraph 3 as follows:

    In addition, some identifiers appearing as a token or pp-token are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
  2. In 5.13.9 [lex.ext], modify all occurrences as follows:

    operator "" X
    
  3. Change in 5.13.9 [lex.ext] paragraph 7 as follows:

    long double operator "" _w(long double);
    std::string operator "" _w(const char16_t*, std::size_t);
    unsigned operator "" _w(const char*);
    int main() {
      1.2_w;      // calls operator "" _w(1.2L)
      u"one"_w;   // calls operator "" _w(u"one", 3)
      12_w;       // calls operator "" _w("12")
      "two"_w;    // error: no applicable literal operator
    }
    
  4. Change in 12.6 [over.literal] paragraph 1 as follows:

    The string-literal or user-defined-string-literal in a literal-operator-id shall have no encoding-prefix and shall contain no characters other than the implicit terminating '\0'. The ud-suffix of the user-defined-string-literal or the identifier in a literal-operator-id is called a literal suffix identifier. The first form of literal-operator-id is deprecated. Some literal suffix identifiers are reserved for future standardization; see 16.4.5.3.6 [usrlit.suffix]. A declaration whose literal-operator-id uses such a literal suffix identifier is ill-formed, no diagnostic required.
  5. Change in 12.6 [over.literal] paragraph 8 as follows:

      void operator "" _km(long double);         // OK
      string operator "" _i18n(const char*, std::size_t); // OK, deprecated
      template <char...> double operator "" _\u03C0();  // OK, UCN for lowercase pi
      float operator ""_e(const char*);          // OK
      float operator ""E(const char*);          // ill-formed, no diagnostic required:
    			    // reserved literal suffix ([usrlit.suffix], [lex.ext])
      double operator""_Bq(long double);         // OK, does not use the reserved identifier _Bq ([lex.name])
      double operator"" _Bq(long double);         // ill-formed, no diagnostic required:
    			    // uses the reserved identifier _Bq ([lex.name])
      float operator " " B(const char*);         // error: non-empty string-literal
      string operator "" 5X(const char*, std::size_t);  // error: invalid literal suffix identifier
      double operator "" _miles(double);         // error: invalid parameter-declaration-clause
      template <char...> int operator "" _j(const char*); // error: invalid parameter-declaration-clause
      extern "C" void operator "" _m(long double);    // error: C language linkage
    
  6. Change in 16.4.5.3.6 [usrlit.suffix] as follows:

    Literal suffix identifiers (12.6 [over.literal]) that do not start with an underscore are reserved for future standardization. Literal suffix identifiers that contain a double underscore __ are reserved for use by C++ implementations.
  7. Add a new subclause after D.7 [depr.impldec]:

    D.9 Literal operator function declarations using an identifier [depr.lit]

    A literal-operator-id (12.6 [over.literal]) of the form

        operator string-literal identifier
    
    is deprecated.