[clang] 5ce5e98 - [Clang] Add warnings for CWG2521

Po-yao Chang via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 18 16:24:01 PDT 2023


Author: Po-yao Chang
Date: 2023-07-19T07:23:34+08:00
New Revision: 5ce5e983f82c802e44faa8ed42d605d70c045ba9

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

LOG: [Clang] Add warnings for CWG2521

1. Teach -Wuser-defined-literals to warn on using double underscores in
   literal suffix identifiers.
2. Add -Wdeprecated-literal-operator to warn about the use of the first
   grammar production of literal-operator-id, which defaults to off for now.

Differential Revision: https://reviews.llvm.org/D152632

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Basic/IdentifierTable.h
    clang/lib/Basic/IdentifierTable.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/CXX/drs/dr25xx.cpp
    clang/www/cxx_dr_status.html

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cad10dd090263c..7d7c07f818e0fd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -142,6 +142,22 @@ Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Implemented `DR2397 <https://wg21.link/CWG2397>`_ which allows ``auto`` specifier for pointers
   and reference to arrays.
+- Implemented `CWG2521 <https://wg21.link/CWG2521>`_ which reserves using ``__`` in user-defined
+  literal suffixes and deprecates literal operator function declarations using an identifier.
+  Taught ``-Wuser-defined-literals`` for the former, on by default, and added
+  ``-Wdeprecated-literal-operator`` for the latter, off by default for now.
+
+  .. code-block:: c++
+
+    // What follows is warned by -Wuser-defined-literals
+    // albeit "ill-formed, no diagnostic required".
+    // Its behavior is undefined, [reserved.names.general]p2.
+    string operator ""__i18n(const char*, std::size_t);
+
+    // Assume this declaration is not in the global namespace.
+    // -Wdeprecated-literal-operator diagnoses the extra space.
+    string operator "" _i18n(const char*, std::size_t);
+    //                ^ an extra space
 
 C Language Changes
 ------------------

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index c0797166585e44..7b4d415bf06494 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -183,6 +183,7 @@ def DeprecatedCopyWithUserProvidedCopy : DiagGroup<"deprecated-copy-with-user-pr
 def DeprecatedCopyWithUserProvidedDtor : DiagGroup<"deprecated-copy-with-user-provided-dtor">;
 def DeprecatedCopy : DiagGroup<"deprecated-copy", [DeprecatedCopyWithUserProvidedCopy]>;
 def DeprecatedCopyWithDtor : DiagGroup<"deprecated-copy-with-dtor", [DeprecatedCopyWithUserProvidedDtor]>;
+def DeprecatedLiteralOperator : DiagGroup<"deprecated-literal-operator">;
 // For compatibility with GCC.
 def : DiagGroup<"deprecated-copy-dtor", [DeprecatedCopyWithDtor]>;
 def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">;
@@ -220,6 +221,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
                                           DeprecatedEnumFloatConversion,
                                           DeprecatedBuiltins,
                                           DeprecatedIncrementBool,
+                                          DeprecatedLiteralOperator,
                                           DeprecatedPragma,
                                           DeprecatedRegister,
                                           DeprecatedThisCapture,
@@ -865,7 +867,7 @@ def SignedEnumBitfield : DiagGroup<"signed-enum-bitfield">;
 
 def ReservedModuleIdentifier : DiagGroup<"reserved-module-identifier">;
 def ReservedIdentifier : DiagGroup<"reserved-identifier",
-    [ReservedIdAsMacro, ReservedModuleIdentifier]>;
+    [ReservedIdAsMacro, ReservedModuleIdentifier, UserDefinedLiterals]>;
 
 // Unreachable code warning groups.
 //

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d9932e0aa31a2a..52cca5acfd9245 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -406,6 +406,9 @@ def warn_reserved_extern_symbol: Warning<
   "it starts with '_' followed by a capital letter|"
   "it contains '__'}1">,
   InGroup<ReservedIdentifier>, DefaultIgnore;
+def warn_deprecated_literal_operator_id: Warning<
+  "identifier %0 preceded by whitespace in a literal operator declaration "
+  "is deprecated">, InGroup<DeprecatedLiteralOperator>, DefaultIgnore;
 def warn_reserved_module_name : Warning<
   "%0 is a reserved name for a module">, InGroup<ReservedModuleIdentifier>;
 
