[clang] 27a972a - Diagnose -Wunused-value based on CFG reachability

Yuanfang Chen via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 28 10:00:46 PDT 2021


Author: Yuanfang Chen
Date: 2021-09-28T10:00:15-07:00
New Revision: 27a972a699cd875c7fa9114dc0888015cd724f31

URL: https://github.com/llvm/llvm-project/commit/27a972a699cd875c7fa9114dc0888015cd724f31
DIFF: https://github.com/llvm/llvm-project/commit/27a972a699cd875c7fa9114dc0888015cd724f31.diff

LOG: Diagnose -Wunused-value based on CFG reachability

(This relands 59337263ab45d7657e and makes sure comma operator
 diagnostics are suppressed in a SFINAE context.)

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

Added: 
    

Modified: 
    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

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 07c5e85913712..00b6acf8bbe68 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -8560,6 +8560,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>;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d35f5c520a949..bd5cf12183712 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4908,7 +4908,7 @@ class Sema final {
 
   /// 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);
 
@@ -5114,6 +5114,16 @@ class Sema final {
   /// 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.
   ///

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8eee366fbec67..8d483f317a421 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -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;

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index f4a27a00a2e2e..07d27aaf7bdc5 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -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,

diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 98e6275bfda07..7182790ae9bb9 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -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,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
     return;
   }
 
-  DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2);
+  // Do not diagnose use of a comma operator in a SFINAE context because the
+  // type of the left operand could be used for SFINAE, so technically it is
+  // *used*.
+  if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext())
+    DiagIfReachable(Loc, S ? llvm::makeArrayRef(S) : llvm::None,
+                    PDiag(DiagID) << R1 << R2);
 }
 
 void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) {

diff  --git a/clang/test/Analysis/dead-stores.c b/clang/test/Analysis/dead-stores.c
index 145b81bd03327..2ce94eb31b198 100644
--- a/clang/test/Analysis/dead-stores.c
+++ b/clang/test/Analysis/dead-stores.c
@@ -339,12 +339,12 @@ void f22() {
     (void)(0 && x);
     (void)y7;
     (void)(0 || (y8, ({ return; }), 1));
-    // non-nested-warning at -1 {{expression result unused}}
+    // non-nested-warning at -1 {{left operand of comma operator has no effect}}
     (void)x;
     break;
   case 8:
     (void)(1 && (y9, ({ return; }), 1));
-    // non-nested-warning at -1 {{expression result unused}}
+    // non-nested-warning at -1 {{left operand of comma operator has no effect}}
     (void)x;
     break;
   case 9:

diff  --git a/clang/test/CXX/basic/basic.link/p8.cpp b/clang/test/CXX/basic/basic.link/p8.cpp
index 54b977d77f684..e348562c2eee2 100644
--- a/clang/test/CXX/basic/basic.link/p8.cpp
+++ b/clang/test/CXX/basic/basic.link/p8.cpp
@@ -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({});
 }

diff  --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp
index 70bf1ea70e38e..4d64943e9eea0 100644
--- a/clang/test/CXX/drs/dr14xx.cpp
+++ b/clang/test/CXX/drs/dr14xx.cpp
@@ -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'

diff  --git a/clang/test/CXX/drs/dr20xx.cpp b/clang/test/CXX/drs/dr20xx.cpp
index 9a0c772973eca..aef14dd222595 100644
--- a/clang/test/CXX/drs/dr20xx.cpp
+++ b/clang/test/CXX/drs/dr20xx.cpp
@@ -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 at -6 {{enclosing function}}
       // expected-error at -6 {{enclosing function}}

diff  --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp
index 147560d3037b9..2b72425f705c6 100644
--- a/clang/test/CXX/drs/dr7xx.cpp
+++ b/clang/test/CXX/drs/dr7xx.cpp
@@ -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}}
       }
     };
   }

