X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=808f75072bb4c6f1ecc872083a8a683c24c246a7;hb=46ef2e565f46ee5876872ef250796e428c3ac6df;hp=5022ed4db0db08c45c52170ac046f8639ed9a684;hpb=0fe6fe13c95274afdd4675ec3fa953ccec868789;p=cparser diff --git a/parser.c b/parser.c index 5022ed4..808f750 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; @@ -58,14 +58,14 @@ struct argument_list_t { typedef struct gnu_attribute_t gnu_attribute_t; struct gnu_attribute_t { - gnu_attribute_kind_t kind; /**< The kind of the GNU attribute. */ + gnu_attribute_kind_t kind; /**< The kind of the GNU attribute. */ gnu_attribute_t *next; - bool invalid; /**< Set if this attribute had argument errors, */ - bool have_arguments; /**< True, if this attribute has arguments. */ + bool invalid; /**< Set if this attribute had argument errors, */ + bool has_arguments; /**< True, if this attribute has arguments. */ union { size_t value; string_t string; - atomic_type_kind_t akind; + symbol_t *symbol; long argument; /**< Single argument. */ argument_list_t *arguments; /**< List of argument expressions. */ } u; @@ -113,7 +113,7 @@ static token_t token; /** The lookahead ring-buffer. */ static token_t lookahead_buffer[MAX_LOOKAHEAD]; /** Position of the next token in the lookahead buffer. */ -static int lookahead_bufpos; +static size_t lookahead_bufpos; static stack_entry_t *environment_stack = NULL; static stack_entry_t *label_stack = NULL; static scope_t *file_scope = NULL; @@ -351,7 +351,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 +396,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 +409,33 @@ 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_SYMBOL] = sizeof(builtin_symbol_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 +443,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 +526,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]; @@ -562,7 +562,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]; } @@ -579,14 +579,6 @@ static initializer_t *allocate_initializer_zero(initializer_kind_t kind) return result; } -/** - * Free a type from the type obstack. - */ -static void free_type(void *type) -{ - obstack_free(type_obst, type); -} - /** * Returns the index of the top element of the environment stack. */ @@ -612,7 +604,7 @@ static inline void next_token(void) lookahead_buffer[lookahead_bufpos] = lexer_token; lexer_next_token(); - lookahead_bufpos = (lookahead_bufpos+1) % MAX_LOOKAHEAD; + lookahead_bufpos = (lookahead_bufpos + 1) % MAX_LOOKAHEAD; #ifdef PRINT_TOKENS print_token(stderr, &token); @@ -623,10 +615,10 @@ static inline void next_token(void) /** * Return the next token with a given lookahead. */ -static inline const token_t *look_ahead(int num) +static inline const token_t *look_ahead(size_t num) { - assert(num > 0 && num <= MAX_LOOKAHEAD); - int pos = (lookahead_bufpos+num-1) % MAX_LOOKAHEAD; + assert(0 < num && num <= MAX_LOOKAHEAD); + size_t pos = (lookahead_bufpos + num - 1) % MAX_LOOKAHEAD; return &lookahead_buffer[pos]; } @@ -757,7 +749,7 @@ static void eat_block(void) next_token(); } -#define eat(token_type) do { assert(token.type == (token_type)); next_token(); } while (0) +#define eat(token_type) (assert(token.type == (token_type)), next_token()) /** * Report a parse error because an expected token was not found. @@ -977,13 +969,8 @@ static int get_akind_rank(atomic_type_kind_t akind) static int get_rank(const type_t *type) { assert(!is_typeref(type)); - /* The C-standard allows promoting enums to int or unsigned int (see § 7.2.2 - * and esp. footnote 108). However we can't fold constants (yet), so we - * can't decide whether unsigned int is possible, while int always works. - * (unsigned int would be preferable when possible... for stuff like - * struct { enum { ... } bla : 4; } ) */ if (type->kind == TYPE_ENUM) - return get_akind_rank(ATOMIC_TYPE_INT); + return get_akind_rank(type->enumt.akind); assert(type->kind == TYPE_ATOMIC); return get_akind_rank(type->atomic.akind); @@ -1133,7 +1120,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) { @@ -1324,7 +1311,7 @@ static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) attribute->kind = kind; attribute->next = NULL; attribute->invalid = false; - attribute->have_arguments = false; + attribute->has_arguments = false; return attribute; } @@ -1473,35 +1460,13 @@ static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute) */ static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute) { - /* TODO: find out what is allowed here... */ - - /* at least: byte, word, pointer, list of machine modes - * __XXX___ is interpreted as XXX */ add_anchor_token(')'); if (token.type != T_IDENTIFIER) { expect(T_IDENTIFIER, end_error); } - /* This isn't really correct, the backend should provide a list of machine - * specific modes (according to gcc philosophy that is...) */ - const char *symbol_str = token.v.symbol->string; - if (strcmp_underscore("QI", symbol_str) == 0 || - strcmp_underscore("byte", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_CHAR; - } else if (strcmp_underscore("HI", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_SHORT; - } else if (strcmp_underscore("SI", symbol_str) == 0 - || strcmp_underscore("word", symbol_str) == 0 - || strcmp_underscore("pointer", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_INT; - } else if (strcmp_underscore("DI", symbol_str) == 0) { - attribute->u.akind = ATOMIC_TYPE_LONGLONG; - } else { - if (warning.other) - warningf(HERE, "ignoring unknown mode '%s'", symbol_str); - attribute->invalid = true; - } + attribute->u.symbol = token.v.symbol; next_token(); rem_anchor_token(')'); @@ -1587,7 +1552,7 @@ end_error: */ static void check_no_argument(gnu_attribute_t *attribute, const char *name) { - if (!attribute->have_arguments) + if (!attribute->has_arguments) return; /* should have no arguments */ @@ -1737,7 +1702,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) /* empty args are allowed */ next_token(); } else - attribute->have_arguments = true; + attribute->has_arguments = true; } switch (kind) { @@ -1796,7 +1761,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_ALIGNED: /* __align__ may be used without an argument */ - if (attribute->have_arguments) { + if (attribute->has_arguments) { parse_gnu_attribute_const_arg(attribute); } break; @@ -1804,7 +1769,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_FORMAT_ARG: case GNU_AK_REGPARM: case GNU_AK_TRAP_EXIT: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); attribute->invalid = true; @@ -1814,7 +1779,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_ALIAS: case GNU_AK_SECTION: case GNU_AK_SP_SWITCH: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); attribute->invalid = true; @@ -1822,7 +1787,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) parse_gnu_attribute_string_arg(attribute, &attribute->u.string); break; case GNU_AK_FORMAT: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); attribute->invalid = true; @@ -1831,29 +1796,29 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) break; case GNU_AK_WEAKREF: /* may have one string argument */ - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_string_arg(attribute, &attribute->u.string); break; case GNU_AK_NONNULL: - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_const_arg_list(attribute); break; case GNU_AK_TLS_MODEL: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else parse_gnu_attribute_tls_model_arg(attribute); break; case GNU_AK_VISIBILITY: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else parse_gnu_attribute_visibility_arg(attribute); break; case GNU_AK_MODEL: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else { @@ -1861,7 +1826,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) } break; case GNU_AK_MODE: - if (!attribute->have_arguments) { + if (!attribute->has_arguments) { /* should have arguments */ errorf(HERE, "wrong number of arguments specified for '%s' attribute", name); } else { @@ -1870,12 +1835,12 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) break; case GNU_AK_INTERRUPT: /* may have one string argument */ - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_interrupt_arg(attribute); break; case GNU_AK_SENTINEL: /* may have one string argument */ - if (attribute->have_arguments) + if (attribute->has_arguments) parse_gnu_attribute_const_arg(attribute); break; case GNU_AK_LAST: @@ -2174,7 +2139,7 @@ unary: 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: @@ -2264,7 +2229,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); @@ -2282,6 +2247,7 @@ static initializer_t *initializer_from_expression(type_t *orig_type, return initializer_from_string(array_type, &expression->string.value); } + break; case EXPR_WIDE_STRING_LITERAL: { type_t *bare_wchar_type = skip_typeref(type_wchar_t); @@ -2289,6 +2255,7 @@ static initializer_t *initializer_from_expression(type_t *orig_type, return initializer_from_wide_string(array_type, &expression->wide_string.value); } + break; } default: @@ -2326,7 +2293,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) @@ -2942,7 +2909,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) { @@ -3175,6 +3142,7 @@ static type_t *parse_enum_specifier(void) type_t *const type = allocate_type_zero(TYPE_ENUM); type->enumt.enume = &entity->enume; + type->enumt.akind = ATOMIC_TYPE_INT; if (token.type == '{') { if (symbol != NULL) { @@ -3233,7 +3201,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; @@ -3289,13 +3257,7 @@ static type_t *create_builtin_type(symbol_t *const symbol, type_t *type = allocate_type_zero(TYPE_BUILTIN); type->builtin.symbol = symbol; type->builtin.real_type = real_type; - - type_t *result = typehash_insert(type); - if (type != result) { - free_type(type); - } - - return result; + return identify_new_type(type); } static type_t *get_typedef_type(symbol_t *symbol) @@ -3624,6 +3586,78 @@ static void finish_union_type(compound_type_t *type) type->base.alignment = alignment; } +static type_t *handle_attribute_mode(const gnu_attribute_t *attribute, + type_t *orig_type) +{ + type_t *type = skip_typeref(orig_type); + + /* at least: byte, word, pointer, list of machine modes + * __XXX___ is interpreted as XXX */ + + /* This isn't really correct, the backend should provide a list of machine + * specific modes (according to gcc philosophy that is...) */ + const char *symbol_str = attribute->u.symbol->string; + bool sign = is_type_signed(type); + atomic_type_kind_t akind; + if (strcmp_underscore("QI", symbol_str) == 0 || + strcmp_underscore("byte", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR; + } else if (strcmp_underscore("HI", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT; + } else if (strcmp_underscore("SI", symbol_str) == 0 + || strcmp_underscore("word", symbol_str) == 0 + || strcmp_underscore("pointer", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT; + } else if (strcmp_underscore("DI", symbol_str) == 0) { + akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG; + } else { + if (warning.other) + warningf(HERE, "ignoring unknown mode '%s'", symbol_str); + return orig_type; + } + + if (type->kind == TYPE_ATOMIC) { + type_t *copy = duplicate_type(type); + copy->atomic.akind = akind; + return identify_new_type(copy); + } else if (type->kind == TYPE_ENUM) { + type_t *copy = duplicate_type(type); + copy->enumt.akind = akind; + return identify_new_type(copy); + } else if (is_type_pointer(type)) { + warningf(HERE, "__attribute__((mode)) on pointers not implemented yet (ignored)"); + return type; + } + + errorf(HERE, "__attribute__((mode)) only allowed on integer, enum or pointer type"); + return orig_type; +} + +static type_t *handle_type_attributes(const gnu_attribute_t *attributes, + type_t *type) +{ + const gnu_attribute_t *attribute = attributes; + for ( ; attribute != NULL; attribute = attribute->next) { + if (attribute->invalid) + continue; + + if (attribute->kind == GNU_AK_MODE) { + type = handle_attribute_mode(attribute, type); + } else if (attribute->kind == GNU_AK_ALIGNED) { + int alignment = 32; /* TODO: fill in maximum useful alignment for + target machine */ + if (attribute->has_arguments) + alignment = attribute->u.argument; + + type_t *copy = duplicate_type(type); + copy->base.alignment = attribute->u.argument; + type = identify_new_type(copy); + } + } + + return type; +} + static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) { type_t *type = NULL; @@ -3639,8 +3673,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) while (true) { specifiers->modifiers |= parse_attributes(&specifiers->gnu_attributes); - if (specifiers->modifiers & DM_TRANSPARENT_UNION) - modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; switch (token.type) { /* storage class */ @@ -3861,6 +3893,9 @@ wrong_thread_stoarge_class: } finish_specifiers: + specifiers->modifiers + |= parse_attributes(&specifiers->gnu_attributes); + in_gcc_extension = old_gcc_extension; if (type == NULL || (saw_error && type_specifiers != 0)) { @@ -4035,9 +4070,13 @@ warn_about_long_long: type = allocate_type_zero(TYPE_IMAGINARY); type->imaginary.akind = atomic_type; } else { - type = allocate_type_zero(TYPE_ATOMIC); - type->atomic.akind = atomic_type; + type = allocate_type_zero(TYPE_ATOMIC); + type->atomic.akind = atomic_type; } + type->base.alignment = get_atomic_type_alignment(atomic_type); + unsigned const size = get_atomic_type_size(atomic_type); + type->base.size = + type_specifiers & SPECIFIER_COMPLEX ? size * 2 : size; newtype = true; } else if (type_specifiers != 0) { errorf(HERE, "multiple datatypes in declaration"); @@ -4045,15 +4084,19 @@ warn_about_long_long: /* FIXME: check type qualifiers here */ + if (specifiers->modifiers & DM_TRANSPARENT_UNION) + modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; type->base.qualifiers = qualifiers; type->base.modifiers = modifiers; - type_t *result = typehash_insert(type); - if (newtype && result != type) { - free_type(type); + if (newtype) { + type = identify_new_type(type); + } else { + type = typehash_insert(type); } - specifiers->type = result; + type = handle_type_attributes(specifiers->gnu_attributes, type); + specifiers->type = type; return; end_error: @@ -4553,34 +4596,28 @@ static void parse_declaration_attributes(entity_t *entity) if (type == NULL) return; - /* handle these strange/stupid mode attributes */ gnu_attribute_t *attribute = attributes; for ( ; attribute != NULL; attribute = attribute->next) { - if (attribute->kind != GNU_AK_MODE || attribute->invalid) + if (attribute->invalid) continue; - atomic_type_kind_t akind = attribute->u.akind; - if (!is_type_signed(type)) { - switch (akind) { - case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_UCHAR; break; - case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_USHORT; break; - case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_UINT; break; - case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_ULONGLONG; break; - default: - panic("invalid akind in mode attribute"); - } - } else { - switch (akind) { - case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_SCHAR; break; - case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_SHORT; break; - case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_INT; break; - case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_LONGLONG; break; - default: - panic("invalid akind in mode attribute"); + if (attribute->kind == GNU_AK_MODE) { + type = handle_attribute_mode(attribute, type); + } else if (attribute->kind == GNU_AK_ALIGNED) { + int alignment = 32; /* TODO: fill in maximum usefull alignment for target machine */ + if (attribute->has_arguments) + alignment = attribute->u.argument; + + if (entity->kind == ENTITY_TYPEDEF) { + type_t *copy = duplicate_type(type); + copy->base.alignment = attribute->u.argument; + type = identify_new_type(copy); + } else if(entity->kind == ENTITY_VARIABLE) { + entity->variable.alignment = alignment; + } else if(entity->kind == ENTITY_COMPOUND_MEMBER) { + entity->compound_member.alignment = alignment; } } - - type = make_atomic_type(akind, type->base.qualifiers); } type_modifiers_t type_modifiers = type->base.modifiers; @@ -4588,13 +4625,9 @@ static void parse_declaration_attributes(entity_t *entity) type_modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; if (type->base.modifiers != type_modifiers) { - type_t *copy = duplicate_type(type); + type_t *copy = duplicate_type(type); copy->base.modifiers = type_modifiers; - - type = typehash_insert(copy); - if (type != copy) { - obstack_free(type_obst, copy); - } + type = identify_new_type(copy); } if (entity->kind == ENTITY_TYPEDEF) { @@ -4622,7 +4655,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ function_type->function.return_type = type; type_t *skipped_return_type = skip_typeref(type); - /* §6.7.5.3(1) */ + /* §6.7.5.3:1 */ if (is_type_function(skipped_return_type)) { errorf(HERE, "function returning function is not allowed"); } else if (is_type_array(skipped_return_type)) { @@ -4684,7 +4717,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ } type_t *skipped_type = skip_typeref(type); - /* §6.7.5.2(1) */ + /* §6.7.5.2:1 */ if (is_type_incomplete(skipped_type)) { errorf(HERE, "array of incomplete type '%T' is not allowed", type); } else if (is_type_function(skipped_type)) { @@ -4695,14 +4728,12 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ } } - type_t *hashed_type = typehash_insert(type); - if (hashed_type != type) { - /* the function type was constructed earlier freeing it here will - * destroy other types... */ - if (iter->kind != CONSTRUCT_FUNCTION) { - free_type(type); - } - type = hashed_type; + /* 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); } } @@ -4826,10 +4857,6 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity->variable.get_property_sym = specifiers->get_property_sym; entity->variable.put_property_sym = specifiers->put_property_sym; - if (specifiers->alignment != 0) { - /* TODO: add checks here */ - entity->variable.alignment = specifiers->alignment; - } entity->variable.thread_local = specifiers->thread_local; @@ -4972,6 +4999,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 @@ -4986,7 +5023,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); @@ -5016,160 +5053,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) { @@ -5269,7 +5313,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; @@ -5327,11 +5371,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; } @@ -5495,6 +5537,9 @@ decl_list_end: 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) { @@ -5531,17 +5576,14 @@ decl_list_end: last_parameter = function_parameter; } - /* § 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; - type = typehash_insert(new_type); - if (type != new_type) { - obstack_free(type_obst, new_type); - } + new_type = identify_new_type(new_type); - entity->declaration.type = type; + entity->declaration.type = new_type; rem_anchor_token('{'); } @@ -5714,7 +5756,7 @@ static bool expression_returns(expression_t const *const expr) 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; @@ -6073,7 +6115,7 @@ found_break_parent: if (next == NULL) { noreturn_candidate = false; - type_t *const type = current_function->base.type; + type_t *const type = skip_typeref(current_function->base.type); assert(is_type_function(type)); type_t *const ret = skip_typeref(type->function.return_type); if (warning.return_type && @@ -6326,7 +6368,8 @@ static void parse_external_declaration(void) } assert(is_declaration(ndeclaration)); - type_t *type = skip_typeref(ndeclaration->declaration.type); + type_t *const orig_type = ndeclaration->declaration.type; + type_t * type = skip_typeref(orig_type); if (!is_type_function(type)) { if (is_type_valid(type)) { @@ -6335,6 +6378,11 @@ static void parse_external_declaration(void) } eat_block(); return; + } else if (is_typeref(orig_type)) { + /* §6.9.1:2 */ + errorf(&ndeclaration->base.source_position, + "type of function definition '%#T' is a typedef", + orig_type, ndeclaration->base.symbol); } if (warning.aggregate_return && @@ -6351,18 +6399,15 @@ 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 - && !type->function.kr_style_parameters) { - type_t *duplicate = duplicate_type(type); - duplicate->function.unspecified_parameters = false; + if (type->function.unspecified_parameters && + type->function.parameters == NULL && + !type->function.kr_style_parameters) { + type_t *copy = duplicate_type(type); + copy->function.unspecified_parameters = false; + type = identify_new_type(copy); - type = typehash_insert(duplicate); - if (type != duplicate) { - obstack_free(type_obst, duplicate); - } ndeclaration->declaration.type = type; } @@ -6803,11 +6848,7 @@ static entity_t *create_implicit_function(symbol_t *symbol, ntype->function.return_type = type_int; ntype->function.unspecified_parameters = true; ntype->function.linkage = LINKAGE_C; - - type_t *type = typehash_insert(ntype); - if (type != ntype) { - free_type(ntype); - } + type_t *type = identify_new_type(ntype); entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION); entity->declaration.storage_class = STORAGE_CLASS_EXTERN; @@ -6847,12 +6888,7 @@ static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1, type->function.return_type = return_type; type->function.parameters = parameter1; - type_t *result = typehash_insert(type); - if (result != type) { - free_type(type); - } - - return result; + return identify_new_type(type); } /** @@ -6873,26 +6909,29 @@ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) type->function.return_type = return_type; type->function.parameters = parameter; - type_t *result = typehash_insert(type); - if (result != type) { - free_type(type); - } + return identify_new_type(type); +} - return result; +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); type->function.return_type = return_type; type->function.parameters = NULL; - type_t *result = typehash_insert(type); - if (result != type) { - free_type(type); - } - - return result; + return identify_new_type(type); } /** @@ -6923,13 +6962,18 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol) return make_function_1_type(type_void, type_valist); case T___builtin_expect: return make_function_2_type(type_long, type_long, type_long); + case T___builtin_return_address: + case T___builtin_frame_address: + return make_function_1_type(type_void_ptr, type_unsigned_int); + case T___builtin_prefetch: + return make_function_1_type_variadic(type_float, type_void_ptr); default: internal_errorf(HERE, "not implemented builtin identifier found"); } } /** - * 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 */ @@ -6953,7 +6997,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) { @@ -7504,7 +7548,7 @@ static expression_t *parse_builtin_symbol(void) } /** - * Parses a __builtin_constant() expression. + * Parses a __builtin_constant_p() expression. */ static expression_t *parse_builtin_constant(void) { @@ -7525,28 +7569,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: @@ -7765,23 +7805,23 @@ 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___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: @@ -7791,23 +7831,26 @@ static expression_t *parse_primary_expression(void) case T___builtin_nanf: case T___builtin_nanl: case T___builtin_huge_val: - case T___builtin_va_end: return parse_builtin_symbol(); + case T___builtin_va_end: + case T___builtin_return_address: + case T___builtin_frame_address: + case T___builtin_prefetch: return parse_builtin_symbol(); 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); @@ -8083,6 +8126,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->builtin_symbol.symbol->ID) { + case T___builtin_return_address: + case T___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->builtin_symbol.symbol); + } + break; + } + case T___builtin_prefetch: { + /* second and third argument must be constant if existant */ + 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->builtin_symbol.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->builtin_symbol.symbol); + } + locality = rw->next; + } + break; + } + default: + break; + } +} + /** * Parse a call expression, ie. expression '( ... )'. * @@ -8175,6 +8263,10 @@ static expression_t *parse_call_expression(expression_t *expression) "function call has aggregate value"); } + if (call->function->kind == EXPR_BUILTIN_SYMBOL) { + handle_builtin_argument_restrictions(&result->call); + } + end_error: return result; } @@ -8540,7 +8632,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, static bool is_lvalue(const expression_t *expression) { - /* TODO: doesn't seem to be consistent with §6.3.2.1 (1) */ + /* TODO: doesn't seem to be consistent with §6.3.2.1:1 */ switch (expression->kind) { case EXPR_ARRAY_ACCESS: case EXPR_COMPOUND_LITERAL: @@ -8764,7 +8856,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) { @@ -8866,7 +8958,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); } @@ -8927,7 +9020,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); @@ -8958,7 +9051,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); @@ -9302,17 +9395,17 @@ 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; @@ -9320,46 +9413,48 @@ static bool expression_has_effect(const expression_t *const expr) return true; switch (call->function->builtin_symbol.symbol->ID) { - case T___builtin_va_end: return true; - default: return false; + case T___builtin_prefetch: + case T___builtin_va_end: return true; + default: return false; } } /* 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_SYMBOL: break; /* handled in EXPR_CALL */ + 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 */ @@ -9368,39 +9463,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 @@ -9412,12 +9507,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"); @@ -10071,7 +10166,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; @@ -10564,12 +10660,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; } @@ -10709,10 +10804,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; } } @@ -11352,8 +11450,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); @@ -11376,9 +11474,7 @@ static void complete_incomplete_arrays(void) new_type->array.has_implicit_size = true; new_type->array.size = 1; - type_t *const result = typehash_insert(new_type); - if (type != result) - free_type(type); + type_t *const result = identify_new_type(new_type); decl->type = result; }