@@ -9261,8 +9264,8 @@ def ext_string_literal_operator_template : ExtWarn<
   "string literal operator templates are a GNU extension">,
   InGroup<GNUStringLiteralOperatorTemplate>;
 def warn_user_literal_reserved : Warning<
-  "user-defined literal suffixes not starting with '_' are reserved"
-  "%select{; no literal will invoke this operator|}0">,
+  "user-defined literal suffixes %select{<ERROR>|not starting with '_'|containing '__'}0 are reserved"
+  "%select{; no literal will invoke this operator|}1">,
   InGroup<UserDefinedLiterals>;
 
 // C++ conversion functions

diff  --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index 2c7ce0e4b97532..f87f7671481579 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -50,6 +50,12 @@ enum class ReservedIdentifierStatus {
   ContainsDoubleUnderscore,
 };
 
+enum class ReservedLiteralSuffixIdStatus {
+  NotReserved = 0,
+  NotStartsWithUnderscore,
+  ContainsDoubleUnderscore,
+};
+
 /// Determine whether an identifier is reserved for use as a name at global
 /// scope. Such identifiers might be implementation-specific global functions
 /// or variables.
@@ -491,6 +497,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
   /// 7.1.3, C++ [lib.global.names]).
   ReservedIdentifierStatus isReserved(const LangOptions &LangOpts) const;
 
+  /// Determine whether \p this is a name reserved for future standardization or
+  /// the implementation (C++ [usrlit.suffix]).
+  ReservedLiteralSuffixIdStatus isReservedLiteralSuffixId() const;
+
   /// If the identifier is an "uglified" reserved name, return a cleaned form.
   /// e.g. _Foo => Foo. Otherwise, just returns the name.
   StringRef deuglifiedName() const;

diff  --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index 661e9f79579a6b..0065a6173c2003 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -397,6 +397,19 @@ IdentifierInfo::isReserved(const LangOptions &LangOpts) const {
   return ReservedIdentifierStatus::NotReserved;
 }
 
+ReservedLiteralSuffixIdStatus
+IdentifierInfo::isReservedLiteralSuffixId() const {
+  StringRef Name = getName();
+
+  if (Name[0] != '_')
+    return ReservedLiteralSuffixIdStatus::NotStartsWithUnderscore;
+
+  if (Name.contains("__"))
+    return ReservedLiteralSuffixIdStatus::ContainsDoubleUnderscore;
+
+  return ReservedLiteralSuffixIdStatus::NotReserved;
+}
+
 StringRef IdentifierInfo::deuglifiedName() const {
   StringRef Name = getName();
   if (Name.size() >= 2 && Name.front() == '_' &&

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5c68642712a8a5..4848af9ade35b3 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -16447,15 +16447,18 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
     }
   }
 
-  StringRef LiteralName
-    = FnDecl->getDeclName().getCXXLiteralIdentifier()->getName();
-  if (LiteralName[0] != '_' &&
+  const IdentifierInfo *II = FnDecl->getDeclName().getCXXLiteralIdentifier();
+  ReservedLiteralSuffixIdStatus Status = II->isReservedLiteralSuffixId();
+  if (Status != ReservedLiteralSuffixIdStatus::NotReserved &&
       !getSourceManager().isInSystemHeader(FnDecl->getLocation())) {
-    // C++11 [usrlit.suffix]p1:
-    //   Literal suffix identifiers that do not start with an underscore
-    //   are reserved for future standardization.
+    // C++23 [usrlit.suffix]p1:
+    //   Literal suffix identifiers 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.
     Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved)
-      << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName);
+        << static_cast<int>(Status)
+        << StringLiteralParser::isValidUDSuffix(getLangOpts(), II->getName());
   }
 
   return false;

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 168a0f354683d8..3e43b69dc8bb29 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -502,13 +502,16 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
     IdentifierInfo *II = Name.Identifier;
     ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts());
     SourceLocation Loc = Name.getEndLoc();
