use ir_tarval to calculate case values
[cparser] / parser.c
index 8639a7a..869cc25 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -28,7 +28,7 @@
 #include "parser.h"
 #include "diagnostic.h"
 #include "format_check.h"
-#include "lexer.h"
+#include "preprocessor.h"
 #include "symbol_t.h"
 #include "token_t.h"
 #include "types.h"
@@ -41,6 +41,7 @@
 #include "walk.h"
 #include "warning.h"
 #include "printer.h"
+#include "ast2firm.h"
 #include "adt/bitfiddle.h"
 #include "adt/error.h"
 #include "adt/array.h"
@@ -60,7 +61,7 @@ struct declaration_specifiers_t {
        storage_class_t    storage_class;
        unsigned char      alignment;         /**< Alignment, 0 if not set. */
        bool               is_inline    : 1;
-       bool               thread_local : 1;  /**< GCC __thread */
+       bool               thread_local : 1;
        attribute_t       *attributes;        /**< list of attributes */
        type_t            *type;
 };
@@ -183,7 +184,7 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_static:          \
        case T_auto:            \
        case T_register:        \
-       case T___thread:
+       case T__Thread_local:
 
 #define TYPE_QUALIFIERS     \
        case T_const:           \
@@ -249,10 +250,10 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_MINUSMINUS:                \
        case T_PLUSPLUS:                  \
        case T_STRING_LITERAL:            \
+       case T__Alignof:                  \
        case T___FUNCDNAME__:             \
        case T___FUNCSIG__:               \
        case T___PRETTY_FUNCTION__:       \
-       case T___alignof__:               \
        case T___builtin_classify_type:   \
        case T___builtin_constant_p:      \
        case T___builtin_isgreater:       \
@@ -296,7 +297,6 @@ static size_t get_statement_struct_size(statement_kind_t kind)
                [STATEMENT_GOTO]          = sizeof(goto_statement_t),
                [STATEMENT_LABEL]         = sizeof(label_statement_t),
                [STATEMENT_CASE_LABEL]    = sizeof(case_label_statement_t),
-               [STATEMENT_WHILE]         = sizeof(while_statement_t),
                [STATEMENT_DO_WHILE]      = sizeof(do_while_statement_t),
                [STATEMENT_FOR]           = sizeof(for_statement_t),
                [STATEMENT_ASM]           = sizeof(asm_statement_t),
@@ -323,6 +323,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_LITERAL_INTEGER]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_FLOATINGPOINT]      = sizeof(literal_expression_t),
                [EXPR_LITERAL_CHARACTER]          = sizeof(string_literal_expression_t),
+               [EXPR_LITERAL_MS_NOOP]            = sizeof(literal_expression_t),
                [EXPR_STRING_LITERAL]             = sizeof(string_literal_expression_t),
                [EXPR_COMPOUND_LITERAL]           = sizeof(compound_literal_expression_t),
                [EXPR_CALL]                       = sizeof(call_expression_t),
@@ -467,8 +468,8 @@ static size_t label_top(void)
 static inline void next_token(void)
 {
        token                              = lookahead_buffer[lookahead_bufpos];
-       lookahead_buffer[lookahead_bufpos] = lexer_token;
-       lexer_next_token();
+       lookahead_buffer[lookahead_bufpos] = pp_token;
+       next_preprocessing_token();
 
        lookahead_bufpos = (lookahead_bufpos + 1) % MAX_LOOKAHEAD;
 
@@ -1176,6 +1177,12 @@ static attribute_t *parse_attribute_gnu_single(void)
        char const *const name = symbol->string;
        for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) {
                if (kind > ATTRIBUTE_GNU_LAST) {
+                       /* special case for "__const" */
+                       if (token.kind == T_const) {
+                               kind = ATTRIBUTE_GNU_CONST;
+                               break;
+                       }
+
                        warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name);
                        /* TODO: we should still save the attribute in the list... */
                        kind = ATTRIBUTE_UNKNOWN;
@@ -1954,6 +1961,8 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                return create_empty_initializer();
        }
 
+       initializer_t *result = NULL;
+
        type_t *orig_type = path->top_type;
        type_t *type      = NULL;
 
@@ -2057,14 +2066,14 @@ finish_designator:
 
                        /* handle { "string" } special case */
                        if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
-                               sub = initializer_from_expression(outer_type, expression);
-                               if (sub != NULL) {
+                               result = initializer_from_expression(outer_type, expression);
+                               if (result != NULL) {
                                        next_if(',');
                                        if (token.kind != '}') {
-                                               warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type);
+                                               warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type);
                                        }
                                        /* TODO: eat , ... */
-                                       return sub;
+                                       goto out;
                                }
                        }
 
@@ -2105,12 +2114,8 @@ finish_designator:
                ARR_APP1(initializer_t*, initializers, sub);
 
 error_parse_next:
-               if (token.kind == '}') {
+               if (!next_if(','))
                        break;
-               }
-               add_anchor_token('}');
-               expect(',');
-               rem_anchor_token('}');
                if (token.kind == '}') {
                        break;
                }
@@ -2128,22 +2133,19 @@ error_parse_next:
 
        size_t len  = ARR_LEN(initializers);
        size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]);
-       initializer_t *result = allocate_ast_zero(size);
-       result->kind          = INITIALIZER_LIST;
-       result->list.len      = len;
+       result = allocate_ast_zero(size);
+       result->kind     = INITIALIZER_LIST;
+       result->list.len = len;
        memcpy(&result->list.initializers, initializers,
               len * sizeof(initializers[0]));
-
-       DEL_ARR_F(initializers);
-       ascend_to(path, top_path_level+1);
-
-       return result;
+       goto out;
 
 end_error:
        skip_initializers();
+out:
        DEL_ARR_F(initializers);
        ascend_to(path, top_path_level+1);
-       return NULL;
+       return result;
 }
 
 static expression_t *make_size_literal(size_t value)
@@ -2307,6 +2309,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if (attributes != NULL) {
+               entity->compound.attributes = attributes;
                handle_entity_attributes(attributes, entity);
        }
 
@@ -2655,9 +2658,9 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                                = parse_microsoft_extended_decl_modifier(specifiers->attributes);
                        break;
 
-               case T___thread:
+               case T__Thread_local:
                        if (specifiers->thread_local) {
-                               errorf(HERE, "duplicate '__thread'");
+                               errorf(HERE, "duplicate %K", &token);
                        } else {
                                specifiers->thread_local = true;
 check_thread_storage_class:
@@ -2672,7 +2675,7 @@ check_thread_storage_class:
                                        case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class;
                                        case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_storage_class;
 wrong_thread_storage_class:
-                                               errorf(HERE, "'__thread' used with '%s'", wrong);
+                                               errorf(HERE, "%K used with '%s'", &token, wrong);
                                                break;
                                }
                        }
@@ -4570,8 +4573,7 @@ static void check_declarations(void)
                warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
        }
        if (is_warn_on(WARN_UNUSED_VARIABLE)) {
-               walk_statements(current_function->statement, check_unused_variables,
-                               NULL);
+               walk_statements(current_function->body, check_unused_variables, NULL);
        }
 }
 
@@ -4788,7 +4790,7 @@ static void check_reachable(statement_t *const stmt)
                                return;
 
                        if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
