diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8565,6 +8565,9 @@ "'__builtin_choose_expr' requires a constant expression">; def warn_unused_expr : Warning<"expression result unused">, InGroup; +def warn_unused_comma_left_operand : Warning< + "left operand of comma operator has no effect">, + InGroup; def warn_unused_voidptr : Warning< "expression result unused; should this cast be to 'void'?">, InGroup; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4912,7 +4912,7 @@ /// 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 @@ /// 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 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 --- 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 @@ 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 @@ 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 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( + 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 @@ 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( - 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 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -8523,7 +8523,7 @@ 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 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -216,9 +216,9 @@ 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(S)) - return DiagnoseUnusedExprResult(Label->getSubStmt()); + return DiagnoseUnusedExprResult(Label->getSubStmt(), DiagID); const Expr *E = dyn_cast_or_null(S); if (!E) @@ -264,7 +264,6 @@ // 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(E)) E = Temps->getSubExpr(); if (const CXXBindTemporaryExpr *TempExpr = dyn_cast(E)) @@ -339,7 +338,7 @@ if (LangOpts.OpenMP && isa(Source) && POE->getNumSemanticExprs() == 1 && isa(POE->getSemanticExpr(0))) - return DiagnoseUnusedExprResult(POE->getSemanticExpr(0)); + return DiagnoseUnusedExprResult(POE->getSemanticExpr(0), DiagID); if (isa(Source)) DiagID = diag::warn_unused_container_subscript_expr; else @@ -379,7 +378,11 @@ return; } - DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2); + // Skip diagnose for comma operator in SFINAE context since the type of left + // operand could trigger substitution error 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 --- a/clang/test/Analysis/dead-stores.c +++ b/clang/test/Analysis/dead-stores.c @@ -339,12 +339,12 @@ (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: diff --git a/clang/test/CXX/basic/basic.link/p8.cpp b/clang/test/CXX/basic/basic.link/p8.cpp --- a/clang/test/CXX/basic/basic.link/p8.cpp +++ b/clang/test/CXX/basic/basic.link/p8.cpp @@ -27,7 +27,7 @@ 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 --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -18,7 +18,7 @@ Check::type *var1; // expected-error {{undeclared identifier 'var1'}} Check::type *var2; // ok, variable declaration expected-note 0+{{here}} Check::type *var3; // expected-error {{undeclared identifier 'var3'}} - Check::type *var4; // expected-error {{undeclared identifier 'var4'}} + Check::type *var4; // expected-error {{undeclared identifier 'var4'}} // value-dependent because of the implied type-dependent 'this->', not because of 'd' Check::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 --- a/clang/test/CXX/drs/dr20xx.cpp +++ b/clang/test/CXX/drs/dr20xx.cpp @@ -221,7 +221,7 @@ 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}} diff --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp --- a/clang/test/CXX/drs/dr7xx.cpp +++ b/clang/test/CXX/drs/dr7xx.cpp @@ -26,12 +26,12 @@ 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 --- 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 @@ template requires (T{}) // expected-error{{atomic constraint must be of type 'bool' (found 'int')}} struct B {}; - static_assert((B{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B' required here}} + static_assert(((void)B{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B' required here}} // expected-note@-1{{while checking constraint satisfaction for class template partial specialization 'B' required here}} // expected-note@-2{{during template argument deduction for class template partial specialization 'B' [with T = int *]}} // expected-note@-3{{during template argument deduction for class template partial specialization 'B' [with T = int]}} diff --git a/clang/test/CodeCompletion/pragma-macro-token-caching.c b/clang/test/CodeCompletion/pragma-macro-token-caching.c --- a/clang/test/CodeCompletion/pragma-macro-token-caching.c +++ b/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 diff --git a/clang/test/Frontend/fixed_point_crash.c b/clang/test/Frontend/fixed_point_crash.c --- a/clang/test/Frontend/fixed_point_crash.c +++ b/clang/test/Frontend/fixed_point_crash.c @@ -14,7 +14,7 @@ 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 --- a/clang/test/PCH/cxx-explicit-specifier.cpp +++ b/clang/test/PCH/cxx-explicit-specifier.cpp @@ -12,7 +12,7 @@ template struct T { template - explicit((Y{}, true)) T(A &&a) {} + explicit(((void)Y{}, true)) T(A &&a) {} }; template struct U : T { @@ -28,7 +28,7 @@ U 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 --- a/clang/test/Parser/cxx-ambig-decl-expr.cpp +++ b/clang/test/Parser/cxx-ambig-decl-expr.cpp @@ -24,7 +24,7 @@ // 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 @@ 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 --- a/clang/test/Parser/cxx0x-ambig.cpp +++ b/clang/test/Parser/cxx0x-ambig.cpp @@ -163,7 +163,7 @@ (void)p1; UnsignedTmplArgSink *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' requested here}} diff --git a/clang/test/Parser/cxx1z-init-statement.cpp b/clang/test/Parser/cxx1z-init-statement.cpp --- a/clang/test/Parser/cxx1z-init-statement.cpp +++ b/clang/test/Parser/cxx1z-init-statement.cpp @@ -14,8 +14,8 @@ // 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 @@ // 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 --- a/clang/test/Parser/objc-messaging-1.m +++ b/clang/test/Parser/objc-messaging-1.m @@ -7,20 +7,20 @@ [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 --- a/clang/test/Parser/objc-try-catch-1.m +++ b/clang/test/Parser/objc-try-catch-1.m @@ -28,14 +28,13 @@ } @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 --- a/clang/test/Parser/objcxx11-attributes.mm +++ b/clang/test/Parser/objcxx11-attributes.mm @@ -22,7 +22,7 @@ // 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 --- a/clang/test/Sema/const-eval.c +++ b/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 diff --git a/clang/test/Sema/exprs.c b/clang/test/Sema/exprs.c --- 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 --- a/clang/test/Sema/i-c-e.c +++ b/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 {{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 --- a/clang/test/Sema/sizeless-1.c +++ b/clang/test/Sema/sizeless-1.c @@ -76,9 +76,9 @@ (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 --- a/clang/test/Sema/switch-1.c +++ b/clang/test/Sema/switch-1.c @@ -50,7 +50,7 @@ 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 --- a/clang/test/Sema/vla-2.c +++ b/clang/test/Sema/vla-2.c @@ -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}} } diff --git a/clang/test/Sema/warn-type-safety.c b/clang/test/Sema/warn-type-safety.c --- a/clang/test/Sema/warn-type-safety.c +++ b/clang/test/Sema/warn-type-safety.c @@ -145,7 +145,7 @@ 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 --- a/clang/test/Sema/warn-unused-value.c +++ b/clang/test/Sema/warn-unused-value.c @@ -9,31 +9,31 @@ // 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 @@ 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 --- a/clang/test/SemaCXX/attr-annotate.cpp +++ b/clang/test/SemaCXX/attr-annotate.cpp @@ -42,7 +42,7 @@ template 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 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() {} }; }; diff --git a/clang/test/SemaCXX/builtin-constant-p.cpp b/clang/test/SemaCXX/builtin-constant-p.cpp --- a/clang/test/SemaCXX/builtin-constant-p.cpp +++ b/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 diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/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 { diff --git a/clang/test/SemaCXX/constant-expression.cpp b/clang/test/SemaCXX/constant-expression.cpp --- a/clang/test/SemaCXX/constant-expression.cpp +++ b/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 {{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 --- a/clang/test/SemaCXX/expression-traits.cpp +++ b/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 diff --git a/clang/test/SemaCXX/matrix-type-operators.cpp b/clang/test/SemaCXX/matrix-type-operators.cpp --- a/clang/test/SemaCXX/matrix-type-operators.cpp +++ b/clang/test/SemaCXX/matrix-type-operators.cpp @@ -179,12 +179,12 @@ 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) { diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -157,7 +157,7 @@ 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 --- a/clang/test/SemaCXX/sizeless-1.cpp +++ b/clang/test/SemaCXX/sizeless-1.cpp @@ -85,9 +85,9 @@ (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 --- a/clang/test/SemaCXX/vector.cpp +++ b/clang/test/SemaCXX/vector.cpp @@ -381,8 +381,8 @@ 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; diff --git a/clang/test/SemaCXX/warn-comma-operator.cpp b/clang/test/SemaCXX/warn-comma-operator.cpp --- a/clang/test/SemaCXX/warn-comma-operator.cpp +++ b/clang/test/SemaCXX/warn-comma-operator.cpp @@ -242,8 +242,8 @@ template 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 seq; }; diff --git a/clang/test/SemaCXX/warn-unused-value.cpp b/clang/test/SemaCXX/warn-unused-value.cpp --- 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)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 diagnoses should be suppressed in SFINAE context. +template int c(int) { return 0; } +template int c(double) { return 1; } +int foo() { return c(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 --- a/clang/test/SemaTemplate/derived.cpp +++ b/clang/test/SemaTemplate/derived.cpp @@ -49,6 +49,6 @@ 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 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -18,7 +18,7 @@ namespace PR41576 { template 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}}