diff  --git a/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
index 4372aab591eb6..7d5c8c40da057 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
@@ -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 at -1{{while checking constraint satisfaction for class template partial specialization 'B<int>' required here}}
   // expected-note at -2{{during template argument deduction for class template partial specialization 'B<T *>' [with T = int *]}}
   // expected-note at -3{{during template argument deduction for class template partial specialization 'B<T **>' [with T = int]}}

diff  --git a/clang/test/CodeCompletion/pragma-macro-token-caching.c b/clang/test/CodeCompletion/pragma-macro-token-caching.c
index 59b6621b56ad4..432706e85ceb9 100644
--- a/clang/test/CodeCompletion/pragma-macro-token-caching.c
+++ b/clang/test/CodeCompletion/pragma-macro-token-caching.c
@@ -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

diff  --git a/clang/test/Frontend/fixed_point_crash.c b/clang/test/Frontend/fixed_point_crash.c
index 12dc1944f018e..869b7ee9355a3 100644
--- a/clang/test/Frontend/fixed_point_crash.c
+++ b/clang/test/Frontend/fixed_point_crash.c
@@ -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}}

diff  --git a/clang/test/PCH/cxx-explicit-specifier.cpp b/clang/test/PCH/cxx-explicit-specifier.cpp
index 331c2e84c7815..94ca9f7b080db 100644
--- a/clang/test/PCH/cxx-explicit-specifier.cpp
+++ b/clang/test/PCH/cxx-explicit-specifier.cpp
@@ -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
 

diff  --git a/clang/test/Parser/cxx-ambig-decl-expr.cpp b/clang/test/Parser/cxx-ambig-decl-expr.cpp
index 6203db2fbd228..fef3783ad32b2 100644
--- a/clang/test/Parser/cxx-ambig-decl-expr.cpp
+++ b/clang/test/Parser/cxx-ambig-decl-expr.cpp
@@ -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;

diff  --git a/clang/test/Parser/cxx0x-ambig.cpp b/clang/test/Parser/cxx0x-ambig.cpp
index 2dd53dd6daaba..7f3398ad1386c 100644
--- a/clang/test/Parser/cxx0x-ambig.cpp
+++ b/clang/test/Parser/cxx0x-ambig.cpp
@@ -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}}

diff  --git a/clang/test/Parser/cxx1z-init-statement.cpp b/clang/test/Parser/cxx1z-init-statement.cpp
index ade60dc762d5c..157e2b5f2ee55 100644
--- a/clang/test/Parser/cxx1z-init-statement.cpp
+++ b/clang/test/Parser/cxx1z-init-statement.cpp
@@ -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'}}

diff  --git a/clang/test/Parser/objc-messaging-1.m b/clang/test/Parser/objc-messaging-1.m
index 82450df9f2c36..6c0b78d63b87c 100644
--- a/clang/test/Parser/objc-messaging-1.m
+++ b/clang/test/Parser/objc-messaging-1.m
@@ -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}}
 
 }

diff  --git a/clang/test/Parser/objc-try-catch-1.m b/clang/test/Parser/objc-try-catch-1.m
index 3a60148c8be90..102d782f58e5c 100644
--- a/clang/test/Parser/objc-try-catch-1.m
+++ b/clang/test/Parser/objc-try-catch-1.m
@@ -28,14 +28,13 @@ @interface Frob1
     }
     @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}}
     }
   }
 

diff  --git a/clang/test/Parser/objcxx11-attributes.mm b/clang/test/Parser/objcxx11-attributes.mm
index 4bff2151a9c6d..3c14d03cb28b0 100644
--- a/clang/test/Parser/objcxx11-attributes.mm
+++ b/clang/test/Parser/objcxx11-attributes.mm
@@ -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 ];

diff  --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c
index 427b0566820ae..bbba474748bc5 100644
--- a/clang/test/Sema/const-eval.c
+++ b/clang/test/Sema/const-eval.c
@@ -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