-                               long                    const val      = fold_constant_to_int(expr);
+                               ir_tarval              *const val      = fold_constant_to_tarval(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
                                        if (i->expression == NULL) {
@@ -4796,7 +4798,9 @@ static void check_reachable(statement_t *const stmt)
                                                continue;
                                        }
 
-                                       if (i->first_case <= val && val <= i->last_case) {
+                                       if (i->first_case == val || i->last_case == val ||
+                                               ((tarval_cmp(i->first_case, val) & ir_relation_less_equal)
+                                           && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) {
                                                check_reachable((statement_t*)i);
                                                return;
                                        }
@@ -4841,7 +4845,6 @@ static void check_reachable(statement_t *const stmt)
 
                                next = parent;
                                switch (parent->kind) {
-                                       case STATEMENT_WHILE:    goto continue_while;
                                        case STATEMENT_DO_WHILE: goto continue_do_while;
                                        case STATEMENT_FOR:      goto continue_for;
 
@@ -4857,7 +4860,6 @@ static void check_reachable(statement_t *const stmt)
 
                                switch (parent->kind) {
                                        case STATEMENT_SWITCH:
-                                       case STATEMENT_WHILE:
                                        case STATEMENT_DO_WHILE:
                                        case STATEMENT_FOR:
                                                last = parent;
@@ -4895,25 +4897,6 @@ found_break_parent:
                        next = stmt->case_label.statement;
                        break;
 
-               case STATEMENT_WHILE: {
-                       while_statement_t const *const whiles = &stmt->whiles;
-                       expression_t      const *const cond   = whiles->condition;
-
-                       if (!expression_returns(cond))
-                               return;
-
-                       int const val = determine_truth(cond);
-
-                       if (val >= 0)
-                               check_reachable(whiles->body);
-
-                       if (val > 0)
-                               return;
-
-                       next = stmt->base.next;
-                       break;
-               }
-
                case STATEMENT_DO_WHILE:
                        next = stmt->do_while.body;
                        break;
@@ -5018,31 +5001,6 @@ found_break_parent:
                                next = next->base.next;
                                break;
 
-                       case STATEMENT_WHILE: {
-continue_while:
-                               if (next->base.reachable)
-                                       return;
-                               next->base.reachable = true;
-
-                               while_statement_t const *const whiles = &next->whiles;
-                               expression_t      const *const cond   = whiles->condition;
-
-                               if (!expression_returns(cond))
-                                       return;
-
-                               int const val = determine_truth(cond);
-
-                               if (val >= 0)
-                                       check_reachable(whiles->body);
-
-                               if (val > 0)
-                                       return;
-
-                               last = next;
-                               next = next->base.next;
-                               break;
-                       }
-
                        case STATEMENT_DO_WHILE: {
 continue_do_while:
                                if (next->base.reachable)
@@ -5312,7 +5270,7 @@ static void parse_external_declaration(void)
                environment_push(parameter);
        }
 
-       if (function->statement != NULL) {
+       if (function->body != NULL) {
                parser_error_multiple_definition(entity, HERE);
                eat_block();
        } else {
@@ -5329,7 +5287,7 @@ static void parse_external_declaration(void)
                label_anchor = &label_first;
 
                statement_t *const body = parse_compound_statement(false);
-               function->statement = body;
+               function->body = body;
                first_err = true;
                check_labels();
                check_declarations();
@@ -6839,7 +6797,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
        expression_t  *tp_expression = allocate_expression_zero(kind);
        tp_expression->base.type     = type_size_t;
 
-       eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
+       eat(kind == EXPR_SIZEOF ? T_sizeof : T__Alignof);
 
        type_t       *orig_type;
        expression_t *expression;
@@ -7067,7 +7025,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
                                                   "third argument of '%Y' must be a constant expression",
                                                   call->function->reference.entity->base.symbol);
                                }
-                               locality = rw->next;
                        }
                        break;
                default:
@@ -8649,7 +8606,7 @@ static void init_expression_parsers(void)
        register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS);
        register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS);
        register_expression_parser(parse_sizeof,                      T_sizeof);
-       register_expression_parser(parse_alignof,                     T___alignof__);
+       register_expression_parser(parse_alignof,                     T__Alignof);
        register_expression_parser(parse_extension,                   T___extension__);
        register_expression_parser(parse_builtin_classify_type,       T___builtin_classify_type);
        register_expression_parser(parse_delete,                      T_delete);
@@ -8885,7 +8842,7 @@ static statement_t *parse_case_statement(void)
                }
                statement->case_label.is_bad = true;
        } else {
-               long const val = fold_constant_to_int(expression);
+               ir_tarval *val = fold_constant_to_tarval(expression);
                statement->case_label.first_case = val;
                statement->case_label.last_case  = val;
        }
@@ -8909,10 +8866,11 @@ static statement_t *parse_case_statement(void)
                                }
                                statement->case_label.is_bad = true;
                        } else {
-                               long const val = fold_constant_to_int(end_range);
+                               ir_tarval *val = fold_constant_to_tarval(end_range);
                                statement->case_label.last_case = val;
 
-                               if (val < statement->case_label.first_case) {
+                               if (tarval_cmp(val, statement->case_label.first_case)
+                                   == ir_relation_less) {
                                        statement->case_label.is_empty_range = true;
                                        warningf(WARN_OTHER, pos, "empty range specified");
                                }
@@ -9017,6 +8975,7 @@ static statement_t *parse_label_statement(void)
        } else {
                label->base.source_position = *pos;
                label->statement            = statement;
+               label->n_users             += 1;
        }
 
        eat(':');
@@ -9116,28 +9075,32 @@ static void check_enum_cases(const switch_statement_t *statement)
 {
        if (!is_warn_on(WARN_SWITCH_ENUM))
                return;
-       const type_t *type = skip_typeref(statement->expression->base.type);
+       type_t *type = skip_typeref(statement->expression->base.type);
        if (! is_type_enum(type))
                return;
-       const enum_type_t *enumt = &type->enumt;
+       enum_type_t *enumt = &type->enumt;
 
        /* if we have a default, no warnings */
        if (statement->default_label != NULL)
                return;
 
+       determine_enum_values(enumt);
+
        /* FIXME: calculation of value should be done while parsing */
        /* TODO: quadratic algorithm here. Change to an n log n one */
-       long            last_value = -1;
-       const entity_t *entry      = enumt->enume->base.next;
+       const entity_t *entry = enumt->enume->base.next;
        for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
             entry = entry->base.next) {
-               const expression_t *expression = entry->enum_value.value;
-               long                value      = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
-               bool                found      = false;
-               for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+               ir_tarval *value = entry->enum_value.tv;
+               bool       found = false;
+               for (const case_label_statement_t *l = statement->first_case; l != NULL;
+                    l = l->next) {
                        if (l->expression == NULL)
                                continue;
-                       if (l->first_case <= value && value <= l->last_case) {
+                       if (l->first_case == l->last_case && l->first_case != value)
+                               continue;
+                       if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal)
+                        && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) {
                                found = true;
                                break;
                        }
@@ -9146,7 +9109,6 @@ static void check_enum_cases(const switch_statement_t *statement)
                        source_position_t const *const pos = &statement->base.source_position;
                        warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
                }
-               last_value = value;
        }
 }
 
