arichardson updated this revision to Diff 455258.
arichardson marked 2 inline comments as done.
arichardson added a comment.
Herald added a project: All.

rebase and address feedback


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D108211

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.array/p3.cpp
  clang/test/Parser/objc-static-assert.mm
  clang/test/Sema/static-assert.c
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/static-assert-cxx17.cpp
  clang/test/SemaCXX/static-assert.cpp
  clang/test/SemaTemplate/overload-candidates.cpp

Index: clang/test/SemaTemplate/overload-candidates.cpp
===================================================================
--- clang/test/SemaTemplate/overload-candidates.cpp
+++ clang/test/SemaTemplate/overload-candidates.cpp
@@ -62,6 +62,8 @@
 
 template<typename T> struct NonTemplateFunction {
   typename boost::enable_if<sizeof(T) == 4, int>::type f(); // expected-error{{failed requirement 'sizeof(char) == 4'; 'enable_if' cannot be used to disable this declaration}}
+  // expected-note@-1{{expression evaluates to '1 == 4'}}
+  // expected-note@-2{{with 'sizeof(char)' equal to 1}}
 };
 NonTemplateFunction<char> NTFC; // expected-note{{here}}
 
Index: clang/test/SemaCXX/static-assert.cpp
===================================================================
--- clang/test/SemaCXX/static-assert.cpp
+++ clang/test/SemaCXX/static-assert.cpp
@@ -23,7 +23,9 @@
 
 template<typename T> struct S {
     static_assert(sizeof(T) > sizeof(char), "Type not big enough!"); // expected-error {{static assertion failed due to requirement 'sizeof(char) > sizeof(char)': Type not big enough!}} \
-                                                                     // expected-note {{1 > 1}}
+                                                                     // expected-note {{1 > 1}} \
+                                                                     // expected-note {{with 'sizeof(char)' equal to 1}} \
+                                                                     // expected-note {{with 'sizeof(char)' equal to 1}}
 };
 
 S<char> s1; // expected-note {{in instantiation of template class 'S<char>' requested here}}
@@ -264,3 +266,30 @@
 
 
 }
+
+struct IntAndPointer {
+  int i;
+  void *p;
+};
+static_assert(sizeof(IntAndPointer) == 4, "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '16 == 4'}} \
+// expected-note@-1{{with 'sizeof(IntAndPointer)' equal to 16}}
+static_assert(alignof(IntAndPointer) == 4, "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '8 == 4'}} \
+// expected-note@-1{{with 'alignof(IntAndPointer)' equal to 8}}
+static_assert(alignof(IntAndPointer) == sizeof(IntAndPointer), "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '8 == 16'}} \
+// expected-note@-1{{with 'alignof(IntAndPointer)' equal to 8}} \
+// expected-note@-1{{with 'sizeof(IntAndPointer)' equal to 16}}
+static_assert(alignof(IntAndPointer) + sizeof(int) == sizeof(IntAndPointer), "message");
+// expected-error@-1{{static assertion failed}} \
+// expected-note@-1{{expression evaluates to '12 == 16'}} \
+// expected-note@-1{{with 'alignof(IntAndPointer)' equal to 8}} \
+// expected-note@-1{{with 'sizeof(int)' equal to 4}} \
+// expected-note@-1{{with 'sizeof(IntAndPointer)' equal to 16}}
+/// Should not print the sizeof(int) value here since it's not evaluated.
+static_assert(std::is_same<float, decltype(sizeof(int))>::value, "message");
+// expected-error@-1{{static assertion failed}}
Index: clang/test/SemaCXX/static-assert-cxx17.cpp
===================================================================
--- clang/test/SemaCXX/static-assert-cxx17.cpp
+++ clang/test/SemaCXX/static-assert-cxx17.cpp
@@ -89,7 +89,8 @@
   // 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-note@-1 {{evaluates to '8 == 0'}}
+  // expected-note@-1 {{evaluates to '8 == 0'}} \
+  // expected-note@-1 {{with 'sizeof(X<int>)' equal 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));
@@ -98,7 +99,8 @@
   // 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-note@-1 {{evaluates to '8 == 0'}}
+  // expected-note@-1 {{evaluates to '8 == 0'}} \
+  // expected-note@-1 {{with 'sizeof(X<void>)' equal 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/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1918,12 +1918,14 @@
   // cxx11-note@-2     {{call to virtual function}}
   // cxx20_2b-error@-3 {{static assertion failed}}
   // cxx20_2b-note@-4 {{8 == 16}}
+  // cxx20_2b-note@-5  {{with 'sizeof(VirtualFromBase::X<VirtualFromBase::S1>)' equal to 16}}
 
   // Non-virtual f(), OK.
   constexpr X<X<S2>> xxs2;
   constexpr X<S2> *q = const_cast<X<X<S2>>*>(&xxs2);
   static_assert(q->f() == sizeof(S2), ""); // cxx20_2b-error {{static assertion failed}} \
                                            // cxx20_2b-note {{16 == 8}}
+                                           // cxx20_2b-note@-2 {{with 'sizeof(VirtualFromBase::S2)' equal to 8}}
 }
 
 namespace ConstexprConstructorRecovery {
Index: clang/test/Sema/static-assert.c
===================================================================
--- clang/test/Sema/static-assert.c
+++ clang/test/Sema/static-assert.c
@@ -56,7 +56,9 @@
 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 assertion failed due to requirement 'sizeof(char) == sizeof(short)': type size mismatch}} \
                                // expected-note{{evaluates to '1 == 2'}} \
-                               // ext-warning 3 {{'_Static_assert' is a C11 extension}}
+                               // ext-warning 3 {{'_Static_assert' is a C11 extension}} \
+                               // expected-note {{with 'sizeof(char)' equal to 1}} \
+                               // expected-note {{with 'sizeof(short)' equal to 2}}
 typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}} \
                                // ext-warning 3 {{'_Static_assert' is a C11 extension}}
 
Index: clang/test/Parser/objc-static-assert.mm
===================================================================
--- clang/test/Parser/objc-static-assert.mm
+++ clang/test/Parser/objc-static-assert.mm
@@ -27,7 +27,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}} \
-                                     // expected-note {{evaluates to '4 == 3'}}
+                                     // expected-note {{evaluates to '4 == 3'}} \
+                                     // expected-note {{with 'sizeof (a)' equal to 4}}
 }
 
 static_assert(1, "");
@@ -42,7 +43,8 @@
   _Static_assert(1, "");
   static_assert(sizeof(b) == 4, "");
   static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
-                                     // expected-note {{evaluates to '4 == 3'}}
+                                     // expected-note {{evaluates to '4 == 3'}} \
+                                     // expected-note{{with 'sizeof (b)' equal to 4}}
 }
 
 static_assert(1, "");
@@ -59,7 +61,8 @@
   int b;
   static_assert(sizeof(b) == 4, "");
   static_assert(sizeof(b) == 3, ""); // expected-error {{static assertion failed}} \
-                                     // expected-note {{evaluates to '4 == 3'}}
+                                     // expected-note {{evaluates to '4 == 3'}} \
+                                     // expected-note{{with 'sizeof (b)' equal to 4}}
 }
 @end
 
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
@@ -99,7 +99,8 @@
 
     // Use a failing test to ensure the type isn't considered dependent.
     static_assert(sizeof(arr2) == 13, ""); // expected-error {{failed}} \
-                                           // expected-note {{evaluates to '12 == 13'}}
+                                           // expected-note {{evaluates to '12 == 13'}} \
+                                           // expected-note{{with 'sizeof (arr2)' equal to 12}}
   }
 
   void g() { f<int[3]>(); } // expected-note {{in instantiation of}}
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -3631,8 +3631,10 @@
 // for actual types.
 class FailedBooleanConditionPrinterHelper : public PrinterHelper {
 public:
-  explicit FailedBooleanConditionPrinterHelper(const PrintingPolicy &P)
-      : Policy(P) {}
+  explicit FailedBooleanConditionPrinterHelper(
+      const PrintingPolicy &P, Sema &S,
+      SmallVectorImpl<PartialDiagnosticAt> &Notes)
+      : Policy(P), S(S), Notes(Notes) {}
 
   bool handledStmt(Stmt *E, raw_ostream &OS) override {
     const auto *DR = dyn_cast<DeclRefExpr>(E);
@@ -3651,17 +3653,35 @@
       }
       return true;
     }
+
+    if (auto *UE = dyn_cast<UnaryExprOrTypeTraitExpr>(E)) {
+      Expr::EvalResult Result;
+      if (UE->EvaluateAsConstantExpr(Result, S.Context) && Result.Val.isInt()) {
+        std::string ExprStr;
+        llvm::raw_string_ostream ExprStream(ExprStr);
+        UE->printPretty(ExprStream, nullptr, Policy);
+        ExprStream.flush();
+        Notes.push_back(PartialDiagnosticAt(
+            UE->getExprLoc(),
+            S.PDiag(diag::note_static_assert_requirement_context)
+                << ExprStr << toString(Result.Val.getInt(), 10)
+                << UE->getSourceRange()));
+      }
+    }
     return false;
   }
 
 private:
   const PrintingPolicy Policy;
+  Sema &S;
+  SmallVectorImpl<PartialDiagnosticAt> &Notes;
 };
 
 } // end anonymous namespace
 
 std::pair<Expr *, std::string>
-Sema::findFailedBooleanCondition(Expr *Cond) {
+Sema::findFailedBooleanCondition(Expr *Cond,
+                                 SmallVectorImpl<PartialDiagnosticAt> &Notes) {
   Cond = lookThroughRangesV3Condition(PP, Cond);
 
   // Separate out all of the terms in a conjunction.
@@ -3693,12 +3713,15 @@
   if (!FailedCond)
     FailedCond = Cond->IgnoreParenImpCasts();
 
+  // Create an "evaluates to" note for complex binary expressions.
+  DiagnoseFailedBoolExprDetails(FailedCond, Notes);
+
   std::string Description;
   {
     llvm::raw_string_ostream Out(Description);
     PrintingPolicy Policy = getPrintingPolicy();
     Policy.PrintCanonicalTypes = true;
-    FailedBooleanConditionPrinterHelper Helper(Policy);
+    FailedBooleanConditionPrinterHelper Helper(Policy, *this, Notes);
     FailedCond->printPretty(Out, &Helper, Policy, 0, "\n", nullptr);
   }
   return { FailedCond, Description };
@@ -3786,8 +3809,10 @@
                 == TemplateArgument::Expression) {
             Expr *FailedCond;
             std::string FailedDescription;
+            SmallVector<PartialDiagnosticAt, 2> Notes;
             std::tie(FailedCond, FailedDescription) =
-              findFailedBooleanCondition(TemplateArgs[0].getSourceExpression());
+                findFailedBooleanCondition(
+                    TemplateArgs[0].getSourceExpression(), Notes);
 
             // Remove the old SFINAE diagnostic.
             PartialDiagnosticAt OldDiag =
@@ -3801,6 +3826,8 @@
               PDiag(diag::err_typename_nested_not_found_requirement)
                 << FailedDescription
                 << FailedCond->getSourceRange());
+            for (const PartialDiagnosticAt &Note : Notes)
+              (*DeductionInfo)->addSFINAEDiagnostic(Note.first, Note.second);
           }
         }
       }
@@ -10713,13 +10740,16 @@
       if (Cond) {
         Expr *FailedCond;
         std::string FailedDescription;
+        SmallVector<PartialDiagnosticAt, 2> Notes;
         std::tie(FailedCond, FailedDescription) =
-          findFailedBooleanCondition(Cond);
+            findFailedBooleanCondition(Cond, Notes);
 
         Diag(FailedCond->getExprLoc(),
              diag::err_typename_nested_not_found_requirement)
           << FailedDescription
           << FailedCond->getSourceRange();
+        for (const PartialDiagnosticAt &Note : Notes)
+          Diag(Note.first, Note.second);
         return QualType();
       }
 
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -16670,8 +16670,9 @@
 }
 
 /// Try to print more useful information about a failed static_assert
-/// with expression \E
-void Sema::DiagnoseStaticAssertDetails(const Expr *E) {
+/// with expression \p E and if found append the diagnostic to \p Notes.
+void Sema::DiagnoseFailedBoolExprDetails(
+    const Expr *E, SmallVectorImpl<PartialDiagnosticAt> &Notes) {
   if (const auto *Op = dyn_cast_or_null<BinaryOperator>(E)) {
     const Expr *LHS = Op->getLHS()->IgnoreParenImpCasts();
     const Expr *RHS = Op->getRHS()->IgnoreParenImpCasts();
@@ -16701,9 +16702,11 @@
           DiagSide[I].Result.Val, Side->getType(), DiagSide[I].ValueString);
     }
     if (DiagSide[0].Print && DiagSide[1].Print) {
-      Diag(Op->getExprLoc(), diag::note_expr_evaluates_to)
-          << DiagSide[0].ValueString << Op->getOpcodeStr()
-          << DiagSide[1].ValueString << Op->getSourceRange();
+      Notes.emplace_back(Op->getExprLoc(), PDiag(diag::note_expr_evaluates_to)
+                                               << DiagSide[0].ValueString
+                                               << Op->getOpcodeStr()
+                                               << DiagSide[1].ValueString
+                                               << Op->getSourceRange());
     }
   }
 }
@@ -16751,8 +16754,9 @@
 
       Expr *InnerCond = nullptr;
       std::string InnerCondDescription;
+      SmallVector<PartialDiagnosticAt, 2> Notes;
       std::tie(InnerCond, InnerCondDescription) =
-        findFailedBooleanCondition(Converted.get());
+          findFailedBooleanCondition(Converted.get(), Notes);
       if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) {
         // Drill down into concept specialization expressions to see why they
         // weren't satisfied.
@@ -16766,11 +16770,12 @@
         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();
       }
+      for (const PartialDiagnosticAt &Note : Notes)
+        Diag(Note.first, Note.second);
       Failed = true;
     }
   } else {
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -3980,7 +3980,9 @@
 
   /// Find the failed Boolean condition within a given Boolean
   /// constant expression, and describe it with a string.
-  std::pair<Expr *, std::string> findFailedBooleanCondition(Expr *Cond);
+  std::pair<Expr *, std::string>
+  findFailedBooleanCondition(Expr *Cond,
+                             SmallVectorImpl<PartialDiagnosticAt> &Notes);
 
   /// Emit diagnostics for the diagnose_if attributes on Function, ignoring any
   /// non-ArgDependent DiagnoseIfAttrs.
@@ -7502,7 +7504,9 @@
                                      StringLiteral *AssertMessageExpr,
                                      SourceLocation RParenLoc,
                                      bool Failed);
-  void DiagnoseStaticAssertDetails(const Expr *E);
+  void
+  DiagnoseFailedBoolExprDetails(const Expr *E,
+                                SmallVectorImpl<PartialDiagnosticAt> &Notes);
 
   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,7 @@
 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_static_assert_requirement_context : Note<"with '%0' equal to %1">;
 def note_expr_evaluates_to : Note<
   "expression evaluates to '%0 %1 %2'">;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to