diff  --git a/clang/test/Sema/exprs.c b/clang/test/Sema/exprs.c
index 4e144041acae6..c194d9c50bd4e 100644
--- a/clang/test/Sema/exprs.c
+++ b/clang/test/Sema/exprs.c
@@ -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
   }
 }
 

diff  --git a/clang/test/Sema/i-c-e.c b/clang/test/Sema/i-c-e.c
index 63416454f5a4d..c7991155b142c 100644
--- a/clang/test/Sema/i-c-e.c
+++ b/clang/test/Sema/i-c-e.c
@@ -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}}

diff  --git a/clang/test/Sema/sizeless-1.c b/clang/test/Sema/sizeless-1.c
index a8c08731d53e6..ad999052b0ee6 100644
--- a/clang/test/Sema/sizeless-1.c
+++ b/clang/test/Sema/sizeless-1.c
@@ -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}}

diff  --git a/clang/test/Sema/switch-1.c b/clang/test/Sema/switch-1.c
index 144c3607f5703..163af4f728420 100644
--- a/clang/test/Sema/switch-1.c
+++ b/clang/test/Sema/switch-1.c
@@ -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

diff  --git a/clang/test/Sema/vla-2.c b/clang/test/Sema/vla-2.c
index 819cab91afc52..316931f270607 100644
--- a/clang/test/Sema/vla-2.c
+++ b/clang/test/Sema/vla-2.c
@@ -4,14 +4,14 @@
 // a 
diff erent 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}}
 }

diff  --git a/clang/test/Sema/warn-type-safety.c b/clang/test/Sema/warn-type-safety.c
index da914730d3aad..13e61147a38c5 100644
--- a/clang/test/Sema/warn-type-safety.c
+++ b/clang/test/Sema/warn-type-safety.c
@@ -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

diff  --git a/clang/test/Sema/warn-unused-value.c b/clang/test/Sema/warn-unused-value.c
index edf791593a421..14a4dc1b46eec 100644
--- a/clang/test/Sema/warn-unused-value.c
+++ b/clang/test/Sema/warn-unused-value.c
@@ -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);

diff  --git a/clang/test/SemaCXX/attr-annotate.cpp b/clang/test/SemaCXX/attr-annotate.cpp
index b4da500f36e33..ef0215fb9a3b9 100644
--- a/clang/test/SemaCXX/attr-annotate.cpp
+++ b/clang/test/SemaCXX/attr-annotate.cpp
@@ -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 at -1 {{illegal initializer type 'void'}}
   };
   B<int> b;
@@ -73,7 +73,7 @@ struct B {
     [[clang::annotate("jui", b, cf)]] void t2() {}
     // expected-error at -1 {{'annotate' attribute requires parameter 1 to be a constant expression}}
     // expected-note at -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() {}
   };
 };
 

diff  --git a/clang/test/SemaCXX/builtin-constant-p.cpp b/clang/test/SemaCXX/builtin-constant-p.cpp
index 1b8cf455ef270..71c38c5c63c71 100644
--- a/clang/test/SemaCXX/builtin-constant-p.cpp
+++ b/clang/test/SemaCXX/builtin-constant-p.cpp
@@ -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

diff  --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 86020a09db443..caba033476698 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -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 {

diff  --git a/clang/test/SemaCXX/constant-expression.cpp b/clang/test/SemaCXX/constant-expression.cpp
index a5e571a97eb2e..56417b6a2e524 100644
--- a/clang/test/SemaCXX/constant-expression.cpp
+++ b/clang/test/SemaCXX/constant-expression.cpp
@@ -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}}
       ;

diff  --git a/clang/test/SemaCXX/expression-traits.cpp b/clang/test/SemaCXX/expression-traits.cpp
index d965d14747ae7..a76f0c4a6175f 100644
--- a/clang/test/SemaCXX/expression-traits.cpp
+++ b/clang/test/SemaCXX/expression-traits.cpp
@@ -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

diff  --git a/clang/test/SemaCXX/matrix-type-operators.cpp b/clang/test/SemaCXX/matrix-type-operators.cpp
index 52aa0bad34593..4e2b0f9315e6b 100644
--- a/clang/test/SemaCXX/matrix-type-operators.cpp
+++ b/clang/test/SemaCXX/matrix-type-operators.cpp
@@ -179,12 +179,12 @@ void insert(sx5x10_t a, float f) {
 
   a[4, 5] = 5.0;
   // expected-error at -1 {{comma expressions are not allowed as indices in matrix subscript expressions}}
-  // expected-warning at -2 {{expression result unused}}
+  // expected-warning at -2 {{left operand of comma operator has no effect}}
 
   a[4, 5, 4] = 5.0;
   // expected-error at -1 {{comma expressions are not allowed as indices in matrix subscript expressions}}
-  // expected-warning at -2 {{expression result unused}}
-  // expected-warning at -3 {{expression result unused}}
+  // expected-warning at -2 {{left operand of comma operator has no effect}}
+  // expected-warning at -3 {{left operand of comma operator has no effect}}
 }
 
 void extract(sx5x10_t a, float f) {

diff  --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp
index dff9350cc9847..e3ec42ab96928 100644
--- a/clang/test/SemaCXX/overloaded-operator.cpp
+++ b/clang/test/SemaCXX/overloaded-operator.cpp
@@ -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 {

diff  --git a/clang/test/SemaCXX/sizeless-1.cpp b/clang/test/SemaCXX/sizeless-1.cpp
index cf92dffbd170a..ee3ef51435d53 100644
--- a/clang/test/SemaCXX/sizeless-1.cpp
+++ b/clang/test/SemaCXX/sizeless-1.cpp
@@ -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}}

diff  --git a/clang/test/SemaCXX/vector.cpp b/clang/test/SemaCXX/vector.cpp
index 9608be576fabf..f9a9224e9a608 100644
--- a/clang/test/SemaCXX/vector.cpp
+++ b/clang/test/SemaCXX/vector.cpp
@@ -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 
diff erent 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 
diff erent size}} //expected-warning{{left operand of comma operator has no effect}}
 }
 
 typedef __attribute__((__ext_vector_type__(4))) float vector_float4;

diff  --git a/clang/test/SemaCXX/warn-comma-operator.cpp b/clang/test/SemaCXX/warn-comma-operator.cpp
index 0ed127b943f39..76cd49ed42bff 100644
--- a/clang/test/SemaCXX/warn-comma-operator.cpp
+++ b/clang/test/SemaCXX/warn-comma-operator.cpp
@@ -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;
 };
 

diff  --git a/clang/test/SemaCXX/warn-unused-value.cpp b/clang/test/SemaCXX/warn-unused-value.cpp
index 02bceeca13374..d964684069155 100644
--- a/clang/test/SemaCXX/warn-unused-value.cpp
+++ b/clang/test/SemaCXX/warn-unused-value.cpp
@@ -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,32 @@ 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
+
+// comma operator diagnostics should be suppressed in a SFINAE context.
+template <typename T, int = (T{},0)> int c(int) { return 0; }
+template <typename T, int> int c(double) { return 1; }
+int foo() { return c<int>(0); }
+
+#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

diff  --git a/clang/test/SemaTemplate/derived.cpp b/clang/test/SemaTemplate/derived.cpp
index bad72b5d67662..d95e577fb21c0 100644
--- a/clang/test/SemaTemplate/derived.cpp
+++ b/clang/test/SemaTemplate/derived.cpp
@@ -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}}
   };
 }

diff  --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp
index 8b8a55ccd7784..35b2ffcefea35 100644
--- a/clang/test/SemaTemplate/lambda-capture-pack.cpp
+++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp
@@ -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}}


        


More information about the cfe-commits mailing list