@@ -9207,20 +9169,20 @@ static statement_t *parse_loop_body(statement_t *const loop)
  */
 static statement_t *parse_while(void)
 {
-       statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
+       statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
 
        eat(T_while);
 
        PUSH_PARENT(statement);
-       PUSH_SCOPE_STATEMENT(&statement->whiles.scope);
+       PUSH_SCOPE_STATEMENT(&statement->fors.scope);
 
        expression_t *const cond = parse_condition();
-       statement->whiles.condition = cond;
+       statement->fors.condition = cond;
        /* ยง6.8.5:2    The controlling expression of an iteration statement shall
         *             have scalar type. */
        semantic_condition(cond, "condition of 'while'-statement");
 
-       statement->whiles.body = parse_loop_body(statement);
+       statement->fors.body = parse_loop_body(statement);
 
        POP_SCOPE();
        POP_PARENT();
@@ -9353,6 +9315,7 @@ static statement_t *parse_goto(void)
 
                label_t *const label = get_label("while parsing goto");
                if (label) {
+                       label->n_users        += 1;
                        label->used            = true;
                        statement->gotos.label = label;
 
@@ -9816,11 +9779,12 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token(T_NUMBER);
        add_anchor_token(T_PLUSPLUS);
        add_anchor_token(T_STRING_LITERAL);
+       add_anchor_token(T__Alignof);
        add_anchor_token(T__Bool);
        add_anchor_token(T__Complex);
        add_anchor_token(T__Imaginary);
+       add_anchor_token(T__Thread_local);
        add_anchor_token(T___PRETTY_FUNCTION__);
-       add_anchor_token(T___alignof__);
        add_anchor_token(T___attribute__);
        add_anchor_token(T___builtin_va_start);
        add_anchor_token(T___extension__);
@@ -9828,7 +9792,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token(T___imag__);
        add_anchor_token(T___label__);
        add_anchor_token(T___real__);
-       add_anchor_token(T___thread);
        add_anchor_token(T_asm);
        add_anchor_token(T_auto);
        add_anchor_token(T_bool);
@@ -9976,7 +9939,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        rem_anchor_token(T_bool);
        rem_anchor_token(T_auto);
        rem_anchor_token(T_asm);
-       rem_anchor_token(T___thread);
        rem_anchor_token(T___real__);
        rem_anchor_token(T___label__);
        rem_anchor_token(T___imag__);
@@ -9984,11 +9946,12 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        rem_anchor_token(T___extension__);
        rem_anchor_token(T___builtin_va_start);
        rem_anchor_token(T___attribute__);
-       rem_anchor_token(T___alignof__);
        rem_anchor_token(T___PRETTY_FUNCTION__);
+       rem_anchor_token(T__Thread_local);
        rem_anchor_token(T__Imaginary);
        rem_anchor_token(T__Complex);
        rem_anchor_token(T__Bool);
+       rem_anchor_token(T__Alignof);
        rem_anchor_token(T_STRING_LITERAL);
        rem_anchor_token(T_PLUSPLUS);
        rem_anchor_token(T_NUMBER);
@@ -10040,7 +10003,7 @@ static void check_unused_globals(void)
                                continue;
 
                        why = WARN_UNUSED_FUNCTION;
-                       s   = entity->function.statement != NULL ? "defined" : "declared";
+                       s   = entity->function.body != NULL ? "defined" : "declared";
                } else {
                        why = WARN_UNUSED_VARIABLE;
                        s   = "defined";
@@ -10214,8 +10177,6 @@ void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
-       error_count       = 0;
-       warning_count     = 0;
 
        print_to_file(stderr);
 
@@ -10278,7 +10239,7 @@ static void complete_incomplete_arrays(void)
 
 static void prepare_main_collect2(entity_t *const entity)
 {
-       PUSH_SCOPE(&entity->function.statement->compound.scope);
+       PUSH_SCOPE(&entity->function.body->compound.scope);
 
        // create call to __main
        symbol_t *symbol         = symbol_table_insert("__main");
@@ -10300,9 +10261,9 @@ static void prepare_main_collect2(entity_t *const entity)
        expr_statement->base.source_position  = builtin_source_position;
        expr_statement->expression.expression = call;
 
-       statement_t *statement = entity->function.statement;
-       assert(statement->kind == STATEMENT_COMPOUND);
-       compound_statement_t *compounds = &statement->compound;
+       statement_t *const body = entity->function.body;
+       assert(body->kind == STATEMENT_COMPOUND);
+       compound_statement_t *compounds = &body->compound;
 
        expr_statement->base.next = compounds->statements;
        compounds->statements     = expr_statement;