rZhBoYao updated this revision to Diff 552060.
rZhBoYao marked 5 inline comments as done.
rZhBoYao edited the summary of this revision.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D158372/new/

https://reviews.llvm.org/D158372

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticLexKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/IdentifierTable.h
  clang/lib/Lex/Lexer.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/drs/dr14xx.cpp
  clang/test/CXX/drs/dr17xx.cpp
  clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp
  clang/test/FixIt/fixit-c++11.cpp

Index: clang/test/FixIt/fixit-c++11.cpp
===================================================================
--- clang/test/FixIt/fixit-c++11.cpp
+++ clang/test/FixIt/fixit-c++11.cpp
@@ -68,9 +68,9 @@
 }
 
 #define bar "bar"
-const char *p = "foo" bar;
+const char *p = "foo"bar; // expected-error {{requires a space between}}
 #define ord - '0'
-int k = '4' ord;
+int k = '4'ord; // expected-error {{requires a space between}}
 
 void operator"x" _y(char); // expected-error {{must be '""'}}
 void operator L"" _z(char); // expected-error {{encoding prefix}}
Index: clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp
===================================================================
--- clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp
+++ clang/test/CXX/lex/lex.literal/lex.ext/p10.cpp
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -std=c++11 -verify %s
 
 using size_t = decltype(sizeof(int));
-void operator ""wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}
-void operator ""wibble(const char *, size_t); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}
+void operator ""wibble(const char *); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved}}
+void operator ""wibble(const char *, size_t); // expected-warning {{user-defined literal suffixes not starting with '_' are reserved}}
 
 template<typename T>
 void f() {
Index: clang/test/CXX/drs/dr17xx.cpp
===================================================================
--- clang/test/CXX/drs/dr17xx.cpp
+++ clang/test/CXX/drs/dr17xx.cpp
@@ -141,9 +141,14 @@
 namespace dr1762 { // dr1762: 14
                    // NB: reusing 1473 test
 #if __cplusplus >= 201103L
-  float operator ""_E(const char *);
-  float operator ""E(const char *);
-  // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}
+#define E "!"
+const char
+  *operator""_E(const char*),
+  *operator""E(const char*), // don't err on the lack of spaces even when the literal suffix identifier is invalid
+  // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved}}
+  *s = "not empty"E;
+  // expected-error@-1 {{invalid suffix on literal; C++11 requires a space between literal and a macro}}
+#undef E
 #endif
 }
 
Index: clang/test/CXX/drs/dr14xx.cpp
===================================================================
--- clang/test/CXX/drs/dr14xx.cpp
+++ clang/test/CXX/drs/dr14xx.cpp
@@ -487,9 +487,14 @@
 namespace dr1473 { // dr1473: 18
                    // NB: sup 1762, test reused there
 #if __cplusplus >= 201103L
-  float operator ""_E(const char *);
-  float operator ""E(const char *); // don't err on the lack of spaces even when the literal suffix identifier is invalid
-  // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved; no literal will invoke this operator}}
+#define E "!"
+const char
+  *operator""_E(const char*),
+  *operator""E(const char*), // don't err on the lack of spaces even when the literal suffix identifier is invalid
+  // expected-warning@-1 {{user-defined literal suffixes not starting with '_' are reserved}}
+  *s = "not empty"E;
+  // expected-error@-1 {{invalid suffix on literal; C++11 requires a space between literal and a macro}}
+#undef E
 #endif
 }
 
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16571,8 +16571,7 @@
     //   contain a double underscore __ are reserved for use by C++
     //   implementations.
     Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved)
-        << static_cast<int>(Status)
-        << StringLiteralParser::isValidUDSuffix(getLangOpts(), II->getName());
+        << static_cast<int>(Status);
   }
 
   return false;
Index: clang/lib/Lex/Lexer.cpp
===================================================================
--- clang/lib/Lex/Lexer.cpp
+++ clang/lib/Lex/Lexer.cpp
@@ -1986,36 +1986,26 @@
   assert(LangOpts.CPlusPlus);
 
   // Maximally munch an identifier.
+  const char *const TokStart = CurPtr;
   unsigned Size;
   char C = getCharAndSize(CurPtr, Size);
-  bool Consumed = false;
 
-  if (!isAsciiIdentifierStart(C)) {
-    if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result))
-      Consumed = true;
-    else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr))
-      Consumed = true;
-    else
-      return CurPtr;
-  }
+  if (isAsciiIdentifierStart(C)) {
+    CurPtr = ConsumeChar(CurPtr, Size, Result);
+  } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) {
+  } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) {
+  } else
+    return CurPtr;
 
   if (!LangOpts.CPlusPlus11) {
     if (!isLexingRawMode())
-      Diag(CurPtr,
+      Diag(TokStart,
            C == '_' ? diag::warn_cxx11_compat_user_defined_literal
                     : diag::warn_cxx11_compat_reserved_user_defined_literal)
-        << FixItHint::CreateInsertion(getSourceLocation(CurPtr), " ");
-    return CurPtr;
+          << FixItHint::CreateInsertion(getSourceLocation(TokStart), " ");
+    return TokStart;
   }
 
-  // C++11 [lex.ext]p10, [usrlit.suffix]p1: A program containing a ud-suffix
-  // that does not start with an underscore is ill-formed. We assume a suffix
-  // beginning with a UCN or UTF-8 character is more likely to be a ud-suffix
-  // than a macro, however, and accept that.
-  if (!Consumed)
-    CurPtr = ConsumeChar(CurPtr, Size, Result);
-
-  Result.setFlag(Token::HasUDSuffix);
   while (true) {
     C = getCharAndSize(CurPtr, Size);
     if (isAsciiIdentifierContinue(C)) {
@@ -2026,6 +2016,31 @@
       break;
   }
 
+  bool IsLiteralOperator =
+      StringRef(BufferPtr, 2).equals("\"\"") && BufferPtr + 2 == TokStart;
+  if (unsigned TokLen = CurPtr - TokStart;
+      StringLiteralParser::isValidUDSuffix(LangOpts, {TokStart, TokLen}))
+    Result.setFlag(Token::HasUDSuffix);
+  else if (!isLexingRawMode() && !IsLiteralOperator) {
+    // As a conforming extension, we treat invalid suffixes as if they had
+    // whitespace before them if doing so results in macro expansions.
+    // However, don't diagnose operator""E(...) even if E is a macro as it
+    // results in confusing error messages. Hence, ""E would not be treated as
+    // string concat; instead it's a single PP token (as it should be).
+    Result.setLength(TokLen);
+    Result.setLocation(getSourceLocation(TokStart, TokLen));
+    Result.setKind(tok::raw_identifier);
+    Result.setRawIdentifierData(TokStart);
+    IdentifierInfo *II = PP->LookUpIdentifierInfo(Result);
+    if (II->hasMacroDefinition()) {
+      Diag(TokStart, LangOpts.MSVCCompat
+                         ? diag::ext_ms_reserved_user_defined_literal
+                         : diag::ext_reserved_user_defined_literal)
+          << FixItHint::CreateInsertion(getSourceLocation(TokStart), " ");
+      return TokStart;
+    }
+  }
+
   return CurPtr;
 }
 
Index: clang/include/clang/Basic/IdentifierTable.h
===================================================================
--- clang/include/clang/Basic/IdentifierTable.h
+++ clang/include/clang/Basic/IdentifierTable.h
@@ -51,9 +51,9 @@
 };
 
 enum class ReservedLiteralSuffixIdStatus {
-  NotReserved = 0,
-  NotStartsWithUnderscore,
+  NotStartsWithUnderscore = 0,
   ContainsDoubleUnderscore,
+  NotReserved,
 };
 
 /// Determine whether an identifier is reserved for use as a name at global
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9319,8 +9319,7 @@
   "string literal operator templates are a GNU extension">,
   InGroup<GNUStringLiteralOperatorTemplate>;
 def warn_user_literal_reserved : Warning<
-  "user-defined literal suffixes %select{<ERROR>|not starting with '_'|containing '__'}0 are reserved"
-  "%select{; no literal will invoke this operator|}1">,
+  "user-defined literal suffixes %select{not starting with '_'|containing '__'}0 are reserved">,
   InGroup<UserDefinedLiterals>;
 
 // C++ conversion functions
Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticLexKinds.td
+++ clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -276,6 +276,12 @@
   "identifier after literal will be treated as a reserved user-defined literal "
   "suffix in C++11">,
   InGroup<CXX11CompatReservedUserDefinedLiteral>, DefaultIgnore;
+def ext_reserved_user_defined_literal : ExtWarn<
+  "invalid suffix on literal; C++11 requires a space between literal and "
+  "a macro">, InGroup<ReservedUserDefinedLiteral>, DefaultError;
+def ext_ms_reserved_user_defined_literal : ExtWarn<
+  ext_reserved_user_defined_literal.Summary>,
+  InGroup<ReservedUserDefinedLiteral>;
 def err_unsupported_string_concat : Error<
   "unsupported non-standard concatenation of string literals">;
 
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -94,10 +94,21 @@
 
 Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- Implemented `CWG1473 <https://wg21.link/CWG1473>`_ which allows spaces after ``operator""``.
-  Clang used to err on the lack of space when the literal suffix identifier was invalid in
-  all the language modes, which contradicted the deprecation of the whitespaces.
-  Also turn on ``-Wdeprecated-literal-operator`` by default in all the language modes.
+- Implemented `CWG1473 <https://wg21.link/CWG1473>`_ allowing lack of space after ``operator""``.
+  Clang used to err on the lack of space when the literal suffix identifier was invalid,
+  contradicting ``-Wdeprecated-literal-operator`` which is now default on.
+  Instead, Clang now emits error only if the invalid suffix looks like a macro and the preceding
+  string literal is not empty, and then treat the suffix as if it were preceded by whitespace.
+
+  .. code-block:: cpp
+
+    #define E "!"
+    const char 
+      *operator""E(const char*),
+      // ""E is a single token as it should be pedantically
+      *s = "not empty"E;
+      // treated as if whitespace preceds E hence a string concat:
+      // = "not empty!"
 
 C Language Changes
 ------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to