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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits