Author: Corentin Jabot
Date: 2026-07-10T15:42:16+02:00
New Revision: d600c925f4df79a008ddbb6c1862e1d8b0ee0686

URL: 
https://github.com/llvm/llvm-project/commit/d600c925f4df79a008ddbb6c1862e1d8b0ee0686
DIFF: 
https://github.com/llvm/llvm-project/commit/d600c925f4df79a008ddbb6c1862e1d8b0ee0686.diff

LOG: [Clang] Supports dollars in UDLs and pp-numbers (#208490)

When dollars are supported in identifiers, we should be consistent.

Fixes #173985
Fixes #171190

Added: 
    clang/test/Lexer/dollar-idents.cpp

Modified: 
    clang/docs/ReleaseNotes.md
    clang/lib/Lex/Lexer.cpp
    clang/lib/Lex/TokenConcatenation.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7f0a28acd2ade..bec72fc78394b 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -799,6 +799,7 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 - Fixed an issue where `__typeof_unqual` and `__typeof_unqual__` were rejected 
as a declaration specifier in block scope in C++.
 - Fixed crash when checking for overflow for unary operator that can't 
overflow (#GH170072)
 - Clang no longer handles a `" q-char-sequence "` header name as a string 
literal (#GH132643).
+- Under `-fdollars-in-identifiers`, the `$` can now appear in 
user-defined-literals. (#GH173985)
 - Fixed an assertion where we improperly handled implicit conversions to 
integral types from an atomic-type with a conversion function. (#GH201770)
 - Fixed assertion failures involving code completion with delayed default 
arguments and exception specifications. (#GH200879)
 - Fixed a regression where calling a function that takes a class-type 
parameter by value inside `decltype` of a concept could be incorrectly rejected 
when used as a non-type template argument. (#GH175831)
@@ -1142,7 +1143,7 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 
 - Fixed a crash in code completion when using a C-Style cast with a 
parenthesized
   operand in Objective-C++ mode. (#GH180125)
-- Fixed a crash when code completion is triggered inside an ill-formed 
lambda's trailing requires-clause. (#GH201632)  
+- Fixed a crash when code completion is triggered inside an ill-formed 
lambda's trailing requires-clause. (#GH201632)
 
 ### Static Analyzer
 

diff  --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index f52b84a42ca70..32ad310ca2672 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -2144,6 +2144,7 @@ bool Lexer::LexNumericConstant(Token &Result, const char 
*CurPtr) {
   // If we have a digit separator, continue.
   if (C == '\'' && LangOpts.AllowLiteralDigitSeparator) {
     auto [Next, NextSize] = getCharAndSizeNoWarn(CurPtr + Size, LangOpts);
+    // A digit or non-digit.
     if (isAsciiIdentifierContinue(Next)) {
       if (!isLexingRawMode())
         Diag(CurPtr, LangOpts.CPlusPlus
@@ -2155,6 +2156,11 @@ bool Lexer::LexNumericConstant(Token &Result, const char 
*CurPtr) {
     }
   }
 
+  if (C == '$' && LangOpts.DollarIdents) {
+    CurPtr = ConsumeChar(CurPtr, Size, Result);
+    return LexNumericConstant(Result, CurPtr);
+  }
+
   // If we have a UCN or UTF-8 character (perhaps in a ud-suffix), continue.
   if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result))
     return LexNumericConstant(Result, CurPtr);
@@ -2179,7 +2185,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char 
*CurPtr,
   char C = getCharAndSize(CurPtr, Size);
   bool Consumed = false;
 
-  if (!isAsciiIdentifierStart(C)) {
+  if (!isAsciiIdentifierStart(C, LangOpts.DollarIdents)) {
     if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result))
       Consumed = true;
     else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr, Result))
@@ -2217,7 +2223,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char 
*CurPtr,
       while (true) {
         auto [Next, NextSize] =
             getCharAndSizeNoWarn(CurPtr + Consumed, LangOpts);
-        if (!isAsciiIdentifierContinue(Next)) {
+        if (!isAsciiIdentifierContinue(Next, LangOpts.DollarIdents)) {
           // End of suffix. Check whether this is on the allowed list.
           const StringRef CompleteSuffix(Buffer, Chars);
           IsUDSuffix =
@@ -2249,7 +2255,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char 
*CurPtr,
   Result.setFlag(Token::HasUDSuffix);
   while (true) {
     C = getCharAndSize(CurPtr, Size);
-    if (isAsciiIdentifierContinue(C)) {
+    if (isAsciiIdentifierContinue(C, LangOpts.DollarIdents)) {
       CurPtr = ConsumeChar(CurPtr, Size, Result);
     } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) {
     } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr, Result)) {

diff  --git a/clang/lib/Lex/TokenConcatenation.cpp 
b/clang/lib/Lex/TokenConcatenation.cpp
index f94caee24dc11..2507fa4358893 100644
--- a/clang/lib/Lex/TokenConcatenation.cpp
+++ b/clang/lib/Lex/TokenConcatenation.cpp
@@ -271,8 +271,9 @@ bool TokenConcatenation::AvoidConcat(const Token 
&PrevPrevTok,
     return IsIdentifierStringPrefix(PrevTok);
 
   case tok::numeric_constant:
-    return isPreprocessingNumberBody(FirstChar) ||
-           FirstChar == '+' || FirstChar == '-';
+    return isPreprocessingNumberBody(FirstChar) || FirstChar == '+' ||
+           FirstChar == '-' ||
+           (PP.getLangOpts().DollarIdents && FirstChar == '$');
   case tok::period:          // ..., .*, .1234
     return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
            isDigit(FirstChar) ||

diff  --git a/clang/test/Lexer/dollar-idents.cpp 
b/clang/test/Lexer/dollar-idents.cpp
new file mode 100644
index 0000000000000..138451f8a49c6
--- /dev/null
+++ b/clang/test/Lexer/dollar-idents.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -std=c++11 -Wno-user-defined-literals -verify %s
+// RUN: %clang_cc1 -std=c++11 -Wno-user-defined-literals -verify=no_dollar 
-fno-dollars-in-identifiers %s
+
+int $;  // no_dollar-error {{expected unqualified-id}}
+int $$; // no_dollar-error {{expected unqualified-id}}
+int Σ$; // no_dollar-error {{expected ';' after top level declarator}}
+int $Σ; // no_dollar-error {{expected unqualified-id}}
+
+using size_t = decltype(sizeof(void *));
+
+namespace UDL {
+
+int operator"" $(const char *p, size_t n);  // no_dollar-error {{expected 
identifier}}
+int operator"" $$(const char *p, size_t n); // no_dollar-error {{expected 
identifier}}
+int operator"" Σ$(const char *p, size_t n); // no_dollar-error {{'operator""Σ' 
cannot be the name of a variable or data member}} \
+                                                          // no_dollar-error 
{{expected ';' after top level declarator}}
+int operator"" $Σ(const char *p, size_t n); // no_dollar-error {{expected 
identifier}}
+int operator"" Σ(const char *p, size_t n);
+
+}
+namespace UDL2 {
+
+int operator"" _$(unsigned long long); // expected-warning {{identifier '_$' 
preceded by whitespace in a literal operator declaration is deprecated}} \
+                                       // no_dollar-error {{'operator""_' 
cannot be the name of a variable or data member}} \
+                                       // no_dollar-error {{expected ';' after 
top level declarator}} \
+                                       // no_dollar-warning {{identifier '_' 
preceded by whitespace in a literal operator declaration is deprecated}}
+int a = 1_$;                           // no_dollar-error {{no matching 
literal operator for call}}
+
+int operator"" _a$(unsigned long long); // expected-warning {{identifier '_a$' 
preceded by whitespace in a literal operator declaration is deprecated}} \
+                                        // no_dollar-error {{expected ';' 
after top level declarator}} \
+                                        // no_dollar-error {{'operator""_a' 
cannot be the name of a variable or data member}} \
+                                        // no_dollar-warning {{identifier '_a' 
preceded by whitespace in a literal operator declaration is deprecated}}
+int b = 1_a$;                           // no_dollar-error {{no matching 
literal operator for call}}
+
+
+int operator""_c$(unsigned long long); // no_dollar-error {{'operator""_c' 
cannot be the name of a variable or data member}} \
+                                       // no_dollar-error {{expected ';' after 
top level declarator}}
+int c = 1_c$;                          // no_dollar-error {{no matching 
literal operator for call}}
+
+}
+
+#define CAT(X,Y,Z)CAT_(X,Y##Z)
+#define CAT_(X,Y)X##Y
+void GH171190(){
+    int CAT(X,0,$); // no_dollar-error {{pasting formed '0$', an invalid 
preprocessing token}} \
+                    // no_dollar-error {{expected ';' at end of declaration}}
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to