From 27a972a699cd875c7fa9114dc0888015cd724f31 Mon Sep 17 00:00:00 2001 From: Yuanfang Chen Date: Wed, 23 Jun 2021 23:46:42 -0700 Subject: [PATCH] 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 --- .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/include/clang/Sema/Sema.h | 12 +++- clang/lib/Sema/SemaExpr.cpp | 58 +++++++++++-------- clang/lib/Sema/SemaExprCXX.cpp | 2 +- clang/lib/Sema/SemaStmt.cpp | 14 +++-- clang/test/Analysis/dead-stores.c | 4 +- clang/test/CXX/basic/basic.link/p8.cpp | 2 +- clang/test/CXX/drs/dr14xx.cpp | 2 +- clang/test/CXX/drs/dr20xx.cpp | 2 +- clang/test/CXX/drs/dr7xx.cpp | 4 +- .../partial-specializations.cpp | 2 +- .../pragma-macro-token-caching.c | 2 +- clang/test/Frontend/fixed_point_crash.c | 4 +- clang/test/PCH/cxx-explicit-specifier.cpp | 4 +- clang/test/Parser/cxx-ambig-decl-expr.cpp | 6 +- clang/test/Parser/cxx0x-ambig.cpp | 2 +- clang/test/Parser/cxx1z-init-statement.cpp | 8 +-- clang/test/Parser/objc-messaging-1.m | 14 ++--- clang/test/Parser/objc-try-catch-1.m | 5 +- clang/test/Parser/objcxx11-attributes.mm | 2 +- clang/test/Sema/const-eval.c | 2 +- clang/test/Sema/exprs.c | 2 +- clang/test/Sema/i-c-e.c | 10 ++-- clang/test/Sema/sizeless-1.c | 4 +- clang/test/Sema/switch-1.c | 2 +- clang/test/Sema/vla-2.c | 6 +- clang/test/Sema/warn-type-safety.c | 2 +- clang/test/Sema/warn-unused-value.c | 20 +++---- clang/test/SemaCXX/attr-annotate.cpp | 4 +- clang/test/SemaCXX/builtin-constant-p.cpp | 4 +- .../SemaCXX/constant-expression-cxx2a.cpp | 2 +- clang/test/SemaCXX/constant-expression.cpp | 4 +- clang/test/SemaCXX/expression-traits.cpp | 8 +-- clang/test/SemaCXX/matrix-type-operators.cpp | 6 +- clang/test/SemaCXX/overloaded-operator.cpp | 2 +- clang/test/SemaCXX/sizeless-1.cpp | 4 +- clang/test/SemaCXX/vector.cpp | 4 +- clang/test/SemaCXX/warn-comma-operator.cpp | 4 +- clang/test/SemaCXX/warn-unused-value.cpp | 30 ++++++++++ clang/test/SemaTemplate/derived.cpp | 2 +- .../test/SemaTemplate/lambda-capture-pack.cpp | 2 +- 41 files changed, 168 insertions(+), 108 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 07c5e8591371..00b6acf8bbe6 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; +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 index d35f5c520a94..bd5cf1218371 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4908,7 +4908,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); @@ -5114,6 +5114,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 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 8eee366fbec6..8d483f317a42 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 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 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef 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( - 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 f4a27a00a2e2..07d27aaf7bdc 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 98e6275bfda0..7182790ae9bb 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(S)) - return DiagnoseUnusedExprResult(Label->getSubStmt()); + return DiagnoseUnusedExprResult(Label->getSubStmt(), DiagID); const Expr *E = dyn_cast_or_null(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(E)) E = Temps->getSubExpr(); if (const CXXBindTemporaryExpr *TempExpr = dyn_cast(E)) @@ -339,7 +338,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { 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,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 145b81bd0332..2ce94eb31b19 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@-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 index 54b977d77f68..e348562c2eee 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 70bf1ea70e38..4d64943e9eea 100644 --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -18,7 +18,7 @@ namespace dr1413 { // dr1413: 12 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 index 9a0c772973ec..aef14dd22259 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@-6 {{enclosing function}} // expected-error@-6 {{enclosing function}} diff --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp index 147560d3037b..2b72425f705c 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 4372aab591eb..7d5c8c40da05 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 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 index 59b6621b56ad..432706e85ceb 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 12dc1944f018..869b7ee9355a 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 331c2e84c781..94ca9f7b080d 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 struct T { template - explicit((Y{}, true)) T(A &&a) {} + explicit(((void)Y{}, true)) T(A &&a) {} }; template struct U : T { @@ -28,7 +28,7 @@ namespace inheriting_constructor { 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 index 6203db2fbd22..fef3783ad32b 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 2dd53dd6daab..7f3398ad1386 100644 --- a/clang/test/Parser/cxx0x-ambig.cpp +++ b/clang/test/Parser/cxx0x-ambig.cpp @@ -163,7 +163,7 @@ namespace ellipsis { (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 index ade60dc762d5..157e2b5f2ee5 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 82450df9f2c3..6c0b78d63b87 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 3a60148c8be9..102d782f58e5 100644 --- a/clang/test/Parser/objc-try-catch-1.m +++ b/clang/test/Parser/objc-try-catch-1.m @@ -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}} } } diff --git a/clang/test/Parser/objcxx11-attributes.mm b/clang/test/Parser/objcxx11-attributes.mm index 4bff2151a9c6..3c14d03cb28b 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 427b0566820a..bbba474748bc 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 4e144041acae..c194d9c50bd4 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 63416454f5a4..c7991155b142 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 a8c08731d53e..ad999052b0ee 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 144c3607f570..163af4f72842 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 819cab91afc5..316931f27060 100644 --- 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 index da914730d3aa..13e61147a38c 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 edf791593a42..14a4dc1b46ee 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 b4da500f36e3..ef0215fb9a3b 100644 --- a/clang/test/SemaCXX/attr-annotate.cpp +++ b/clang/test/SemaCXX/attr-annotate.cpp @@ -42,7 +42,7 @@ namespace test0 { 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 @@ 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() {} }; }; diff --git a/clang/test/SemaCXX/builtin-constant-p.cpp b/clang/test/SemaCXX/builtin-constant-p.cpp index 1b8cf455ef27..71c38c5c63c7 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 86020a09db44..caba03347669 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 a5e571a97eb2..56417b6a2e52 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 d965d14747ae..a76f0c4a6175 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 52aa0bad3459..4e2b0f9315e6 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@-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 index dff9350cc984..e3ec42ab9692 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 cf92dffbd170..ee3ef51435d5 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 9608be576fab..f9a9224e9a60 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 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 index 0ed127b943f3..76cd49ed42bf 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 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 index 02bceeca1337..d96468406915 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 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 index bad72b5d6766..d95e577fb21c 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 8b8a55ccd778..35b2ffcefea3 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 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}}