[clang] 20e0116 - [Clang] Produce a warning instead of an error in unevaluated strings before C++26

Corentin Jabot via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 9 23:32:48 PDT 2023


Author: Corentin Jabot
Date: 2023-08-10T08:32:42+02:00
New Revision: 20e01167b15aa17dac09e4742909a7138eca7afc

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

LOG: [Clang] Produce a warning instead of an error in unevaluated strings before C++26

Reviewed By: aaron.ballman, hubert.reinterpretcast

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

Added: 
    clang/test/FixIt/unevaluated-strings.cpp

Modified: 
    clang/include/clang/Basic/DiagnosticLexKinds.td
    clang/lib/Lex/LiteralSupport.cpp
    clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
    clang/test/CXX/dcl.dcl/p4-0x.cpp
    clang/test/Sema/static-assert.c
    clang/test/SemaCXX/static-assert.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 0eb270aeea0e5d..6ad691975bd587 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -285,6 +285,10 @@ def ext_ms_reserved_user_defined_literal : ExtWarn<
 def err_unsupported_string_concat : Error<
   "unsupported non-standard concatenation of string literals">;
 
+def warn_unevaluated_string_prefix : Warning<
+  "encoding prefix '%0' on an unevaluated string literal has no effect"
+  "%select{| and is incompatible with c++2c}1">,
+  InGroup<DiagGroup<"invalid-unevaluated-string">>;
 def err_unevaluated_string_prefix : Error<
   "an unevaluated string literal cannot have an encoding prefix">;
 def err_unevaluated_string_udl : Error<

diff  --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index 21711fcfb5d08a..888ea772ee6011 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -57,6 +57,26 @@ static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
   }
 }
 
+static unsigned getEncodingPrefixLen(tok::TokenKind kind) {
+  switch (kind) {
+  default:
+    llvm_unreachable("Unknown token type!");
+  case tok::char_constant:
+  case tok::string_literal:
+    return 0;
+  case tok::utf8_char_constant:
+  case tok::utf8_string_literal:
+    return 2;
+  case tok::wide_char_constant:
+  case tok::wide_string_literal:
+  case tok::utf16_char_constant:
+  case tok::utf16_string_literal:
+  case tok::utf32_char_constant:
+  case tok::utf32_string_literal:
+    return 1;
+  }
+}
+
 static CharSourceRange MakeCharSourceRange(const LangOptions &Features,
                                            FullSourceLoc TokLoc,
                                            const char *TokBegin,
@@ -343,7 +363,9 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
     Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
          diag::err_unevaluated_string_invalid_escape_sequence)
         << StringRef(EscapeBegin, ThisTokBuf - EscapeBegin);
+    HadError = true;
   }
+
   return ResultChar;
 }
 
@@ -1930,9 +1952,22 @@ void StringLiteralParser::init(ArrayRef<Token> StringToks){
     // Remember if we see any wide or utf-8/16/32 strings.
     // Also check for illegal concatenations.
     if (isUnevaluated() && Tok.getKind() != tok::string_literal) {
-      if (Diags)
-        Diags->Report(Tok.getLocation(), diag::err_unevaluated_string_prefix);
-      hadError = true;
+      if (Diags) {
+        SourceLocation PrefixEndLoc = Lexer::AdvanceToTokenCharacter(
+            Tok.getLocation(), getEncodingPrefixLen(Tok.getKind()), SM,
+            Features);
+        CharSourceRange Range =
+            CharSourceRange::getCharRange({Tok.getLocation(), PrefixEndLoc});
+        StringRef Prefix(SM.getCharacterData(Tok.getLocation()),
+                         getEncodingPrefixLen(Tok.getKind()));
+        Diags->Report(Tok.getLocation(),
+                      Features.CPlusPlus26
+                          ? diag::err_unevaluated_string_prefix
+                          : diag::warn_unevaluated_string_prefix)
+            << Prefix << Features.CPlusPlus << FixItHint::CreateRemoval(Range);
+      }
+      if (Features.CPlusPlus26)
+        hadError = true;
     } else if (Tok.isNot(Kind) && Tok.isNot(tok::string_literal)) {
       if (isOrdinary()) {
         Kind = Tok.getKind();

diff  --git a/clang/test/CXX/dcl.dcl/dcl.link/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
index 206c46f34f05b2..234db01a001fbf 100644
--- a/clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
@@ -8,7 +8,7 @@ extern "C" {
 extern "C" plusplus {
 }
 
-extern u8"C" {}  // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-extern L"C" {}   // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-extern u"C++" {} // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-extern U"C" {}   // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+extern u8"C" {}  // expected-warning {{encoding prefix 'u8' on an unevaluated string literal has no effect and is incompatible with c++2c}}
+extern L"C" {}   // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}}
+extern u"C++" {} // expected-warning {{encoding prefix 'u' on an unevaluated string literal has no effect and is incompatible with c++2c}}
+extern U"C" {}   // expected-warning {{encoding prefix 'U' on an unevaluated string literal has no effect and is incompatible with c++2c}}

diff  --git a/clang/test/CXX/dcl.dcl/p4-0x.cpp b/clang/test/CXX/dcl.dcl/p4-0x.cpp
index 545011822eb7d0..22b10b60ecd1b1 100644
--- a/clang/test/CXX/dcl.dcl/p4-0x.cpp
+++ b/clang/test/CXX/dcl.dcl/p4-0x.cpp
@@ -18,7 +18,7 @@ static_assert(S(false), "not so fast"); // expected-error {{not so fast}}
 static_assert(T(), "");
 static_assert(U(), ""); // expected-error {{ambiguous}}
 
-static_assert(false, L"\x14hi" // expected-error {{an unevaluated string literal cannot have an encoding prefix}} \
+static_assert(false, L"\x14hi" // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
                                // expected-error {{invalid escape sequence '\x14' in an unevaluated string literal}}
                      "!"
                      R"x(")x");

diff  --git a/clang/test/FixIt/unevaluated-strings.cpp b/clang/test/FixIt/unevaluated-strings.cpp
new file mode 100644
index 00000000000000..f42e2fc5fb11d3
--- /dev/null
+++ b/clang/test/FixIt/unevaluated-strings.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -verify -std=c++2c %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -x c++ -std=c++2c -fixit %t
+// RUN: %clang_cc1 -x c++ -std=c++2c %t
+// RUN: not %clang_cc1 -std=c++2c -x c++ -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+static_assert(true, L""); // expected-error{{an unevaluated string literal cannot have an encoding prefix}}
+// CHECK: fix-it:{{.*}}:{7:21-7:22}
+
+static_assert(true, u8""); // expected-error{{an unevaluated string literal cannot have an encoding prefix}}
+// CHECK: fix-it:{{.*}}:{10:21-10:23}
+
+static_assert(true, u""); // expected-error{{an unevaluated string literal cannot have an encoding prefix}}
+// CHECK: fix-it:{{.*}}:{13:21-13:22}
+
+static_assert(true, U""); // expected-error{{an unevaluated string literal cannot have an encoding prefix}}
+// CHECK: fix-it:{{.*}}:{16:21-16:22}

diff  --git a/clang/test/Sema/static-assert.c b/clang/test/Sema/static-assert.c
index 6ede89dc006907..4e9e6b7ee558bd 100644
--- a/clang/test/Sema/static-assert.c
+++ b/clang/test/Sema/static-assert.c
@@ -94,3 +94,20 @@ _Static_assert(__builtin_strlen("1"), "");  // ext-warning {{'_Static_assert' is
 // __builtin_strlen(literal) is considered an integer constant expression
 // and doesn't cause a pedantic warning
 #endif
+
+
+_Static_assert(0, L"\xFFFFFFFF"); // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect}} \
+                                  // expected-error {{invalid escape sequence '\xFFFFFFFF' in an unevaluated string literal}} \
+                                  // expected-error {{hex escape sequence out of range}} \
+                                  // ext-warning {{'_Static_assert' is a C11 extension}}
+_Static_assert(0, L"\u1234"); // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect}} \
+                              // expected-error {{static assertion failed: ሴ}} \
+                              // ext-warning {{'_Static_assert' is a C11 extension}}
+
+_Static_assert(0, L"\x1ff"      // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect}} \
+                                // expected-error {{hex escape sequence out of range}} \
+                                // expected-error {{invalid escape sequence '\x1ff' in an unevaluated string literal}} \
+                                // ext-warning {{'_Static_assert' is a C11 extension}}
+                   "0\x123"     // expected-error {{invalid escape sequence '\x123' in an unevaluated string literal}}
+                   "fx\xfffff"  // expected-error {{invalid escape sequence '\xfffff' in an unevaluated string literal}}
+                   "goop");

diff  --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp
index da8b726a3e4b07..5d64ff682a20e5 100644
--- a/clang/test/SemaCXX/static-assert.cpp
+++ b/clang/test/SemaCXX/static-assert.cpp
@@ -29,13 +29,19 @@ template<typename T> struct S {
 S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
 S<int> s2;
 
-static_assert(false, L"\xFFFFFFFF"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}} \
-                                     // expected-error {{invalid escape sequence '\xFFFFFFFF' in an unevaluated string literal}}
-static_assert(false, u"\U000317FF"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-// FIXME: render this as u8"\u03A9"
-static_assert(false, u8"Ω");     // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-static_assert(false, L"\u1234"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-static_assert(false, L"\x1ff"    // expected-error {{an unevaluated string literal cannot have an encoding prefix}} \
+static_assert(false, L"\xFFFFFFFF"); // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
+                                     // expected-error {{invalid escape sequence '\xFFFFFFFF' in an unevaluated string literal}} \
+                                     // expected-error {{hex escape sequence out of range}}
+static_assert(false, u"\U000317FF"); // expected-warning {{encoding prefix 'u' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
+                                     // expected-error {{static assertion failed}}
+
+static_assert(false, u8"Ω");     // expected-warning {{encoding prefix 'u8' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
+                                 // expected-error {{static assertion failed: Ω}}
+static_assert(false, L"\u1234"); // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
+                                 // expected-error {{static assertion failed: ሴ}}
+
+static_assert(false, L"\x1ff"    // expected-warning {{encoding prefix 'L' on an unevaluated string literal has no effect and is incompatible with c++2c}} \
+                                 // expected-error {{hex escape sequence out of range}} \
                                  // expected-error {{invalid escape sequence '\x1ff' in an unevaluated string literal}}
                      "0\x123"    // expected-error {{invalid escape sequence '\x123' in an unevaluated string literal}}
                      "fx\xfffff" // expected-error {{invalid escape sequence '\xfffff' in an unevaluated string literal}}


        


More information about the cfe-commits mailing list