Diagnose -Wunused-value based on CFG reachability
authorYuanfang Chen <yuanfang.chen@sony.com>
Thu, 24 Jun 2021 06:46:42 +0000 (23:46 -0700)
committerYuanfang Chen <yuanfang.chen@sony.com>
Wed, 22 Sep 2021 21:38:06 +0000 (14:38 -0700)
While at it, add the diagnosis message "left operand of comma operator has no effect" (used by GCC) for comma operator.

This also makes Clang diagnose in the constant evaluation context which aligns with GCC/MSVC behavior. (https://godbolt.org/z/7zxb8Tx96)

Reviewed By: aaron.ballman

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

41 files changed:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/lib/Sema/SemaStmt.cpp
clang/test/Analysis/dead-stores.c
clang/test/CXX/basic/basic.link/p8.cpp
clang/test/CXX/drs/dr14xx.cpp
clang/test/CXX/drs/dr20xx.cpp
clang/test/CXX/drs/dr7xx.cpp
clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
clang/test/CodeCompletion/pragma-macro-token-caching.c
clang/test/Frontend/fixed_point_crash.c
clang/test/PCH/cxx-explicit-specifier.cpp
clang/test/Parser/cxx-ambig-decl-expr.cpp
clang/test/Parser/cxx0x-ambig.cpp
clang/test/Parser/cxx1z-init-statement.cpp
clang/test/Parser/objc-messaging-1.m
clang/test/Parser/objc-try-catch-1.m
clang/test/Parser/objcxx11-attributes.mm
clang/test/Sema/const-eval.c
clang/test/Sema/exprs.c
clang/test/Sema/i-c-e.c
clang/test/Sema/sizeless-1.c
clang/test/Sema/switch-1.c
clang/test/Sema/vla-2.c
clang/test/Sema/warn-type-safety.c
clang/test/Sema/warn-unused-value.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/matrix-type-operators.cpp
clang/test/SemaCXX/overloaded-operator.cpp
clang/test/SemaCXX/sizeless-1.cpp
clang/test/SemaCXX/vector.cpp
clang/test/SemaCXX/warn-comma-operator.cpp
clang/test/SemaCXX/warn-unused-value.cpp
clang/test/SemaTemplate/derived.cpp
clang/test/SemaTemplate/lambda-capture-pack.cpp

index 0e803ee028ce97c4cf05f003392996939e738b16..cafee92e46e75fa581713b00d74f39e083b83de5 100644 (file)
@@ -8565,6 +8565,9 @@ def err_typecheck_choose_expr_requires_constant : Error<
   "'__builtin_choose_expr' requires a constant expression">;
 def warn_unused_expr : Warning<"expression result unused">,
   InGroup<UnusedValue>;
+def warn_unused_comma_left_operand : Warning<
+  "left operand of comma operator has no effect">,
+  InGroup<UnusedValue>;
 def warn_unused_voidptr : Warning<
   "expression result unused; should this cast be to 'void'?">,
   InGroup<UnusedValue>;
index 93d5558b8267cd9a7ddea517320a5beda920d8b7..fc0b6919bd50bb2808c13f2f760396f2fd9cb157 100644 (file)
@@ -4912,7 +4912,7 @@ public:
 
   /// DiagnoseUnusedExprResult - If the statement passed in is an expression
   /// whose result is unused, warn.
-  void DiagnoseUnusedExprResult(const Stmt *S);
+  void DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID);
   void DiagnoseUnusedNestedTypedefs(const RecordDecl *D);
   void DiagnoseUnusedDecl(const NamedDecl *ND);
 
@@ -5118,6 +5118,16 @@ public:
   /// conversion.
   ExprResult tryConvertExprToType(Expr *E, QualType Ty);
 
+  /// Conditionally issue a diagnostic based on the statement's 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.
   ///
index 8eee366fbec67cf32fffcb602ffb6aaf0faf9bd7..8d483f317a421e2a47cbfc5a78a4124c9386fdde 100644 (file)
@@ -28,6 +28,7 @@
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Builtins.h"
+#include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -13371,7 +13372,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
   if (LHS.isInvalid())
     return QualType();
 
