cor3ntin updated this revision to Diff 375476.
cor3ntin added a comment.
Rename commit
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D105759/new/
https://reviews.llvm.org/D105759
Files:
clang-tools-extra/test/clang-tidy/checkers/modernize-unary-static-assert.cpp
clang/include/clang/AST/Expr.h
clang/include/clang/Basic/DiagnosticLexKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Lex/LiteralSupport.h
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/Expr.cpp
clang/lib/Frontend/FrontendAction.cpp
clang/lib/Lex/LiteralSupport.cpp
clang/lib/Lex/PPDirectives.cpp
clang/lib/Lex/PPMacroExpansion.cpp
clang/lib/Lex/Pragma.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Parse/Parser.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaInit.cpp
clang/lib/Sema/SemaStmtAsm.cpp
clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
clang/test/CXX/dcl.dcl/p4-0x.cpp
clang/test/FixIt/fixit-static-assert.cpp
clang/test/Parser/asm.c
clang/test/Parser/asm.cpp
clang/test/Parser/attr-availability-xcore.c
clang/test/Parser/attr-availability.c
clang/test/Sema/asm.c
clang/test/SemaCXX/static-assert.cpp
Index: clang/test/SemaCXX/static-assert.cpp
===================================================================
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -28,12 +28,12 @@
S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
S<int> s2;
-static_assert(false, L"\xFFFFFFFF"); // expected-error {{static_assert failed L"\xFFFFFFFF"}}
-static_assert(false, u"\U000317FF"); // expected-error {{static_assert failed u"\U000317FF"}}
+static_assert(false, L"\xFFFFFFFF"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+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 {{static_assert failed u8"\316\251"}}
-static_assert(false, L"\u1234"); // expected-error {{static_assert failed L"\x1234"}}
-static_assert(false, L"\x1ff" "0\x123" "fx\xfffff" "goop"); // expected-error {{static_assert failed L"\x1FF""0\x123""fx\xFFFFFgoop"}}
+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" "0\x123" "fx\xfffff" "goop"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
template<typename T> struct AlwaysFails {
// Only give one error here.
Index: clang/test/Sema/asm.c
===================================================================
--- clang/test/Sema/asm.c
+++ clang/test/Sema/asm.c
@@ -37,14 +37,17 @@
asm ("nop" : "=c" (a) : "r" (no_clobber_conflict) : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}}
asm ("nop" : "=r" (no_clobber_conflict) : "c" (c) : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}}
asm ("nop" : "=r" (clobber_conflict) : "c" (c) : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}}
- asm ("nop" : "=a" (a) : "b" (b) : "%rcx", "%rbx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}}
+ asm("nop"
+ : "=a"(a)
+ : "b"(b)
+ : "%rcx", "%rbx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}}
}
// rdar://6094010
void test3() {
int x;
- asm(L"foo" : "=r"(x)); // expected-error {{wide string}}
- asm("foo" : L"=r"(x)); // expected-error {{wide string}}
+ asm(L"foo" : "=r"(x)); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+ asm("foo" : L"=r"(x)); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
}
// <rdar://problem/6156893>
Index: clang/test/Parser/attr-availability.c
===================================================================
--- clang/test/Parser/attr-availability.c
+++ clang/test/Parser/attr-availability.c
@@ -18,21 +18,25 @@
void f6() __attribute__((availability(macosx,unavailable,introduced=10.5))); // expected-warning{{'unavailable' availability overrides all other availability information}}
-void f7() __attribute__((availability(macosx,message=L"wide"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+void f7() __attribute__((availability(macosx,message=L"wide"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-void f8() __attribute__((availability(macosx,message="a" L"b"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
-void f9() __attribute__((availability(macosx,message=u8"b"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+void f8() __attribute__((availability(macosx, message = "a"
+ L"b"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-void f10() __attribute__((availability(macosx,message="a" u8"b"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+void f9() __attribute__((availability(macosx,message=u8"b"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-void f11() __attribute__((availability(macosx,message=u"b"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+void f10() __attribute__((availability(macosx, message = "a"
+ u8"b"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-void f12() __attribute__((availability(macosx,message="a" u"b"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+void f11() __attribute__((availability(macosx,message=u"b"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+
+void f12() __attribute__((availability(macosx, message = "a"
+ u"b"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
// rdar://10095131
enum E{
- gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal for optional message in 'availability' attribute}}
+ gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal}}
garf __attribute__((availability(macosx,introduced=8.5, message))), // expected-error {{expected '=' after 'message'}}
foo __attribute__((availability(macosx,introduced=8.5,deprecated=9.0, message="Use CTFontCopyPostScriptName()", deprecated=10.0))) // expected-error {{expected ')'}} \
Index: clang/test/Parser/attr-availability-xcore.c
===================================================================
--- clang/test/Parser/attr-availability-xcore.c
+++ clang/test/Parser/attr-availability-xcore.c
@@ -6,6 +6,6 @@
# error 'availability' attribute is not available
#endif
-void f7() __attribute__((availability(macosx,message=L"wide"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+void f7() __attribute__((availability(macosx,message=L"wide"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
-void f8() __attribute__((availability(macosx,message="a" L"b"))); // expected-error {{expected string literal for optional message in 'availability' attribute}}
+void f8() __attribute__((availability(macosx,message="a" L"b"))); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
Index: clang/test/Parser/asm.cpp
===================================================================
--- clang/test/Parser/asm.cpp
+++ clang/test/Parser/asm.cpp
@@ -1,9 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int foo1 asm ("bar1");
-int foo2 asm (L"bar2"); // expected-error {{cannot use wide string literal in 'asm'}}
-int foo3 asm (u8"bar3"); // expected-error {{cannot use unicode string literal in 'asm'}}
-int foo4 asm (u"bar4"); // expected-error {{cannot use unicode string literal in 'asm'}}
-int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}}
+int foo2 asm(L"bar2"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+int foo3 asm(u8"bar3"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+int foo4 asm(u"bar4"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
+int foo5 asm(U"bar5"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}}
-int foo6 asm ("" L"bar7"); // expected-error {{cannot use wide string literal in 'asm'}}
+int foo6 asm(""
+ L"bar7"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
Index: clang/test/Parser/asm.c
===================================================================
--- clang/test/Parser/asm.c
+++ clang/test/Parser/asm.c
@@ -11,7 +11,9 @@
void f2() {
asm("foo" : "=r" (a)); // expected-error {{use of undeclared identifier 'a'}}
- asm("foo" : : "r" (b)); // expected-error {{use of undeclared identifier 'b'}}
+ asm("foo"
+ :
+ : "r"(b)); // expected-error {{use of undeclared identifier 'b'}}
}
void a() __asm__(""); // expected-error {{cannot use an empty string literal in 'asm'}}
@@ -23,7 +25,7 @@
__asm ; // expected-error {{expected '(' after 'asm'}}
// <rdar://problem/10465079> - Don't crash on wide string literals in 'asm'.
-int foo asm (L"bar"); // expected-error {{cannot use wide string literal in 'asm'}}
+int foo asm(L"bar"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
asm() // expected-error {{expected string literal in 'asm'}}
// expected-error@-1 {{expected ';' after top-level asm block}}
Index: clang/test/FixIt/fixit-static-assert.cpp
===================================================================
--- clang/test/FixIt/fixit-static-assert.cpp
+++ clang/test/FixIt/fixit-static-assert.cpp
@@ -11,8 +11,6 @@
// String literal prefixes are good.
static_assert(true && R"(RawString)");
// CHECK-DAG: {[[@LINE-1]]:20-[[@LINE-1]]:22}:","
-static_assert(true && L"RawString");
-// CHECK-DAG: {[[@LINE-1]]:20-[[@LINE-1]]:22}:","
static_assert(true);
// CHECK-DAG: {[[@LINE-1]]:19-[[@LINE-1]]:19}:", \"\""
Index: clang/test/CXX/dcl.dcl/p4-0x.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/p4-0x.cpp
+++ clang/test/CXX/dcl.dcl/p4-0x.cpp
@@ -18,4 +18,4 @@
static_assert(T(), "");
static_assert(U(), ""); // expected-error {{ambiguous}}
-static_assert(false, L"\x14hi" "!" R"x(")x"); // expected-error {{static_assert failed L"\024hi!\""}}
+static_assert(false, L"\x14hi" "!" R"x(")x"); // expected-error {{an unevaluated string literal cannot have an encoding prefix}}
Index: clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
+++ clang/test/CXX/dcl.dcl/dcl.link/p2.cpp
@@ -8,7 +8,7 @@
extern "C" plusplus {
}
-extern u8"C" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
-extern L"C" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
-extern u"C++" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
-extern U"C" {} // expected-error {{string literal in language linkage specifier cannot have an encoding-prefix}}
+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}}
Index: clang/lib/Sema/SemaStmtAsm.cpp
===================================================================
--- clang/lib/Sema/SemaStmtAsm.cpp
+++ clang/lib/Sema/SemaStmtAsm.cpp
@@ -254,7 +254,7 @@
SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos;
// The parser verifies that there is a string literal here.
- assert(AsmString->isAscii());
+ assert(AsmString->isUnevaluated());
FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
llvm::StringMap<bool> FeatureMap;
@@ -262,7 +262,7 @@
for (unsigned i = 0; i != NumOutputs; i++) {
StringLiteral *Literal = Constraints[i];
- assert(Literal->isAscii());
+ assert(Literal->isUnevaluated());
StringRef OutputName;
if (Names[i])
@@ -353,7 +353,7 @@
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
StringLiteral *Literal = Constraints[i];
- assert(Literal->isAscii());
+ assert(Literal->isUnevaluated());
StringRef InputName;
if (Names[i])
@@ -459,7 +459,7 @@
// Check that the clobbers are valid.
for (unsigned i = 0; i != NumClobbers; i++) {
StringLiteral *Literal = Clobbers[i];
- assert(Literal->isAscii());
+ assert(Literal->isUnevaluated());
StringRef Clobber = Literal->getString();
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -129,6 +129,9 @@
if (IsWideCharCompatible(ElemTy, Context))
return SIF_IncompatWideStringIntoWideChar;
return SIF_Other;
+ case StringLiteral::Unevaluated:
+ assert(false && "Unevaluated string literal in initialization");
+ break;
}
llvm_unreachable("missed a StringLiteral kind?");
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -3975,6 +3975,9 @@
case StringLiteral::Wide:
return Context.typesAreCompatible(Context.getWideCharType(),
QualType(ToPointeeType, 0));
+ case StringLiteral::Unevaluated:
+ assert(false && "Unevaluated string literal in expression");
+ break;
}
}
}
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -1777,6 +1777,29 @@
return S.BuildLiteralOperatorCall(R, OpNameInfo, Args, LitEndLoc);
}
+ExprResult Sema::ActOnUnevaluatedStringLiteral(ArrayRef<Token> StringToks) {
+ StringLiteralParser Literal(StringToks, PP, StringLiteralKind::Unevaluated);
+ if (Literal.hadError)
+ return ExprError();
+
+ SmallVector<SourceLocation, 4> StringTokLocs;
+ for (const Token &Tok : StringToks)
+ StringTokLocs.push_back(Tok.getLocation());
+
+ StringLiteral *Lit = StringLiteral::Create(
+ Context, Literal.GetString(), StringLiteral::Unevaluated, false, {},
+ &StringTokLocs[0], StringTokLocs.size());
+
+ if (!Literal.getUDSuffix().empty()) {
+ SourceLocation UDSuffixLoc =
+ getUDSuffixLoc(*this, StringTokLocs[Literal.getUDSuffixToken()],
+ Literal.getUDSuffixOffset());
+ return ExprError(Diag(UDSuffixLoc, diag::err_invalid_string_udl));
+ }
+
+ return Lit;
+}
+
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16103,11 +16103,7 @@
Expr *LangStr,
SourceLocation LBraceLoc) {
StringLiteral *Lit = cast<StringLiteral>(LangStr);
- if (!Lit->isAscii()) {
- Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_not_ascii)
- << LangStr->getSourceRange();
- return nullptr;
- }
+ assert(Lit->isUnevaluated() && "Unexpected string literal kind");
StringRef Lang = Lit->getString();
LinkageSpecDecl::LanguageIDs Language;
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -360,7 +360,9 @@
if (ArgLocation)
*ArgLocation = ArgExpr->getBeginLoc();
- if (!Literal || !Literal->isAscii()) {
+ // TODO all StringLiteral here should be unevaluated
+
+ if (!Literal || (!Literal->isUnevaluated() && !Literal->isAscii())) {
Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentString;
return false;
Index: clang/lib/Parse/Parser.cpp
===================================================================
--- clang/lib/Parse/Parser.cpp
+++ clang/lib/Parse/Parser.cpp
@@ -1529,15 +1529,9 @@
return ExprError();
}
- ExprResult AsmString(ParseStringLiteralExpression());
+ ExprResult AsmString(ParseUnevaluatedStringLiteralExpression());
if (!AsmString.isInvalid()) {
const auto *SL = cast<StringLiteral>(AsmString.get());
- if (!SL->isAscii()) {
- Diag(Tok, diag::err_asm_operand_wide_string_literal)
- << SL->isWide()
- << SL->getSourceRange();
- return ExprError();
- }
if (ForAsmLabel && SL->getString().empty()) {
Diag(Tok, diag::err_asm_operand_wide_string_literal)
<< 2 /* an empty */ << SL->getSourceRange();
Index: clang/lib/Parse/ParseExpr.cpp
===================================================================
--- clang/lib/Parse/ParseExpr.cpp
+++ clang/lib/Parse/ParseExpr.cpp
@@ -3165,6 +3165,20 @@
/// string-literal
/// \verbatim
ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
+ return ParseStringLiteralExpression(AllowUserDefinedLiteral, false);
+}
+
+ExprResult Parser::ParseUnevaluatedStringLiteralExpression() {
+ if (!isTokenStringLiteral()) {
+ Diag(Tok.getLocation(), diag::err_expected_string_literal);
+ return ExprError();
+ }
+
+ return ParseStringLiteralExpression(false, true);
+}
+
+ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral,
+ bool Unevaluated) {
assert(isTokenStringLiteral() && "Not a string literal!");
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
@@ -3176,6 +3190,11 @@
ConsumeStringToken();
} while (isTokenStringLiteral());
+ if (Unevaluated) {
+ assert(!AllowUserDefinedLiteral && "UDL are always evaluated");
+ return Actions.ActOnUnevaluatedStringLiteral(StringToks);
+ }
+
// Pass the set of string tokens, ready for concatenation, to the actions.
return Actions.ActOnStringLiteral(StringToks,
AllowUserDefinedLiteral ? getCurScope()
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -334,7 +334,7 @@
///
Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
assert(isTokenStringLiteral() && "Not a string literal!");
- ExprResult Lang = ParseStringLiteralExpression(false);
+ ExprResult Lang = ParseUnevaluatedStringLiteralExpression();
ParseScope LinkageScope(this, Scope::DeclScope);
Decl *LinkageSpec =
@@ -967,7 +967,7 @@
return nullptr;
}
- AssertMessage = ParseStringLiteralExpression();
+ AssertMessage = ParseUnevaluatedStringLiteralExpression();
if (AssertMessage.isInvalid()) {
SkipMalformedDecl();
return nullptr;
@@ -4630,7 +4630,7 @@
Toks[0].setLiteralData(StrBuffer.data());
Toks[0].setLength(StrBuffer.size());
StringLiteral *UuidString =
- cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
+ cast<StringLiteral>(Actions.ActOnStringLiteral(Toks).get());
ArgExprs.push_back(UuidString);
}
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -371,13 +371,14 @@
if (ChangeKWThisToIdent && Tok.is(tok::kw_this))
Tok.setKind(tok::identifier);
+ ParsedAttr::Kind AttrKind =
+ ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
+
ArgsVector ArgExprs;
if (Tok.is(tok::identifier)) {
// If this attribute wants an 'identifier' argument, make it so.
bool IsIdentifierArg = attributeHasIdentifierArg(*AttrName) ||
attributeHasVariadicIdentifierArg(*AttrName);
- ParsedAttr::Kind AttrKind =
- ParsedAttr::getParsedKind(AttrName, ScopeName, Syntax);
// If we don't know how to parse this attribute, but this is the only
// token in this argument, assume it's meant to be an identifier.
@@ -423,8 +424,8 @@
Uneval ? Sema::ExpressionEvaluationContext::Unevaluated
: Sema::ExpressionEvaluationContext::ConstantEvaluated);
- ExprResult ArgExpr(
- Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
+ ExprResult ArgExpr(Actions.CorrectDelayedTyposInExpr(
+ ParseAttributeArgAsUnevaluatedLiteralOrExpression(AttrKind)));
if (ArgExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return 0;
@@ -454,6 +455,17 @@
return static_cast<unsigned>(ArgExprs.size() + !TheParsedType.get().isNull());
}
+ExprResult Parser::ParseAttributeArgAsUnevaluatedLiteralOrExpression(
+ ParsedAttr::Kind Kind) {
+ if (isTokenStringLiteral() && (Kind == ParsedAttr::AT_Deprecated ||
+ Kind == ParsedAttr::AT_WarnUnusedResult)) {
+ ExprResult Result = ParseUnevaluatedStringLiteralExpression();
+ if (!Result.isInvalid())
+ return Result;
+ }
+ return ParseAssignmentExpression();
+}
+
/// Parse the arguments to a parameterized GNU attribute or
/// a C++11 attribute in "gnu" namespace.
void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
@@ -1140,32 +1152,28 @@
return;
}
ConsumeToken();
- if (Keyword == Ident_message || Keyword == Ident_replacement) {
- if (Tok.isNot(tok::string_literal)) {
- Diag(Tok, diag::err_expected_string_literal)
- << /*Source='availability attribute'*/2;
+ if ((Keyword == Ident_message || Keyword == Ident_replacement) &&
+ !tok::isStringLiteral(Tok.getKind())) {
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='availability attribute'*/ 2;
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ if (Keyword == Ident_message) {
+ MessageExpr = ParseUnevaluatedStringLiteralExpression();
+ if (MessageExpr.isInvalid()) {
SkipUntil(tok::r_paren, StopAtSemi);
return;
}
- if (Keyword == Ident_message)
- MessageExpr = ParseStringLiteralExpression();
- else
- ReplacementExpr = ParseStringLiteralExpression();
- // Also reject wide string literals.
- if (StringLiteral *MessageStringLiteral =
- cast_or_null<StringLiteral>(MessageExpr.get())) {
- if (!MessageStringLiteral->isAscii()) {
- Diag(MessageStringLiteral->getSourceRange().getBegin(),
- diag::err_expected_string_literal)
- << /*Source='availability attribute'*/ 2;
- SkipUntil(tok::r_paren, StopAtSemi);
- return;
- }
+ break;
+ }
+ if (Keyword == Ident_replacement) {
+ ReplacementExpr = ParseUnevaluatedStringLiteralExpression();
+ if (ReplacementExpr.isInvalid()) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
}
- if (Keyword == Ident_message)
- break;
- else
- continue;
+ continue;
}
// Special handling of 'NA' only when applied to introduced or
@@ -1340,19 +1348,19 @@
if (HadLanguage) {
Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause)
<< Keyword;
- ParseStringLiteralExpression();
+ ParseUnevaluatedStringLiteralExpression();
continue;
}
- Language = ParseStringLiteralExpression();
+ Language = ParseUnevaluatedStringLiteralExpression();
} else {
assert(Keyword == Ident_defined_in && "Invalid clause keyword!");
if (HadDefinedIn) {
Diag(KeywordLoc, diag::err_external_source_symbol_duplicate_clause)
<< Keyword;
- ParseStringLiteralExpression();
+ ParseUnevaluatedStringLiteralExpression();
continue;
}
- DefinedInExpr = ParseStringLiteralExpression();
+ DefinedInExpr = ParseUnevaluatedStringLiteralExpression();
}
} while (TryConsumeToken(tok::comma));
Index: clang/lib/Lex/Pragma.cpp
===================================================================
--- clang/lib/Lex/Pragma.cpp
+++ clang/lib/Lex/Pragma.cpp
@@ -1141,7 +1141,7 @@
if (DiagName.is(tok::eod))
PP.getDiagnostics().dump();
else if (DiagName.is(tok::string_literal) && !DiagName.hasUDSuffix()) {
- StringLiteralParser Literal(DiagName, PP);
+ StringLiteralParser Literal(DiagName, PP, StringLiteralKind::Unevaluated);
if (Literal.hadError)
return;
PP.getDiagnostics().dump(Literal.GetString());
Index: clang/lib/Lex/PPMacroExpansion.cpp
===================================================================
--- clang/lib/Lex/PPMacroExpansion.cpp
+++ clang/lib/Lex/PPMacroExpansion.cpp
@@ -1808,7 +1808,7 @@
if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
Tok.setKind(tok::identifier);
else if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
- StringLiteralParser Literal(Tok, *this);
+ StringLiteralParser Literal(Tok, *this, StringLiteralKind::Unevaluated);
if (Literal.hadError)
return;
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -1290,17 +1290,11 @@
return;
} else {
// Parse and validate the string, converting it into a unique ID.
- StringLiteralParser Literal(StrTok, *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
+ StringLiteralParser Literal(StrTok, *this, StringLiteralKind::Unevaluated);
if (Literal.hadError) {
DiscardUntilEndOfDirective();
return;
}
- if (Literal.Pascal) {
- Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
- DiscardUntilEndOfDirective();
- return;
- }
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
// Verify that there is nothing after the string, other than EOD. Because
@@ -1440,17 +1434,11 @@
return;
} else {
// Parse and validate the string, converting it into a unique ID.
- StringLiteralParser Literal(StrTok, *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
+ StringLiteralParser Literal(StrTok, *this, StringLiteralKind::Unevaluated);
if (Literal.hadError) {
DiscardUntilEndOfDirective();
return;
}
- if (Literal.Pascal) {
- Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
- DiscardUntilEndOfDirective();
- return;
- }
FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
// If a filename was present, read any flags that are present.
Index: clang/lib/Lex/LiteralSupport.cpp
===================================================================
--- clang/lib/Lex/LiteralSupport.cpp
+++ clang/lib/Lex/LiteralSupport.cpp
@@ -86,14 +86,27 @@
MakeCharSourceRange(Features, TokLoc, TokBegin, TokRangeBegin, TokRangeEnd);
}
+static bool EscapeValidInUnevaluatedStringLiteral(char Escape) {
+ switch (Escape) {
+ case '\\':
+ case '\'':
+ case '"':
+ case '?':
+ case 'n':
+ case 't':
+ case 'r':
+ return true;
+ }
+ return false;
+}
+
/// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
/// either a character or a string literal.
-static unsigned ProcessCharEscape(const char *ThisTokBegin,
- const char *&ThisTokBuf,
- const char *ThisTokEnd, bool &HadError,
- FullSourceLoc Loc, unsigned CharWidth,
- DiagnosticsEngine *Diags,
- const LangOptions &Features) {
+static unsigned
+ProcessCharEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
+ const char *ThisTokEnd, bool &HadError, FullSourceLoc Loc,
+ unsigned CharWidth, DiagnosticsEngine *Diags,
+ const LangOptions &Features, StringLiteralKind StringKind) {
const char *EscapeBegin = ThisTokBuf;
bool Delimited = false;
bool EndDelimiterFound = false;
@@ -313,6 +326,11 @@
}
}
+ if (StringKind == StringLiteralKind::Unevaluated && !EscapeValidInUnevaluatedStringLiteral(*EscapeBegin)) {
+ Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
+ diag::err_unevaluated_string_invalid_escape_sequence)
+ << StringRef(EscapeBegin + 1, 1);
+ }
return ResultChar;
}
@@ -1541,10 +1559,10 @@
continue;
}
unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
- uint64_t result =
- ProcessCharEscape(TokBegin, begin, end, HadError,
- FullSourceLoc(Loc,PP.getSourceManager()),
- CharWidth, &PP.getDiagnostics(), PP.getLangOpts());
+ uint64_t result = ProcessCharEscape(
+ TokBegin, begin, end, HadError,
+ FullSourceLoc(Loc, PP.getSourceManager()), CharWidth,
+ &PP.getDiagnostics(), PP.getLangOpts(), StringLiteralKind::Evaluated);
*buffer_begin++ = result;
}
@@ -1652,13 +1670,13 @@
/// hex-digit hex-digit hex-digit hex-digit
/// \endverbatim
///
-StringLiteralParser::
-StringLiteralParser(ArrayRef<Token> StringToks,
- Preprocessor &PP)
- : SM(PP.getSourceManager()), Features(PP.getLangOpts()),
- Target(PP.getTargetInfo()), Diags(&PP.getDiagnostics()),
- MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
- ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
+StringLiteralParser::StringLiteralParser(ArrayRef<Token> StringToks,
+ Preprocessor &PP, StringLiteralKind StringKind)
+ : SM(PP.getSourceManager()), Features(PP.getLangOpts()),
+ Target(PP.getTargetInfo()), Diags(&PP.getDiagnostics()),
+ MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
+ ResultPtr(ResultBuf.data()), hadError(false), Pascal(false),
+ StringKind(StringKind) {
init(StringToks);
}
@@ -1676,11 +1694,30 @@
MaxTokenLength = StringToks[0].getLength();
assert(StringToks[0].getLength() >= 2 && "literal token is invalid!");
SizeBound = StringToks[0].getLength()-2; // -2 for "".
- Kind = StringToks[0].getKind();
-
hadError = false;
- // Implement Translation Phase #6: concatenation of string literals
+ // Determines the kind of string from the prefix
+ Kind = tok::string_literal;
+ for (const auto &Tok : StringToks) {
+ // Unevaluated string literals can never have a prefix.
+ if (isUnevaluated() && Tok.getKind() != tok::string_literal) {
+ if (Diags)
+ Diags->Report(Tok.getLocation(), diag::err_unevaluated_string_prefix);
+ hadError = true;
+ continue;
+ }
+ if (Tok.is(tok::string_literal))
+ continue;
+ if (Tok.is(Kind) || Kind == tok::string_literal) {
+ Kind = Tok.getKind();
+ continue;
+ }
+ if (Diags) {
+ Diags->Report(Tok.getLocation(), diag::err_unsupported_string_concat);
+ hadError = true;
+ }
+ }
+
/// (C99 5.1.1.2p1). The common case is only one string fragment.
for (unsigned i = 1; i != StringToks.size(); ++i) {
if (StringToks[i].getLength() < 2)
@@ -1694,19 +1731,6 @@
// Remember maximum string piece length.
if (StringToks[i].getLength() > MaxTokenLength)
MaxTokenLength = StringToks[i].getLength();
-
- // Remember if we see any wide or utf-8/16/32 strings.
- // Also check for illegal concatenations.
- if (StringToks[i].isNot(Kind) && StringToks[i].isNot(tok::string_literal)) {
- if (isAscii()) {
- Kind = StringToks[i].getKind();
- } else {
- if (Diags)
- Diags->Report(StringToks[i].getLocation(),
- diag::err_unsupported_string_concat);
- hadError = true;
- }
- }
}
// Include space for the null terminator.
@@ -1781,13 +1805,16 @@
// result of a concatenation involving at least one user-defined-string-
// literal, all the participating user-defined-string-literals shall
// have the same ud-suffix.
- if (UDSuffixBuf != UDSuffix) {
+ bool UnevaluatedStringHasUDL = isUnevaluated() && !UDSuffix.empty();
+ if (UDSuffixBuf != UDSuffix || UnevaluatedStringHasUDL) {
if (Diags) {
SourceLocation TokLoc = StringToks[i].getLocation();
- Diags->Report(TokLoc, diag::err_string_concat_mixed_suffix)
- << UDSuffixBuf << UDSuffix
- << SourceRange(UDSuffixTokLoc, UDSuffixTokLoc)
- << SourceRange(TokLoc, TokLoc);
+ Diags->Report(TokLoc, UnevaluatedStringHasUDL
+ ? diag::err_unevaluated_string_udl
+ : diag::err_string_concat_mixed_suffix)
+ << UDSuffixBuf << UDSuffix
+ << SourceRange(UDSuffixTokLoc, UDSuffixTokLoc)
+ << SourceRange(TokLoc, TokLoc);
}
hadError = true;
}
@@ -1859,8 +1886,9 @@
++ThisTokBuf; // skip "
// Check if this is a pascal string
- if (Features.PascalStrings && ThisTokBuf + 1 != ThisTokEnd &&
- ThisTokBuf[0] == '\\' && ThisTokBuf[1] == 'p') {
+ if (!isUnevaluated() && Features.PascalStrings &&
+ ThisTokBuf + 1 != ThisTokEnd && ThisTokBuf[0] == '\\' &&
+ ThisTokBuf[1] == 'p') {
// If the \p sequence is found in the first token, we have a pascal string
// Otherwise, if we already have a pascal string, ignore the first \p
@@ -1895,9 +1923,9 @@
}
// Otherwise, this is a non-UCN escape character. Process it.
unsigned ResultChar =
- ProcessCharEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError,
- FullSourceLoc(StringToks[i].getLocation(), SM),
- CharByteWidth*8, Diags, Features);
+ ProcessCharEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError,
+ FullSourceLoc(StringToks[i].getLocation(), SM),
+ CharByteWidth * 8, Diags, Features, StringKind);
if (CharByteWidth == 4) {
// FIXME: Make the type of the result buffer correct instead of
@@ -1919,6 +1947,7 @@
}
}
+ assert((!Pascal || !isUnevaluated()) && "Pascal string in unevaluated context");
if (Pascal) {
if (CharByteWidth == 4) {
// FIXME: Make the type of the result buffer correct instead of
@@ -2091,8 +2120,8 @@
ByteNo -= Len;
} else {
ProcessCharEscape(SpellingStart, SpellingPtr, SpellingEnd, HadError,
- FullSourceLoc(Tok.getLocation(), SM),
- CharByteWidth*8, Diags, Features);
+ FullSourceLoc(Tok.getLocation(), SM), CharByteWidth * 8,
+ Diags, Features, StringLiteralKind::Evaluated);
--ByteNo;
}
assert(!HadError && "This method isn't valid on erroneous strings");
Index: clang/lib/Frontend/FrontendAction.cpp
===================================================================
--- clang/lib/Frontend/FrontendAction.cpp
+++ clang/lib/Frontend/FrontendAction.cpp
@@ -266,7 +266,7 @@
if (T.isAtStartOfLine() || T.getKind() != tok::string_literal)
return SourceLocation();
- StringLiteralParser Literal(T, CI.getPreprocessor());
+ StringLiteralParser Literal(T, CI.getPreprocessor(), StringLiteralKind::Unevaluated);
if (Literal.hadError)
return SourceLocation();
RawLexer->LexFromRawLexer(T);
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -1058,6 +1058,9 @@
case UTF32:
CharByteWidth = Target.getChar32Width();
break;
+ case Unevaluated:
+ return sizeof(char); // Host;
+ break;
}
assert((CharByteWidth & 7) == 0 && "Assumes character size is byte multiple");
CharByteWidth /= 8;
@@ -1071,35 +1074,44 @@
const SourceLocation *Loc,
unsigned NumConcatenated)
: Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary) {
- assert(Ctx.getAsConstantArrayType(Ty) &&
- "StringLiteral must be of constant array type!");
- unsigned CharByteWidth = mapCharByteWidth(Ctx.getTargetInfo(), Kind);
- unsigned ByteLength = Str.size();
- assert((ByteLength % CharByteWidth == 0) &&
- "The size of the data must be a multiple of CharByteWidth!");
-
- // Avoid the expensive division. The compiler should be able to figure it
- // out by itself. However as of clang 7, even with the appropriate
- // llvm_unreachable added just here, it is not able to do so.
- unsigned Length;
- switch (CharByteWidth) {
- case 1:
- Length = ByteLength;
- break;
- case 2:
- Length = ByteLength / 2;
- break;
- case 4:
- Length = ByteLength / 4;
- break;
- default:
- llvm_unreachable("Unsupported character width!");
- }
+
+ unsigned Length = Str.size();
StringLiteralBits.Kind = Kind;
- StringLiteralBits.CharByteWidth = CharByteWidth;
- StringLiteralBits.IsPascal = Pascal;
StringLiteralBits.NumConcatenated = NumConcatenated;
+
+ if (Kind != StringKind::Unevaluated) {
+ assert(Ctx.getAsConstantArrayType(Ty) &&
+ "StringLiteral must be of constant array type!");
+ unsigned CharByteWidth = mapCharByteWidth(Ctx.getTargetInfo(), Kind);
+ unsigned ByteLength = Str.size();
+ assert((ByteLength % CharByteWidth == 0) &&
+ "The size of the data must be a multiple of CharByteWidth!");
+
+ // Avoid the expensive division. The compiler should be able to figure it
+ // out by itself. However as of clang 7, even with the appropriate
+ // llvm_unreachable added just here, it is not able to do so.
+ switch (CharByteWidth) {
+ case 1:
+ Length = ByteLength;
+ break;
+ case 2:
+ Length = ByteLength / 2;
+ break;
+ case 4:
+ Length = ByteLength / 4;
+ break;
+ default:
+ llvm_unreachable("Unsupported character width!");
+ }
+
+ StringLiteralBits.CharByteWidth = CharByteWidth;
+ StringLiteralBits.IsPascal = Pascal;
+ } else {
+ StringLiteralBits.CharByteWidth = 1;
+ StringLiteralBits.IsPascal = false;
+ }
+
*getTrailingObjects<unsigned>() = Length;
// Initialize the trailing array of SourceLocation.
@@ -1108,7 +1120,7 @@
NumConcatenated * sizeof(SourceLocation));
// Initialize the trailing array of char holding the string data.
- std::memcpy(getTrailingObjects<char>(), Str.data(), ByteLength);
+ std::memcpy(getTrailingObjects<char>(), Str.data(), Str.size());
setDependence(ExprDependence::None);
}
@@ -1145,6 +1157,7 @@
void StringLiteral::outputString(raw_ostream &OS) const {
switch (getKind()) {
+ case Unevaluated: // fallthrough. no prefix.
case Ascii: break; // no prefix.
case Wide: OS << 'L'; break;
case UTF8: OS << "u8"; break;
@@ -1261,7 +1274,8 @@
const TargetInfo &Target, unsigned *StartToken,
unsigned *StartTokenByteOffset) const {
assert((getKind() == StringLiteral::Ascii ||
- getKind() == StringLiteral::UTF8) &&
+ getKind() == StringLiteral::UTF8 ||
+ getKind() == StringLiteral::Unevaluated) &&
"Only narrow string literals are currently supported");
// Loop over all of the tokens in this string until we find the one that
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5269,6 +5269,8 @@
ExprResult ActOnStringLiteral(ArrayRef<Token> StringToks,
Scope *UDLScope = nullptr);
+ ExprResult ActOnUnevaluatedStringLiteral(ArrayRef<Token> StringToks);
+
ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -1750,8 +1750,12 @@
bool IsUnevaluated);
ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false);
+ ExprResult ParseUnevaluatedStringLiteralExpression();
private:
+ ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral,
+ bool Unevaluated);
+
ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc);
ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
@@ -2649,6 +2653,9 @@
IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
ParsedAttr::Syntax Syntax);
+ ExprResult
+ ParseAttributeArgAsUnevaluatedLiteralOrExpression(ParsedAttr::Kind Kind);
+
enum ParseAttrKindMask {
PAKM_GNU = 1 << 0,
PAKM_Declspec = 1 << 1,
Index: clang/include/clang/Lex/LiteralSupport.h
===================================================================
--- clang/include/clang/Lex/LiteralSupport.h
+++ clang/include/clang/Lex/LiteralSupport.h
@@ -204,6 +204,11 @@
}
};
+enum class StringLiteralKind {
+ Evaluated,
+ Unevaluated,
+};
+
/// StringLiteralParser - This decodes string escape characters and performs
/// wide string analysis and Translation Phase #6 (concatenation of string
/// literals) (C99 5.1.1.2p1).
@@ -223,21 +228,21 @@
unsigned UDSuffixToken;
unsigned UDSuffixOffset;
public:
- StringLiteralParser(ArrayRef<Token> StringToks,
- Preprocessor &PP);
- StringLiteralParser(ArrayRef<Token> StringToks,
- const SourceManager &sm, const LangOptions &features,
- const TargetInfo &target,
+ StringLiteralParser(ArrayRef<Token> StringToks, Preprocessor &PP,
+ StringLiteralKind StringKind = StringLiteralKind::Evaluated);
+ StringLiteralParser(ArrayRef<Token> StringToks, const SourceManager &sm,
+ const LangOptions &features, const TargetInfo &target,
DiagnosticsEngine *diags = nullptr)
- : SM(sm), Features(features), Target(target), Diags(diags),
- MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
- ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) {
+ : SM(sm), Features(features), Target(target), Diags(diags),
+ MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
+ ResultPtr(ResultBuf.data()), hadError(false), Pascal(false),
+ StringKind(StringLiteralKind::Evaluated) {
init(StringToks);
}
-
bool hadError;
bool Pascal;
+ StringLiteralKind StringKind;
StringRef GetString() const {
return StringRef(ResultBuf.data(), GetStringLength());
@@ -261,6 +266,7 @@
bool isUTF16() const { return Kind == tok::utf16_string_literal; }
bool isUTF32() const { return Kind == tok::utf32_string_literal; }
bool isPascal() const { return Pascal; }
+ bool isUnevaluated() const { return StringKind == StringLiteralKind::Unevaluated; }
StringRef getUDSuffix() const { return UDSuffixBuf; }
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -417,9 +417,6 @@
"ISO C requires a named parameter before '...'">;
def err_declarator_need_ident : Error<"declarator requires an identifier">;
def err_language_linkage_spec_unknown : Error<"unknown linkage language">;
-def err_language_linkage_spec_not_ascii : Error<
- "string literal in language linkage specifier cannot have an "
- "encoding-prefix">;
def ext_use_out_of_scope_declaration : ExtWarn<
"use of out-of-scope declaration of %0%select{| whose type is not "
"compatible with that of an implicit declaration}1">,
Index: clang/include/clang/Basic/DiagnosticLexKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticLexKinds.td
+++ clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -253,6 +253,13 @@
"identifier">, InGroup<ReservedUserDefinedLiteral>;
def err_unsupported_string_concat : Error<
"unsupported non-standard concatenation of string literals">;
+
+def err_unevaluated_string_prefix : Error<
+ "an unevaluated string literal cannot have an encoding prefix">;
+def err_unevaluated_string_udl : Error<
+ "an unevaluated string literal cannot be a user-defined literal">;
+def err_unevaluated_string_invalid_escape_sequence : Error<
+ "invalid escape sequence '%0' in an unevaluated string literal">;
def err_string_concat_mixed_suffix : Error<
"differing user-defined suffixes ('%0' and '%1') in string literal "
"concatenation">;
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -1780,7 +1780,7 @@
/// * An array of getByteLength() char used to store the string data.
public:
- enum StringKind { Ascii, Wide, UTF8, UTF16, UTF32 };
+ enum StringKind { Ascii, Wide, UTF8, UTF16, UTF32, Unevaluated };
private:
unsigned numTrailingObjects(OverloadToken<unsigned>) const { return 1; }
@@ -1842,7 +1842,7 @@
unsigned CharByteWidth);
StringRef getString() const {
- assert(getCharByteWidth() == 1 &&
+ assert((isUnevaluated() || getCharByteWidth() == 1) &&
"This function is used in places that assume strings use char");
return StringRef(getStrDataAsChar(), getByteLength());
}
@@ -1882,6 +1882,7 @@
bool isUTF8() const { return getKind() == UTF8; }
bool isUTF16() const { return getKind() == UTF16; }
bool isUTF32() const { return getKind() == UTF32; }
+ bool isUnevaluated() const { return getKind() == Unevaluated; }
bool isPascal() const { return StringLiteralBits.IsPascal; }
bool containsNonAscii() const {
Index: clang-tools-extra/test/clang-tidy/checkers/modernize-unary-static-assert.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/modernize-unary-static-assert.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/modernize-unary-static-assert.cpp
@@ -7,9 +7,6 @@
static_assert(sizeof(a) <= 10, "");
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when the string literal is an empty string [modernize-unary-static-assert]
// CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 10 );{{$}}
- static_assert(sizeof(a) <= 12, L"");
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use unary 'static_assert' when
- // CHECK-FIXES: {{^}} static_assert(sizeof(a) <= 12 );{{$}}
FOO
// CHECK-FIXES: {{^}} FOO{{$}}
static_assert(sizeof(a) <= 17, MSG);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits