[Sema] Further improvements to to static_assert diagnostics.

Summary:
We're now handling cases like `static_assert(!expr)` and
static_assert(!(expr))`.

Reviewers: aaron.ballman, Quuxplusone

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D55270

llvm-svn: 348741
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 56302d6..c7d67cd 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3052,30 +3052,42 @@
   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<DeclRefExpr>(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<VarTemplateSpecializationDecl>(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:
+  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &Policy)
+      : Policy(Policy) {}
+
+  bool handledStmt(Stmt *E, raw_ostream &OS) override {
+    const auto *DR = dyn_cast<DeclRefExpr>(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<VarTemplateSpecializationDecl>(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;
+};
+
+} // end anonymous namespace
 
 std::pair<Expr *, std::string>
-Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
+Sema::findFailedBooleanCondition(Expr *Cond) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
 
   // Separate out all of the terms in a conjunction.
@@ -3087,11 +3099,6 @@
   for (Expr *Term : Terms) {
     Expr *TermAsWritten = Term->IgnoreParenImpCasts();
 
-    // Literals are uninteresting.
-    if (isa<CXXBoolLiteralExpr>(TermAsWritten) ||
-        isa<IntegerLiteral>(TermAsWritten))
-      continue;
-
     // The initialization of the parameter from the argument is
     // a constant-evaluated context.
     EnterExpressionEvaluationContext ConstantEvaluated(
@@ -3104,18 +3111,18 @@
       break;
     }
   }
-
-  if (!FailedCond) {
-    if (!AllowTopLevelCond)
-      return { nullptr, "" };
-
+  if (!FailedCond)
     FailedCond = Cond->IgnoreParenImpCasts();
-  }
+
+  // Literals are uninteresting.
+  if (isa<CXXBoolLiteralExpr>(FailedCond) || isa<IntegerLiteral>(FailedCond))
+    return {nullptr, ""};
 
   std::string Description;
   {
     llvm::raw_string_ostream Out(Description);
-    prettyPrintFailedBooleanCondition(Out, FailedCond, getPrintingPolicy());
+    FailedBooleanConditionPrinterHelper Helper(getPrintingPolicy());
+    FailedCond->printPretty(Out, &Helper, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
@@ -3199,9 +3206,7 @@
             Expr *FailedCond;
             std::string FailedDescription;
             std::tie(FailedCond, FailedDescription) =
-              findFailedBooleanCondition(
-                TemplateArgs[0].getSourceExpression(),
-                /*AllowTopLevelCond=*/true);
+              findFailedBooleanCondition(TemplateArgs[0].getSourceExpression());
 
             // Remove the old SFINAE diagnostic.
             PartialDiagnosticAt OldDiag =
@@ -9649,7 +9654,7 @@
         Expr *FailedCond;
         std::string FailedDescription;
         std::tie(FailedCond, FailedDescription) =
-          findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
+          findFailedBooleanCondition(Cond);
 
         Diag(FailedCond->getExprLoc(),
              diag::err_typename_nested_not_found_requirement)