r313315 - Diagnostic specific failed condition in a static_assert.

Douglas Gregor via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 14 16:38:42 PDT 2017


Author: dgregor
Date: Thu Sep 14 16:38:42 2017
New Revision: 313315

URL: http://llvm.org/viewvc/llvm-project?rev=313315&view=rev
Log:
Diagnostic specific failed condition in a static_assert.

When a static_assert fails, dig out a specific condition to diagnose,
using the same logic that we use to find the enable_if condition to
diagnose.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaCXX/static-assert.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=313315&r1=313314&r2=313315&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Sep 14 16:38:42 2017
@@ -1219,6 +1219,8 @@ def warn_messaging_unqualified_id : Warn
 def err_static_assert_expression_is_not_constant : Error<
   "static_assert expression is not an integral constant expression">;
 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">;
 def ext_static_assert_no_message : ExtWarn<
   "static_assert with no message is a C++17 extension">, InGroup<CXX17>;
 def warn_cxx14_compat_static_assert_no_message : Warning<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=313315&r1=313314&r2=313315&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Sep 14 16:38:42 2017
@@ -2783,6 +2783,14 @@ public:
   EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
                               bool MissingImplicitThis = false);
 
+  /// Find the failed Boolean condition within a given Boolean
+  /// constant expression, and describe it with a string.
+  ///
+  /// \param AllowTopLevelCond Whether to allow the result to be the
+  /// complete top-level condition.
+  std::pair<Expr *, std::string>
+  findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond);
+
   /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
   /// non-ArgDependent DiagnoseIfAttrs.
   ///

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=313315&r1=313314&r2=313315&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Sep 14 16:38:42 2017
@@ -13296,8 +13296,20 @@ Decl *Sema::BuildStaticAssertDeclaration
       llvm::raw_svector_ostream Msg(MsgBuffer);
       if (AssertMessage)
         AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy());
-      Diag(StaticAssertLoc, diag::err_static_assert_failed)
-        << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+
+      Expr *InnerCond = nullptr;
+      std::string InnerCondDescription;
+      std::tie(InnerCond, InnerCondDescription) =
+        findFailedBooleanCondition(Converted.get(),
+                                   /*AllowTopLevelCond=*/false);
+      if (InnerCond) {
+        Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
+          << InnerCondDescription << !AssertMessage
+          << Msg.str() << InnerCond->getSourceRange();
+      } else {
+        Diag(StaticAssertLoc, diag::err_static_assert_failed)
+          << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
+      }
       Failed = true;
     }
   }

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=313315&r1=313314&r2=313315&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Sep 14 16:38:42 2017
@@ -2863,11 +2863,9 @@ static Expr *lookThroughRangesV3Conditio
   return Cond;
 }
 
-/// Find the failed subexpression within enable_if, and describe it
-/// with a string.
-static std::pair<Expr *, std::string>
-findFailedEnableIfCondition(Sema &S, Expr *Cond) {
-  Cond = lookThroughRangesV3Condition(S.PP, Cond);
+std::pair<Expr *, std::string>
+Sema::findFailedBooleanCondition(Expr *Cond, bool AllowTopLevelCond) {
+  Cond = lookThroughRangesV3Condition(PP, Cond);
 
   // Separate out all of the terms in a conjunction.
   SmallVector<Expr *, 4> Terms;
@@ -2876,27 +2874,37 @@ findFailedEnableIfCondition(Sema &S, Exp
   // Determine which term failed.
   Expr *FailedCond = nullptr;
   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(
-      S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+      *this, Sema::ExpressionEvaluationContext::ConstantEvaluated);
 
     bool Succeeded;
-    if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) &&
+    if (Term->EvaluateAsBooleanCondition(Succeeded, Context) &&
         !Succeeded) {
-      FailedCond = Term->IgnoreParenImpCasts();
+      FailedCond = TermAsWritten;
       break;
     }
   }
 
-  if (!FailedCond)
+  if (!FailedCond) {
+    if (!AllowTopLevelCond)
+      return { nullptr, "" };
+
     FailedCond = Cond->IgnoreParenImpCasts();
+  }
 
   std::string Description;
   {
     llvm::raw_string_ostream Out(Description);
-    FailedCond->printPretty(Out, nullptr,
-                            PrintingPolicy(S.Context.getLangOpts()));
+    FailedCond->printPretty(Out, nullptr, getPrintingPolicy());
   }
   return { FailedCond, Description };
 }
@@ -2980,8 +2988,9 @@ QualType Sema::CheckTemplateIdType(Templ
             Expr *FailedCond;
             std::string FailedDescription;
             std::tie(FailedCond, FailedDescription) =
-              findFailedEnableIfCondition(
-                *this, TemplateArgs[0].getSourceExpression());
+              findFailedBooleanCondition(
+                TemplateArgs[0].getSourceExpression(),
+                /*AllowTopLevelCond=*/true);
 
             // Remove the old SFINAE diagnostic.
             PartialDiagnosticAt OldDiag =
@@ -9513,7 +9522,7 @@ Sema::CheckTypenameType(ElaboratedTypeKe
         Expr *FailedCond;
         std::string FailedDescription;
         std::tie(FailedCond, FailedDescription) =
-          findFailedEnableIfCondition(*this, Cond);
+          findFailedBooleanCondition(Cond, /*AllowTopLevelCond=*/true);
 
         Diag(FailedCond->getExprLoc(),
              diag::err_typename_nested_not_found_requirement)

Modified: cfe/trunk/test/SemaCXX/static-assert.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/static-assert.cpp?rev=313315&r1=313314&r2=313315&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/static-assert.cpp (original)
+++ cfe/trunk/test/SemaCXX/static-assert.cpp Thu Sep 14 16:38:42 2017
@@ -51,3 +51,20 @@ StaticAssertProtected<X> sap2; // expect
 
 static_assert(true); // expected-warning {{C++17 extension}}
 static_assert(false); // expected-error-re {{failed{{$}}}} expected-warning {{extension}}
+
+
+// Diagnostics for static_assert with multiple conditions
+template<typename T> struct first_trait {
+  static const bool value = false;
+};
+
+template<>
+struct first_trait<X> {
+  static const bool value = true;
+};
+
+template<typename T> struct second_trait {
+  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"}}




More information about the cfe-commits mailing list