forked from OSchip/llvm-project
Diagnose -Wunused-value based on CFG reachability
(This relands 59337263ab
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
This commit is contained in:
parent
74a47e54be
commit
27a972a699
|
@ -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>;
|
||||
|
|
|
@ -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<const Stmt *> Stmts,
|
||||
const PartialDiagnostic &PD);
|
||||
|
||||
/// Conditionally issue a diagnostic based on the current
|
||||
/// evaluation context.
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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({});
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace class_templates
|
|||
template<typename T> requires (T{}) // expected-error{{atomic constraint must be of type 'bool' (found 'int')}}
|
||||
struct B<T**> {};
|
||||
|
||||
static_assert((B<int**>{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B<int *>' required here}}
|
||||
static_assert(((void)B<int**>{}, true)); // expected-note{{while checking constraint satisfaction for class template partial specialization 'B<int *>' required here}}
|
||||
// expected-note@-1{{while checking constraint satisfaction for class template partial specialization 'B<int>' required here}}
|
||||
// expected-note@-2{{during template argument deduction for class template partial specialization 'B<T *>' [with T = int *]}}
|
||||
// expected-note@-3{{during template argument deduction for class template partial specialization 'B<T **>' [with T = int]}}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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}}
|
||||
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace test0 {
|
|||
|
||||
template<typename T>
|
||||
struct B {
|
||||
[[clang::annotate("test", (T{}, 9))]] void t() {}
|
||||
[[clang::annotate("test", ((void)T{}, 9))]] void t() {}
|
||||
// expected-error@-1 {{illegal initializer type 'void'}}
|
||||
};
|
||||
B<int> b;
|
||||
|
@ -73,7 +73,7 @@ struct B {
|
|||
[[clang::annotate("jui", b, cf)]] void t2() {}
|
||||
// expected-error@-1 {{'annotate' attribute requires parameter 1 to be a constant expression}}
|
||||
// expected-note@-2 {{is not allowed in a constant expression}}
|
||||
[[clang::annotate("jui", (b, 0), cf)]] [[clang::annotate("jui", &b, cf, &foo::t2, str())]] void t3() {}
|
||||
[[clang::annotate("jui", ((void)b, 0), cf)]] [[clang::annotate("jui", &b, cf, &foo::t2, str())]] void t3() {}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}}
|
||||
;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue