cor3ntin created this revision. Herald added a subscriber: martong. cor3ntin requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
...g). `FormatDiagnostic` is modified to escape non printable characters and invalid UTF-8. This ensures that unicode characters, spaces and new lines are properly rendered in static messages. This make clang more consistent with other implementation and fixes this tweet https://twitter.com/jfbastien/status/1298307325443231744 :) Of note, `PaddingChecker` did print out new lines that were later remove by the diagnostic printing code. To be consistent with its tests, the new lines are removed from the diagnostic. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D108469 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/Basic/Diagnostic.cpp clang/lib/Sema/SemaDeclCXX.cpp clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp clang/test/Lexer/null-character-in-literal.c clang/test/Misc/diag-special-chars.c clang/test/PCH/cxx-static_assert.cpp clang/test/Sema/static-assert.c clang/test/SemaCXX/int-ptr-cast-SFINAE.cpp 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 @@ -4,25 +4,25 @@ static_assert(f(), "f"); // expected-error {{static_assert expression is not an integral constant expression}} expected-note {{non-constexpr function 'f' cannot be used in a constant expression}} static_assert(true, "true is not false"); -static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}} +static_assert(false, "false is false"); // expected-error {{static_assert failed: false is false}} void g() { - static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}} + static_assert(false, "false is false"); // expected-error {{static_assert failed: false is false}} } class C { - static_assert(false, "false is false"); // expected-error {{static_assert failed "false is false"}} + static_assert(false, "false is false"); // expected-error {{static_assert failed: false is false}} }; template<int N> struct T { - static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed due to requirement '1 == 2' "N is not 2!"}} + static_assert(N == 2, "N is not 2!"); // expected-error {{static_assert failed due to requirement '1 == 2': N is not 2!}} }; T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}} T<2> t2; template<typename T> struct S { - static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed due to requirement 'sizeof(char) > sizeof(char)' "Type not big enough!"}} + static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static_assert failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} }; S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}} @@ -67,7 +67,7 @@ static const bool value = false; }; -static_assert(first_trait<X>::value && second_trait<X>::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait<X>::value' "message"}} +static_assert(first_trait<X>::value && second_trait<X>::value, "message"); // expected-error{{static_assert failed due to requirement 'second_trait<X>::value': message}} namespace std { @@ -111,29 +111,29 @@ }; static_assert(std::is_same<ExampleTypes::T, ExampleTypes::U>::value, "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_same<int, float>::value' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_same<int, float>::value': message}} static_assert(std::is_const<ExampleTypes::T>::value, "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value': message}} static_assert(!std::is_const<const ExampleTypes::T>::value, "message"); -// expected-error@-1{{static_assert failed due to requirement '!std::is_const<const int>::value' "message"}} +// expected-error@-1{{static_assert failed due to requirement '!std::is_const<const int>::value': message}} static_assert(!(std::is_const<const ExampleTypes::T>::value), "message"); -// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>::value)' "message"}} +// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>::value)': message}} static_assert(std::is_const<const ExampleTypes::T>::value == false, "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_const<const int>::value == false' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<const int>::value == false': message}} static_assert(!(std::is_const<const ExampleTypes::T>::value == true), "message"); -// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>::value == true)' "message"}} +// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>::value == true)': message}} static_assert(std::is_const<ExampleTypes::T>(), "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>()' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>()': message}} static_assert(!(std::is_const<const ExampleTypes::T>()()), "message"); -// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>()())' "message"}} +// expected-error@-1{{static_assert failed due to requirement '!(std::is_const<const int>()())': message}} static_assert(std::is_same<decltype(std::is_const<const ExampleTypes::T>()), int>::value, "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_same<std::is_const<const int>, int>::value' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_same<std::is_const<const int>, int>::value': message}} static_assert(std::is_const<decltype(ExampleTypes::T(3))>::value, "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value': message}} static_assert(std::is_const<decltype(ExampleTypes::T())>::value, "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<int>::value': message}} static_assert(std::is_const<decltype(ExampleTypes(3))>::value, "message"); -// expected-error@-1{{static_assert failed due to requirement 'std::is_const<ExampleTypes>::value' "message"}} +// expected-error@-1{{static_assert failed due to requirement 'std::is_const<ExampleTypes>::value': message}} struct BI_tag {}; struct RAI_tag : BI_tag {}; @@ -146,7 +146,7 @@ template <class Container> void foo() { static_assert(std::is_same<RAI_tag, typename Container::iterator::tag>::value, "message"); - // expected-error@-1{{static_assert failed due to requirement 'std::is_same<RAI_tag, BI_tag>::value' "message"}} + // expected-error@-1{{static_assert failed due to requirement 'std::is_same<RAI_tag, BI_tag>::value': message}} } template void foo<MyContainer>(); // expected-note@-1{{in instantiation of function template specialization 'foo<MyContainer>' requested here}} @@ -164,7 +164,7 @@ template <typename T, typename U, int a> void foo2() { static_assert(::ns::NestedTemplates1<T, a>::NestedTemplates2::template NestedTemplates3<U>::value, "message"); - // expected-error@-1{{static_assert failed due to requirement '::ns::NestedTemplates1<int, 3>::NestedTemplates2::NestedTemplates3<float>::value' "message"}} + // expected-error@-1{{static_assert failed due to requirement '::ns::NestedTemplates1<int, 3>::NestedTemplates2::NestedTemplates3<float>::value': message}} } template void foo2<int, float, 3>(); // expected-note@-1{{in instantiation of function template specialization 'foo2<int, float, 3>' requested here}} @@ -172,9 +172,9 @@ template <class T> void foo3(T t) { static_assert(std::is_const<T>::value, "message"); - // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}} + // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value': message}} static_assert(std::is_const<decltype(t)>::value, "message"); - // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value' "message"}} + // expected-error-re@-1{{static_assert failed due to requirement 'std::is_const<(lambda at {{.*}}static-assert.cpp:{{[0-9]*}}:{{[0-9]*}})>::value': message}} } void callFoo3() { foo3([]() {}); Index: clang/test/SemaCXX/int-ptr-cast-SFINAE.cpp =================================================================== --- clang/test/SemaCXX/int-ptr-cast-SFINAE.cpp +++ clang/test/SemaCXX/int-ptr-cast-SFINAE.cpp @@ -19,4 +19,4 @@ template<typename T> static const auto has_minus_assign = decltype(test<T>())::value; -static_assert(has_minus_assign<int*>, "failed"); // expected-error {{static_assert failed due to requirement 'has_minus_assign<int *>' "failed"}} +static_assert(has_minus_assign<int*>, "failed"); // expected-error {{static_assert failed due to requirement 'has_minus_assign<int *>': failed}} Index: clang/test/Sema/static-assert.c =================================================================== --- clang/test/Sema/static-assert.c +++ clang/test/Sema/static-assert.c @@ -9,7 +9,7 @@ #endif _Static_assert(1, "1 is nonzero"); // ext-warning {{'_Static_assert' is a C11 extension}} -_Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}} \ +_Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed: 0 is nonzero}} \ // ext-warning {{'_Static_assert' is a C11 extension}} #ifdef MS @@ -18,7 +18,7 @@ void foo(void) { _Static_assert(1, "1 is nonzero"); // ext-warning {{'_Static_assert' is a C11 extension}} - _Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}} \ + _Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed: 0 is nonzero}} \ // ext-warning {{'_Static_assert' is a C11 extension}} #ifdef MS static_assert(1, "1 is nonzero"); // ms-warning {{use of 'static_assert' without}} @@ -31,7 +31,7 @@ struct A { int a; _Static_assert(1, "1 is nonzero"); // ext-warning {{'_Static_assert' is a C11 extension}} - _Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}} \ + _Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed: 0 is nonzero}} \ // ext-warning {{'_Static_assert' is a C11 extension}} #ifdef MS static_assert(1, "1 is nonzero"); // ms-warning {{use of 'static_assert' without}} @@ -54,7 +54,7 @@ typedef UNION(unsigned, struct A) U1; // ext-warning 3 {{'_Static_assert' is a C11 extension}} UNION(char[2], short) u2 = { .one = { 'a', 'b' } }; // ext-warning 3 {{'_Static_assert' is a C11 extension}} cxx-warning {{designated initializers are a C++20 extension}} -typedef UNION(char, short) U3; // expected-error {{static_assert failed due to requirement 'sizeof(char) == sizeof(short)' "type size mismatch"}} \ +typedef UNION(char, short) U3; // expected-error {{static_assert failed due to requirement 'sizeof(char) == sizeof(short)': type size mismatch}} \ // ext-warning 3 {{'_Static_assert' is a C11 extension}} typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}} \ // ext-warning 3 {{'_Static_assert' is a C11 extension}} Index: clang/test/PCH/cxx-static_assert.cpp =================================================================== --- clang/test/PCH/cxx-static_assert.cpp +++ clang/test/PCH/cxx-static_assert.cpp @@ -17,7 +17,7 @@ #else -// expected-error@15 {{static_assert failed due to requirement '1 == 2' "N is not 2!"}} +// expected-error@15 {{static_assert failed due to requirement '1 == 2': N is not 2!}} T<1> t1; // expected-note {{in instantiation of template class 'T<1>' requested here}} T<2> t2; Index: clang/test/Misc/diag-special-chars.c =================================================================== --- clang/test/Misc/diag-special-chars.c +++ clang/test/Misc/diag-special-chars.c @@ -5,7 +5,7 @@ // marker character for diagnostic printing. Ensure diagnostics involving // this character does not cause problems with the diagnostic printer. #error Hi Bye -//expected-error@-1 {{Hi Bye}} +//expected-error@-1 {{Hi <U+007F> Bye}} -// CHECK: error: Hi Bye +// CHECK: error: Hi <U+007F> Bye // CHECK: #error Hi <U+007F> Bye Index: clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp =================================================================== --- clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp +++ clang/test/CXX/expr/expr.prim/expr.prim.id/p3.cpp @@ -164,7 +164,7 @@ // expected-error@-1 {{static_assert failed}} // expected-note@-2 {{because 'small' does not satisfy 'Large'}} static_assert(Large<small>, "small isn't large"); -// expected-error@-1 {{static_assert failed "small isn't large"}} +// expected-error@-1 {{static_assert failed: small isn't large}} // expected-note@-2 {{because 'small' does not satisfy 'Large'}} // Make sure access-checking can fail a concept specialization Index: clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp @@ -332,10 +332,10 @@ } Os << " (" << BaselinePad.getQuantity() << " padding bytes, where " - << OptimalPad.getQuantity() << " is optimal). \n" - << "Optimal fields order: \n"; + << OptimalPad.getQuantity() << " is optimal). " + << "Optimal fields order: "; for (const auto *FD : OptimalFieldsOrder) - Os << FD->getName() << ", \n"; + Os << FD->getName() << ", "; Os << "consider reordering the fields or adding explicit padding " "members."; Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -16357,8 +16357,12 @@ if (!Failed && !Cond) { SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); - if (AssertMessage) - AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy()); + if (AssertMessage) { + assert(isa<StringLiteral>(AssertMessage)); + if (StringLiteral *MsgStr = cast<StringLiteral>(AssertMessage)) { + Msg << MsgStr->getString(); + } + } Expr *InnerCond = nullptr; std::string InnerCondDescription; Index: clang/lib/Basic/Diagnostic.cpp =================================================================== --- clang/lib/Basic/Diagnostic.cpp +++ clang/lib/Basic/Diagnostic.cpp @@ -25,6 +25,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/Locale.h" #include "llvm/Support/raw_ostream.h" @@ -787,6 +788,46 @@ FormatDiagnostic(Diag.begin(), Diag.end(), OutStr); } +static void PushEscapedString(StringRef Str, SmallVectorImpl<char> &OutStr) { + OutStr.reserve(OutStr.size() + Str.size()); + auto it = reinterpret_cast<const unsigned char *>(Str.data()); + auto end = it + Str.size(); + while (it != end) { + // ASCII case + if (isPrintable(*it) || isWhitespace(*it)) { + OutStr.push_back(*it); + ++it; + continue; + } + if (llvm::isLegalUTF8Sequence(it, end)) { + llvm::UTF32 c; + llvm::UTF32 *cptr = &c; + unsigned char const *start = it; + unsigned char const *cp_end = it + llvm::getNumBytesForUTF8(*it); + llvm::ConversionResult res = llvm::ConvertUTF8toUTF32( + &it, cp_end, &cptr, cptr + 1, llvm::strictConversion); + (void)res; + assert(llvm::conversionOK == res); + assert(it == cp_end && "we must be further along in the string now"); + if (llvm::sys::locale::isPrint(c)) { + OutStr.append(start, cp_end); + continue; + } + std::string number; + llvm::raw_string_ostream stream(number); + stream << "<U+" << llvm::format_hex_no_prefix(c, 4, true) << ">"; + OutStr.append(number.begin(), number.end()); + continue; + } + SmallString<16> expandedByte("<XX>"); + unsigned char byte = *it; + expandedByte[1] = llvm::hexdigit(byte / 16); + expandedByte[2] = llvm::hexdigit(byte % 16); + OutStr.append(expandedByte.begin(), expandedByte.end()); + ++it; + } +} + void Diagnostic:: FormatDiagnostic(const char *DiagStr, const char *DiagEnd, SmallVectorImpl<char> &OutStr) const { @@ -797,11 +838,7 @@ StringRef(DiagStr, DiagEnd - DiagStr).equals("%0") && getArgKind(0) == DiagnosticsEngine::ak_std_string) { const std::string &S = getArgStdStr(0); - for (char c : S) { - if (llvm::sys::locale::isPrint(c) || c == '\t') { - OutStr.push_back(c); - } - } + PushEscapedString(S, OutStr); return; } @@ -908,7 +945,7 @@ case DiagnosticsEngine::ak_std_string: { const std::string &S = getArgStdStr(ArgNo); assert(ModifierLen == 0 && "No modifiers for strings yet"); - OutStr.append(S.begin(), S.end()); + PushEscapedString(S, OutStr); break; } case DiagnosticsEngine::ak_c_string: { @@ -918,8 +955,7 @@ // Don't crash if get passed a null pointer by accident. if (!S) S = "(null)"; - - OutStr.append(S, S + strlen(S)); + PushEscapedString(S, OutStr); break; } // ---- INTEGERS ---- Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1498,9 +1498,9 @@ "static_assert expression is not an integral constant expression">; def err_constexpr_if_condition_expression_is_not_constant : Error< "constexpr if condition is not a constant expression">; -def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; +def err_static_assert_failed : Error<"static_assert failed%select{: %1|}0">; def err_static_assert_requirement_failed : Error< - "static_assert failed due to requirement '%0'%select{ %2|}1">; + "static_assert failed due to requirement '%0'%select{: %2 |}1">; def ext_inline_variable : ExtWarn< "inline variables are a C++17 extension">, InGroup<CXX17>;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits