Implement -Wunused-value.
authorChristoph Mallon <christoph.mallon@gmx.de>
Thu, 13 Dec 2007 21:51:13 +0000 (21:51 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Thu, 13 Dec 2007 21:51:13 +0000 (21:51 +0000)
[r18732]

parser.c
warning.c
warning.h

index 051337a..efccdcd 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -4408,8 +4408,114 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        expression->expression.datatype = orig_type_left;
 }
 
+static bool expression_has_effect(const expression_t *const expr)
+{
+       switch (expr->kind) {
+               case EXPR_UNKNOWN:                   break;
+               case EXPR_INVALID:                   break;
+               case EXPR_REFERENCE:                 return false;
+               case EXPR_CONST:                     return false;
+               case EXPR_STRING_LITERAL:            return false;
+               case EXPR_WIDE_STRING_LITERAL:       return false;
+               case EXPR_CALL: {
+                       const call_expression_t *const call = &expr->call;
+                       if (call->function->kind == EXPR_BUILTIN_SYMBOL) {
+                               switch (call->function->builtin_symbol.symbol->ID) {
+                                       case T___builtin_va_end: return true;
+                                       default:                 return false;
+                               }
+                       }
+               }
+               case EXPR_CONDITIONAL: {
+                       const conditional_expression_t *const cond = &expr->conditional;
+                       return
+                               expression_has_effect(cond->true_expression) &&
+                               expression_has_effect(cond->false_expression);
+               }
+               case EXPR_SELECT:                    return false;
+               case EXPR_ARRAY_ACCESS:              return false;
+               case EXPR_SIZEOF:                    return false;
+               case EXPR_CLASSIFY_TYPE:             return false;
+               case EXPR_ALIGNOF:                   return false;
+
+               case EXPR_FUNCTION:                  return false;
+               case EXPR_PRETTY_FUNCTION:           return false;
+               case EXPR_BUILTIN_SYMBOL:            break; /* handled in EXPR_CALL */
+               case EXPR_BUILTIN_CONSTANT_P:        return false;
+               case EXPR_BUILTIN_PREFETCH:          return true;
+               case EXPR_OFFSETOF:                  return false;
+               case EXPR_VA_START:                  return true;
+               case EXPR_VA_ARG:                    return true;
+               case EXPR_STATEMENT:                 return true; // TODO
+
+               case EXPR_UNARY_NEGATE:              return false;
+               case EXPR_UNARY_PLUS:                return false;
+               case EXPR_UNARY_BITWISE_NEGATE:      return false;
+               case EXPR_UNARY_NOT:                 return false;
+               case EXPR_UNARY_DEREFERENCE:         return false;
+               case EXPR_UNARY_TAKE_ADDRESS:        return false;
+               case EXPR_UNARY_POSTFIX_INCREMENT:   return true;
+               case EXPR_UNARY_POSTFIX_DECREMENT:   return true;
+               case EXPR_UNARY_PREFIX_INCREMENT:    return true;
+               case EXPR_UNARY_PREFIX_DECREMENT:    return true;
+               case EXPR_UNARY_CAST:
+                       return is_type_atomic(expr->base.datatype, ATOMIC_TYPE_VOID);
+               case EXPR_UNARY_CAST_IMPLICIT:       return true;
+               case EXPR_UNARY_ASSUME:              return true;
+               case EXPR_UNARY_BITFIELD_EXTRACT:    return false;
+
+               case EXPR_BINARY_ADD:                return false;
+               case EXPR_BINARY_SUB:                return false;
+               case EXPR_BINARY_MUL:                return false;
+               case EXPR_BINARY_DIV:                return false;
+               case EXPR_BINARY_MOD:                return false;
+               case EXPR_BINARY_EQUAL:              return false;
+               case EXPR_BINARY_NOTEQUAL:           return false;
+               case EXPR_BINARY_LESS:               return false;
+               case EXPR_BINARY_LESSEQUAL:          return false;
+               case EXPR_BINARY_GREATER:            return false;
+               case EXPR_BINARY_GREATEREQUAL:       return false;
+               case EXPR_BINARY_BITWISE_AND:        return false;
+               case EXPR_BINARY_BITWISE_OR:         return false;
+               case EXPR_BINARY_BITWISE_XOR:        return false;
+               case EXPR_BINARY_LOGICAL_AND:        return false;
+               case EXPR_BINARY_LOGICAL_OR:         return false;
+               case EXPR_BINARY_SHIFTLEFT:          return false;
+               case EXPR_BINARY_SHIFTRIGHT:         return false;
+               case EXPR_BINARY_ASSIGN:             return true;
+               case EXPR_BINARY_MUL_ASSIGN:         return true;
+               case EXPR_BINARY_DIV_ASSIGN:         return true;
+               case EXPR_BINARY_MOD_ASSIGN:         return true;
+               case EXPR_BINARY_ADD_ASSIGN:         return true;
+               case EXPR_BINARY_SUB_ASSIGN:         return true;
+               case EXPR_BINARY_SHIFTLEFT_ASSIGN:   return true;
+               case EXPR_BINARY_SHIFTRIGHT_ASSIGN:  return true;
+               case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
+               case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
+               case EXPR_BINARY_BITWISE_OR_ASSIGN:  return true;
+               case EXPR_BINARY_COMMA:
+                       return expression_has_effect(expr->binary.right);
+
+               case EXPR_BINARY_BUILTIN_EXPECT:     return true;
+               case EXPR_BINARY_ISGREATER:          return false;
+               case EXPR_BINARY_ISGREATEREQUAL:     return false;
+               case EXPR_BINARY_ISLESS:             return false;
+               case EXPR_BINARY_ISLESSEQUAL:        return false;
+               case EXPR_BINARY_ISLESSGREATER:      return false;
+               case EXPR_BINARY_ISUNORDERED:        return false;
+       }
+
+       panic("unexpected statement");
+}
+
 static void semantic_comma(binary_expression_t *expression)
 {
+       if (warning.unused_value) {
+               const expression_t *const left = expression->left;
+               if (!expression_has_effect(left)) {
+                       warningf(left->base.source_position, "left-hand operand of comma expression has no effect");
+               }
+       }
        expression->expression.datatype = expression->right->base.datatype;
 }
 
