Repair semantics of !: Result type is int, not the operand type.
[cparser] / parser.c
index 38dffce..c26ca18 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -3274,17 +3274,24 @@ finish_specifiers:
                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:
@@ -3766,7 +3773,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
        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 == '*') {
@@ -3781,9 +3788,12 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
                }
 
                /* 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) {
@@ -4664,6 +4674,8 @@ static int determine_truth(expression_t const* const cond)
                -1;
 }
 
+static bool noreturn_candidate;
+
 static void check_reachable(statement_t *const stmt)
 {
        if (stmt->base.reachable)
@@ -4686,6 +4698,7 @@ static void check_reachable(statement_t *const stmt)
                        break;
 
                case STATEMENT_RETURN:
+                       noreturn_candidate = false;
                        return;
 
                case STATEMENT_IF: {
@@ -4796,6 +4809,7 @@ static void check_reachable(statement_t *const stmt)
                                        case STATEMENT_WHILE:
                                        case STATEMENT_DO_WHILE:
                                        case STATEMENT_FOR:
+                                               last = parent;
                                                next = parent->base.next;
                                                goto found_break_parent;
 
@@ -4867,6 +4881,8 @@ 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);
@@ -4988,8 +5004,7 @@ static void check_unreachable(statement_t const* const stmt)
            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) {
@@ -5046,19 +5061,24 @@ static void check_unreachable(statement_t const* const stmt)
                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);
@@ -5191,10 +5211,20 @@ static void parse_external_declaration(void)
                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);
@@ -6956,7 +6986,7 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
        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);
@@ -6967,7 +6997,7 @@ static void semantic_unexpr_scalar(unary_expression_t *expression)
                return;
        }
 
-       expression->base.type = orig_type;
+       expression->base.type = type_int;
 }
 
 static void semantic_unexpr_integer(unary_expression_t *expression)
@@ -7056,7 +7086,7 @@ CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE,
 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,
@@ -8128,8 +8158,8 @@ static statement_t *parse_case_statement(void)
                        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;
                }