-  S.DiagnoseUnusedExprResult(LHS.get());
+  S.DiagnoseUnusedExprResult(LHS.get(), diag::warn_unused_comma_left_operand);
 
   if (!S.getLangOpts().CPlusPlus) {
     RHS = S.DefaultFunctionArrayLvalueConversion(RHS.get());
@@ -18898,6 +18899,38 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
   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() && getCurFunctionOrMethodDecl()) {
+    if (!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.
 ///
@@ -18930,28 +18963,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts,
 
   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 f4a27a00a2e2efd5aa7c22df2c03c63de41493c7..07d27aaf7bdc5d139b906337e19573b6dfac878b 100644 (file)
@@ -8523,7 +8523,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
     if (FullExpr.isInvalid())
       return ExprError();
 
-    DiagnoseUnusedExprResult(FullExpr.get());
+    DiagnoseUnusedExprResult(FullExpr.get(), diag::warn_unused_expr);
   }
 
   FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr,
index 98e6275bfda0766358d2f28f43a61cf2033834a6..5ef619816834ff1a3c88475754962d4ec29987fc 100644 (file)
@@ -216,9 +216,9 @@ static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A,
   return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2;
 }
 
-void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
+void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
   if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
-    return DiagnoseUnusedExprResult(Label->getSubStmt());
+    return DiagnoseUnusedExprResult(Label->getSubStmt(), DiagID);
 
   const Expr *E = dyn_cast_or_null<Expr>(S);
   if (!E)
@@ -264,7 +264,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
   // Okay, we have an unused result.  Depending on what the base expression is,
   // we might want to make a more specific diagnostic.  Check for one of these
   // cases now.
-  unsigned DiagID = diag::warn_unused_expr;
   if (const FullExpr *Temps = dyn_cast<FullExpr>(E))
     E = Temps->getSubExpr();
   if (const CXXBindTemporaryExpr *TempExpr = dyn_cast<CXXBindTemporaryExpr>(E))
@@ -339,7 +338,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
     if (LangOpts.OpenMP && isa<CallExpr>(Source) &&
         POE->getNumSemanticExprs() == 1 &&
         isa<CallExpr>(POE->getSemanticExpr(0)))
-      return DiagnoseUnusedExprResult(POE->getSemanticExpr(0));
+      return DiagnoseUnusedExprResult(POE->getSemanticExpr(0), DiagID);
     if (isa<ObjCSubscriptRefExpr>(Source))
       DiagID = diag::warn_unused_container_subscript_expr;
     else
@@ -379,7 +378,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
     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 145b81bd03327dc9150cd126b873cb59a797e4c2..2ce94eb31b198bcff2e59e72c2058662f81cc412 100644 (file)
