.\" Please adjust this date whenever revising the manpage.
-.Dd November 29, 2008
+.Dd December 7, 2008
.Dt CPARSER 1
.Sh NAME
.Nm cparser
.Fl Winit-self ,
.Fl Wmain ,
.Fl Wnonnull ,
+.Fl Wparentheses ,
.Fl Wpointer-arith ,
.Fl Wredundant-decls ,
.Fl Wreturn-type ,
Warn if a multicharacter constant ('FOOF') is used.
.It Fl Wnested-externs
Warn if an 'extern' declaration is encountered within a function.
+.It Fl Wparentheses
+Warn if parentheses are omitted in certain contexts.
+Warn if an assignment is used as condition, e.g. if\ (x\ =\ 23).
+Warn if && without parentheses is used within ||, e.g. if\ (x\ ||\ y\ &&\ z).
+Warn if it there may be confusion which 'if'-statement an 'else'-branch belongs to, e.g. if\ (x)\ if\ (y)\ {}\ else\ {}.
+Warn if cascaded comparisons appear which do not have their mathematical meaning, e.g. if\ (23\ <=\ x\ <\ 42).
.It Fl Wredundant-decls
Warn about redundant declarations, i.e. multiple declarations of the same object or static forward declarations which have no use before their definition.
.It Fl Wunreachable-code
.Fl Wunused-value ,
.Fl Wunused-variable .
.It Fl Wunused-parameter
-Warn when a parameter is never used or only ever read to calculate its own new value, e.g. x = x + 1.
+Warn when a parameter is never used or only ever read to calculate its own new value, e.g. x\ =\ x\ +\ 1.
.It Fl Wunused-variable
-Warn when a variable is never used or only ever read to calculate its own new value, e.g. x = x + 1.
+Warn when a variable is never used or only ever read to calculate its own new value, e.g. x\ =\ x\ +\ 1.
.It Fl w
Suppress all warnings.
.It Fl I Ar dir
add_anchor_token(')');
expression_t *result = parse_expression();
+ result->base.parenthesized = true;
rem_anchor_token(')');
expect(')', end_error);
}
}
+static void warn_assignment_in_condition(const expression_t *const expr)
+{
+ if (!warning.parentheses)
+ return;
+ if (expr->base.kind != EXPR_BINARY_ASSIGN)
+ return;
+ if (expr->base.parenthesized)
+ return;
+ warningf(&expr->base.source_position,
+ "suggest parentheses around assignment used as truth value");
+}
+
static void semantic_condition(expression_t const *const expr,
char const *const context)
{
type_t *const type = skip_typeref(expr->base.type);
if (is_type_scalar(type)) {
warn_reference_address_as_bool(expr);
+ warn_assignment_in_condition(expr);
} else if (is_type_valid(type)) {
errorf(&expr->base.source_position,
"%s must have scalar type", context);
}
}
+static void warn_comparison_in_comparison(const expression_t *const expr)
+{
+ if (expr->base.parenthesized)
+ return;
+ switch (expr->base.kind) {
+ case EXPR_BINARY_LESS:
+ case EXPR_BINARY_GREATER:
+ case EXPR_BINARY_LESSEQUAL:
+ case EXPR_BINARY_GREATEREQUAL:
+ case EXPR_BINARY_NOTEQUAL:
+ case EXPR_BINARY_EQUAL:
+ warningf(&expr->base.source_position,
+ "comparisons like 'x <= y < z' do not have their mathematical meaning");
+ break;
+ default:
+ break;
+ }
+}
+
/**
* Check the semantics of comparison expressions.
*
}
}
+ if (warning.parentheses) {
+ warn_comparison_in_comparison(left);
+ warn_comparison_in_comparison(right);
+ }
+
type_t *orig_type_left = left->base.type;
type_t *orig_type_right = right->base.type;
type_t *type_left = skip_typeref(orig_type_left);
}
}
+static void warn_logical_and_within_or(const expression_t *const expr)
+{
+ if (expr->base.kind != EXPR_BINARY_LOGICAL_AND)
+ return;
+ if (expr->base.parenthesized)
+ return;
+ warningf(&expr->base.source_position,
+ "suggest parentheses around && within ||");
+}
+
/**
* Check the semantic restrictions of a logical expression.
*/
* ยง6.5.14:2 Each of the operands shall have scalar type. */
semantic_condition(expression->left, "left operand of logical operator");
semantic_condition(expression->right, "right operand of logical operator");
+ if (expression->base.kind == EXPR_BINARY_LOGICAL_OR &&
+ warning.parentheses) {
+ warn_logical_and_within_or(expression->left);
+ warn_logical_and_within_or(expression->right);
+ }
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
rem_anchor_token('{');
add_anchor_token(T_else);
- statement->ifs.true_statement = parse_statement();
+ statement_t *const true_stmt = parse_statement();
+ statement->ifs.true_statement = true_stmt;
rem_anchor_token(T_else);
if (token.type == T_else) {
next_token();
statement->ifs.false_statement = parse_statement();
+ } else if (warning.parentheses &&
+ true_stmt->kind == STATEMENT_IF &&
+ true_stmt->ifs.false_statement != NULL) {
+ warningf(&true_stmt->base.source_position,
+ "suggest explicit braces to avoid ambiguous 'else'");
}
POP_PARENT;