case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_INT:
atomic_type = ATOMIC_TYPE_ULONG;
break;
+
case SPECIFIER_LONG | SPECIFIER_LONG_LONG:
case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG:
case SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT:
case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG
| SPECIFIER_INT:
atomic_type = ATOMIC_TYPE_LONGLONG;
- break;
+ goto warn_about_long_long;
+
case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG:
case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG
| SPECIFIER_INT:
atomic_type = ATOMIC_TYPE_ULONGLONG;
+warn_about_long_long:
+ if (warning.long_long) {
+ warningf(&specifiers->source_position,
+ "ISO C90 does not support 'long long'");
+ }
break;
case SPECIFIER_UNSIGNED | SPECIFIER_INT8:
construct_type_t *last = NULL;
gnu_attribute_t *attributes = NULL;
- declaration->modifiers |= parse_attributes(&attributes);
+ decl_modifiers_t modifiers = parse_attributes(&attributes);
/* pointers */
while (token.type == '*') {
}
/* TODO: find out if this is correct */
- declaration->modifiers |= parse_attributes(&attributes);
+ modifiers |= parse_attributes(&attributes);
}
+ if (declaration != NULL)
+ declaration->modifiers |= modifiers;
+
construct_type_t *inner_types = NULL;
switch(token.type) {
-1;
}
+static bool noreturn_candidate;
+
static void check_reachable(statement_t *const stmt)
{
if (stmt->base.reachable)
break;
case STATEMENT_RETURN:
+ noreturn_candidate = false;
return;
case STATEMENT_IF: {
case STATEMENT_WHILE:
case STATEMENT_DO_WHILE:
case STATEMENT_FOR:
+ last = parent;
next = parent->base.next;
goto found_break_parent;
while (next == NULL) {
next = last->base.parent;
if (next == NULL) {
+ noreturn_candidate = false;
+
type_t *const type = current_function->type;
assert(is_type_function(type));
type_t *const ret = skip_typeref(type->function.return_type);
stmt->kind != STATEMENT_COMPOUND &&
stmt->kind != STATEMENT_DO_WHILE &&
stmt->kind != STATEMENT_FOR) {
- warningf(&stmt->base.source_position,
- "statement is unreachable");
+ warningf(&stmt->base.source_position, "statement is unreachable");
}
switch (stmt->kind) {
case STATEMENT_FOR: {
for_statement_t const* const fors = &stmt->fors;
- if (!stmt->base.reachable && fors->initialisation != NULL) {
- warningf(&fors->initialisation->base.source_position,
- "initialisation of for-statement is unreachable");
- }
+ // if init and step are unreachable, cond is unreachable, too
+ if (!stmt->base.reachable && !fors->step_reachable) {
+ warningf(&stmt->base.source_position, "statement is unreachable");
+ } else {
+ if (!stmt->base.reachable && fors->initialisation != NULL) {
+ warningf(&fors->initialisation->base.source_position,
+ "initialisation of for-statement is unreachable");
+ }
- if (!fors->condition_reachable && fors->condition != NULL) {
- warningf(&fors->condition->base.source_position,
- "condition of for-statement is unreachable");
- }
+ if (!fors->condition_reachable && fors->condition != NULL) {
+ warningf(&fors->condition->base.source_position,
+ "condition of for-statement is unreachable");
+ }
- if (!fors->step_reachable && fors->step != NULL) {
- warningf(&fors->step->base.source_position,
- "step of for-statement is unreachable");
+ if (!fors->step_reachable && fors->step != NULL) {
+ warningf(&fors->step->base.source_position,
+ "step of for-statement is unreachable");
+ }
}
check_unreachable(stmt->fors.body);
first_err = true;
check_labels();
check_declarations();
- if (warning.return_type || warning.unreachable_code) {
+ if (warning.return_type ||
+ warning.unreachable_code ||
+ (warning.missing_noreturn && !(declaration->modifiers & DM_NORETURN))) {
+ noreturn_candidate = true;
check_reachable(body);
if (warning.unreachable_code)
check_unreachable(body);
+ if (warning.missing_noreturn &&
+ noreturn_candidate &&
+ !(declaration->modifiers & DM_NORETURN)) {
+ warningf(&body->base.source_position,
+ "function '%#T' is candidate for attribute 'noreturn'",
+ type, declaration->symbol);
+ }
}
assert(current_parent == NULL);
expression->base.type = orig_type;
}
-static void semantic_unexpr_scalar(unary_expression_t *expression)
+static void semantic_not(unary_expression_t *expression)
{
type_t *const orig_type = expression->value->base.type;
type_t *const type = skip_typeref(orig_type);
return;
}
- expression->base.type = orig_type;
+ expression->base.type = type_int;
}
static void semantic_unexpr_integer(unary_expression_t *expression)
CREATE_UNARY_EXPRESSION_PARSER('+', EXPR_UNARY_PLUS,
semantic_unexpr_arithmetic)
CREATE_UNARY_EXPRESSION_PARSER('!', EXPR_UNARY_NOT,
- semantic_unexpr_scalar)
+ semantic_not)
CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE,
semantic_dereference)
CREATE_UNARY_EXPRESSION_PARSER('&', EXPR_UNARY_TAKE_ADDRESS,
if (e == NULL || !is_constant_expression(e) || fold_constant(e) != val)
continue;
- errorf(pos, "duplicate case value");
- errorf(&l->base.source_position, "previously used here");
+ errorf(pos, "duplicate case value (previously used %P)",
+ &l->base.source_position);
break;
}