[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