X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=b5a0136407c81d61afe77ce1c4ba6c30c96ad739;hb=368123ed15555886729567e502705e73e88d757c;hp=fdaabbee34636d2df2f51e136c5baf201717d694;hpb=062550d93a3ee900a2aa9f57cf8bf1a378dcf3dc;p=cparser diff --git a/parser.c b/parser.c index fdaabbe..b5a0136 100644 --- a/parser.c +++ b/parser.c @@ -42,7 +42,7 @@ #include "adt/array.h" //#define PRINT_TOKENS -#define MAX_LOOKAHEAD 2 +#define MAX_LOOKAHEAD 1 typedef struct { entity_t *old_entity; @@ -98,14 +98,6 @@ typedef struct parse_initializer_env_t { bool must_be_constant; } parse_initializer_env_t; -/** - * Capture a MS __base extension. - */ -typedef struct based_spec_t { - source_position_t source_position; - variable_t *base_variable; -} based_spec_t; - typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition); /** The current token. */ @@ -206,6 +198,9 @@ static entity_t *record_entity(entity_t *entity, bool is_definition); static void semantic_comparison(binary_expression_t *expression); +static void create_gnu_builtins(void); +static void create_microsoft_intrinsics(void); + #define STORAGE_CLASSES \ STORAGE_CLASSES_NO_EXTERN \ case T_extern: @@ -288,27 +283,16 @@ static void semantic_comparison(binary_expression_t *expression); case T___FUNCTION__: \ case T___PRETTY_FUNCTION__: \ case T___alignof__: \ - case T___builtin_alloca: \ case T___builtin_classify_type: \ case T___builtin_constant_p: \ - case T___builtin_expect: \ - case T___builtin_huge_val: \ - case T___builtin_inf: \ - case T___builtin_inff: \ - case T___builtin_infl: \ case T___builtin_isgreater: \ case T___builtin_isgreaterequal: \ case T___builtin_isless: \ case T___builtin_islessequal: \ case T___builtin_islessgreater: \ case T___builtin_isunordered: \ - case T___builtin_nan: \ - case T___builtin_nanf: \ - case T___builtin_nanl: \ case T___builtin_offsetof: \ - case T___builtin_prefetch: \ case T___builtin_va_arg: \ - case T___builtin_va_end: \ case T___builtin_va_start: \ case T___func__: \ case T___noop: \ @@ -351,7 +335,7 @@ static size_t get_entity_struct_size(entity_kind_t kind) [ENTITY_LOCAL_LABEL] = sizeof(label_t), [ENTITY_NAMESPACE] = sizeof(namespace_t) }; - assert(kind < sizeof(sizes) / sizeof(sizes[0])); + assert(kind < lengthof(sizes)); assert(sizes[kind] != 0); return sizes[kind]; } @@ -396,7 +380,7 @@ static size_t get_statement_struct_size(statement_kind_t kind) [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t), [STATEMENT_LEAVE] = sizeof(leave_statement_t) }; - assert(kind < sizeof(sizes) / sizeof(sizes[0])); + assert(kind < lengthof(sizes)); assert(sizes[kind] != 0); return sizes[kind]; } @@ -409,33 +393,32 @@ static size_t get_statement_struct_size(statement_kind_t kind) static size_t get_expression_struct_size(expression_kind_t kind) { static const size_t sizes[] = { - [EXPR_INVALID] = sizeof(expression_base_t), - [EXPR_REFERENCE] = sizeof(reference_expression_t), - [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t), - [EXPR_CONST] = sizeof(const_expression_t), - [EXPR_CHARACTER_CONSTANT] = sizeof(const_expression_t), - [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t), - [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t), - [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t), - [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t), - [EXPR_CALL] = sizeof(call_expression_t), - [EXPR_UNARY_FIRST] = sizeof(unary_expression_t), - [EXPR_BINARY_FIRST] = sizeof(binary_expression_t), - [EXPR_CONDITIONAL] = sizeof(conditional_expression_t), - [EXPR_SELECT] = sizeof(select_expression_t), - [EXPR_ARRAY_ACCESS] = sizeof(array_access_expression_t), - [EXPR_SIZEOF] = sizeof(typeprop_expression_t), - [EXPR_ALIGNOF] = sizeof(typeprop_expression_t), - [EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t), - [EXPR_FUNCNAME] = sizeof(funcname_expression_t), - [EXPR_BUILTIN_SYMBOL] = sizeof(builtin_symbol_expression_t), - [EXPR_BUILTIN_CONSTANT_P] = sizeof(builtin_constant_expression_t), - [EXPR_BUILTIN_PREFETCH] = sizeof(builtin_prefetch_expression_t), - [EXPR_OFFSETOF] = sizeof(offsetof_expression_t), - [EXPR_VA_START] = sizeof(va_start_expression_t), - [EXPR_VA_ARG] = sizeof(va_arg_expression_t), - [EXPR_STATEMENT] = sizeof(statement_expression_t), - [EXPR_LABEL_ADDRESS] = sizeof(label_address_expression_t), + [EXPR_INVALID] = sizeof(expression_base_t), + [EXPR_REFERENCE] = sizeof(reference_expression_t), + [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t), + [EXPR_CONST] = sizeof(const_expression_t), + [EXPR_CHARACTER_CONSTANT] = sizeof(const_expression_t), + [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t), + [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t), + [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t), + [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t), + [EXPR_CALL] = sizeof(call_expression_t), + [EXPR_UNARY_FIRST] = sizeof(unary_expression_t), + [EXPR_BINARY_FIRST] = sizeof(binary_expression_t), + [EXPR_CONDITIONAL] = sizeof(conditional_expression_t), + [EXPR_SELECT] = sizeof(select_expression_t), + [EXPR_ARRAY_ACCESS] = sizeof(array_access_expression_t), + [EXPR_SIZEOF] = sizeof(typeprop_expression_t), + [EXPR_ALIGNOF] = sizeof(typeprop_expression_t), + [EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t), + [EXPR_FUNCNAME] = sizeof(funcname_expression_t), + [EXPR_BUILTIN_CONSTANT_P] = sizeof(builtin_constant_expression_t), + [EXPR_BUILTIN_TYPES_COMPATIBLE_P] = sizeof(builtin_types_compatible_expression_t), + [EXPR_OFFSETOF] = sizeof(offsetof_expression_t), + [EXPR_VA_START] = sizeof(va_start_expression_t), + [EXPR_VA_ARG] = sizeof(va_arg_expression_t), + [EXPR_STATEMENT] = sizeof(statement_expression_t), + [EXPR_LABEL_ADDRESS] = sizeof(label_address_expression_t), }; if (kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) { return sizes[EXPR_UNARY_FIRST]; @@ -443,7 +426,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) { return sizes[EXPR_BINARY_FIRST]; } - assert(kind < sizeof(sizes) / sizeof(sizes[0])); + assert(kind < lengthof(sizes)); assert(sizes[kind] != 0); return sizes[kind]; } @@ -526,7 +509,7 @@ static size_t get_type_struct_size(type_kind_t kind) [TYPE_TYPEDEF] = sizeof(typedef_type_t), [TYPE_TYPEOF] = sizeof(typeof_type_t), }; - assert(sizeof(sizes) / sizeof(sizes[0]) == (int) TYPE_TYPEOF + 1); + assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1); assert(kind <= TYPE_TYPEOF); assert(sizes[kind] != 0); return sizes[kind]; @@ -548,6 +531,14 @@ static type_t *allocate_type_zero(type_kind_t kind) return res; } +static function_parameter_t *allocate_parameter(type_t *const type) +{ + function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param)); + memset(param, 0, sizeof(*param)); + param->type = type; + return param; +} + /** * Returns the size of an initializer node. * @@ -562,7 +553,7 @@ static size_t get_initializer_size(initializer_kind_t kind) [INITIALIZER_LIST] = sizeof(initializer_list_t), [INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t) }; - assert(kind < sizeof(sizes) / sizeof(*sizes)); + assert(kind < lengthof(sizes)); assert(sizes[kind] != 0); return sizes[kind]; } @@ -1120,7 +1111,7 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left, } } -/** Implements the rules from § 6.5.16.1 */ +/** Implements the rules from §6.5.16.1 */ static assign_error_t semantic_assign(type_t *orig_type_left, const expression_t *const right) { @@ -2137,9 +2128,8 @@ unary: case EXPR_CLASSIFY_TYPE: case EXPR_ALIGNOF: case EXPR_FUNCNAME: - case EXPR_BUILTIN_SYMBOL: case EXPR_BUILTIN_CONSTANT_P: - case EXPR_BUILTIN_PREFETCH: + case EXPR_BUILTIN_TYPES_COMPATIBLE_P: case EXPR_OFFSETOF: case EXPR_STATEMENT: // TODO case EXPR_LABEL_ADDRESS: @@ -2229,7 +2219,7 @@ static initializer_t *initializer_from_expression(type_t *orig_type, { /* TODO check that expression is a constant expression */ - /* § 6.7.8.14/15 char array may be initialized by string literals */ + /* §6.7.8.14/15 char array may be initialized by string literals */ type_t *type = skip_typeref(orig_type); type_t *expr_type_orig = expression->base.type; type_t *expr_type = skip_typeref(expr_type_orig); @@ -2293,7 +2283,7 @@ static bool is_initializer_constant(const expression_t *expression) /** * Parses an scalar initializer. * - * § 6.7.8.11; eat {} without warning + * §6.7.8.11; eat {} without warning */ static initializer_t *parse_scalar_initializer(type_t *type, bool must_be_constant) @@ -2909,7 +2899,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) result = parse_scalar_initializer(type, env->must_be_constant); } - /* § 6.7.8:22 array initializers for arrays with unknown size determine + /* §6.7.8:22 array initializers for arrays with unknown size determine * the array type size */ if (is_type_array(type) && type->array.size_expression == NULL && result != NULL) { @@ -3201,7 +3191,7 @@ static type_t *parse_typeof(void) type = parse_typename(); } else { expression = parse_expression(); - type = expression->base.type; + type = revert_automatic_type_conversion(expression); } break; @@ -3452,29 +3442,23 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind) return entity; } -static void parse_microsoft_based(based_spec_t *based_spec) +static variable_t *parse_microsoft_based(void) { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing __based", T_IDENTIFIER, NULL); - return; + return NULL; } symbol_t *symbol = token.v.symbol; entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL); + variable_t *variable; if (entity == NULL || entity->base.kind != ENTITY_VARIABLE) { errorf(HERE, "'%Y' is not a variable name.", symbol); - entity = create_error_entity(symbol, ENTITY_VARIABLE); + variable = &create_error_entity(symbol, ENTITY_VARIABLE)->variable; } else { - variable_t *variable = &entity->variable; - - if (based_spec->base_variable != NULL) { - errorf(HERE, "__based type qualifier specified more than once"); - } - based_spec->source_position = token.source_position; - based_spec->base_variable = variable; + variable = &entity->variable; type_t *const type = variable->base.type; - if (is_type_valid(type)) { if (! is_type_pointer(skip_typeref(type))) { errorf(HERE, "variable in __based modifier must have pointer type instead of '%T'", type); @@ -3485,6 +3469,7 @@ static void parse_microsoft_based(based_spec_t *based_spec) } } next_token(); + return variable; } /** @@ -4179,6 +4164,24 @@ static void semantic_parameter_incomplete(const entity_t *entity) } } +static bool has_parameters(void) +{ + /* func(void) is not a parameter */ + if (token.type == T_IDENTIFIER) { + entity_t const *const entity = get_entity(token.v.symbol, NAMESPACE_NORMAL); + if (entity->kind != ENTITY_TYPEDEF) + return true; + if (skip_typeref(entity->typedefe.type) != type_void) + return true; + } else if (token.type != T_void) { + return true; + } + if (look_ahead(1)->type != ')') + return true; + next_token(); + return false; +} + /** * Parses function type parameters (and optionally creates variable_t entities * for them in a scope) @@ -4207,61 +4210,49 @@ static void parse_parameters(function_type_t *type, scope_t *scope) goto parameters_finished; } - function_parameter_t *parameter; - function_parameter_t *last_parameter = NULL; + if (has_parameters()) { + function_parameter_t **anchor = &type->parameters; + for (;;) { + switch (token.type) { + case T_DOTDOTDOT: + next_token(); + type->variadic = true; + goto parameters_finished; - while (true) { - switch (token.type) { - case T_DOTDOTDOT: - next_token(); - type->variadic = true; - goto parameters_finished; + case T_IDENTIFIER: + case T___extension__: + DECLARATION_START + { + entity_t *entity = parse_parameter(); + if (entity->kind == ENTITY_TYPEDEF) { + errorf(&entity->base.source_position, + "typedef not allowed as function parameter"); + break; + } + assert(is_declaration(entity)); - case T_IDENTIFIER: - case T___extension__: - DECLARATION_START - { - entity_t *entity = parse_parameter(); - if (entity->kind == ENTITY_TYPEDEF) { - errorf(&entity->base.source_position, - "typedef not allowed as function parameter"); - break; - } - assert(is_declaration(entity)); + semantic_parameter_incomplete(entity); - /* func(void) is not a parameter */ - if (last_parameter == NULL - && token.type == ')' - && entity->base.symbol == NULL - && skip_typeref(entity->declaration.type) == type_void) { - goto parameters_finished; - } - semantic_parameter_incomplete(entity); + function_parameter_t *const parameter = + allocate_parameter(entity->declaration.type); - parameter = obstack_alloc(type_obst, sizeof(parameter[0])); - memset(parameter, 0, sizeof(parameter[0])); - parameter->type = entity->declaration.type; + if (scope != NULL) { + append_entity(scope, entity); + } - if (scope != NULL) { - append_entity(scope, entity); + *anchor = parameter; + anchor = ¶meter->next; + break; } - if (last_parameter != NULL) { - last_parameter->next = parameter; - } else { - type->parameters = parameter; + default: + goto parameters_finished; } - last_parameter = parameter; - break; - } - - default: - goto parameters_finished; - } - if (token.type != ',') { - goto parameters_finished; + if (token.type != ',') { + goto parameters_finished; + } + next_token(); } - next_token(); } @@ -4281,67 +4272,69 @@ typedef enum construct_type_kind_t { CONSTRUCT_ARRAY } construct_type_kind_t; -typedef struct construct_type_t construct_type_t; -struct construct_type_t { +typedef union construct_type_t construct_type_t; + +typedef struct construct_type_base_t { construct_type_kind_t kind; construct_type_t *next; -}; - -typedef struct parsed_pointer_t parsed_pointer_t; -struct parsed_pointer_t { - construct_type_t construct_type; - type_qualifiers_t type_qualifiers; - variable_t *base_variable; /**< MS __based extension. */ -}; - -typedef struct parsed_reference_t parsed_reference_t; -struct parsed_reference_t { - construct_type_t construct_type; -}; - -typedef struct construct_function_type_t construct_function_type_t; -struct construct_function_type_t { - construct_type_t construct_type; - type_t *function_type; -}; - -typedef struct parsed_array_t parsed_array_t; -struct parsed_array_t { - construct_type_t construct_type; - type_qualifiers_t type_qualifiers; - bool is_static; - bool is_variable; - expression_t *size; -}; - -typedef struct construct_base_type_t construct_base_type_t; -struct construct_base_type_t { - construct_type_t construct_type; - type_t *type; +} construct_type_base_t; + +typedef struct parsed_pointer_t { + construct_type_base_t base; + type_qualifiers_t type_qualifiers; + variable_t *base_variable; /**< MS __based extension. */ +} parsed_pointer_t; + +typedef struct parsed_reference_t { + construct_type_base_t base; +} parsed_reference_t; + +typedef struct construct_function_type_t { + construct_type_base_t base; + type_t *function_type; +} construct_function_type_t; + +typedef struct parsed_array_t { + construct_type_base_t base; + type_qualifiers_t type_qualifiers; + bool is_static; + bool is_variable; + expression_t *size; +} parsed_array_t; + +union construct_type_t { + construct_type_kind_t kind; + construct_type_base_t base; + parsed_pointer_t pointer; + parsed_reference_t reference; + construct_function_type_t function; + parsed_array_t array; }; static construct_type_t *parse_pointer_declarator(variable_t *base_variable) { eat('*'); - parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0])); - memset(pointer, 0, sizeof(pointer[0])); - pointer->construct_type.kind = CONSTRUCT_POINTER; - pointer->type_qualifiers = parse_type_qualifiers(); - pointer->base_variable = base_variable; + construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->pointer)); + parsed_pointer_t *pointer = &cons->pointer; + memset(pointer, 0, sizeof(*pointer)); + cons->kind = CONSTRUCT_POINTER; + pointer->type_qualifiers = parse_type_qualifiers(); + pointer->base_variable = base_variable; - return &pointer->construct_type; + return cons; } static construct_type_t *parse_reference_declarator(void) { eat('&'); - parsed_reference_t *reference = obstack_alloc(&temp_obst, sizeof(reference[0])); - memset(reference, 0, sizeof(reference[0])); - reference->construct_type.kind = CONSTRUCT_REFERENCE; + construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->reference)); + parsed_reference_t *reference = &cons->reference; + memset(reference, 0, sizeof(*reference)); + cons->kind = CONSTRUCT_REFERENCE; - return (construct_type_t*)reference; + return cons; } static construct_type_t *parse_array_declarator(void) @@ -4349,9 +4342,10 @@ static construct_type_t *parse_array_declarator(void) eat('['); add_anchor_token(']'); - parsed_array_t *array = obstack_alloc(&temp_obst, sizeof(array[0])); - memset(array, 0, sizeof(array[0])); - array->construct_type.kind = CONSTRUCT_ARRAY; + construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->array)); + parsed_array_t *array = &cons->array; + memset(array, 0, sizeof(*array)); + cons->kind = CONSTRUCT_ARRAY; if (token.type == T_static) { array->is_static = true; @@ -4380,7 +4374,7 @@ static construct_type_t *parse_array_declarator(void) expect(']', end_error); end_error: - return &array->construct_type; + return cons; } static construct_type_t *parse_function_declarator(scope_t *scope, @@ -4405,13 +4399,13 @@ static construct_type_t *parse_function_declarator(scope_t *scope, parse_parameters(ftype, scope); - construct_function_type_t *construct_function_type = - obstack_alloc(&temp_obst, sizeof(construct_function_type[0])); - memset(construct_function_type, 0, sizeof(construct_function_type[0])); - construct_function_type->construct_type.kind = CONSTRUCT_FUNCTION; - construct_function_type->function_type = type; + construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->function)); + construct_function_type_t *function = &cons->function; + memset(function, 0, sizeof(*function)); + cons->kind = CONSTRUCT_FUNCTION; + function->function_type = type; - return &construct_function_type->construct_type; + return cons; } typedef struct parse_declarator_env_t { @@ -4426,66 +4420,57 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env, { /* construct a single linked list of construct_type_t's which describe * how to construct the final declarator type */ - construct_type_t *first = NULL; - construct_type_t *last = NULL; - gnu_attribute_t *attributes = NULL; + construct_type_t *first = NULL; + construct_type_t **anchor = &first; + gnu_attribute_t *attributes = NULL; decl_modifiers_t modifiers = parse_attributes(&attributes); - /* MS __based extension */ - based_spec_t base_spec; - base_spec.base_variable = NULL; - for (;;) { construct_type_t *type; + variable_t *based = NULL; /* MS __based extension */ switch (token.type) { case '&': if (!(c_mode & _CXX)) errorf(HERE, "references are only available for C++"); - if (base_spec.base_variable != NULL && warning.other) { - warningf(&base_spec.source_position, - "__based does not precede a pointer operator, ignored"); - } type = parse_reference_declarator(); - /* consumed */ - base_spec.base_variable = NULL; - break; - - case '*': - type = parse_pointer_declarator(base_spec.base_variable); - /* consumed */ - base_spec.base_variable = NULL; break; - case T__based: + case T__based: { + source_position_t const pos = *HERE; next_token(); expect('(', end_error); add_anchor_token(')'); - parse_microsoft_based(&base_spec); + based = parse_microsoft_based(); rem_anchor_token(')'); expect(')', end_error); - continue; + if (token.type != '*') { + if (token.type == T__based) { + errorf(&pos, "__based type modifier specified more than once"); + } else if (warning.other) { + warningf(&pos, + "__based does not precede a pointer declarator, ignored"); + } + continue; + } + /* FALLTHROUGH */ + } + + case '*': + type = parse_pointer_declarator(based); + break; default: goto ptr_operator_end; } - if (last == NULL) { - first = type; - last = type; - } else { - last->next = type; - last = type; - } + *anchor = type; + anchor = &type->base.next; /* TODO: find out if this is correct */ modifiers |= parse_attributes(&attributes); } ptr_operator_end: - if (base_spec.base_variable != NULL && warning.other) { - warningf(&base_spec.source_position, - "__based does not precede a pointer operator, ignored"); - } if (env != NULL) { modifiers |= env->modifiers; @@ -4528,9 +4513,9 @@ ptr_operator_end: return NULL; } - construct_type_t *p = last; + construct_type_t **const p = anchor; - while (true) { + for (;;) { construct_type_t *type; switch (token.type) { case '(': { @@ -4548,28 +4533,17 @@ ptr_operator_end: goto declarator_finished; } - /* insert in the middle of the list (behind p) */ - if (p != NULL) { - type->next = p->next; - p->next = type; - } else { - type->next = first; - first = type; - } - if (last == p) { - last = type; - } + /* insert in the middle of the list (at p) */ + type->base.next = *p; + *p = type; + if (anchor == p) + anchor = &type->base.next; } declarator_finished: - /* append inner_types at the end of the list, we don't to set last anymore + /* append inner_types at the end of the list, we don't to set anchor anymore * as it's not needed anymore */ - if (last == NULL) { - assert(first == NULL); - first = inner_types; - } else { - last->next = inner_types; - } + *anchor = inner_types; return first; end_error: @@ -4642,15 +4616,13 @@ static void parse_declaration_attributes(entity_t *entity) static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type) { construct_type_t *iter = construct_list; - for (; iter != NULL; iter = iter->next) { + for (; iter != NULL; iter = iter->base.next) { switch (iter->kind) { case CONSTRUCT_INVALID: - internal_errorf(HERE, "invalid type construction found"); + break; case CONSTRUCT_FUNCTION: { - construct_function_type_t *construct_function_type - = (construct_function_type_t*) iter; - - type_t *function_type = construct_function_type->function_type; + construct_function_type_t *function = &iter->function; + type_t *function_type = function->function_type; function_type->function.return_type = type; @@ -4667,16 +4639,18 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ } } - type = function_type; - break; + /* The function type was constructed earlier. Freeing it here will + * destroy other types. */ + type = typehash_insert(function_type); + continue; } case CONSTRUCT_POINTER: { if (is_type_reference(skip_typeref(type))) errorf(HERE, "cannot declare a pointer to reference"); - parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter; - type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, parsed_pointer->base_variable); + parsed_pointer_t *pointer = &iter->pointer; + type = make_based_pointer_type(type, pointer->type_qualifiers, pointer->base_variable); continue; } @@ -4691,19 +4665,19 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ if (is_type_reference(skip_typeref(type))) errorf(HERE, "cannot declare an array of references"); - parsed_array_t *parsed_array = (parsed_array_t*) iter; - type_t *array_type = allocate_type_zero(TYPE_ARRAY); + parsed_array_t *array = &iter->array; + type_t *array_type = allocate_type_zero(TYPE_ARRAY); - expression_t *size_expression = parsed_array->size; + expression_t *size_expression = array->size; if (size_expression != NULL) { size_expression = create_implicit_cast(size_expression, type_size_t); } - array_type->base.qualifiers = parsed_array->type_qualifiers; + array_type->base.qualifiers = array->type_qualifiers; array_type->array.element_type = type; - array_type->array.is_static = parsed_array->is_static; - array_type->array.is_variable = parsed_array->is_variable; + array_type->array.is_static = array->is_static; + array_type->array.is_variable = array->is_variable; array_type->array.size_expression = size_expression; if (size_expression != NULL) { @@ -4723,18 +4697,11 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ } else if (is_type_function(skipped_type)) { errorf(HERE, "array of functions is not allowed"); } - type = array_type; - break; + type = identify_new_type(array_type); + continue; } } - - /* The function type was constructed earlier. Freeing it here will - * destroy other types. */ - if (iter->kind == CONSTRUCT_FUNCTION) { - type = typehash_insert(type); - } else { - type = identify_new_type(type); - } + internal_errorf(HERE, "invalid type construction found"); } return type; @@ -4999,6 +4966,16 @@ static void error_redefined_as_different_kind(const source_position_t *pos, get_entity_kind_name(new_kind), &old->base.source_position); } +static bool is_error_entity(entity_t *const ent) +{ + if (is_declaration(ent)) { + return is_type_valid(skip_typeref(ent->declaration.type)); + } else if (ent->kind == ENTITY_TYPEDEF) { + return is_type_valid(skip_typeref(ent->typedefe.type)); + } + return false; +} + /** * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings * for various problems that occur for multiple definitions @@ -5013,7 +4990,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (symbol == NULL) return entity; - entity_t *previous_entity = get_entity(symbol, namespc); + entity_t *const previous_entity = get_entity(symbol, namespc); /* pushing the same entity twice will break the stack structure */ assert(previous_entity != entity); @@ -5043,160 +5020,167 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) entity->declaration.type, symbol); } - if (previous_entity != NULL && - previous_entity->base.parent_scope == ¤t_function->parameters && - previous_entity->base.parent_scope->depth + 1 == current_scope->depth) { - assert(previous_entity->kind == ENTITY_PARAMETER); - errorf(pos, - "declaration '%#T' redeclares the parameter '%#T' (declared %P)", - entity->declaration.type, symbol, - previous_entity->declaration.type, symbol, - &previous_entity->base.source_position); - goto finish; - } - - if (previous_entity != NULL && - previous_entity->base.parent_scope == current_scope) { - if (previous_entity->kind != entity->kind) { - error_redefined_as_different_kind(pos, previous_entity, - entity->kind); - goto finish; - } - if (previous_entity->kind == ENTITY_ENUM_VALUE) { - errorf(pos, "redeclaration of enum entry '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); - goto finish; - } - if (previous_entity->kind == ENTITY_TYPEDEF) { - /* TODO: C++ allows this for exactly the same type */ - errorf(pos, "redefinition of typedef '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); + if (previous_entity != NULL) { + if (previous_entity->base.parent_scope == ¤t_function->parameters && + previous_entity->base.parent_scope->depth + 1 == current_scope->depth) { + assert(previous_entity->kind == ENTITY_PARAMETER); + errorf(pos, + "declaration '%#T' redeclares the parameter '%#T' (declared %P)", + entity->declaration.type, symbol, + previous_entity->declaration.type, symbol, + &previous_entity->base.source_position); goto finish; } - /* at this point we should have only VARIABLES or FUNCTIONS */ - assert(is_declaration(previous_entity) && is_declaration(entity)); - - declaration_t *const prev_decl = &previous_entity->declaration; - declaration_t *const decl = &entity->declaration; + if (previous_entity->base.parent_scope == current_scope) { + if (previous_entity->kind != entity->kind) { + if (!is_error_entity(previous_entity) && !is_error_entity(entity)) { + error_redefined_as_different_kind(pos, previous_entity, + entity->kind); + } + goto finish; + } + if (previous_entity->kind == ENTITY_ENUM_VALUE) { + errorf(pos, "redeclaration of enum entry '%Y' (declared %P)", + symbol, &previous_entity->base.source_position); + goto finish; + } + if (previous_entity->kind == ENTITY_TYPEDEF) { + /* TODO: C++ allows this for exactly the same type */ + errorf(pos, "redefinition of typedef '%Y' (declared %P)", + symbol, &previous_entity->base.source_position); + goto finish; + } - /* can happen for K&R style declarations */ - if (prev_decl->type == NULL && - previous_entity->kind == ENTITY_PARAMETER && - entity->kind == ENTITY_PARAMETER) { - prev_decl->type = decl->type; - prev_decl->storage_class = decl->storage_class; - prev_decl->declared_storage_class = decl->declared_storage_class; - prev_decl->modifiers = decl->modifiers; - prev_decl->deprecated_string = decl->deprecated_string; - return previous_entity; - } + /* at this point we should have only VARIABLES or FUNCTIONS */ + assert(is_declaration(previous_entity) && is_declaration(entity)); + + declaration_t *const prev_decl = &previous_entity->declaration; + declaration_t *const decl = &entity->declaration; + + /* can happen for K&R style declarations */ + if (prev_decl->type == NULL && + previous_entity->kind == ENTITY_PARAMETER && + entity->kind == ENTITY_PARAMETER) { + prev_decl->type = decl->type; + prev_decl->storage_class = decl->storage_class; + prev_decl->declared_storage_class = decl->declared_storage_class; + prev_decl->modifiers = decl->modifiers; + prev_decl->deprecated_string = decl->deprecated_string; + return previous_entity; + } - type_t *const orig_type = decl->type; - assert(orig_type != NULL); - type_t *const type = skip_typeref(orig_type); - type_t * prev_type = skip_typeref(prev_decl->type); + type_t *const orig_type = decl->type; + assert(orig_type != NULL); + type_t *const type = skip_typeref(orig_type); + type_t *const prev_type = skip_typeref(prev_decl->type); - if (!types_compatible(type, prev_type)) { - errorf(pos, - "declaration '%#T' is incompatible with '%#T' (declared %P)", - orig_type, symbol, prev_decl->type, symbol, - &previous_entity->base.source_position); - } else { - unsigned old_storage_class = prev_decl->storage_class; - if (warning.redundant_decls && - is_definition && - !prev_decl->used && - !(prev_decl->modifiers & DM_USED) && - prev_decl->storage_class == STORAGE_CLASS_STATIC) { - warningf(&previous_entity->base.source_position, - "unnecessary static forward declaration for '%#T'", - prev_decl->type, symbol); - } - - unsigned new_storage_class = decl->storage_class; - if (is_type_incomplete(prev_type)) { - prev_decl->type = type; - prev_type = type; - } - - /* pretend no storage class means extern for function - * declarations (except if the previous declaration is neither - * none nor extern) */ - if (entity->kind == ENTITY_FUNCTION) { - if (prev_type->function.unspecified_parameters) { - prev_decl->type = type; - prev_type = type; + if (!types_compatible(type, prev_type)) { + errorf(pos, + "declaration '%#T' is incompatible with '%#T' (declared %P)", + orig_type, symbol, prev_decl->type, symbol, + &previous_entity->base.source_position); + } else { + unsigned old_storage_class = prev_decl->storage_class; + if (warning.redundant_decls && + is_definition && + !prev_decl->used && + !(prev_decl->modifiers & DM_USED) && + prev_decl->storage_class == STORAGE_CLASS_STATIC) { + warningf(&previous_entity->base.source_position, + "unnecessary static forward declaration for '%#T'", + prev_decl->type, symbol); } - switch (old_storage_class) { - case STORAGE_CLASS_NONE: - old_storage_class = STORAGE_CLASS_EXTERN; - /* FALLTHROUGH */ - - case STORAGE_CLASS_EXTERN: - if (is_definition) { - if (warning.missing_prototypes && - prev_type->function.unspecified_parameters && - !is_sym_main(symbol)) { - warningf(pos, "no previous prototype for '%#T'", - orig_type, symbol); - } - } else if (new_storage_class == STORAGE_CLASS_NONE) { - new_storage_class = STORAGE_CLASS_EXTERN; - } - break; + storage_class_t new_storage_class = decl->storage_class; + + /* pretend no storage class means extern for function + * declarations (except if the previous declaration is neither + * none nor extern) */ + if (entity->kind == ENTITY_FUNCTION) { + /* the previous declaration could have unspecified parameters or + * be a typedef, so use the new type */ + if (prev_type->function.unspecified_parameters || is_definition) + prev_decl->type = type; + + switch (old_storage_class) { + case STORAGE_CLASS_NONE: + old_storage_class = STORAGE_CLASS_EXTERN; + /* FALLTHROUGH */ + + case STORAGE_CLASS_EXTERN: + if (is_definition) { + if (warning.missing_prototypes && + prev_type->function.unspecified_parameters && + !is_sym_main(symbol)) { + warningf(pos, "no previous prototype for '%#T'", + orig_type, symbol); + } + } else if (new_storage_class == STORAGE_CLASS_NONE) { + new_storage_class = STORAGE_CLASS_EXTERN; + } + break; - default: - break; + default: + break; + } + } else if (is_type_incomplete(prev_type)) { + prev_decl->type = type; } - } - if (old_storage_class == STORAGE_CLASS_EXTERN && - new_storage_class == STORAGE_CLASS_EXTERN) { + if (old_storage_class == STORAGE_CLASS_EXTERN && + new_storage_class == STORAGE_CLASS_EXTERN) { warn_redundant_declaration: - if (!is_definition && - warning.redundant_decls && - is_type_valid(prev_type) && - strcmp(previous_entity->base.source_position.input_name, - "") != 0) { - warningf(pos, - "redundant declaration for '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); - } - } else if (current_function == NULL) { - if (old_storage_class != STORAGE_CLASS_STATIC && - new_storage_class == STORAGE_CLASS_STATIC) { - errorf(pos, - "static declaration of '%Y' follows non-static declaration (declared %P)", - symbol, &previous_entity->base.source_position); - } else if (old_storage_class == STORAGE_CLASS_EXTERN) { - prev_decl->storage_class = STORAGE_CLASS_NONE; - prev_decl->declared_storage_class = STORAGE_CLASS_NONE; - } else { - /* ISO/IEC 14882:1998(E) §C.1.2:1 */ - if (c_mode & _CXX) - goto error_redeclaration; - goto warn_redundant_declaration; - } - } else if (is_type_valid(prev_type)) { - if (old_storage_class == new_storage_class) { + if (!is_definition && + warning.redundant_decls && + is_type_valid(prev_type) && + strcmp(previous_entity->base.source_position.input_name, + "") != 0) { + warningf(pos, + "redundant declaration for '%Y' (declared %P)", + symbol, &previous_entity->base.source_position); + } + } else if (current_function == NULL) { + if (old_storage_class != STORAGE_CLASS_STATIC && + new_storage_class == STORAGE_CLASS_STATIC) { + errorf(pos, + "static declaration of '%Y' follows non-static declaration (declared %P)", + symbol, &previous_entity->base.source_position); + } else if (old_storage_class == STORAGE_CLASS_EXTERN) { + prev_decl->storage_class = STORAGE_CLASS_NONE; + prev_decl->declared_storage_class = STORAGE_CLASS_NONE; + } else { + /* ISO/IEC 14882:1998(E) §C.1.2:1 */ + if (c_mode & _CXX) + goto error_redeclaration; + goto warn_redundant_declaration; + } + } else if (is_type_valid(prev_type)) { + if (old_storage_class == new_storage_class) { error_redeclaration: - errorf(pos, "redeclaration of '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); - } else { - errorf(pos, - "redeclaration of '%Y' with different linkage (declared %P)", - symbol, &previous_entity->base.source_position); + errorf(pos, "redeclaration of '%Y' (declared %P)", + symbol, &previous_entity->base.source_position); + } else { + errorf(pos, + "redeclaration of '%Y' with different linkage (declared %P)", + symbol, &previous_entity->base.source_position); + } } } + + prev_decl->modifiers |= decl->modifiers; + if (entity->kind == ENTITY_FUNCTION) { + previous_entity->function.is_inline |= entity->function.is_inline; + } + return previous_entity; } - prev_decl->modifiers |= decl->modifiers; - if (entity->kind == ENTITY_FUNCTION) { - previous_entity->function.is_inline |= entity->function.is_inline; + if (warning.shadow) { + warningf(pos, "%s '%Y' shadows %s (declared %P)", + get_entity_kind_name(entity->kind), symbol, + get_entity_kind_name(previous_entity->kind), + &previous_entity->base.source_position); } - return previous_entity; } if (entity->kind == ENTITY_FUNCTION) { @@ -5296,7 +5280,7 @@ static void parse_init_declarator_rest(entity_t *entity) current_init_decl = NULL; if (entity->kind == ENTITY_VARIABLE) { - /* § 6.7.5:22 array initializers for arrays with unknown size + /* §6.7.5:22 array initializers for arrays with unknown size * determine the array type size */ declaration->type = env.type; entity->variable.initializer = initializer; @@ -5346,7 +5330,8 @@ static void check_variable_type_complete(entity_t *ent) /* §6.7:7 If an identifier for an object is declared with no linkage, the * type for the object shall be complete [...] */ declaration_t *decl = &ent->declaration; - if (decl->storage_class != STORAGE_CLASS_NONE) + if (decl->storage_class == STORAGE_CLASS_EXTERN || + decl->storage_class == STORAGE_CLASS_STATIC) return; type_t *const orig_type = decl->type; @@ -5354,11 +5339,9 @@ static void check_variable_type_complete(entity_t *ent) if (!is_type_incomplete(type)) return; - /* GCC allows global arrays without size and assigns them a length of one, - * if no different declaration follows */ - if (is_type_array(type) && - c_mode & _GNUC && - ent->base.parent_scope == file_scope) { + /* §6.9.2:2 and §6.9.2:5: At the end of the translation incomplete arrays + * are given length one. */ + if (is_type_array(type) && ent->base.parent_scope == file_scope) { ARR_APP1(declaration_t*, incomplete_arrays, decl); return; } @@ -5461,7 +5444,7 @@ static type_t *get_default_promoted_type(type_t *orig_type) type_t *type = skip_typeref(orig_type); if (is_type_integer(type)) { result = promote_integer(type); - } else if (type == type_float) { + } else if (is_type_atomic(type, ATOMIC_TYPE_FLOAT)) { result = type_double; } @@ -5517,11 +5500,14 @@ decl_list_end: /* update function type */ type_t *new_type = duplicate_type(type); - function_parameter_t *parameters = NULL; - function_parameter_t *last_parameter = NULL; + function_parameter_t *parameters = NULL; + function_parameter_t **anchor = ¶meters; parameter = entity->function.parameters.entities; for (; parameter != NULL; parameter = parameter->base.next) { + if (parameter->kind != ENTITY_PARAMETER) + continue; + type_t *parameter_type = parameter->declaration.type; if (parameter_type == NULL) { if (strict_mode) { @@ -5545,20 +5531,14 @@ decl_list_end: */ parameter_type = get_default_promoted_type(parameter_type); - function_parameter_t *function_parameter - = obstack_alloc(type_obst, sizeof(function_parameter[0])); - memset(function_parameter, 0, sizeof(function_parameter[0])); + function_parameter_t *const parameter = + allocate_parameter(parameter_type); - function_parameter->type = parameter_type; - if (last_parameter != NULL) { - last_parameter->next = function_parameter; - } else { - parameters = function_parameter; - } - last_parameter = function_parameter; + *anchor = parameter; + anchor = ¶meter->next; } - /* § 6.9.1.7: A K&R style parameter list does NOT act as a function + /* §6.9.1.7: A K&R style parameter list does NOT act as a function * prototype */ new_type->function.parameters = parameters; new_type->function.unspecified_parameters = true; @@ -5736,9 +5716,8 @@ static bool expression_returns(expression_t const *const expr) case EXPR_SIZEOF: // TODO handle obscure VLA case case EXPR_ALIGNOF: case EXPR_FUNCNAME: - case EXPR_BUILTIN_SYMBOL: case EXPR_BUILTIN_CONSTANT_P: - case EXPR_BUILTIN_PREFETCH: + case EXPR_BUILTIN_TYPES_COMPATIBLE_P: case EXPR_OFFSETOF: case EXPR_INVALID: return true; @@ -6381,7 +6360,7 @@ static void parse_external_declaration(void) ndeclaration->base.symbol); } - /* § 6.7.5.3:14 a function definition with () means no + /* §6.7.5.3:14 a function definition with () means no * parameters (and not unspecified parameters) */ if (type->function.unspecified_parameters && type->function.parameters == NULL && @@ -6593,11 +6572,9 @@ static void parse_compound_declarators(compound_t *compound, entity->base.symbol, orig_type); } else if (is_type_incomplete(type)) { /* §6.7.2.1:16 flexible array member */ - if (is_type_array(type) && - token.type == ';' && - look_ahead(1)->type == '}') { - compound->has_flexible_member = true; - } else { + if (!is_type_array(type) || + token.type != ';' || + look_ahead(1)->type != '}') { errorf(&entity->base.source_position, "compound member '%Y' has incomplete type '%T'", entity->base.symbol, orig_type); @@ -6855,15 +6832,8 @@ static entity_t *create_implicit_function(symbol_t *symbol, static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1, type_t *argument_type2) { - function_parameter_t *parameter2 - = obstack_alloc(type_obst, sizeof(parameter2[0])); - memset(parameter2, 0, sizeof(parameter2[0])); - parameter2->type = argument_type2; - - function_parameter_t *parameter1 - = obstack_alloc(type_obst, sizeof(parameter1[0])); - memset(parameter1, 0, sizeof(parameter1[0])); - parameter1->type = argument_type1; + function_parameter_t *const parameter2 = allocate_parameter(argument_type2); + function_parameter_t *const parameter1 = allocate_parameter(argument_type1); parameter1->next = parameter2; type_t *type = allocate_type_zero(TYPE_FUNCTION); @@ -6882,10 +6852,7 @@ static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1, */ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) { - function_parameter_t *parameter - = obstack_alloc(type_obst, sizeof(parameter[0])); - memset(parameter, 0, sizeof(parameter[0])); - parameter->type = argument_type; + function_parameter_t *const parameter = allocate_parameter(argument_type); type_t *type = allocate_type_zero(TYPE_FUNCTION); type->function.return_type = return_type; @@ -6894,6 +6861,19 @@ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) return identify_new_type(type); } +static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type) +{ + type_t *res = make_function_1_type(return_type, argument_type); + res->function.variadic = 1; + return res; +} + +/** + * Creates a return_type (func)(void) function type if not + * already exists. + * + * @param return_type the return type + */ static type_t *make_function_0_type(type_t *return_type) { type_t *type = allocate_type_zero(TYPE_FUNCTION); @@ -6904,40 +6884,24 @@ static type_t *make_function_0_type(type_t *return_type) } /** - * Creates a function type for some function like builtins. + * Creates a NO_RETURN return_type (func)(void) function type if not + * already exists. * - * @param symbol the symbol describing the builtin - */ -static type_t *get_builtin_symbol_type(symbol_t *symbol) -{ - switch (symbol->ID) { - case T___builtin_alloca: - return make_function_1_type(type_void_ptr, type_size_t); - case T___builtin_huge_val: - return make_function_0_type(type_double); - case T___builtin_inf: - return make_function_0_type(type_double); - case T___builtin_inff: - return make_function_0_type(type_float); - case T___builtin_infl: - return make_function_0_type(type_long_double); - case T___builtin_nan: - return make_function_1_type(type_double, type_char_ptr); - case T___builtin_nanf: - return make_function_1_type(type_float, type_char_ptr); - case T___builtin_nanl: - return make_function_1_type(type_long_double, type_char_ptr); - case T___builtin_va_end: - return make_function_1_type(type_void, type_valist); - case T___builtin_expect: - return make_function_2_type(type_long, type_long, type_long); - default: - internal_errorf(HERE, "not implemented builtin identifier found"); - } + * @param return_type the return type + */ +static type_t *make_function_0_type_noreturn(type_t *return_type) +{ + type_t *type = allocate_type_zero(TYPE_FUNCTION); + type->function.return_type = return_type; + type->function.parameters = NULL; + type->function.base.modifiers |= DM_NORETURN; + return type; + + return identify_new_type(type); } /** - * Performs automatic type cast as described in § 6.3.2.1. + * Performs automatic type cast as described in §6.3.2.1. * * @param orig_type the original type */ @@ -6961,7 +6925,7 @@ static type_t *automatic_type_conversion(type_t *orig_type) /** * reverts the automatic casts of array to pointer types and function - * to function-pointer types as defined § 6.3.2.1 + * to function-pointer types as defined §6.3.2.1 */ type_t *revert_automatic_type_conversion(const expression_t *expression) { @@ -6993,9 +6957,6 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) return type->pointer.points_to; } - case EXPR_BUILTIN_SYMBOL: - return get_builtin_symbol_type(expression->builtin_symbol.symbol); - case EXPR_ARRAY_ACCESS: { const expression_t *array_ref = expression->array_access.array_ref; type_t *type_left = skip_typeref(array_ref->base.type); @@ -7495,24 +7456,8 @@ end_error: return create_invalid_expression(); } -static expression_t *parse_builtin_symbol(void) -{ - expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_SYMBOL); - - symbol_t *symbol = token.v.symbol; - - expression->builtin_symbol.symbol = symbol; - next_token(); - - type_t *type = get_builtin_symbol_type(symbol); - type = automatic_type_conversion(type); - - expression->base.type = type; - return expression; -} - /** - * Parses a __builtin_constant() expression. + * Parses a __builtin_constant_p() expression. */ static expression_t *parse_builtin_constant(void) { @@ -7533,28 +7478,24 @@ end_error: } /** - * Parses a __builtin_prefetch() expression. + * Parses a __builtin_types_compatible_p() expression. */ -static expression_t *parse_builtin_prefetch(void) +static expression_t *parse_builtin_types_compatible(void) { - expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_PREFETCH); + expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_TYPES_COMPATIBLE_P); - eat(T___builtin_prefetch); + eat(T___builtin_types_compatible_p); expect('(', end_error); add_anchor_token(')'); - expression->builtin_prefetch.adr = parse_assignment_expression(); - if (token.type == ',') { - next_token(); - expression->builtin_prefetch.rw = parse_assignment_expression(); - } - if (token.type == ',') { - next_token(); - expression->builtin_prefetch.locality = parse_assignment_expression(); - } + add_anchor_token(','); + expression->builtin_types_compatible.left = parse_typename(); + rem_anchor_token(','); + expect(',', end_error); + expression->builtin_types_compatible.right = parse_typename(); rem_anchor_token(')'); expect(')', end_error); - expression->base.type = type_void; + expression->base.type = type_int; return expression; end_error: @@ -7773,49 +7714,39 @@ end_error: static expression_t *parse_primary_expression(void) { switch (token.type) { - case T_false: return parse_bool_const(false); - case T_true: return parse_bool_const(true); - case T_INTEGER: return parse_int_const(); - case T_CHARACTER_CONSTANT: return parse_character_constant(); - case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant(); - case T_FLOATINGPOINT: return parse_float_const(); + case T_false: return parse_bool_const(false); + case T_true: return parse_bool_const(true); + case T_INTEGER: return parse_int_const(); + case T_CHARACTER_CONSTANT: return parse_character_constant(); + case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant(); + case T_FLOATINGPOINT: return parse_float_const(); case T_STRING_LITERAL: - case T_WIDE_STRING_LITERAL: return parse_string_const(); - case T_IDENTIFIER: return parse_reference(); + case T_WIDE_STRING_LITERAL: return parse_string_const(); + case T_IDENTIFIER: return parse_reference(); case T___FUNCTION__: - case T___func__: return parse_function_keyword(); - case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword(); - case T___FUNCSIG__: return parse_funcsig_keyword(); - case T___FUNCDNAME__: return parse_funcdname_keyword(); - case T___builtin_offsetof: return parse_offsetof(); - case T___builtin_va_start: return parse_va_start(); - case T___builtin_va_arg: return parse_va_arg(); - case T___builtin_expect: - case T___builtin_alloca: - case T___builtin_inf: - case T___builtin_inff: - case T___builtin_infl: - case T___builtin_nan: - case T___builtin_nanf: - case T___builtin_nanl: - case T___builtin_huge_val: - case T___builtin_va_end: return parse_builtin_symbol(); + case T___func__: return parse_function_keyword(); + case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword(); + case T___FUNCSIG__: return parse_funcsig_keyword(); + case T___FUNCDNAME__: return parse_funcdname_keyword(); + case T___builtin_offsetof: return parse_offsetof(); + case T___builtin_va_start: return parse_va_start(); + case T___builtin_va_arg: return parse_va_arg(); case T___builtin_isgreater: case T___builtin_isgreaterequal: case T___builtin_isless: case T___builtin_islessequal: case T___builtin_islessgreater: - case T___builtin_isunordered: return parse_compare_builtin(); - case T___builtin_constant_p: return parse_builtin_constant(); - case T___builtin_prefetch: return parse_builtin_prefetch(); - case T__assume: return parse_assume(); + case T___builtin_isunordered: return parse_compare_builtin(); + case T___builtin_constant_p: return parse_builtin_constant(); + case T___builtin_types_compatible_p: return parse_builtin_types_compatible(); + case T__assume: return parse_assume(); case T_ANDAND: if (GNU_MODE) return parse_label_address(); break; - case '(': return parse_parenthesized_expression(); - case T___noop: return parse_noop_expression(); + case '(': return parse_parenthesized_expression(); + case T___noop: return parse_noop_expression(); } errorf(HERE, "unexpected token %K, expected an expression", &token); @@ -8091,6 +8022,51 @@ static void check_call_argument(const function_parameter_t *parameter, } } +/** + * Handle the semantic restrictions of builtin calls + */ +static void handle_builtin_argument_restrictions(call_expression_t *call) { + switch (call->function->reference.entity->function.btk) { + case bk_gnu_builtin_return_address: + case bk_gnu_builtin_frame_address: { + /* argument must be constant */ + call_argument_t *argument = call->arguments; + + if (! is_constant_expression(argument->expression)) { + errorf(&call->base.source_position, + "argument of '%Y' must be a constant expression", + call->function->reference.entity->base.symbol); + } + break; + } + case bk_gnu_builtin_prefetch: { + /* second and third argument must be constant if existent */ + call_argument_t *rw = call->arguments->next; + call_argument_t *locality = NULL; + + if (rw != NULL) { + if (! is_constant_expression(rw->expression)) { + errorf(&call->base.source_position, + "second argument of '%Y' must be a constant expression", + call->function->reference.entity->base.symbol); + } + locality = rw->next; + } + if (locality != NULL) { + if (! is_constant_expression(locality->expression)) { + errorf(&call->base.source_position, + "third argument of '%Y' must be a constant expression", + call->function->reference.entity->base.symbol); + } + locality = rw->next; + } + break; + } + default: + break; + } +} + /** * Parse a call expression, ie. expression '( ... )'. * @@ -8125,18 +8101,13 @@ static expression_t *parse_call_expression(expression_t *expression) add_anchor_token(','); if (token.type != ')') { - call_argument_t *last_argument = NULL; - - while (true) { - call_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); - + call_argument_t **anchor = &call->arguments; + for (;;) { + call_argument_t *argument = allocate_ast_zero(sizeof(*argument)); argument->expression = parse_assignment_expression(); - if (last_argument == NULL) { - call->arguments = argument; - } else { - last_argument->next = argument; - } - last_argument = argument; + + *anchor = argument; + anchor = &argument->next; if (token.type != ',') break; @@ -8183,6 +8154,13 @@ static expression_t *parse_call_expression(expression_t *expression) "function call has aggregate value"); } + if (call->function->kind == EXPR_REFERENCE) { + reference_expression_t *reference = &call->function->reference; + if (reference->entity->kind == ENTITY_FUNCTION && + reference->entity->function.btk != bk_none) + handle_builtin_argument_restrictions(call); + } + end_error: return result; } @@ -8772,7 +8750,7 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) type_left = get_unqualified_type(type_left); type_right = get_unqualified_type(type_right); - /* § 6.3.1.8 Usual arithmetic conversions */ + /* §6.3.1.8 Usual arithmetic conversions */ if (type_left == type_long_double || type_right == type_long_double) { return type_long_double; } else if (type_left == type_double || type_right == type_double) { @@ -8874,7 +8852,8 @@ static void warn_div_by_zero(binary_expression_t const *const expression) /** * Check the semantic restrictions for a div/mod expression. */ -static void semantic_divmod_arithmetic(binary_expression_t *expression) { +static void semantic_divmod_arithmetic(binary_expression_t *expression) +{ semantic_binexpr_arithmetic(expression); warn_div_by_zero(expression); } @@ -8935,7 +8914,7 @@ static void semantic_add(binary_expression_t *expression) type_t *const type_left = skip_typeref(orig_type_left); type_t *const type_right = skip_typeref(orig_type_right); - /* § 6.5.6 */ + /* §6.5.6 */ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) { type_t *arithmetic_type = semantic_arithmetic(type_left, type_right); expression->left = create_implicit_cast(left, arithmetic_type); @@ -8966,7 +8945,7 @@ static void semantic_sub(binary_expression_t *expression) type_t *const type_right = skip_typeref(orig_type_right); source_position_t const *const pos = &expression->base.source_position; - /* § 5.6.5 */ + /* §5.6.5 */ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) { type_t *arithmetic_type = semantic_arithmetic(type_left, type_right); expression->left = create_implicit_cast(left, arithmetic_type); @@ -9310,64 +9289,64 @@ static void semantic_binexpr_assign(binary_expression_t *expression) static bool expression_has_effect(const expression_t *const expr) { switch (expr->kind) { - case EXPR_UNKNOWN: break; - case EXPR_INVALID: return true; /* do NOT warn */ - case EXPR_REFERENCE: return false; - case EXPR_REFERENCE_ENUM_VALUE: return false; + case EXPR_UNKNOWN: break; + case EXPR_INVALID: return true; /* do NOT warn */ + case EXPR_REFERENCE: return false; + case EXPR_REFERENCE_ENUM_VALUE: return false; /* suppress the warning for microsoft __noop operations */ - case EXPR_CONST: return expr->conste.is_ms_noop; - case EXPR_CHARACTER_CONSTANT: return false; - case EXPR_WIDE_CHARACTER_CONSTANT: return false; - case EXPR_STRING_LITERAL: return false; - case EXPR_WIDE_STRING_LITERAL: return false; - case EXPR_LABEL_ADDRESS: return false; + case EXPR_CONST: return expr->conste.is_ms_noop; + case EXPR_CHARACTER_CONSTANT: return false; + case EXPR_WIDE_CHARACTER_CONSTANT: return false; + case EXPR_STRING_LITERAL: return false; + case EXPR_WIDE_STRING_LITERAL: return false; + case EXPR_LABEL_ADDRESS: return false; case EXPR_CALL: { const call_expression_t *const call = &expr->call; - if (call->function->kind != EXPR_BUILTIN_SYMBOL) + if (call->function->kind != EXPR_REFERENCE) return true; - switch (call->function->builtin_symbol.symbol->ID) { - case T___builtin_va_end: return true; - default: return false; + switch (call->function->reference.entity->function.btk) { + /* FIXME: which builtins have no effect? */ + default: return true; } } /* Generate the warning if either the left or right hand side of a * conditional expression has no effect */ case EXPR_CONDITIONAL: { - const conditional_expression_t *const cond = &expr->conditional; + conditional_expression_t const *const cond = &expr->conditional; + expression_t const *const t = cond->true_expression; return - expression_has_effect(cond->true_expression) && + (t == NULL || expression_has_effect(t)) && expression_has_effect(cond->false_expression); } - case EXPR_SELECT: return false; - case EXPR_ARRAY_ACCESS: return false; - case EXPR_SIZEOF: return false; - case EXPR_CLASSIFY_TYPE: return false; - case EXPR_ALIGNOF: return false; - - case EXPR_FUNCNAME: return false; - case EXPR_BUILTIN_SYMBOL: break; /* handled in EXPR_CALL */ - case EXPR_BUILTIN_CONSTANT_P: return false; - case EXPR_BUILTIN_PREFETCH: return true; - case EXPR_OFFSETOF: return false; - case EXPR_VA_START: return true; - case EXPR_VA_ARG: return true; - case EXPR_STATEMENT: return true; // TODO - case EXPR_COMPOUND_LITERAL: return false; - - case EXPR_UNARY_NEGATE: return false; - case EXPR_UNARY_PLUS: return false; - case EXPR_UNARY_BITWISE_NEGATE: return false; - case EXPR_UNARY_NOT: return false; - case EXPR_UNARY_DEREFERENCE: return false; - case EXPR_UNARY_TAKE_ADDRESS: return false; - case EXPR_UNARY_POSTFIX_INCREMENT: return true; - case EXPR_UNARY_POSTFIX_DECREMENT: return true; - case EXPR_UNARY_PREFIX_INCREMENT: return true; - case EXPR_UNARY_PREFIX_DECREMENT: return true; + case EXPR_SELECT: return false; + case EXPR_ARRAY_ACCESS: return false; + case EXPR_SIZEOF: return false; + case EXPR_CLASSIFY_TYPE: return false; + case EXPR_ALIGNOF: return false; + + case EXPR_FUNCNAME: return false; + case EXPR_BUILTIN_CONSTANT_P: return false; + case EXPR_BUILTIN_TYPES_COMPATIBLE_P: return false; + case EXPR_OFFSETOF: return false; + case EXPR_VA_START: return true; + case EXPR_VA_ARG: return true; + case EXPR_STATEMENT: return true; // TODO + case EXPR_COMPOUND_LITERAL: return false; + + case EXPR_UNARY_NEGATE: return false; + case EXPR_UNARY_PLUS: return false; + case EXPR_UNARY_BITWISE_NEGATE: return false; + case EXPR_UNARY_NOT: return false; + case EXPR_UNARY_DEREFERENCE: return false; + case EXPR_UNARY_TAKE_ADDRESS: return false; + case EXPR_UNARY_POSTFIX_INCREMENT: return true; + case EXPR_UNARY_POSTFIX_DECREMENT: return true; + case EXPR_UNARY_PREFIX_INCREMENT: return true; + case EXPR_UNARY_PREFIX_DECREMENT: return true; /* Treat void casts as if they have an effect in order to being able to * suppress the warning */ @@ -9376,39 +9355,39 @@ static bool expression_has_effect(const expression_t *const expr) return is_type_atomic(type, ATOMIC_TYPE_VOID); } - case EXPR_UNARY_CAST_IMPLICIT: return true; - case EXPR_UNARY_ASSUME: return true; - case EXPR_UNARY_DELETE: return true; - case EXPR_UNARY_DELETE_ARRAY: return true; - case EXPR_UNARY_THROW: return true; - - case EXPR_BINARY_ADD: return false; - case EXPR_BINARY_SUB: return false; - case EXPR_BINARY_MUL: return false; - case EXPR_BINARY_DIV: return false; - case EXPR_BINARY_MOD: return false; - case EXPR_BINARY_EQUAL: return false; - case EXPR_BINARY_NOTEQUAL: return false; - case EXPR_BINARY_LESS: return false; - case EXPR_BINARY_LESSEQUAL: return false; - case EXPR_BINARY_GREATER: return false; - case EXPR_BINARY_GREATEREQUAL: return false; - case EXPR_BINARY_BITWISE_AND: return false; - case EXPR_BINARY_BITWISE_OR: return false; - case EXPR_BINARY_BITWISE_XOR: return false; - case EXPR_BINARY_SHIFTLEFT: return false; - case EXPR_BINARY_SHIFTRIGHT: return false; - case EXPR_BINARY_ASSIGN: return true; - case EXPR_BINARY_MUL_ASSIGN: return true; - case EXPR_BINARY_DIV_ASSIGN: return true; - case EXPR_BINARY_MOD_ASSIGN: return true; - case EXPR_BINARY_ADD_ASSIGN: return true; - case EXPR_BINARY_SUB_ASSIGN: return true; - case EXPR_BINARY_SHIFTLEFT_ASSIGN: return true; - case EXPR_BINARY_SHIFTRIGHT_ASSIGN: return true; - case EXPR_BINARY_BITWISE_AND_ASSIGN: return true; - case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true; - case EXPR_BINARY_BITWISE_OR_ASSIGN: return true; + case EXPR_UNARY_CAST_IMPLICIT: return true; + case EXPR_UNARY_ASSUME: return true; + case EXPR_UNARY_DELETE: return true; + case EXPR_UNARY_DELETE_ARRAY: return true; + case EXPR_UNARY_THROW: return true; + + case EXPR_BINARY_ADD: return false; + case EXPR_BINARY_SUB: return false; + case EXPR_BINARY_MUL: return false; + case EXPR_BINARY_DIV: return false; + case EXPR_BINARY_MOD: return false; + case EXPR_BINARY_EQUAL: return false; + case EXPR_BINARY_NOTEQUAL: return false; + case EXPR_BINARY_LESS: return false; + case EXPR_BINARY_LESSEQUAL: return false; + case EXPR_BINARY_GREATER: return false; + case EXPR_BINARY_GREATEREQUAL: return false; + case EXPR_BINARY_BITWISE_AND: return false; + case EXPR_BINARY_BITWISE_OR: return false; + case EXPR_BINARY_BITWISE_XOR: return false; + case EXPR_BINARY_SHIFTLEFT: return false; + case EXPR_BINARY_SHIFTRIGHT: return false; + case EXPR_BINARY_ASSIGN: return true; + case EXPR_BINARY_MUL_ASSIGN: return true; + case EXPR_BINARY_DIV_ASSIGN: return true; + case EXPR_BINARY_MOD_ASSIGN: return true; + case EXPR_BINARY_ADD_ASSIGN: return true; + case EXPR_BINARY_SUB_ASSIGN: return true; + case EXPR_BINARY_SHIFTLEFT_ASSIGN: return true; + case EXPR_BINARY_SHIFTRIGHT_ASSIGN: return true; + case EXPR_BINARY_BITWISE_AND_ASSIGN: return true; + case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true; + case EXPR_BINARY_BITWISE_OR_ASSIGN: return true; /* Only examine the right hand side of && and ||, because the left hand * side already has the effect of controlling the execution of the right @@ -9420,12 +9399,12 @@ static bool expression_has_effect(const expression_t *const expr) case EXPR_BINARY_COMMA: return expression_has_effect(expr->binary.right); - case EXPR_BINARY_ISGREATER: return false; - case EXPR_BINARY_ISGREATEREQUAL: return false; - case EXPR_BINARY_ISLESS: return false; - case EXPR_BINARY_ISLESSEQUAL: return false; - case EXPR_BINARY_ISLESSGREATER: return false; - case EXPR_BINARY_ISUNORDERED: return false; + case EXPR_BINARY_ISGREATER: return false; + case EXPR_BINARY_ISGREATEREQUAL: return false; + case EXPR_BINARY_ISLESS: return false; + case EXPR_BINARY_ISLESSEQUAL: return false; + case EXPR_BINARY_ISLESSGREATER: return false; + case EXPR_BINARY_ISUNORDERED: return false; } internal_errorf(HERE, "unexpected expression"); @@ -10079,7 +10058,8 @@ end_error: * * @param statement the switch statement to check */ -static void check_enum_cases(const switch_statement_t *statement) { +static void check_enum_cases(const switch_statement_t *statement) +{ const type_t *type = skip_typeref(statement->expression->base.type); if (! is_type_enum(type)) return; @@ -10572,12 +10552,11 @@ static statement_t *parse_declaration_statement(void) parse_declaration(record_entity, DECL_FLAGS_NONE); } - if (before == NULL) { - statement->declaration.declarations_begin = current_scope->entities; - } else { - statement->declaration.declarations_begin = before->base.next; - } - statement->declaration.declarations_end = current_scope->last_entity; + declaration_statement_t *const decl = &statement->declaration; + entity_t *const begin = + before != NULL ? before->base.next : current_scope->entities; + decl->declarations_begin = begin; + decl->declarations_end = begin != NULL ? current_scope->last_entity : NULL; return statement; } @@ -10717,10 +10696,13 @@ static void parse_namespace_definition(void) next_token(); entity = get_entity(symbol, NAMESPACE_NORMAL); - if (entity != NULL && entity->kind != ENTITY_NAMESPACE - && entity->base.parent_scope == current_scope) { - error_redefined_as_different_kind(&token.source_position, - entity, ENTITY_NAMESPACE); + if (entity != NULL && + entity->kind != ENTITY_NAMESPACE && + entity->base.parent_scope == current_scope) { + if (!is_error_entity(entity)) { + error_redefined_as_different_kind(&token.source_position, + entity, ENTITY_NAMESPACE); + } entity = NULL; } } @@ -11341,6 +11323,10 @@ void start_parsing(void) assert(current_scope == NULL); scope_push(&unit->scope); + + create_gnu_builtins(); + if (c_mode & _MS) + create_microsoft_intrinsics(); } translation_unit_t *finish_parsing(void) @@ -11360,8 +11346,8 @@ translation_unit_t *finish_parsing(void) return result; } -/* GCC allows global arrays without size and assigns them a length of one, - * if no different declaration follows */ +/* §6.9.2:2 and §6.9.2:5: At the end of the translation incomplete arrays + * are given length one. */ static void complete_incomplete_arrays(void) { size_t n = ARR_LEN(incomplete_arrays); @@ -11404,6 +11390,103 @@ void parse(void) incomplete_arrays = NULL; } +/** + * create a builtin function. + */ +static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type) +{ + symbol_t *symbol = symbol_table_insert(name); + entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION); + entity->declaration.storage_class = STORAGE_CLASS_EXTERN; + entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN; + entity->declaration.type = function_type; + entity->declaration.implicit = true; + entity->base.symbol = symbol; + entity->base.source_position = builtin_source_position; + + entity->function.btk = kind; + + record_entity(entity, /*is_definition=*/false); + return entity; +} + + +/** + * Create predefined gnu builtins. + */ +static void create_gnu_builtins(void) +{ +#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b) + + GNU_BUILTIN(alloca, make_function_1_type(type_void_ptr, type_size_t)); + GNU_BUILTIN(huge_val, make_function_0_type(type_double)); + GNU_BUILTIN(inf, make_function_0_type(type_double)); + GNU_BUILTIN(inff, make_function_0_type(type_float)); + GNU_BUILTIN(infl, make_function_0_type(type_long_double)); + GNU_BUILTIN(nan, make_function_1_type(type_double, type_char_ptr)); + GNU_BUILTIN(nanf, make_function_1_type(type_float, type_char_ptr)); + GNU_BUILTIN(nanl, make_function_1_type(type_long_double, type_char_ptr)); + GNU_BUILTIN(va_end, make_function_1_type(type_void, type_valist)); + GNU_BUILTIN(expect, make_function_2_type(type_long, type_long, type_long)); + GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int)); + GNU_BUILTIN(frame_address, make_function_1_type(type_void_ptr, type_unsigned_int)); + GNU_BUILTIN(ffs, make_function_1_type(type_int, type_unsigned_int)); + GNU_BUILTIN(clz, make_function_1_type(type_int, type_unsigned_int)); + GNU_BUILTIN(ctz, make_function_1_type(type_int, type_unsigned_int)); + GNU_BUILTIN(popcount, make_function_1_type(type_int, type_unsigned_int)); + GNU_BUILTIN(parity, make_function_1_type(type_int, type_unsigned_int)); + GNU_BUILTIN(prefetch, make_function_1_type_variadic(type_float, type_void_ptr)); + GNU_BUILTIN(trap, make_function_0_type_noreturn(type_void)); + +#undef GNU_BUILTIN +} + +/** + * Create predefined MS intrinsics. + */ +static void create_microsoft_intrinsics(void) +{ +#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b) + + /* intrinsics for all architectures */ + MS_BUILTIN(_rotl, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int)); + MS_BUILTIN(_rotr, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int)); + MS_BUILTIN(_rotl64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int)); + MS_BUILTIN(_rotr64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int)); + MS_BUILTIN(_byteswap_ushort, make_function_1_type(type_unsigned_short, type_unsigned_short)); + MS_BUILTIN(_byteswap_ulong, make_function_1_type(type_unsigned_long, type_unsigned_long)); + MS_BUILTIN(_byteswap_uint64, make_function_1_type(type_unsigned_int64, type_unsigned_int64)); + + MS_BUILTIN(__debugbreak, make_function_0_type(type_void)); + MS_BUILTIN(_ReturnAddress, make_function_0_type(type_void_ptr)); + MS_BUILTIN(__popcount, make_function_1_type(type_unsigned_int, type_unsigned_int)); + + /* x86/x64 only */ + MS_BUILTIN(_enable, make_function_0_type(type_void)); + MS_BUILTIN(_disable, make_function_0_type(type_void)); + MS_BUILTIN(__inbyte, make_function_1_type(type_unsigned_char, type_unsigned_short)); + MS_BUILTIN(__inword, make_function_1_type(type_unsigned_short, type_unsigned_short)); + MS_BUILTIN(__indword, make_function_1_type(type_unsigned_long, type_unsigned_short)); + MS_BUILTIN(__outbyte, make_function_2_type(type_void, type_unsigned_short, type_unsigned_char)); + MS_BUILTIN(__outword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_short)); + MS_BUILTIN(__outdword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_long)); + MS_BUILTIN(__ud2, make_function_0_type_noreturn(type_void)); + MS_BUILTIN(_BitScanForward, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long)); + MS_BUILTIN(_BitScanReverse, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long)); + MS_BUILTIN(_InterlockedExchange, make_function_2_type(type_long, type_long_ptr, type_long)); + MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64)); + + if (machine_size <= 32) { + MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int)); + MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int)); + } else { + MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int64)); + MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int64)); + } + +#undef MS_BUILTIN +} + /** * Initialize the parser. */