tbaeder updated this revision to Diff 449199.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130894/new/

https://reviews.llvm.org/D130894

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/CXX/drs/dr7xx.cpp
  clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
  clang/test/PCH/cxx-templates.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaTemplate/instantiate-var-template.cpp
  clang/test/SemaTemplate/instantiation-dependence.cpp

Index: clang/test/SemaTemplate/instantiation-dependence.cpp
===================================================================
--- clang/test/SemaTemplate/instantiation-dependence.cpp
+++ clang/test/SemaTemplate/instantiation-dependence.cpp
@@ -68,8 +68,10 @@
   struct D : B, C {};
 
   static_assert(trait<A>::specialization == 0);
-  static_assert(trait<B>::specialization == 1); // FIXME expected-error {{failed}}
-  static_assert(trait<C>::specialization == 2); // FIXME expected-error {{failed}}
+  static_assert(trait<B>::specialization == 1); // FIXME expected-error {{failed}} \
+                                                // expected-note {{evaluates to '0'}}
+  static_assert(trait<C>::specialization == 2); // FIXME expected-error {{failed}} \
+                                                // expected-note {{evaluates to '0'}}
   static_assert(trait<D>::specialization == 0); // FIXME-error {{ambiguous partial specialization}}
 }
 
Index: clang/test/SemaTemplate/instantiate-var-template.cpp
===================================================================
--- clang/test/SemaTemplate/instantiate-var-template.cpp
+++ clang/test/SemaTemplate/instantiate-var-template.cpp
@@ -31,7 +31,8 @@
   static_assert(b<char> == 1, ""); // expected-note {{in instantiation of}} expected-error {{not an integral constant}}
 
   template<typename T> void f() {
-    static_assert(a<sizeof(sizeof(f(T())))> == 0, ""); // expected-error {{static assertion failed due to requirement 'a<sizeof (sizeof (f(type-parameter-0-0())))> == 0'}}
+    static_assert(a<sizeof(sizeof(f(T())))> == 0, ""); // expected-error {{static assertion failed due to requirement 'a<sizeof (sizeof (f(type-parameter-0-0())))> == 0'}} \
+                                                       // expected-note {{evaluates to '1'}}
   }
 }
 
Index: clang/test/SemaCXX/static-assert-cxx17.cpp
===================================================================
--- clang/test/SemaCXX/static-assert-cxx17.cpp
+++ clang/test/SemaCXX/static-assert-cxx17.cpp
@@ -88,7 +88,8 @@
   static_assert(typename T::T(0));
   // expected-error@-1{{static assertion failed due to requirement 'int(0)'}}
   static_assert(sizeof(X<typename T::T>) == 0);
-  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X<int>) == 0'}}
+  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X<int>) == 0'}} \
+  // expected-note@-1 {{evaluates to '8'}}
   static_assert((const X<typename T::T> *)nullptr);
   // expected-error@-1{{static assertion failed due to requirement '(const X<int> *)nullptr'}}
   static_assert(static_cast<const X<typename T::T> *>(nullptr));
@@ -96,7 +97,8 @@
   static_assert((const X<typename T::T>[]){} == nullptr);
   // expected-error@-1{{static assertion failed due to requirement '(const X<int>[0]){} == nullptr'}}
   static_assert(sizeof(X<decltype(X<typename T::T>().X<typename T::T>::~X())>) == 0);
-  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}}
+  // expected-error@-1{{static assertion failed due to requirement 'sizeof(X<void>) == 0'}} \
+  // expected-note@-1 {{evaluates to '8'}}
   static_assert(constexpr_return_false<typename T::T, typename T::U>());
   // expected-error@-1{{static assertion failed due to requirement 'constexpr_return_false<int, float>()'}}
 }
Index: clang/test/Parser/objc-static-assert.mm
===================================================================
--- clang/test/Parser/objc-static-assert.mm
+++ clang/test/Parser/objc-static-assert.mm
@@ -26,7 +26,8 @@
 
   static_assert(a, ""); // expected-error {{static assertion expression is not an integral constant expression}}
   static_assert(sizeof(a) == 4, "");
-  static_assert(sizeof(a) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(a) == 3, ""); // expected-error {{static assertion failed}} \
+                                     // expected-note {{evaluates to '4'}}
 }
 
 static_assert(1, "");
@@ -40,7 +41,8 @@
   static_assert(1, "");
   _Static_assert(1, "");
   static_assert(sizeof(b) == 4, "");
-  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
+                                     // expected-note {{evaluates to '4'}}
 }
 
 static_assert(1, "");
@@ -56,7 +58,8 @@
 @interface B () {
   int b;
   static_assert(sizeof(b) == 4, "");
-  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}}
+  static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
+                                     // expected-note {{evaluates to '4'}}
 }
 @end
 
Index: clang/test/PCH/cxx-templates.cpp
===================================================================
--- clang/test/PCH/cxx-templates.cpp
+++ clang/test/PCH/cxx-templates.cpp
@@ -167,7 +167,8 @@
   // This used to mark 'f' invalid without producing any diagnostic. That's a
   // little hard to detect, but we can make sure that constexpr evaluation
   // fails when it should.
-  static_assert(A<int>().f() == 1); // expected-error {{static assertion failed}}
+  static_assert(A<int>().f() == 1); // expected-error {{static assertion failed}} \
+                                    // expected-note {{left-hand side of operator '==' evaluates to '0'}}
 #endif
 }
 
Index: clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
===================================================================
--- clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
+++ clang/test/CXX/temp/temp.decls/temp.variadic/init-capture.cpp
@@ -40,8 +40,10 @@
 
 template<int ...a> constexpr auto x = [...z = a] (auto F) { return F(z...); };
 static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 123);
-static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}}
+static_assert(x<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}} \
+                                                                                          // expected-note {{evaluates to '123'}}
 
 template<int ...a> constexpr auto y = [z = a...] (auto F) { return F(z...); }; // expected-error {{must appear before the name of the capture}}
 static_assert(y<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 123);
-static_assert(y<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}}
+static_assert(y<1,2,3>([](int a, int b, int c) { return 100 * a + 10 * b + c; }) == 124); // expected-error {{failed}} \
+                                                                                          // expected-note {{evaluates to '123'}}
Index: clang/test/CXX/drs/dr7xx.cpp
===================================================================
--- clang/test/CXX/drs/dr7xx.cpp
+++ clang/test/CXX/drs/dr7xx.cpp
@@ -178,7 +178,8 @@
     static_assert(B<0>().v<1> == 3, "");
     static_assert(B<0>().v<0> == 4, "");
 #if __cplusplus < 201702L
-    // expected-error@-2 {{failed}}
+    // expected-error@-2 {{failed}} \
+    // expected-note@-2 {{left-hand side of operator '==' evaluates to '2'}}
 #endif
 
     static_assert(B<1>().w<1> == 1, "");
Index: clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
===================================================================
--- clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
+++ clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
@@ -98,7 +98,8 @@
     static_assert(sizeof(arr2) == 12, "");
 
     // Use a failing test to ensure the type isn't considered dependent.
-    static_assert(sizeof(arr2) == 13, ""); // expected-error {{failed}}
+    static_assert(sizeof(arr2) == 13, ""); // expected-error {{failed}} \
+                                           // expected-note {{evaluates to '12'}}
   }
 
   void g() { f<int[3]>(); } // expected-note {{in instantiation of}}
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16554,6 +16554,48 @@
                                       AssertMessage, RParenLoc, false);
 }
 
+/// Try to print more useful information about a failed static_assert
+/// with expression \E
+void Sema::DiagnoseStaticAssertDetails(const Expr *E) {
+  if (const BinaryOperator *Op = dyn_cast_or_null<BinaryOperator>(E)) {
+    unsigned ExprIsRHS = true;
+    const Expr *ExprSide;
+
+    if (isa<IntegerLiteral>(Op->getRHS()->IgnoreParenImpCasts())) {
+      ExprIsRHS = false;
+      ExprSide = Op->getLHS();
+    } else if (isa<IntegerLiteral>(Op->getLHS()->IgnoreParenImpCasts())) {
+      ExprIsRHS = true;
+      ExprSide = Op->getRHS();
+    } else
+      return;
+
+    // We already print enough info about these earlier,
+    // e.g. "requirement '2 == 1' failed" where 2 is
+    // a substituted template parameter.
+    if (isa<SubstNonTypeTemplateParmExpr>(ExprSide))
+      return;
+
+    if (isa<IntegerLiteral>(ExprSide))
+      return;
+
+    // Evaluate the expression again
+    Expr::EvalResult EvalResult;
+    SmallVector<PartialDiagnosticAt, 0> Notes;
+    EvalResult.Diag = &Notes;
+    ExprSide->EvaluateAsRValue(EvalResult, Context, true);
+
+    SmallString<12> ValueString;
+    if (EvalResult.Val.isInt())
+      EvalResult.Val.getInt().toString(ValueString);
+    else
+      return;
+
+    Diag(ExprSide->getExprLoc(), diag::note_bin_op_evaluates)
+        << (unsigned)ExprIsRHS << Op->getOpcodeStr() << ValueString;
+  }
+}
+
 Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
                                          Expr *AssertExpr,
                                          StringLiteral *AssertMessage,
@@ -16612,6 +16654,7 @@
         Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed)
           << InnerCondDescription << !AssertMessage
           << Msg.str() << InnerCond->getSourceRange();
+        DiagnoseStaticAssertDetails(InnerCond);
       } else {
         Diag(StaticAssertLoc, diag::err_static_assert_failed)
           << !AssertMessage << Msg.str() << AssertExpr->getSourceRange();
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -7482,6 +7482,7 @@
                                      StringLiteral *AssertMessageExpr,
                                      SourceLocation RParenLoc,
                                      bool Failed);
+  void DiagnoseStaticAssertDetails(const Expr *E);
 
   FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart,
                                   SourceLocation FriendLoc,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1532,6 +1532,8 @@
 def err_static_assert_failed : Error<"static assertion failed%select{: %1|}0">;
 def err_static_assert_requirement_failed : Error<
   "static assertion failed due to requirement '%0'%select{: %2|}1">;
+def note_bin_op_evaluates : Note<
+  "%select{left-hand|right-hand}0 side of operator '%1' evaluates to '%2'">;
 
 def warn_consteval_if_always_true : Warning<
   "consteval if is always true in an %select{unevaluated|immediate}0 context">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to