-    if (isReservedInAllContexts(Status) &&
-        !PP.getSourceManager().isInSystemHeader(Loc)) {
-      Diag(Loc, diag::warn_reserved_extern_symbol)
-          << II << static_cast<int>(Status)
-          << FixItHint::CreateReplacement(
-                 Name.getSourceRange(),
-                 (StringRef("operator\"\"") + II->getName()).str());
+    if (!PP.getSourceManager().isInSystemHeader(Loc)) {
+      if (auto Hint = FixItHint::CreateReplacement(
+              Name.getSourceRange(),
+              (StringRef("operator\"\"") + II->getName()).str());
+          isReservedInAllContexts(Status)) {
+        Diag(Loc, diag::warn_reserved_extern_symbol)
+            << II << static_cast<int>(Status) << Hint;
+      } else {
+        Diag(Loc, diag::warn_deprecated_literal_operator_id) << II << Hint;
+      }
     }
   }
 

diff  --git a/clang/test/CXX/drs/dr25xx.cpp b/clang/test/CXX/drs/dr25xx.cpp
index b41f026e629f02..a535f65e085608 100644
--- a/clang/test/CXX/drs/dr25xx.cpp
+++ b/clang/test/CXX/drs/dr25xx.cpp
@@ -1,4 +1,14 @@
-// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify
+// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+
+#if __cplusplus < 201103L
+// expected-no-diagnostics
+#endif
 
 namespace dr2516 { // dr2516: yes
                    // NB: reusing 1482 test
@@ -13,9 +23,13 @@ enum E2 : S<E2>::I { e };
 
 namespace dr2518 { // dr2518: 17
 
+#if __cplusplus >= 201103L
 template <class T>
 void f(T t) {
   if constexpr (sizeof(T) != sizeof(int)) {
+#if __cplusplus < 201703L
+// expected-error at -2 {{constexpr if is a C++17 extension}}
+#endif
     static_assert(false, "must be int-sized"); // expected-error {{must be int-size}}
   }
 }
@@ -28,6 +42,9 @@ void g(char c) {
 template <typename Ty>
 struct S {
   static_assert(false); // expected-error {{static assertion failed}}
+#if __cplusplus < 201703L
+// expected-error at -2 {{'static_assert' with no message is a C++17 extension}}
+#endif
 };
 
 template <>
@@ -41,11 +58,31 @@ int test_specialization() {
   S<float> s2;
   S<double> s3; // expected-note {{in instantiation of template class 'dr2518::S<double>' requested here}}
 }
+#endif
 
 }
 
+namespace dr2521 { // dr2521: 17
+#if __cplusplus >= 201103L
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wdeprecated-literal-operator"
+long double operator""      _\u03C0___(long double);
+// expected-warning at -1 {{identifier '_π___' preceded by whitespace in a literal operator declaration is deprecated}}
+// expected-warning at -2 {{user-defined literal suffixes containing '__' are reserved}}
+
+template <char... Chars> decltype(sizeof 0)
+operator""  _div();
+// expected-warning at -1 {{identifier '_div' preceded by whitespace in a literal operator declaration is deprecated}}
+
+using ::dr2521::operator"" _\u03C0___;
+using ::dr2521::operator""_div;
+// expected-warning at -2 {{identifier '_π___' preceded by whitespace in a literal operator declaration is deprecated}}
+#pragma clang diagnostic pop
+#endif
+} // namespace dr2521
 
 namespace dr2565 { // dr2565: 16 open
+#if __cplusplus >= 202002L
   template<typename T>
     concept C = requires (typename T::type x) {
       x + 1;
@@ -107,4 +144,5 @@ namespace dr2565 { // dr2565: 16 open
   // expected-error at -1{{static assertion failed}}
   // expected-note at -2{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
 
+#endif
 }

diff  --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 07c51401b6b41e..c950b5b08d1afa 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -14933,7 +14933,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://cplusplus.github.io/CWG/issues/2521.html">2521</a></td>
     <td>DR</td>
     <td>User-defined literals and reserved identifiers</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 17</td>
   </tr>
   <tr class="open" id="2522">
     <td><a href="https://cplusplus.github.io/CWG/issues/2522.html">2522</a></td>


        


More information about the cfe-commits mailing list