ychen updated this revision to Diff 351343.
ychen added a comment.

- Add `DiagIfReachable` and use it in `Sema::DiagnoseUnusedExprResult`.
- Update tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D103938

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CXX/drs/dr14xx.cpp
  clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
  clang/test/CodeCompletion/pragma-macro-token-caching.c
  clang/test/PCH/cxx-explicit-specifier.cpp
  clang/test/Parser/cxx-ambig-decl-expr.cpp
  clang/test/Parser/cxx0x-ambig.cpp
  clang/test/Sema/const-eval.c
  clang/test/Sema/exprs.c
  clang/test/Sema/i-c-e.c
  clang/test/Sema/vla-2.c
  clang/test/SemaCXX/attr-annotate.cpp
  clang/test/SemaCXX/builtin-constant-p.cpp
  clang/test/SemaCXX/constant-expression-cxx2a.cpp
  clang/test/SemaCXX/constant-expression.cpp
  clang/test/SemaCXX/expression-traits.cpp
  clang/test/SemaCXX/warn-comma-operator.cpp
  clang/test/SemaCXX/warn-unused-value.cpp

Index: clang/test/SemaCXX/warn-unused-value.cpp
===================================================================
--- clang/test/SemaCXX/warn-unused-value.cpp
+++ clang/test/SemaCXX/warn-unused-value.cpp
@@ -138,3 +138,13 @@
   (void)arr3;
   (void)arr4;
 }
+
+#if __cplusplus >= 201103L // C++11 or later
+namespace test5 {
+int v[(5, 6)]; // expected-warning {{expression result unused}}
+void foo() {
+  new double[false ? (1, 2) : 3]
+            [false ? (1, 2) : 3]; // expected-warning {{expression result unused}}
+}
+} // namespace test5
+#endif
Index: clang/test/SemaCXX/warn-comma-operator.cpp
===================================================================
--- clang/test/SemaCXX/warn-comma-operator.cpp
+++ clang/test/SemaCXX/warn-comma-operator.cpp
@@ -242,8 +242,8 @@
 
 template <typename... xs>
 class Foo {
-  typedef bool_seq<(xs::value, true)...> all_true;
-  typedef bool_seq<(xs::value, false)...> all_false;
+  typedef bool_seq<((void)xs::value, true)...> all_true;
+  typedef bool_seq<((void)xs::value, false)...> all_false;
   typedef bool_seq<xs::value...> seq;
 };
 
Index: clang/test/SemaCXX/expression-traits.cpp
===================================================================
--- clang/test/SemaCXX/expression-traits.cpp
+++ clang/test/SemaCXX/expression-traits.cpp
@@ -583,10 +583,10 @@
 
     // Can't use the ASSERT_XXXX macros without adding parens around
     // the comma expression.
-    static_assert(__is_lvalue_expr(x,x), "expected an lvalue");
-    static_assert(__is_rvalue_expr(x,1), "expected an rvalue");
-    static_assert(__is_lvalue_expr(1,x), "expected an lvalue");
-    static_assert(__is_rvalue_expr(1,1), "expected an rvalue");
+    static_assert(__is_lvalue_expr((void)x,x), "expected an lvalue");
+    static_assert(__is_rvalue_expr((void)x,1), "expected an rvalue");
+    static_assert(__is_lvalue_expr((void)1,x), "expected an lvalue");
+    static_assert(__is_rvalue_expr((void)1,1), "expected an rvalue");
 }
 
 #if 0
Index: clang/test/SemaCXX/constant-expression.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression.cpp
+++ clang/test/SemaCXX/constant-expression.cpp
@@ -88,8 +88,8 @@
 
 void diags(int n) {
   switch (n) {
-    case (1/0, 1): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
-    case (int)(1/0, 2.0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
+    case (1/0, 1): // expected-error {{not an integral constant expression}} expected-note {{division by zero}} expected-warning {{expression result unused}}
+    case (int)(1/0, 2.0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}} expected-warning {{expression result unused}}
     case __imag(1/0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
     case (int)__imag((double)(1/0)): // expected-error {{not an integral constant expression}} expected-note {{division by zero}}
       ;
Index: clang/test/SemaCXX/constant-expression-cxx2a.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -745,7 +745,7 @@
   // Ensure that we can handle temporary cleanups for array temporaries.
   struct ArrElem { constexpr ~ArrElem() {} };
   using Arr = ArrElem[3];
-  static_assert((Arr{}, true));
+  static_assert(((void)Arr{}, true));
 }
 
 namespace dynamic_alloc {
Index: clang/test/SemaCXX/builtin-constant-p.cpp
===================================================================
--- clang/test/SemaCXX/builtin-constant-p.cpp
+++ clang/test/SemaCXX/builtin-constant-p.cpp
@@ -157,12 +157,12 @@
     constexpr ~A() { *p = 0; }
   };
   struct Q { int n; constexpr int *get() { return &n; } };
-  static_assert(!__builtin_constant_p((A{}, 123)));
+  static_assert(!__builtin_constant_p(((void)A{}, 123)));
   // FIXME: We should probably accept this. GCC does.
   // However, GCC appears to do so by running the destructors at the end of the
   // enclosing full-expression, which seems broken; running them at the end of
   // the evaluation of the __builtin_constant_p argument would be more
   // defensible.
-  static_assert(!__builtin_constant_p((A{Q().get()}, 123)));
+  static_assert(!__builtin_constant_p(((void)A{Q().get()}, 123)));
 }
 #endif
Index: clang/test/SemaCXX/attr-annotate.cpp
===================================================================
--- clang/test/SemaCXX/attr-annotate.cpp
+++ clang/test/SemaCXX/attr-annotate.cpp
@@ -42,7 +42,7 @@
 
   template<typename T>
   struct B {
-    [[clang::annotate("test", (T{}, 9))]] void t() {}
+    [[clang::annotate("test", ((void)T{}, 9))]] void t() {}
     // expected-error@-1 {{illegal initializer type 'void'}}
   };
   B<int> b;
@@ -73,7 +73,7 @@
     [[clang::annotate("jui", b, cf)]] void t2() {}
     // expected-error@-1 {{'annotate' attribute requires parameter 1 to be a constant expression}}
     // expected-note@-2 {{is not allowed in a constant expression}}
-    [[clang::annotate("jui", (b, 0), cf)]] [[clang::annotate("jui", &b, cf, &foo::t2, str())]] void t3() {}
+    [[clang::annotate("jui", ((void)b, 0), cf)]] [[clang::annotate("jui", &b, cf, &foo::t2, str())]] void t3() {}
   };
 };
 
Index: clang/test/Sema/vla-2.c
===================================================================
--- clang/test/Sema/vla-2.c
+++ clang/test/Sema/vla-2.c
@@ -13,5 +13,5 @@
 }
 
 void PotentiallyEvaluatedArrayBoundWarn(int n) {
-  (void)*(int(*)[(0 << 32,n)])0; // FIXME: We should warn here.
+  (void)*(int(*)[(0 << 32,n)])0; // expected-warning {{expression result unused}}
 }
Index: clang/test/Sema/i-c-e.c
===================================================================
--- clang/test/Sema/i-c-e.c
+++ clang/test/Sema/i-c-e.c
@@ -70,10 +70,12 @@
 char z[__builtin_constant_p(4) ? 1 : -1];
 
 // Comma tests
-int comma1[0?1,2:3];
-int comma2[1||(1,2)]; // expected-warning {{use of logical '||' with constant operand}} \
-                      // expected-note {{use '|' for a bitwise operation}}
-int comma3[(1,2)]; // expected-warning {{variable length array folded to constant array as an extension}}
+int comma1[0?1,2:3]; // expected-warning {{expression result unused}}
+int comma2[1 || (1, 2)]; // expected-warning {{use of logical '||' with constant operand}} \
+                      // expected-note {{use '|' for a bitwise operation}} \
+                      // expected-warning {{expression result unused}}
+int comma3[(1, 2)];   // expected-warning {{variable length array folded to constant array as an extension}} \
+                      // expected-warning {{expression result unused}}
 
 // Pointer + __builtin_constant_p
 char pbcp[__builtin_constant_p(4) ? (intptr_t)&expr : 0]; // expected-error {{variable length array declaration not allowed at file scope}}
Index: clang/test/Sema/exprs.c
===================================================================
--- clang/test/Sema/exprs.c
+++ clang/test/Sema/exprs.c
@@ -13,10 +13,9 @@
 
 
 // Test that we don't report divide-by-zero errors in unreachable code.
-// This test should be left as is, as it also tests CFG functionality.
 void radar9171946() {
   if (0) {
-    0 / (0 ? 1 : 0); // expected-warning {{expression result unused}}
+    0 / (0 ? 1 : 0); // no-warning
   }
 }
 
Index: clang/test/Sema/const-eval.c
===================================================================
--- clang/test/Sema/const-eval.c
+++ clang/test/Sema/const-eval.c
@@ -74,7 +74,7 @@
 EVAL_EXPR(35, constbool)
 EVAL_EXPR(36, constbool)
 
-EVAL_EXPR(37, (1,2.0) == 2.0 ? 1 : -1)
+EVAL_EXPR(37, ((void)1,2.0) == 2.0 ? 1 : -1)
 EVAL_EXPR(38, __builtin_expect(1,1) == 1 ? 1 : -1)
 
 // PR7884
Index: clang/test/Parser/cxx0x-ambig.cpp
===================================================================
--- clang/test/Parser/cxx0x-ambig.cpp
+++ clang/test/Parser/cxx0x-ambig.cpp
@@ -163,7 +163,7 @@
     (void)p1;
 
     UnsignedTmplArgSink<T(CtorSink(t ...)) ...> *t0; // ok
-    UnsignedTmplArgSink<((T *)0, 42u) ...> **t0p = &t0;
+    UnsignedTmplArgSink<((T *)0, 42u) ...> **t0p = &t0; // expected-warning 2{{expression result unused}}
   }
 
   template void foo(int, int, int); // expected-note {{in instantiation of function template specialization 'ellipsis::foo<int, int>' requested here}}
Index: clang/test/Parser/cxx-ambig-decl-expr.cpp
===================================================================
--- clang/test/Parser/cxx-ambig-decl-expr.cpp
+++ clang/test/Parser/cxx-ambig-decl-expr.cpp
@@ -36,8 +36,8 @@
   int(a[{0}]); // expected-warning {{unused}}
 
   // These are array declarations.
-  int(x[(1,1)]); // expected-error {{redefinition}}
-  int(x[true ? 1,1 : 1]); // expected-error {{redefinition}}
+  int(x[((void)1,1)]); // expected-error {{redefinition}}
+  int(x[true ? 1 : (1,1)]); // expected-error {{redefinition}} // expected-warning {{unused}}
 
   int (*_Atomic atomic_ptr_to_int);
   *atomic_ptr_to_int = 42;
Index: clang/test/PCH/cxx-explicit-specifier.cpp
===================================================================
--- clang/test/PCH/cxx-explicit-specifier.cpp
+++ clang/test/PCH/cxx-explicit-specifier.cpp
@@ -12,7 +12,7 @@
 
   template<typename X, typename Y> struct T {
     template<typename A>
-    explicit((Y{}, true)) T(A &&a) {}
+    explicit(((void)Y{}, true)) T(A &&a) {}
   };
 
   template<typename X, typename Y> struct U : T<X, Y> {
@@ -28,7 +28,7 @@
 U<S, char> a = foo('0');
 }
 
-//CHECK: explicit((char{} , true))
+//CHECK: explicit(((void)char{} , true))
 
 #endif
 
Index: clang/test/CodeCompletion/pragma-macro-token-caching.c
===================================================================
--- clang/test/CodeCompletion/pragma-macro-token-caching.c
+++ clang/test/CodeCompletion/pragma-macro-token-caching.c
@@ -12,7 +12,7 @@
 
 void completeParamPragmaError(int param) {
     Outer(__extension__({ _Pragma(2) })); // expected-error {{_Pragma takes a parenthesized string literal}}
-    param; // expected-warning {{expression result unused}}
+    param;
 }
 
 // RUN: %clang_cc1 -fsyntax-only -verify -code-completion-at=%s:16:1 %s | FileCheck %s
Index: clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
===================================================================
--- clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
+++ clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
@@ -26,7 +26,7 @@
   template<typename T> requires (T{}) // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
   struct B<T**> {};
 
-  static_assert((B<int**>{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B<int *>' required here}}
+  static_assert(((void)B<int**>{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B<int *>' required here}}
   // expected-note@-1{{while checking constraint satisfaction for class template partial specialization 'B<int>' required here}}
   // expected-note@-2{{during template argument deduction for class template partial specialization 'B<T *>' [with T = int *]}}
   // expected-note@-3{{during template argument deduction for class template partial specialization 'B<T **>' [with T = int]}}
Index: clang/test/CXX/drs/dr14xx.cpp
===================================================================
--- clang/test/CXX/drs/dr14xx.cpp
+++ clang/test/CXX/drs/dr14xx.cpp
@@ -18,7 +18,7 @@
       Check<true ? 0 : A::unknown_spec>::type *var1; // expected-error {{undeclared identifier 'var1'}}
       Check<true ? 0 : a>::type *var2; // ok, variable declaration  expected-note 0+{{here}}
       Check<true ? 0 : b>::type *var3; // expected-error {{undeclared identifier 'var3'}}
-      Check<true ? 0 : (c, 0)>::type *var4; // expected-error {{undeclared identifier 'var4'}}
+      Check<true ? 0 : ((void)c, 0)>::type *var4; // expected-error {{undeclared identifier 'var4'}}
       // value-dependent because of the implied type-dependent 'this->', not because of 'd'
       Check<true ? 0 : (d(), 0)>::type *var5; // expected-error {{undeclared identifier 'var5'}}
       // value-dependent because of the value-dependent '&' operator, not because of 'A::d'
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -379,7 +379,8 @@
     return;
   }
 
-  DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2);
+  DiagIfReachable(Loc, S ? llvm::makeArrayRef(S) : llvm::None,
+                  PDiag(DiagID) << R1 << R2);
 }
 
 void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -18779,6 +18779,37 @@
   EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E);
 }
 
+/// Emit a diagnostic when statements are reachable.
+/// FIXME: check for reachability even in expressions for which we don't build a
+///        CFG (eg, in the initializer of a global or in a constant expression).
+///        For example,
+///        namespace { auto *p = new double[3][false ? (1, 2) : 3]; }
+bool Sema::DiagIfReachable(SourceLocation Loc, ArrayRef<const Stmt *> Stmts,
+                           const PartialDiagnostic &PD) {
+  if (!Stmts.empty() && !FunctionScopes.empty()) {
+    FunctionScopes.back()->PossiblyUnreachableDiags.push_back(
+        sema::PossiblyUnreachableDiag(PD, Loc, Stmts));
+    return true;
+  }
+
+  // The initializer of a constexpr variable or of the first declaration of a
+  // static data member is not syntactically a constant evaluated constant,
+  // but nonetheless is always required to be a constant expression, so we
+  // can skip diagnosing.
+  // FIXME: Using the mangling context here is a hack.
+  if (auto *VD = dyn_cast_or_null<VarDecl>(
+          ExprEvalContexts.back().ManglingContextDecl)) {
+    if (VD->isConstexpr() ||
+        (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline()))
+      return false;
+    // FIXME: For any other kind of variable, we should build a CFG for its
+    // initializer and check whether the context in question is reachable.
+  }
+
+  Diag(Loc, PD);
+  return true;
+}
+
 /// Emit a diagnostic that describes an effect on the run-time behavior
 /// of the program being compiled.
 ///
@@ -18811,28 +18842,7 @@
 
   case ExpressionEvaluationContext::PotentiallyEvaluated:
   case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
-    if (!Stmts.empty() && getCurFunctionOrMethodDecl()) {
-      FunctionScopes.back()->PossiblyUnreachableDiags.
-        push_back(sema::PossiblyUnreachableDiag(PD, Loc, Stmts));
-      return true;
-    }
-
-    // The initializer of a constexpr variable or of the first declaration of a
-    // static data member is not syntactically a constant evaluated constant,
-    // but nonetheless is always required to be a constant expression, so we
-    // can skip diagnosing.
-    // FIXME: Using the mangling context here is a hack.
-    if (auto *VD = dyn_cast_or_null<VarDecl>(
-            ExprEvalContexts.back().ManglingContextDecl)) {
-      if (VD->isConstexpr() ||
-          (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline()))
-        break;
-      // FIXME: For any other kind of variable, we should build a CFG for its
-      // initializer and check whether the context in question is reachable.
-    }
-
-    Diag(Loc, PD);
-    return true;
+    return DiagIfReachable(Loc, Stmts, PD);
   }
 
   return false;
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5077,6 +5077,16 @@
   /// conversion.
   ExprResult tryConvertExprToType(Expr *E, QualType Ty);
 
+  /// Conditionally issue a diagnostic based on the statements reachability
+  /// analysis evaluation context.
+  ///
+  /// \param Statement If Statement is non-null, delay reporting the
+  /// diagnostic until the function body is parsed, and then do a basic
+  /// reachability analysis to determine if the statement is reachable.
+  /// If it is unreachable, the diagnostic will not be emitted.
+  bool DiagIfReachable(SourceLocation Loc, ArrayRef<const Stmt *> Stmts,
+                       const PartialDiagnostic &PD);
+
   /// Conditionally issue a diagnostic based on the current
   /// evaluation context.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D103938: ... Yuanfang Chen via Phabricator via cfe-commits

Reply via email to