Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -3052,27 +3052,41 @@ return Cond; } -// Print a diagnostic for the failing static_assert expression. Defaults to -// pretty-printing the expression. -static void prettyPrintFailedBooleanCondition(llvm::raw_string_ostream &OS, - const Expr *FailedCond, - const PrintingPolicy &Policy) { - const auto *DR = dyn_cast(FailedCond); - if (DR && DR->getQualifier()) { - // If this is a qualified name, expand the template arguments in nested - // qualifiers. - DR->getQualifier()->print(OS, Policy, true); - // Then print the decl itself. - const ValueDecl *VD = DR->getDecl(); - OS << VD->getName(); - if (const auto *IV = dyn_cast(VD)) { - // This is a template variable, print the expanded template arguments. - printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy); +namespace { + +// A PrinterHelper that prints more helpful diagnostics for some sub-expressions +// within failing boolean expression, such as substituting template parameters +// for actual types. +class FailedBooleanConditionPrinterHelper : public PrinterHelper { +public: + FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy) + : Policy(Policy) {} + + ~FailedBooleanConditionPrinterHelper() override {} + + bool handledStmt(Stmt *E, raw_ostream &OS) override { + const auto *DR = dyn_cast(E); + if (DR && DR->getQualifier()) { + // If this is a qualified name, expand the template arguments in nested + // qualifiers. + DR->getQualifier()->print(OS, Policy, true); + // Then print the decl itself. + const ValueDecl *VD = DR->getDecl(); + OS << VD->getName(); + if (const auto *IV = dyn_cast(VD)) { + // This is a template variable, print the expanded template arguments. + printTemplateArgumentList(OS, IV->getTemplateArgs().asArray(), Policy); + } + return true; } - return; + return false; } - FailedCond->printPretty(OS, nullptr, Policy); -} + +private: + const PrintingPolicy &Policy; +}; + +} // namespace std::pair Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) { @@ -3115,7 +3129,8 @@ std::string Description; { llvm::raw_string_ostream Out(Description); - prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy()); + FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy()); + FailedCond->printPretty(Out, &Helper, getPrintingPolicy()); } return { FailedCond, Description }; } Index: test/SemaCXX/static-assert.cpp =================================================================== --- test/SemaCXX/static-assert.cpp +++ test/SemaCXX/static-assert.cpp @@ -111,6 +111,10 @@ // expected-error@-1{{static_assert failed due to requirement 'std::is_same::value' "message"}} static_assert(std::is_const::value, "message"); // expected-error@-1{{static_assert failed due to requirement 'std::is_const::value' "message"}} +static_assert(!std::is_const::value, "message"); +// expected-error@-1{{static_assert failed due to requirement '!std::is_const::value' "message"}} +static_assert(!(std::is_const::value), "message"); +// expected-error@-1{{static_assert failed due to requirement '!(std::is_const::value)' "message"}} struct BI_tag {}; struct RAI_tag : BI_tag {};