@@ -339,12 +339,12 @@ void f22() {
     (void)(0 && x);
     (void)y7;
     (void)(0 || (y8, ({ return; }), 1));
-    // non-nested-warning@-1 {{expression result unused}}
+    // non-nested-warning@-1 {{left operand of comma operator has no effect}}
     (void)x;
     break;
   case 8:
     (void)(1 && (y9, ({ return; }), 1));
-    // non-nested-warning@-1 {{expression result unused}}
+    // non-nested-warning@-1 {{left operand of comma operator has no effect}}
     (void)x;
     break;
   case 9:
index 54b977d77f684b957f0feea5069925a81ce6df03..e348562c2eee25cb08f4af18ee6e248e0a7ac94d 100644 (file)
@@ -27,7 +27,7 @@ extern Linkage1 linkage1f();
 void linkage2f(Linkage2);
 
 void use_linkage() {
-  &linkage1v, &linkage1iv, &linkage2v, &linkage2iv, &linkaget1v; // expected-warning 5{{unused}}
+  &linkage1v, &linkage1iv, &linkage2v, &linkage2iv, &linkaget1v; // expected-warning 4{{left operand of comma operator has no effect}} expected-warning {{unused}}
   linkage1f();
   linkage2f({});
 }
index 70bf1ea70e38eaa9befef050991d31fbf4886070..4d64943e9eea0ef1c23f7040e523c6b68038705f 100644 (file)
@@ -18,7 +18,7 @@ namespace dr1413 { // dr1413: 12
       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 9a0c772973eca791bf751cc9395cae8d8aad8245..aef14dd222595cd3a8416d6662737135e7bf9dad 100644 (file)
@@ -221,7 +221,7 @@ namespace dr2083 { // dr2083: partial
         a.*&A::x; // expected-warning {{unused}}
         true ? a.x : a.y; // expected-warning {{unused}}
         (void)a.x;
-        a.x, discarded_lval(); // expected-warning {{unused}}
+        a.x, discarded_lval(); // expected-warning {{left operand of comma operator has no effect}}
 #if 1 // FIXME: These errors are all incorrect; the above code is valid.
       // expected-error@-6 {{enclosing function}}
       // expected-error@-6 {{enclosing function}}
index 147560d3037b976afeb89f89307daed962caffc4..2b72425f705c66f1af2acf77e4ca454023a55257 100644 (file)
@@ -26,12 +26,12 @@ namespace dr712 { // dr712: partial
         use(a);
         use((a));
         use(cond ? a : a);
-        use((cond, a)); // expected-warning 2{{unused}} FIXME: should only warn once
+        use((cond, a)); // expected-warning 2{{left operand of comma operator has no effect}} FIXME: should only warn once
 
         (void)a; // FIXME: expected-error {{declared in enclosing}}
         (void)(a); // FIXME: expected-error {{declared in enclosing}}
         (void)(cond ? a : a); // FIXME: expected-error 2{{declared in enclosing}}
-        (void)(cond, a); // FIXME: expected-error {{declared in enclosing}} expected-warning {{unused}}
+        (void)(cond, a); // FIXME: expected-error {{declared in enclosing}} expected-warning {{left operand of comma operator has no effect}}
       }
     };
   }
index 4372aab591eb6bc35ec898d11d04d1d03a306473..7d5c8c40da057990fbe703b0078e3495530f732c 100644 (file)
@@ -26,7 +26,7 @@ namespace class_templates
   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 59b6621b56ad4771a09822cf74eed58c9f6f5865..432706e85ceb9c48b9be9448a11129a9fa8760a9 100644 (file)
@@ -12,7 +12,7 @@ void completeParam(int param) {
 
 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 12dc1944f018e02c7be45c490dc50985333682d9..869b7ee9355a39590761bfbe5725095284084285 100644 (file)
@@ -14,7 +14,7 @@ int fn1() {
 int fn2() {
   union a m;
   m.x = 7, 5.6k; // expected-warning {{expression result unused}}
-  return m.x, m.i; // expected-warning {{expression result unused}}
+  return m.x, m.i; // expected-warning {{left operand of comma operator has no effect}}
 }
 
-_Accum acc = (0.5r, 6.9k); // expected-warning {{expression result unused}}
+_Accum acc = (0.5r, 6.9k); // expected-warning {{left operand of comma operator has no effect}}
index 331c2e84c78158b41ecee256717ad917903a58cf..94ca9f7b080db3da0c399e178a1b15143dc4a0f1 100644 (file)
@@ -12,7 +12,7 @@ namespace inheriting_constructor {
 
   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 @@ namespace inheriting_constructor {
 U<S, char> a = foo('0');
 }
 
-//CHECK: explicit((char{} , true))
+//CHECK: explicit(((void)char{} , true))
 
 #endif
 
index 6203db2fbd228788a4d5f09d4f4d8521a083805c..fef3783ad32b2746717fa346b73d775902aab981 100644 (file)
@@ -24,7 +24,7 @@ void arr() {
 
   // This is array indexing not an array declarator because a comma expression
   // is not syntactically a constant-expression.
-  int(x[1,1]); // expected-warning 2{{unused}}
+  int(x[1,1]); // expected-warning {{left operand of comma operator has no effect}} expected-warning {{unused}}
 
   // This is array indexing not an array declaration because a braced-init-list
   // is not syntactically a constant-expression.
@@ -36,8 +36,8 @@ void arr() {
   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 {{left operand of comma operator has no effect}}
 
   int (*_Atomic atomic_ptr_to_int);
   *atomic_ptr_to_int = 42;
index 2dd53dd6daabad76c5fd9b996fdf1bdfaa2842bb..7f3398ad1386c29b59ae20f1a92e78b94795f611 100644 (file)
@@ -163,7 +163,7 @@ namespace ellipsis {
     (void)p1;
 
     UnsignedTmplArgSink<T(CtorSink(t ...)) ...> *t0; // ok
-    UnsignedTmplArgSink<((T *)0, 42u) ...> **t0p = &t0;
+    UnsignedTmplArgSink<((T *)0, 42u) ...> **t0p = &t0; // expected-warning 2{{left operand of comma operator has no effect}}
   }
 
   template void foo(int, int, int); // expected-note {{in instantiation of function template specialization 'ellipsis::foo<int, int>' requested here}}
index ade60dc762d5c8dfb92c4cb60edc1f03054d9571..157e2b5f2ee55c7048227ae3a7c4b9f3f665b3b9 100644 (file)
@@ -14,8 +14,8 @@ int f() {
 
   // init-statement expressions
   if (T{f()}; f()) {} // expected-warning {{expression result unused}}
-  if (T{f()}, g, h; f()) {} // expected-warning 2{{unused}} expected-warning {{expression result unused}}
-  if (T(f()), g, h + 1; f()) {} // expected-warning 2{{unused}} expected-warning {{expression result unused}}
+  if (T{f()}, g, h; f()) {} // expected-warning 2{{left operand of comma operator has no effect}} expected-warning {{expression result unused}}
+  if (T(f()), g, h + 1; f()) {} // expected-warning 2{{left operand of comma operator has no effect}} expected-warning {{expression result unused}}
 
   // condition declarations
   if (T(n){g}) {}
@@ -26,8 +26,8 @@ int f() {
   // condition expressions
   if (T(f())) {}
   if (T{f()}) {}
-  if (T(f()), g, h) {} // expected-warning 2{{unused}}
-  if (T{f()}, g, h) {} // expected-warning 2{{unused}}
+  if (T(f()), g, h) {} // expected-warning 2{{left operand of comma operator has no effect}}
+  if (T{f()}, g, h) {} // expected-warning 2{{left operand of comma operator has no effect}}
 
   // none of the above, disambiguated as expression (can't be a declaration)
   if (T(n)(g)) {} // expected-error {{undeclared identifier 'n'}}
index 82450df9f2c36cf78714b92177a316bbbc0eed05..6c0b78d63b87c2960b798c66241f132d4f6d4be0 100644 (file)
@@ -7,20 +7,20 @@ int main ()
        [a ii]; // expected-warning{{not found}}
        [a if: 1 :2]; // expected-warning{{not found}}
        [a inout: 1 :2 another:(2,3,4)]; // expected-warning{{not found}} \
-           // expected-warning 2{{expression result unused}}
+           // expected-warning 2{{left operand of comma operator has no effect}}
        [a inout: 1 :2 another:(2,3,4), 6,6,8]; // expected-warning{{not found}} \
-           // expected-warning 2{{expression result unused}}
+           // expected-warning 2{{left operand of comma operator has no effect}}
        [a inout: 1 :2 another:(2,3,4), (6,4,5),6,8]; // expected-warning{{not found}} \
-           // expected-warning 4{{expression result unused}}
+           // expected-warning 4{{left operand of comma operator has no effect}}
        [a inout: 1 :2 another:(i+10), (i,j-1,5),6,8]; // expected-warning{{not found}} \
-           // expected-warning 2{{expression result unused}}
+           // expected-warning 2{{left operand of comma operator has no effect}}
        [a long: 1 :2 another:(i+10), (i,j-1,5),6,8]; // expected-warning{{not found}} \
-           // expected-warning 2{{expression result unused}}
+           // expected-warning 2{{left operand of comma operator has no effect}}
        [a : "Hello\n" :2 another:(i+10), (i,j-1,5),6,8]; // expected-warning{{not found}} \
-           // expected-warning 2{{expression result unused}}
+           // expected-warning 2{{left operand of comma operator has no effect}}
 
        // Comma expression as receiver (rdar://6222856)
        [a, b, c foo]; // expected-warning{{not found}} \
-           // expected-warning 2{{expression result unused}}
+           // expected-warning 2{{left operand of comma operator has no effect}}
 
 }
index 3a60148c8be9091ec172c550238c98148b9134a4..102d782f58e5cf61d63d39d664465378df29a33d 100644 (file)
@@ -28,14 +28,13 @@ void * foo()
     }
     @catch (Frob* ex) {
       @throw 1,2; // expected-error {{@throw requires an Objective-C object type ('int' invalid)}} \
-                                 // expected-warning {{expression result unused}}
+                                 // expected-warning {{left operand of comma operator has no effect}}
     }
     @catch (float x) {  // expected-error {{@catch parameter is not a pointer to an interface type}}
       
     }
     @catch(...) {
-      @throw (4,3,proc()); // expected-warning {{expression result unused}} \
-                                                  // expected-warning {{expression result unused}}
+      @throw (4,3,proc()); // expected-warning 2{{left operand of comma operator has no effect}}
     }
   }
 
index 4bff2151a9c6d0bdf41e218075d256aa273b29c5..3c14d03cb28b02558a609e5ab9668555d77eaff2 100644 (file)
@@ -22,7 +22,7 @@ void f(X *noreturn) {
 
   // A message send which contains a message send is OK.
   [ [ X alloc ] init ];
-  [ [ int(), noreturn getSelf ] getSize ]; // expected-warning {{unused}}
+  [ [ int(), noreturn getSelf ] getSize ]; // expected-warning {{left operand of comma operator has no effect}}
 
   // A message send which contains a lambda is OK.
   [ [noreturn] { return noreturn; } () setSize: 4 ];
index 427b0566820aef24719ac25d66af39b5d8a34f69..bbba474748bc5465d7f46dec6aeb8e6a8d72e010 100644 (file)
@@ -74,7 +74,7 @@ const _Bool constbool = 0;
 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 4e144041acae6c0ffef0436538b57c70485521e7..c194d9c50bd4e55c4dcfe84b808b0aca36f0a1e5 100644 (file)
@@ -16,7 +16,7 @@
 // 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 63416454f5a4d5f9a7edc7a8529388b9309e1985..c7991155b142c3141995174dbdb7160000641c6c 100644 (file)
@@ -70,10 +70,12 @@ char y[__builtin_constant_p(expr) ? -1 : 1];
 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 {{left operand of comma operator has no effect}}
+int comma2[1 || (1, 2)]; // expected-warning {{use of logical '||' with constant operand}} \
+                      // expected-note {{use '|' for a bitwise operation}} \
+                      // expected-warning {{left operand of comma operator has no effect}}
+int comma3[(1, 2)];   // expected-warning {{variable length array folded to constant array as an extension}} \
+                      // expected-warning {{left operand of comma operator has no effect}}
 
 // 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 a8c08731d53e628b60c3980b41264ecaf345739e..ad999052b0ee62fdfeb0673e8e8671b3ce8b7f99 100644 (file)
@@ -76,9 +76,9 @@ void func(int sel) {
 
   (void)local_int8;
 
-  local_int8, 0; // expected-warning + {{expression result unused}}
+  local_int8, 0; // expected-warning {{left operand of comma operator has no effect}}
 
-  0, local_int8; // expected-warning + {{expression result unused}}
+  0, local_int8; // expected-warning {{left operand of comma operator has no effect}} expected-warning {{expression result unused}}
 
   svint8_t init_int8 = local_int8;
   svint8_t bad_init_int8 = for; // expected-error {{expected expression}}
index 144c3607f57038ce2ea7618508057201b6ead68d..163af4f728420e6cce6c2e7fa4dfffa401f0a207 100644 (file)
@@ -50,7 +50,7 @@ int f(int i) {
       return 0;
   }
   return (i, 65537) * 65537; // expected-warning {{overflow in expression; result is 131073 with type 'int'}} \
-                            // expected-warning {{expression result unused}}
+                            // expected-warning {{left operand of comma operator has no effect}}
 }
 
 // rdar://18405357
index 819cab91afc528b8dc20df2c31483b45b59b297d..316931f2706077d220ebfad73617998fc98ee836 100644 (file)
@@ -4,14 +4,14 @@
 // a different codepath when we have already emitted an error.)
 
 int PotentiallyEvaluatedSizeofWarn(int n) {
-  return (int)sizeof *(0 << 32,(int(*)[n])0); // expected-warning {{expression result unused}} expected-warning {{shift count >= width of type}}
+  return (int)sizeof *(0 << 32,(int(*)[n])0); // expected-warning {{left operand of comma operator has no effect}} expected-warning {{shift count >= width of type}}
 }
 
 void PotentiallyEvaluatedTypeofWarn(int n) {
-  __typeof(*(0 << 32,(int(*)[n])0)) x; // expected-warning {{expression result unused}} expected-warning {{shift count >= width of type}}
+  __typeof(*(0 << 32,(int(*)[n])0)) x; // expected-warning {{left operand of comma operator has no effect}} expected-warning {{shift count >= width of type}}
   (void)x;
 }
 
 void PotentiallyEvaluatedArrayBoundWarn(int n) {
-  (void)*(int(*)[(0 << 32,n)])0; // FIXME: We should warn here.
+  (void)*(int(*)[(0 << 32,n)])0; // expected-warning {{left operand of comma operator has no effect}}
 }
index da914730d3aad85e6aa079335d86fc3535fedd61..13e61147a38c5a2255793aa131792ba605e0bf6e 100644 (file)
@@ -145,7 +145,7 @@ void test_argument_with_type_tag(struct flock *f)
 void test_tag_expresssion(int b) {
   fcntl(0, b ? F_DUPFD : F_SETLK, 10); // no-warning
   fcntl(0, b + F_DUPFD, 10); // no-warning
-  fcntl(0, (b, F_DUPFD), 10); // expected-warning {{expression result unused}}
+  fcntl(0, (b, F_DUPFD), 10); // expected-warning {{left operand of comma operator has no effect}}
 }
 
 // Check that using 64-bit magic values as tags works and tag values do not
index edf791593a4213db9e9c463a5b114df7df0dadd5..14a4dc1b46eec86849930d6e977e97f647aac3c8 100644 (file)
@@ -9,31 +9,31 @@ void foo();
 
 // PR4806
 void pr4806() {
-  1,foo();          // expected-warning {{expression result unused}}
+  1,foo();          // expected-warning {{left operand of comma operator has no effect}}
 
   // other
   foo();
   i;                // expected-warning {{expression result unused}}
 
-  i,foo();          // expected-warning {{expression result unused}}
+  i,foo();          // expected-warning {{left operand of comma operator has no effect}}
   foo(),i;          // expected-warning {{expression result unused}}
 
-  i,j,foo();        // expected-warning {{expression result unused}} expected-warning {{expression result unused}}
-  i,foo(),j;        // expected-warning {{expression result unused}} expected-warning {{expression result unused}}
-  foo(),i,j;        // expected-warning {{expression result unused}} expected-warning {{expression result unused}}
+  i,j,foo();        // expected-warning 2{{left operand of comma operator has no effect}}
+  i,foo(),j;        // expected-warning {{left operand of comma operator has no effect}} expected-warning {{expression result unused}}
+  foo(),i,j;        // expected-warning {{expression result unused}} expected-warning {{left operand of comma operator has no effect}}
 
   i++;
 
   i++,foo();
   foo(),i++;
 
-  i++,j,foo();      // expected-warning {{expression result unused}}
+  i++,j,foo();      // expected-warning {{left operand of comma operator has no effect}}
   i++,foo(),j;      // expected-warning {{expression result unused}}
   foo(),i++,j;      // expected-warning {{expression result unused}}
 
-  i,j++,foo();      // expected-warning {{expression result unused}}
-  i,foo(),j++;      // expected-warning {{expression result unused}}
-  foo(),i,j++;      // expected-warning {{expression result unused}}
+  i,j++,foo();      // expected-warning {{left operand of comma operator has no effect}}
+  i,foo(),j++;      // expected-warning {{left operand of comma operator has no effect}}
+  foo(),i,j++;      // expected-warning {{left operand of comma operator has no effect}}
 
   i++,j++,foo();
   i++,foo(),j++;
@@ -86,7 +86,7 @@ struct s0 { int f0; };
 void f0(int a);
 void f1(struct s0 *a) {
   // rdar://8139785
-  f0((int)(a->f0 + 1, 10)); // expected-warning {{expression result unused}}
+  f0((int)(a->f0 + 1, 10)); // expected-warning {{left operand of comma operator has no effect}}
 }
 
 void blah(int a);
index b4da500f36e33c629af72b953c00905f9487d027..ef0215fb9a3b9b38dde01b19760e251b725fb388 100644 (file)
@@ -42,7 +42,7 @@ namespace test0 {
 
   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 @@ struct B {
     [[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 1b8cf455ef270ced074ae7d34ea0eff3a4153d88..71c38c5c63c710c48dcd7f72c5916fd25fab00ea 100644 (file)
@@ -157,12 +157,12 @@ namespace constexpr_dtor {
     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 86020a09db443215404578f2f9bdd98192998332..caba03347669842cca536242e6e9e7f0404841a3 100644 (file)
@@ -745,7 +745,7 @@ namespace dtor {
   // 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 a5e571a97eb2e04e4399d3519b5d11c63c1e892f..56417b6a2e524035fba451d3836fe2be092e2bd4 100644 (file)
@@ -88,8 +88,8 @@ enum {
 
 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 {{left operand of comma operator has no effect}}
+    case (int)(1/0, 2.0): // expected-error {{not an integral constant expression}} expected-note {{division by zero}} expected-warning {{left operand of comma operator has no effect}}
     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 d965d14747ae7a5ceba39760a5e748e3be3c3116..a76f0c4a6175ffc6678658a5c48ac9c6c3b46ced 100644 (file)
@@ -583,10 +583,10 @@ void expr_comma(int x)
 
     // 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 52aa0bad345936806af620c7eaba0741b77a32e4..4e2b0f9315e6b9f1282440cacca17ea0689b4939 100644 (file)
@@ -179,12 +179,12 @@ void insert(sx5x10_t a, float f) {
 
   a[4, 5] = 5.0;
   // expected-error@-1 {{comma expressions are not allowed as indices in matrix subscript expressions}}
-  // expected-warning@-2 {{expression result unused}}
+  // expected-warning@-2 {{left operand of comma operator has no effect}}
 
   a[4, 5, 4] = 5.0;
   // expected-error@-1 {{comma expressions are not allowed as indices in matrix subscript expressions}}
-  // expected-warning@-2 {{expression result unused}}
-  // expected-warning@-3 {{expression result unused}}
+  // expected-warning@-2 {{left operand of comma operator has no effect}}
+  // expected-warning@-3 {{left operand of comma operator has no effect}}
 }
 
 void extract(sx5x10_t a, float f) {
index dff9350cc984717a12a6240864619f33a5cab8b5..e3ec42ab969283433410dcdb27c1d1d9476640e2 100644 (file)
@@ -157,7 +157,7 @@ bool& operator,(X, Y);
 
 void test_comma(X x, Y y) {
   bool& b1 = (x, y);
-  X& xr = (x, x); // expected-warning {{expression result unused}}
+  X& xr = (x, x); // expected-warning {{left operand of comma operator has no effect}}
 }
 
 struct Callable {
index cf92dffbd170abf3acc2d961dd5b6e47f4d13931..ee3ef51435d5397bc3884371c4f47c7b477fef90 100644 (file)
@@ -85,9 +85,9 @@ void func(int sel) {
 
   (void)local_int8;
 
-  local_int8, 0; // expected-warning + {{expression result unused}}
+  local_int8, 0; // expected-warning {{left operand of comma operator has no effect}}
 
-  0, local_int8; // expected-warning + {{expression result unused}}
+  0, local_int8; // expected-warning {{left operand of comma operator has no effect}} expected-warning {{expression result unused}}
 
   svint8_t init_int8 = local_int8;
   svint8_t bad_init_int8 = for; // expected-error {{expected expression}}
index 9608be576fabfeeb8d7b3ca1ba54854e6953d2d9..f9a9224e9a608e5f3917b55cdbcdaeef9da288f3 100644 (file)
@@ -381,8 +381,8 @@ void Init() {
 typedef int inte2 __attribute__((__ext_vector_type__(2)));
 
 void test_vector_literal(inte4 res) {
-  inte2 a = (inte2)(1, 2); //expected-warning{{expression result unused}}
-  inte4 b = (inte4)(a, a); //expected-error{{C-style cast from vector 'inte2' (vector of 2 'int' values) to vector 'inte4' (vector of 4 'int' values) of different size}} //expected-warning{{expression result unused}}
+  inte2 a = (inte2)(1, 2); //expected-warning{{left operand of comma operator has no effect}}
+  inte4 b = (inte4)(a, a); //expected-error{{C-style cast from vector 'inte2' (vector of 2 'int' values) to vector 'inte4' (vector of 4 'int' values) of different size}} //expected-warning{{left operand of comma operator has no effect}}
 }
 
 typedef __attribute__((__ext_vector_type__(4))) float vector_float4;
index 0ed127b943f39d5cc346b8a6323e51de3499caca..76cd49ed42bffa942f40146be7a4d803fd0d366a 100644 (file)
@@ -242,8 +242,8 @@ struct bool_seq;
 
 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 02bceeca133747af3732b6f53d28311841704eeb..35e8fcface8be00d390f1b63bca28ca29ad4cabf 100644 (file)
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value %s
 // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++98 %s
 // RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused-value -std=c++17 %s
 
 // PR4806
 namespace test0 {
@@ -138,3 +139,26 @@ void volatile_array() {
   (void)arr3;
   (void)arr4;
 }
+
+#if __cplusplus >= 201103L // C++11 or later
+namespace test5 {
+int v[(5, 6)]; // expected-warning {{left operand of comma operator has no effect}}
+void foo() {
+  new double[false ? (1, 2) : 3]
+            // FIXME: We shouldn't diagnose the unreachable constant expression
+            // here.
+            [false ? (1, 2) : 3]; // expected-warning {{left operand of comma operator has no effect}}
+}
+} // namespace test5
+#endif
+
+#if __cplusplus >= 201703L // C++17 or later
+namespace test6 {
+auto b() {
+  if constexpr (false)
+    return (1,0);
+  else
+    return (1.0,0.0); // expected-warning {{left operand of comma operator has no effect}}
+}
+} // namespace test6
+#endif
index bad72b5d676628b14f76bfd715325226bb4d7131..d95e577fb21c0d06df473d5e511fbdc38523d61f 100644 (file)
@@ -49,6 +49,6 @@ namespace rdar14183893 {
 
   class A {
     TFP m_p;
-    void Enable() { 0, A(); } // expected-warning {{unused}}
+    void Enable() { 0, A(); } // expected-warning {{left operand of comma operator has no effect}}
   };
 }
index 8b8a55ccd778478536c98eb02fdcd2a85d6c1d41..35b2ffcefea35519e3585863bebb6a0a9e09d86e 100644 (file)
@@ -18,7 +18,7 @@ template void f(int, char, double);
 namespace PR41576 {
   template <class... Xs> constexpr int f(Xs ...xs) {
     return [&](auto ...ys) { // expected-note {{instantiation}}
-      return ((xs + ys), ...); // expected-warning {{unused}}
+      return ((xs + ys), ...); // expected-warning {{left operand of comma operator has no effect}}
     }(1, 2);
   }
   static_assert(f(3, 4) == 6); // expected-note {{instantiation}}