case T_union: \
case T_unsigned: \
case T_void: \
+ case T_wchar_t: \
COMPLEX_SPECIFIERS \
IMAGINARY_SPECIFIERS
SPECIFIER_INT = 1 << 3,
SPECIFIER_DOUBLE = 1 << 4,
SPECIFIER_CHAR = 1 << 5,
- SPECIFIER_SHORT = 1 << 6,
- SPECIFIER_LONG_LONG = 1 << 7,
- SPECIFIER_FLOAT = 1 << 8,
- SPECIFIER_BOOL = 1 << 9,
- SPECIFIER_VOID = 1 << 10,
- SPECIFIER_INT8 = 1 << 11,
- SPECIFIER_INT16 = 1 << 12,
- SPECIFIER_INT32 = 1 << 13,
- SPECIFIER_INT64 = 1 << 14,
- SPECIFIER_INT128 = 1 << 15,
- SPECIFIER_COMPLEX = 1 << 16,
- SPECIFIER_IMAGINARY = 1 << 17,
+ SPECIFIER_WCHAR_T = 1 << 6,
+ SPECIFIER_SHORT = 1 << 7,
+ SPECIFIER_LONG_LONG = 1 << 8,
+ SPECIFIER_FLOAT = 1 << 9,
+ SPECIFIER_BOOL = 1 << 10,
+ SPECIFIER_VOID = 1 << 11,
+ SPECIFIER_INT8 = 1 << 12,
+ SPECIFIER_INT16 = 1 << 13,
+ SPECIFIER_INT32 = 1 << 14,
+ SPECIFIER_INT64 = 1 << 15,
+ SPECIFIER_INT128 = 1 << 16,
+ SPECIFIER_COMPLEX = 1 << 17,
+ SPECIFIER_IMAGINARY = 1 << 18,
} specifiers_t;
static type_t *create_builtin_type(symbol_t *const symbol,
MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed");
MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned");
MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void");
+ MATCH_SPECIFIER(T_wchar_t, SPECIFIER_WCHAR_T, "wchar_t");
case T__forceinline:
/* only in microsoft mode */
case SPECIFIER_VOID:
atomic_type = ATOMIC_TYPE_VOID;
break;
+ case SPECIFIER_WCHAR_T:
+ atomic_type = ATOMIC_TYPE_WCHAR_T;
+ break;
case SPECIFIER_CHAR:
atomic_type = ATOMIC_TYPE_CHAR;
break;
!is_typedef_symbol(token.v.symbol)) {
token_type_t la1_type = (token_type_t)look_ahead(1)->type;
if (la1_type == ',' || la1_type == ')') {
- type->kr_style_parameters = true;
+ type->kr_style_parameters = true;
+ type->unspecified_parameters = true;
parse_identifier_list(scope);
goto parameters_finished;
}
declaration_statement_t const *const decl = &stmt->declaration;
entity_t const * ent = decl->declarations_begin;
entity_t const *const last = decl->declarations_end;
- for (;; ent = ent->base.next) {
- if (ent->kind == ENTITY_VARIABLE &&
- ent->variable.initializer != NULL) {
- goto warn_unreachable;
+ if (ent != NULL) {
+ for (;; ent = ent->base.next) {
+ if (ent->kind == ENTITY_VARIABLE &&
+ ent->variable.initializer != NULL) {
+ goto warn_unreachable;
+ }
+ if (ent == last)
+ return;
}
- if (ent == last)
- return;
}
}
add_anchor_token(')');
expression_t *result = parse_expression();
+ result->base.parenthesized = true;
rem_anchor_token(')');
expect(')', end_error);
tp_expression->typeprop.type = orig_type;
type_t const* const type = skip_typeref(orig_type);
char const* const wrong_type =
- is_type_incomplete(type) ? "incomplete" :
- type->kind == TYPE_FUNCTION ? "function designator" :
- type->kind == TYPE_BITFIELD ? "bitfield" :
+ GNU_MODE && is_type_atomic(type, ATOMIC_TYPE_VOID) ? NULL :
+ is_type_incomplete(type) ? "incomplete" :
+ type->kind == TYPE_FUNCTION ? "function designator" :
+ type->kind == TYPE_BITFIELD ? "bitfield" :
NULL;
if (wrong_type != NULL) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
}
}
+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);
}
rem_anchor_token(':');
expect(':', end_error);
+end_error:;
expression_t *false_expression =
parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
= create_implicit_cast(false_expression, result_type);
conditional->base.type = result_type;
return result;
-end_error:
- return create_invalid_expression();
}
/**
{
/* TODO: doesn't seem to be consistent with §6.3.2.1 (1) */
switch (expression->kind) {
- case EXPR_REFERENCE:
case EXPR_ARRAY_ACCESS:
+ case EXPR_COMPOUND_LITERAL:
+ case EXPR_REFERENCE:
case EXPR_SELECT:
case EXPR_UNARY_DEREFERENCE:
return true;
}
}
+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;
assert(is_type_function(func_type));
type_t *const return_type = skip_typeref(func_type->function.return_type);
+ source_position_t const *const pos = &statement->base.source_position;
if (return_value != NULL) {
type_t *return_value_type = skip_typeref(return_value->base.type);
- if (is_type_atomic(return_type, ATOMIC_TYPE_VOID) &&
- !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
- if (warning.other) {
- warningf(&statement->base.source_position,
- "'return' with a value, in function returning void");
+ if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
+ if (is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
+ /* ISO/IEC 14882:1998(E) §6.6.3:2 */
+ /* Only warn in C mode, because GCC does the same */
+ if (c_mode & _CXX || strict_mode) {
+ errorf(pos,
+ "'return' with a value, in function returning 'void'");
+ } else if (warning.other) {
+ warningf(pos,
+ "'return' with a value, in function returning 'void'");
+ }
+ } else if (!(c_mode & _CXX)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */
+ /* Only warn in C mode, because GCC does the same */
+ if (strict_mode) {
+ errorf(pos,
+ "'return' with expression in function return 'void'");
+ } else if (warning.other) {
+ warningf(pos,
+ "'return' with expression in function return 'void'");
+ }
}
- return_value = NULL;
} else {
assign_error_t error = semantic_assign(return_type, return_value);
report_assign_error(error, return_type, return_value, "'return'",
- &statement->base.source_position);
- return_value = create_implicit_cast(return_value, return_type);
+ pos);
}
+ return_value = create_implicit_cast(return_value, return_type);
/* check for returning address of a local var */
if (warning.other && return_value != NULL
&& return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
const expression_t *expression = return_value->unary.value;
if (expression_is_local_variable(expression)) {
- warningf(&statement->base.source_position,
- "function returns address of local variable");
+ warningf(pos, "function returns address of local variable");
}
}
} else if (warning.other && !is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
- warningf(&statement->base.source_position,
- "'return' without value, in function returning non-void");
+ /* ISO/IEC 14882:1998(E) §6.6.3:3 */
+ if (c_mode & _CXX || strict_mode) {
+ errorf(pos,
+ "'return' without value, in function returning non-void");
+ } else {
+ warningf(pos,
+ "'return' without value, in function returning non-void");
+ }
}
statement->returns.value = return_value;