[clang] 2f6ec89 - [Clang] Implement P3658R1 (#212131)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 27 22:46:28 PDT 2026
Author: Corentin Jabot
Date: 2026-07-28T07:46:23+02:00
New Revision: 2f6ec89938aa12ba5190477032b974524c956b54
URL: https://github.com/llvm/llvm-project/commit/2f6ec89938aa12ba5190477032b974524c956b54
DIFF: https://github.com/llvm/llvm-project/commit/2f6ec89938aa12ba5190477032b974524c956b54.diff
LOG: [Clang] Implement P3658R1 (#212131)
As a DR in all C++ language modes.
Because we already supported the feature this is only modifying the
extensions warnings.
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/include/clang/Basic/DiagnosticLexKinds.td
clang/lib/Lex/Lexer.cpp
clang/lib/Lex/UnicodeCharSets.h
clang/test/Lexer/unicode.c
clang/www/cxx_status.html
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index ac2688886c1ee..83f5c95797664 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -95,6 +95,10 @@ features cannot lower the translation-unit ABI level;
#### C++2d Feature Support
+- Clang now supports [P3658R1](https://wg21.link/p3658r1) (Adjust identifier
+ following new Unicode recommendations), applied as a DR to all C++ language
+ modes.
+
#### C++2c Feature Support
- Clang now supports [P3533R2](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3533r2.html) (constexpr virtual inheritance).
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 18143fc9f0feb..8330166e05199 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -145,6 +145,8 @@ def warn_utf8_symbol_homoglyph : Warning<
def warn_utf8_symbol_zero_width : Warning<
"identifier contains character %0 that is invisible in "
"some environments">, InGroup<DiagGroup<"unicode-zero-width">>;
+defm mathematical_notation : CXX29Compat<
+ "mathematical notation character %0 in an identifier is">;
def ext_mathematical_notation : ExtWarn<
"mathematical notation character %0 in an identifier is a Clang extension">,
InGroup<DiagGroup<"mathematical-notation-identifier-extension">>;
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 5826485c8b16a..d63865b024b82 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1603,12 +1603,9 @@ static bool isUnicodeWhitespace(uint32_t Codepoint) {
return UnicodeWhitespaceChars.contains(Codepoint);
}
-// To mitigate https://github.com/llvm/llvm-project/issues/54732,
-// we allow "Mathematical Notation Characters" in identifiers.
-// This is a proposed profile that extends the XID_Start/XID_continue
-// with mathematical symbols, superscipts and subscripts digits
-// found in some production software.
-// https://www.unicode.org/L2/L2022/22230-math-profile.pdf
+// The mathematical compatibility notation profile extends XID_Start and
+// XID_Continue with mathematical symbols, superscript and subscript digits.
+// https://www.unicode.org/reports/tr31/#Mathematical_Compatibility_Notation
static bool isMathematicalExtensionID(uint32_t C, const LangOptions &LangOpts,
bool IsStart, bool &IsExtension) {
static const llvm::sys::UnicodeCharSet MathStartChars(
@@ -1677,8 +1674,10 @@ static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts,
return !C99DisallowedInitialIDChars.contains(C);
}
-static void diagnoseExtensionInIdentifier(DiagnosticsEngine &Diags, uint32_t C,
- CharSourceRange Range) {
+static void
+diagnoseMathematicalNotationInIdentifier(DiagnosticsEngine &Diags,
+ const LangOptions &LangOpts,
+ uint32_t C, CharSourceRange Range) {
static const llvm::sys::UnicodeCharSet MathStartChars(
MathematicalNotationProfileIDStartRanges);
@@ -1689,7 +1688,11 @@ static void diagnoseExtensionInIdentifier(DiagnosticsEngine &Diags, uint32_t C,
(void)MathContinueChars;
assert((MathStartChars.contains(C) || MathContinueChars.contains(C)) &&
"Unexpected mathematical notation codepoint");
- Diags.Report(Range.getBegin(), diag::ext_mathematical_notation)
+ unsigned DiagID = LangOpts.CPlusPlus
+ ? DiagnosticIDs::getCompatDiagId(
+ LangOpts, diag_compat::mathematical_notation)
+ : diag::ext_mathematical_notation;
+ Diags.Report(Range.getBegin(), DiagID)
<< EscapeSingleCodepointForDiagnostic(C) << Range;
}
@@ -1861,8 +1864,9 @@ bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size,
// Carry on as if the codepoint was valid for recovery purposes.
} else if (!isLexingRawMode()) {
if (IsExtension)
- diagnoseExtensionInIdentifier(PP->getDiagnostics(), CodePoint,
- makeCharRange(*this, CurPtr, UCNPtr));
+ diagnoseMathematicalNotationInIdentifier(
+ PP->getDiagnostics(), LangOpts, CodePoint,
+ makeCharRange(*this, CurPtr, UCNPtr));
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
makeCharRange(*this, CurPtr, UCNPtr),
@@ -1917,8 +1921,8 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr, Token &Result) {
// valid for recovery purposes.
} else if (!isLexingRawMode()) {
if (IsExtension)
- diagnoseExtensionInIdentifier(
- PP->getDiagnostics(), CodePoint,
+ diagnoseMathematicalNotationInIdentifier(
+ PP->getDiagnostics(), LangOpts, CodePoint,
makeCharRange(*this, CharStart, UnicodePtr));
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
makeCharRange(*this, CharStart, UnicodePtr),
@@ -1942,8 +1946,9 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
!PP->isPreprocessedOutput()) {
if (IsExtension)
- diagnoseExtensionInIdentifier(PP->getDiagnostics(), C,
- makeCharRange(*this, BufferPtr, CurPtr));
+ diagnoseMathematicalNotationInIdentifier(
+ PP->getDiagnostics(), LangOpts, C,
+ makeCharRange(*this, BufferPtr, CurPtr));
maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C,
makeCharRange(*this, BufferPtr, CurPtr),
/*IsFirst=*/true);
diff --git a/clang/lib/Lex/UnicodeCharSets.h b/clang/lib/Lex/UnicodeCharSets.h
index 0ceab85d15586..eaee53172050f 100644
--- a/clang/lib/Lex/UnicodeCharSets.h
+++ b/clang/lib/Lex/UnicodeCharSets.h
@@ -393,9 +393,7 @@ static const llvm::sys::UnicodeCharRange XIDContinueRanges[] = {
{0x1FBF0, 0x1FBF9}, {0xE0100, 0xE01EF},
};
-// Clang supports the "Mathematical notation profile" as an extension,
-// as described in https://www.unicode.org/L2/L2022/22230-math-profile.pdf
-// Math_Start
+// Unicode 18.0 ID_Compat_Math_Start
static const llvm::sys::UnicodeCharRange
MathematicalNotationProfileIDStartRanges[] = {
{0x02202, 0x02202}, // โ
@@ -413,7 +411,7 @@ static const llvm::sys::UnicodeCharRange
{0x1D7C3, 0x1D7C3}, // ๐
};
-// Math_Continue
+// Unicode 18.0 ID_Compat_Math_Continue, excluding ID_Compat_Math_Start
static const llvm::sys::UnicodeCharRange
MathematicalNotationProfileIDContinueRanges[] = {
{0x000B2, 0x000B3}, // ยฒ-ยณ
diff --git a/clang/test/Lexer/unicode.c b/clang/test/Lexer/unicode.c
index 0974c976aee1c..53acca6ba04b7 100644
--- a/clang/test/Lexer/unicode.c
+++ b/clang/test/Lexer/unicode.c
@@ -1,6 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -x c -std=c11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,c2x -x c -std=c2x %s
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,c2x,math -x c -std=c2x %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx,math,ext -x c++ -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ -std=c++2d %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx,math,compat -x c++ -std=c++2d -Wpre-c++2d-compat %s
// RUN: %clang_cc1 -std=c99 -E -DPP_ONLY=1 %s | FileCheck %s --strict-whitespace
// RUN: %clang_cc1 -E -DPP_ONLY=1 %s | FileCheck %s --strict-whitespace
// UNSUPPORTED: system-zos
@@ -52,19 +54,23 @@ extern int a\N{TANGSALETTERGA}; // expected-error {{'TANGSALETTERGA' is not a va
// expected-error {{expected ';' after top level declarator}} \
// expected-note {{character names in Unicode escape sequences are sensitive to case and whitespace}}
-extern int ๐; // expected-warning {{mathematical notation character '๐' U+1D6DB in an identifier is a Clang extension}}
+// Mathematical notation characters are standard in C++ (P3658R1) and a Clang
+// extension in C. The 'math' prefix matches whichever warning applies.
+extern int ๐; // c2x-warning {{mathematical notation character '๐' U+1D6DB in an identifier is a Clang extension}} \
+ ext-warning {{mathematical notation character '๐' U+1D6DB in an identifier is a C++2d extension}} \
+ compat-warning {{mathematical notation character '๐' U+1D6DB in an identifier is incompatible with C++ standards before C++2d}}
extern int โ; // expected-error {{character 'โ' U+2089 not allowed at the start of an identifier}} \\
expected-warning {{declaration does not declare anything}}
extern int a\N{PICKLE}; // expected-error {{character '๐ซ' U+1FADD not allowed in an identifier}}
-int aยนbโโโโโ; // expected-warning 6{{mathematical notation character}}
+int aยนbโโโโโ; // math-warning 6{{mathematical notation character}}
-int \u{221E} = 1; // expected-warning {{mathematical notation character}}
+int \u{221E} = 1; // math-warning {{mathematical notation character}}
int \N{MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL} = 1;
- // expected-warning at -1 {{mathematical notation character}}
+ // math-warning at -1 {{mathematical notation character}}
-int a\N{SUBSCRIPT EQUALS SIGN} = 1; // expected-warning {{mathematical notation character}}
+int a\N{SUBSCRIPT EQUALS SIGN} = 1; // math-warning {{mathematical notation character}}
// This character doesn't have the XID_Start property
extern int \U00016AC0; // TANGSA DIGIT ZERO // cxx-error {{expected unqualified-id}} \
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index a12115f8b785a..16ebeb1052b79 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -137,7 +137,7 @@ <h2 id="cxx29">C++2d implementation status</h2>
<tr>
<td>Adjust identifier following new Unicode recommendations</td>
<td><a href="https://wg21.link/P3658R1">P3658R1</a> <a href="#dr">(DR)</a></td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">Clang 24</td>
</tr>
<tr>
<td><code>return_value</code> & <code>return_void</code> are not mutually exclusive</td>
More information about the cfe-commits
mailing list