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
