forked from OSchip/llvm-project
First cut at warning about expressions whose results are ignored. For example,
this produces: warn.c:4:3: warning: expression result unused X == Y; ^~~~~~ warn.c:5:3: warning: expression result unused (void)X; ^~~~~~~ warn.c:11:3: warning: expression result unused A == foo(1, 2); ^~~~~~~~~~~~~~ warn.c:13:3: warning: expression result unused foo(1,2)+foo(4,3); ^~~~~~~~~~~~~~~~~ llvm-svn: 39682
This commit is contained in:
parent
eb2def66be
commit
1ec5f563c7
|
@ -122,6 +122,61 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Generic Expression Routines
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// hasLocalSideEffect - Return true if this immediate expression has side
|
||||
/// effects, not counting any sub-expressions.
|
||||
bool Expr::hasLocalSideEffect() const {
|
||||
switch (getStmtClass()) {
|
||||
default:
|
||||
return false;
|
||||
case ParenExprClass:
|
||||
return cast<ParenExpr>(this)->getSubExpr()->hasLocalSideEffect();
|
||||
case UnaryOperatorClass: {
|
||||
const UnaryOperator *UO = cast<UnaryOperator>(this);
|
||||
|
||||
switch (UO->getOpcode()) {
|
||||
default: return false;
|
||||
case UnaryOperator::PostInc:
|
||||
case UnaryOperator::PostDec:
|
||||
case UnaryOperator::PreInc:
|
||||
case UnaryOperator::PreDec:
|
||||
return true; // ++/--
|
||||
|
||||
// FIXME: real/imag volatile
|
||||
// deref volatile;
|
||||
|
||||
case UnaryOperator::Extension:
|
||||
return UO->getSubExpr()->hasLocalSideEffect();
|
||||
}
|
||||
}
|
||||
case BinaryOperatorClass:
|
||||
return cast<BinaryOperator>(this)->isAssignmentOp();
|
||||
|
||||
case ArraySubscriptExprClass:
|
||||
// volatile
|
||||
return false;
|
||||
|
||||
case CallExprClass:
|
||||
// TODO: check attributes for pure/const.
|
||||
return true;
|
||||
|
||||
case MemberExprClass:
|
||||
// volatile load.
|
||||
return false;
|
||||
|
||||
case CastExprClass:
|
||||
// If this is a cast to void, check the operand. Otherwise, the result of
|
||||
// the cast is unused.
|
||||
if (getType()->isVoidType())
|
||||
return cast<CastExpr>(this)->getSubExpr()->hasLocalSideEffect();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an
|
||||
/// incomplete type other than void. Nonarray expressions that can be lvalues:
|
||||
/// - name, where name must be a variable
|
||||
|
@ -172,10 +227,10 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue() {
|
|||
isLvalueResult lvalResult = isLvalue();
|
||||
|
||||
switch (lvalResult) {
|
||||
case LV_Valid: break;
|
||||
case LV_NotObjectType: return MLV_NotObjectType;
|
||||
case LV_IncompleteVoidType: return MLV_IncompleteVoidType;
|
||||
case LV_InvalidExpression: return MLV_InvalidExpression;
|
||||
case LV_Valid: break;
|
||||
case LV_NotObjectType: return MLV_NotObjectType;
|
||||
case LV_IncompleteVoidType: return MLV_IncompleteVoidType;
|
||||
case LV_InvalidExpression: return MLV_InvalidExpression;
|
||||
}
|
||||
if (TR.isConstQualified())
|
||||
return MLV_ConstQualified;
|
||||
|
|
|
@ -157,6 +157,8 @@ private:
|
|||
//===--------------------------------------------------------------------===//
|
||||
// Statement Parsing Callbacks: SemaStmt.cpp.
|
||||
public:
|
||||
virtual StmtResult ParseExprStmt(ExprTy *Expr);
|
||||
|
||||
virtual StmtResult ParseNullStmt(SourceLocation SemiLoc);
|
||||
virtual StmtResult ParseCompoundStmt(SourceLocation L, SourceLocation R,
|
||||
StmtTy **Elts, unsigned NumElts);
|
||||
|
|
|
@ -20,6 +20,19 @@
|
|||
#include "clang/Lex/IdentifierTable.h"
|
||||
using namespace clang;
|
||||
|
||||
Sema::StmtResult Sema::ParseExprStmt(ExprTy *expr) {
|
||||
Expr *E = static_cast<Expr*>(expr);
|
||||
|
||||
// Exprs are statements, so there is no need to do a conversion here. However,
|
||||
// diagnose some potentially bad code.
|
||||
if (!E->hasLocalSideEffect())
|
||||
Diag(E->getLocStart()/*
|
||||
getExprLoc()*/, diag::warn_unused_expr, E->getSourceRange());
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
|
||||
Sema::StmtResult Sema::ParseNullStmt(SourceLocation SemiLoc) {
|
||||
return new NullStmt(SemiLoc);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ public:
|
|||
SourceLocation getLocStart() const { return getSourceRange().Begin(); }
|
||||
SourceLocation getLocEnd() const { return getSourceRange().End(); }
|
||||
|
||||
/// hasLocalSideEffect - Return true if this immediate expression has side
|
||||
/// effects, not counting any sub-expressions.
|
||||
bool hasLocalSideEffect() const;
|
||||
|
||||
/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or
|
||||
/// incomplete type other than void. Nonarray expressions that can be lvalues:
|
||||
/// - name, where name must be a variable
|
||||
|
@ -114,6 +118,7 @@ public:
|
|||
const Decl *getDecl() const { return D; }
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DeclRefExprClass;
|
||||
|
@ -400,6 +405,7 @@ public:
|
|||
Expr *getBase() const { return Base; }
|
||||
FieldDecl *getMemberDecl() const { return MemberDecl; }
|
||||
bool isArrow() const { return IsArrow; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getBase()->getLocStart(), MemberLoc);
|
||||
}
|
||||
|
@ -426,6 +432,7 @@ public:
|
|||
|
||||
QualType getDestType() const { return Ty; }
|
||||
Expr *getSubExpr() const { return Op; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(Loc, getSubExpr()->getSourceRange().End());
|
||||
}
|
||||
|
@ -484,7 +491,6 @@ public:
|
|||
bool isLogicalOp() const { return Opc == LAnd || Opc == LOr; }
|
||||
bool isAssignmentOp() const { return Opc >= Assign && Opc <= OrAssign; }
|
||||
|
||||
|
||||
virtual void visit(StmtVisitor &Visitor);
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == BinaryOperatorClass;
|
||||
|
|
|
@ -633,6 +633,9 @@ DIAG(err_typecheck_cond_incompatible_operands, ERROR,
|
|||
DIAG(ext_typecheck_cond_incompatible_pointers, EXTENSION,
|
||||
"pointer type mismatch ('%0' and '%1')")
|
||||
|
||||
DIAG(warn_unused_expr, WARNING,
|
||||
"expression result unused")
|
||||
|
||||
// Statements.
|
||||
DIAG(err_continue_not_in_loop, ERROR,
|
||||
"'continue' statement not in loop statement")
|
||||
|
|
Loading…
Reference in New Issue