@@ -5258,7 +5364,12 @@ static statement_t *parse_expression_statement(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_EXPRESSION);
 
        statement->base.source_position  = token.source_position;
-       statement->expression.expression = parse_expression();
+       expression_t *const expr         = parse_expression();
+       statement->expression.expression = expr;
+
+       if (warning.unused_value  && !expression_has_effect(expr)) {
+               warningf(expr->base.source_position, "statement has no effect");
+       }
 
        expect(';');
 
index 98a4cf5..d914ae9 100644 (file)
--- a/warning.c
+++ b/warning.c
@@ -39,7 +39,10 @@ void set_warning_opt(const char *const opt)
                SET(unused_value)
        }
 #endif
+       OPT("unused-value",                  unused_value)
 #undef OPT
+#undef SET
+#undef OPT_X
        else {
                fprintf(stderr, "warning: ignoring unknown option -W%s\n", opt);
        }
@@ -52,5 +55,6 @@ warning_t warning = {
        .implicit_int                  = true,
        .missing_declarations          = true,
        .strict_prototypes             = true,
-       .redundant_decls               = true
+       .redundant_decls               = true,
+       .unused_value                  = true
 };
index ca72709..df36717 100644 (file)
--- a/warning.h
+++ b/warning.h
@@ -69,7 +69,9 @@ typedef struct warning_t {
        bool unused_label:1;                  /* Warn whenever a label is declared but not used */
        bool unused_parameter:1;              /* Warn whenever a function parameter is unused aside from its declaration */
        bool unused_variable:1;               /* Warn whenever a local variable or non-constant static variable is unused aside from its declaration */
+#endif
        bool unused_value:1;                  /* Warn whenever a statement computes a result that is explicitly not used */
+#if 0 // TODO
        bool write_strings:1;                 /* Give string constants the type 'const char[LENGTH]' so that copying the address of one into a 'char *' pointer will get a warning */
 #endif
 } warning_t;