X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=3323840b1005bfdbd67d3fa8144829e015150665;hb=8b02727be2ef5bf846b3efdaa9a7b34b68cf45e9;hp=b85ac28eb1a40aa2a8fbd0de5d2bf0bc6f596c84;hpb=134cb409e23b44ac9b9ac5d28f331b714bd58e39;p=cparser diff --git a/parser.c b/parser.c index b85ac28..3323840 100644 --- a/parser.c +++ b/parser.c @@ -1,13 +1,33 @@ +/* + * This file is part of cparser. + * Copyright (C) 2007-2008 Matthias Braun + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ #include #include #include #include +#include "parser.h" #include "diagnostic.h" #include "format_check.h" -#include "parser.h" #include "lexer.h" +#include "symbol_t.h" #include "token_t.h" #include "types.h" #include "type_t.h" @@ -31,7 +51,7 @@ typedef struct { typedef struct declaration_specifiers_t declaration_specifiers_t; struct declaration_specifiers_t { source_position_t source_position; - unsigned char storage_class; + unsigned char declared_storage_class; bool is_inline; decl_modifiers_t decl_modifiers; type_t *type; @@ -195,31 +215,32 @@ static statement_t *allocate_statement_zero(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_CONST] = sizeof(const_expression_t), - [EXPR_CHAR_CONST] = 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_FUNCTION] = sizeof(string_literal_expression_t), - [EXPR_PRETTY_FUNCTION] = sizeof(string_literal_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_INVALID] = sizeof(expression_base_t), + [EXPR_REFERENCE] = 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_FUNCTION] = sizeof(string_literal_expression_t), + [EXPR_PRETTY_FUNCTION] = sizeof(string_literal_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), }; if(kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) { return sizes[EXPR_UNARY_FIRST]; @@ -457,6 +478,10 @@ static void eat_paren(void) if(token.type == ')' || token.type == ';' || token.type == '}') { return; } + if(token.type == ')') { + next_token(); + return; + } if(token.type == '(') { eat_paren(); continue; @@ -467,7 +492,6 @@ static void eat_paren(void) } next_token(); } - eat(')'); } #define expect(expected) \ @@ -514,7 +538,8 @@ static void set_scope(scope_t *new_scope) * Search a symbol in a given namespace and returns its declaration or * NULL if this symbol was not found. */ -static declaration_t *get_declaration(const symbol_t *const symbol, const namespace_t namespc) +static declaration_t *get_declaration(const symbol_t *const symbol, + const namespace_t namespc) { declaration_t *declaration = symbol->declaration; for( ; declaration != NULL; declaration = declaration->symbol_next) { @@ -809,11 +834,12 @@ static type_t *make_global_typedef(const char *name, type_t *type) symbol_t *const symbol = symbol_table_insert(name); declaration_t *const declaration = allocate_declaration_zero(); - declaration->namespc = NAMESPACE_NORMAL; - declaration->storage_class = STORAGE_CLASS_TYPEDEF; - declaration->type = type; - declaration->symbol = symbol; - declaration->source_position = builtin_source_position; + declaration->namespc = NAMESPACE_NORMAL; + declaration->storage_class = STORAGE_CLASS_TYPEDEF; + declaration->declared_storage_class = STORAGE_CLASS_TYPEDEF; + declaration->type = type; + declaration->symbol = symbol; + declaration->source_position = builtin_source_position; record_declaration(declaration); @@ -1003,7 +1029,14 @@ static initializer_t *initializer_from_expression(type_t *orig_type, return result; } -static initializer_t *parse_scalar_initializer(type_t *type) +static bool is_initializer_constant(const expression_t *expression) +{ + return is_constant_expression(expression) + || is_address_constant(expression); +} + +static initializer_t *parse_scalar_initializer(type_t *type, + bool must_be_constant) { /* there might be extra {} hierarchies */ int braces = 0; @@ -1015,7 +1048,13 @@ static initializer_t *parse_scalar_initializer(type_t *type) braces++; } - expression_t *expression = parse_assignment_expression(); + expression_t *expression = parse_assignment_expression(); + if(must_be_constant && !is_initializer_constant(expression)) { + errorf(expression->base.source_position, + "Initialisation expression '%E' is not constant\n", + expression); + } + initializer_t *initializer = initializer_from_expression(type, expression); if(initializer == NULL) { @@ -1056,11 +1095,13 @@ struct type_path_entry_t { typedef struct type_path_t type_path_t; struct type_path_t { type_path_entry_t *path; - type_t *top_type; + type_t *top_type; /**< type of the element the path points */ + size_t max_index; /**< largest index in outermost array */ bool invalid; }; -static __attribute__((unused)) void debug_print_type_path(const type_path_t *path) +static __attribute__((unused)) void debug_print_type_path( + const type_path_t *path) { size_t len = ARR_LEN(path->path); @@ -1304,7 +1345,7 @@ static void skip_initializers(void) } static initializer_t *parse_sub_initializer(type_path_t *path, - type_t *outer_type, size_t top_path_level) + type_t *outer_type, size_t top_path_level, bool must_be_constant) { type_t *orig_type = path->top_type; type_t *type = skip_typeref(orig_type); @@ -1340,12 +1381,13 @@ static initializer_t *parse_sub_initializer(type_path_t *path, if(token.type == '{') { if(is_type_scalar(type)) { - sub = parse_scalar_initializer(type); + sub = parse_scalar_initializer(type, must_be_constant); } else { eat('{'); descend_into_subtype(path); - sub = parse_sub_initializer(path, orig_type, top_path_level+1); + sub = parse_sub_initializer(path, orig_type, top_path_level+1, + must_be_constant); ascend_from_subtype(path); @@ -1355,6 +1397,12 @@ static initializer_t *parse_sub_initializer(type_path_t *path, /* must be an expression */ expression_t *expression = parse_assignment_expression(); + if(must_be_constant && !is_initializer_constant(expression)) { + errorf(expression->base.source_position, + "Initialisation expression '%E' is not constant\n", + expression); + } + /* handle { "string" } special case */ if((expression->kind == EXPR_STRING_LITERAL || expression->kind == EXPR_WIDE_STRING_LITERAL) @@ -1395,6 +1443,18 @@ static initializer_t *parse_sub_initializer(type_path_t *path, descend_into_subtype(path); } } + + /* update largest index of top array */ + const type_path_entry_t *first = &path->path[0]; + type_t *first_type = first->type; + first_type = skip_typeref(first_type); + if(is_type_array(first_type)) { + size_t index = first->v.index; + if(index > path->max_index) + path->max_index = index; + } + + /* append to initializers list */ ARR_APP1(initializer_t*, initializers, sub); if(token.type == '}') { @@ -1404,7 +1464,10 @@ static initializer_t *parse_sub_initializer(type_path_t *path, if(token.type == '}') { break; } + advance_current_object(path, top_path_level); + orig_type = path->top_type; + type = skip_typeref(orig_type); } size_t len = ARR_LEN(initializers); @@ -1417,8 +1480,6 @@ static initializer_t *parse_sub_initializer(type_path_t *path, ascend_to(path, top_path_level); - /* TODO: if(is_global && !is_constant(...)) { error } */ - return result; end_error: @@ -1428,52 +1489,81 @@ end_error: return NULL; } -static initializer_t *parse_initializer(type_t *const orig_type) -{ - initializer_t *result; - - type_t *const type = skip_typeref(orig_type); +typedef struct parse_initializer_env_t { + type_t *type; /* the type of the initializer. In case of an + array type with unspecified size this gets + adjusted to the actual size. */ + initializer_t *initializer; /* initializer will be filled in here */ + bool must_be_constant; +} parse_initializer_env_t; - if(token.type != '{') { - expression_t *expression = parse_assignment_expression(); - initializer_t *initializer = initializer_from_expression(type, expression); - if(initializer == NULL) { - errorf(HERE, - "initializer expression '%E' of type '%T' is incompatible with type '%T'", - expression, expression->base.type, orig_type); - } - return initializer; - } +static void parse_initializer(parse_initializer_env_t *env) +{ + type_t *type = skip_typeref(env->type); + initializer_t *result = NULL; + size_t max_index; if(is_type_scalar(type)) { /* TODO: § 6.7.8.11; eat {} without warning */ - - result = parse_scalar_initializer(type); - - if(token.type == ',') - next_token(); - - return result; + result = parse_scalar_initializer(type, env->must_be_constant); } else if(token.type == '{') { - next_token(); + eat('{'); type_path_t path; memset(&path, 0, sizeof(path)); - path.top_type = orig_type; + path.top_type = env->type; path.path = NEW_ARR_F(type_path_entry_t, 0); descend_into_subtype(&path); - result = parse_sub_initializer(&path, orig_type, 1); + result = parse_sub_initializer(&path, env->type, 1, + env->must_be_constant); + max_index = path.max_index; DEL_ARR_F(path.path); - expect('}'); + expect_void('}'); } else { - /* TODO ... */ + /* parse_scalar_initializer also works in this case: we simply + * have an expression without {} around it */ + result = parse_scalar_initializer(type, env->must_be_constant); } - return result; + /* § 6.7.5 (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) { + size_t size; + switch (result->kind) { + case INITIALIZER_LIST: + size = max_index + 1; + break; + + case INITIALIZER_STRING: + size = result->string.string.size; + break; + + case INITIALIZER_WIDE_STRING: + size = result->wide_string.string.size; + break; + + default: + panic("invalid initializer type"); + } + + expression_t *cnst = allocate_expression_zero(EXPR_CONST); + cnst->base.type = type_size_t; + cnst->conste.v.int_value = size; + + type_t *new_type = duplicate_type(type); + + new_type->array.size_expression = cnst; + new_type->array.size_constant = true; + new_type->array.size = size; + env->type = new_type; + } + + env->initializer = result; } static declaration_t *append_declaration(declaration_t *declaration); @@ -1756,13 +1846,13 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) switch(token.type) { /* storage class */ -#define MATCH_STORAGE_CLASS(token, class) \ - case token: \ - if(specifiers->storage_class != STORAGE_CLASS_NONE) { \ +#define MATCH_STORAGE_CLASS(token, class) \ + case token: \ + if(specifiers->declared_storage_class != STORAGE_CLASS_NONE) { \ errorf(HERE, "multiple storage classes in declaration specifiers"); \ - } \ - specifiers->storage_class = class; \ - next_token(); \ + } \ + specifiers->declared_storage_class = class; \ + next_token(); \ break; MATCH_STORAGE_CLASS(T_typedef, STORAGE_CLASS_TYPEDEF) @@ -1772,22 +1862,22 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER) case T___thread: - switch (specifiers->storage_class) { - case STORAGE_CLASS_NONE: - specifiers->storage_class = STORAGE_CLASS_THREAD; - break; + switch (specifiers->declared_storage_class) { + case STORAGE_CLASS_NONE: + specifiers->declared_storage_class = STORAGE_CLASS_THREAD; + break; - case STORAGE_CLASS_EXTERN: - specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN; - break; + case STORAGE_CLASS_EXTERN: + specifiers->declared_storage_class = STORAGE_CLASS_THREAD_EXTERN; + break; - case STORAGE_CLASS_STATIC: - specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC; - break; + case STORAGE_CLASS_STATIC: + specifiers->declared_storage_class = STORAGE_CLASS_THREAD_STATIC; + break; - default: - errorf(HERE, "multiple storage classes in declaration specifiers"); - break; + default: + errorf(HERE, "multiple storage classes in declaration specifiers"); + break; } next_token(); break; @@ -2081,10 +2171,10 @@ static void semantic_parameter(declaration_t *declaration) { /* TODO: improve error messages */ - if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) { + if(declaration->declared_storage_class == STORAGE_CLASS_TYPEDEF) { errorf(HERE, "typedef not allowed in parameter list"); - } else if(declaration->storage_class != STORAGE_CLASS_NONE - && declaration->storage_class != STORAGE_CLASS_REGISTER) { + } else if(declaration->declared_storage_class != STORAGE_CLASS_NONE + && declaration->declared_storage_class != STORAGE_CLASS_REGISTER) { errorf(HERE, "parameter may only have none or register storage class"); } @@ -2437,6 +2527,10 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *array_type = allocate_type_zero(TYPE_ARRAY, (source_position_t){NULL, 0}); expression_t *size_expression = parsed_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->array.element_type = type; @@ -2444,11 +2538,14 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, array_type->array.is_variable = parsed_array->is_variable; array_type->array.size_expression = size_expression; - if(size_expression != NULL && - is_constant_expression(size_expression)) { - array_type->array.size_constant = true; - array_type->array.size - = fold_constant(size_expression); + if(size_expression != NULL) { + if(is_constant_expression(size_expression)) { + array_type->array.size_constant = true; + array_type->array.size + = fold_constant(size_expression); + } else { + array_type->array.is_vla = true; + } } type_t *skipped_type = skip_typeref(type); @@ -2479,10 +2576,16 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, static declaration_t *parse_declarator( const declaration_specifiers_t *specifiers, bool may_be_abstract) { - declaration_t *const declaration = allocate_declaration_zero(); - declaration->storage_class = specifiers->storage_class; - declaration->modifiers = specifiers->decl_modifiers; - declaration->is_inline = specifiers->is_inline; + declaration_t *const declaration = allocate_declaration_zero(); + declaration->declared_storage_class = specifiers->declared_storage_class; + declaration->modifiers = specifiers->decl_modifiers; + declaration->is_inline = specifiers->is_inline; + + declaration->storage_class = specifiers->declared_storage_class; + if(declaration->storage_class == STORAGE_CLASS_NONE + && scope != global_scope) { + declaration->storage_class = STORAGE_CLASS_AUTO; + } construct_type_t *construct_type = parse_inner_declarator(declaration, may_be_abstract); @@ -2674,6 +2777,7 @@ warn_redundant_declaration: } if (new_storage_class == STORAGE_CLASS_NONE) { previous_declaration->storage_class = STORAGE_CLASS_NONE; + previous_declaration->declared_storage_class = STORAGE_CLASS_NONE; } } } else { @@ -2764,52 +2868,28 @@ static void parse_init_declarator_rest(declaration_t *declaration) eat('='); type_t *orig_type = declaration->type; - type_t *type = type = skip_typeref(orig_type); + type_t *type = skip_typeref(orig_type); if(declaration->init.initializer != NULL) { parser_error_multiple_definition(declaration, token.source_position); } - initializer_t *initializer = parse_initializer(type); - - /* § 6.7.5 (22) array initializers for arrays with unknown size determine - * the array type size */ - if(is_type_array(type) && initializer != NULL) { - array_type_t *array_type = &type->array; - - if(array_type->size_expression == NULL) { - size_t size; - switch (initializer->kind) { - case INITIALIZER_LIST: { - /* TODO */ - size = initializer->list.len; - break; - } - - case INITIALIZER_STRING: { - size = initializer->string.string.size; - break; - } - - case INITIALIZER_WIDE_STRING: { - size = initializer->wide_string.string.size; - break; - } - - default: { - panic("invalid initializer type"); - break; - } - } + bool must_be_constant = false; + if(declaration->storage_class == STORAGE_CLASS_STATIC + || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC + || declaration->parent_scope == global_scope) { + must_be_constant = true; + } - expression_t *cnst = allocate_expression_zero(EXPR_CONST); - cnst->base.type = type_size_t; - cnst->conste.v.int_value = size; + parse_initializer_env_t env; + env.type = orig_type; + env.must_be_constant = must_be_constant; + parse_initializer(&env); - array_type->size_expression = cnst; - array_type->size_constant = true; - array_type->size = size; - } + if(env.type != orig_type) { + orig_type = env.type; + type = skip_typeref(orig_type); + declaration->type = env.type; } if(is_type_function(type)) { @@ -2817,7 +2897,7 @@ static void parse_init_declarator_rest(declaration_t *declaration) "initializers not allowed for function types at declator '%Y' (type '%T')", declaration->symbol, orig_type); } else { - declaration->init.initializer = initializer; + declaration->init.initializer = env.initializer; } } @@ -2828,14 +2908,15 @@ static void parse_anonymous_declaration_rest( { eat(';'); - declaration_t *const declaration = allocate_declaration_zero(); - declaration->type = specifiers->type; - declaration->storage_class = specifiers->storage_class; - declaration->source_position = specifiers->source_position; + declaration_t *const declaration = allocate_declaration_zero(); + declaration->type = specifiers->type; + declaration->declared_storage_class = specifiers->declared_storage_class; + declaration->source_position = specifiers->source_position; - if (declaration->storage_class != STORAGE_CLASS_NONE) { + if (declaration->declared_storage_class != STORAGE_CLASS_NONE) { warningf(declaration->source_position, "useless storage class in empty declaration"); } + declaration->storage_class = STORAGE_CLASS_NONE; type_t *type = declaration->type; switch (type->kind) { @@ -2910,6 +2991,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration) if(previous_declaration->type == NULL) { previous_declaration->type = declaration->type; + previous_declaration->declared_storage_class = declaration->declared_storage_class; previous_declaration->storage_class = declaration->storage_class; previous_declaration->parent_scope = scope; return previous_declaration; @@ -3255,12 +3337,13 @@ static void parse_compound_declarators(declaration_t *struct_declaration, type_t *type = make_bitfield_type(base_type, size, source_position); - declaration = allocate_declaration_zero(); - declaration->namespc = NAMESPACE_NORMAL; - declaration->storage_class = STORAGE_CLASS_NONE; - declaration->source_position = source_position; - declaration->modifiers = specifiers->decl_modifiers; - declaration->type = type; + declaration = allocate_declaration_zero(); + declaration->namespc = NAMESPACE_NORMAL; + declaration->declared_storage_class = STORAGE_CLASS_NONE; + declaration->storage_class = STORAGE_CLASS_NONE; + declaration->source_position = source_position; + declaration->modifiers = specifiers->decl_modifiers; + declaration->type = type; } else { declaration = parse_declarator(specifiers,/*may_be_abstract=*/true); @@ -3345,7 +3428,7 @@ static type_t *parse_typename(void) declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); - if(specifiers.storage_class != STORAGE_CLASS_NONE) { + if(specifiers.declared_storage_class != STORAGE_CLASS_NONE) { /* TODO: improve error message, user does probably not know what a * storage class is... */ @@ -3413,6 +3496,9 @@ static expression_t *parse_string_const(void) } if (token.type != T_WIDE_STRING_LITERAL) { expression_t *const cnst = allocate_expression_zero(EXPR_STRING_LITERAL); + /* note: that we use type_char_ptr here, which is already the + * automatic converted type. revert_automatic_type_conversion + * will construct the array type */ cnst->base.type = type_char_ptr; cnst->string.value = res; return cnst; @@ -3463,15 +3549,39 @@ static expression_t *parse_int_const(void) /** * Parse a character constant. */ -static expression_t *parse_char_const(void) +static expression_t *parse_character_constant(void) { - expression_t *cnst = allocate_expression_zero(EXPR_CHAR_CONST); + expression_t *cnst = allocate_expression_zero(EXPR_CHARACTER_CONSTANT); + cnst->base.source_position = HERE; cnst->base.type = token.datatype; - cnst->conste.v.chars.begin = token.v.string.begin; - cnst->conste.v.chars.size = token.v.string.size; + cnst->conste.v.character = token.v.string; + + if (cnst->conste.v.character.size != 1) { + if (warning.multichar && (c_mode & _GNUC)) { + /* TODO */ + warningf(HERE, "multi-character character constant"); + } else { + errorf(HERE, "more than 1 characters in character constant"); + } + } + next_token(); + + return cnst; +} + +/** + * Parse a wide character constant. + */ +static expression_t *parse_wide_character_constant(void) +{ + expression_t *cnst = allocate_expression_zero(EXPR_WIDE_CHARACTER_CONSTANT); + + cnst->base.source_position = HERE; + cnst->base.type = token.datatype; + cnst->conste.v.wide_character = token.v.wide_string; - if (cnst->conste.v.chars.size != 1) { + if (cnst->conste.v.wide_character.size != 1) { if (warning.multichar && (c_mode & _GNUC)) { /* TODO */ warningf(HERE, "multi-character character constant"); @@ -3510,12 +3620,13 @@ static declaration_t *create_implicit_function(symbol_t *symbol, free_type(ntype); } - declaration_t *const declaration = allocate_declaration_zero(); - declaration->storage_class = STORAGE_CLASS_EXTERN; - declaration->type = type; - declaration->symbol = symbol; - declaration->source_position = source_position; - declaration->parent_scope = global_scope; + declaration_t *const declaration = allocate_declaration_zero(); + declaration->storage_class = STORAGE_CLASS_EXTERN; + declaration->declared_storage_class = STORAGE_CLASS_EXTERN; + declaration->type = type; + declaration->symbol = symbol; + declaration->source_position = source_position; + declaration->parent_scope = global_scope; scope_t *old_scope = scope; set_scope(global_scope); @@ -3632,6 +3743,19 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) return type_left->pointer.points_to; } + case EXPR_STRING_LITERAL: { + size_t size = expression->string.value.size; + return make_array_type(type_char, size, TYPE_QUALIFIER_NONE); + } + + case EXPR_WIDE_STRING_LITERAL: { + size_t size = expression->wide_string.value.size; + return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE); + } + + case EXPR_COMPOUND_LITERAL: + return expression->compound_literal.type; + default: break; } @@ -3692,8 +3816,14 @@ static expression_t *parse_compound_literal(type_t *type) { expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL); + parse_initializer_env_t env; + env.type = type; + env.must_be_constant = false; + parse_initializer(&env); + type = env.type; + expression->compound_literal.type = type; - expression->compound_literal.initializer = parse_initializer(type); + expression->compound_literal.initializer = env.initializer; expression->base.type = automatic_type_conversion(type); return expression; @@ -4074,7 +4204,8 @@ static expression_t *parse_primary_expression(void) { switch (token.type) { case T_INTEGER: return parse_int_const(); - case T_CHARS: return parse_char_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(); @@ -5002,6 +5133,18 @@ static void semantic_binexpr_assign(binary_expression_t *expression) expression->base.type = orig_type_left; } +/** + * Determine if the outermost operation (or parts thereof) of the given + * expression has no effect in order to generate a warning about this fact. + * Therefore in some cases this only examines some of the operands of the + * expression (see comments in the function and examples below). + * Examples: + * f() + 23; // warning, because + has no effect + * x || f(); // no warning, because x controls execution of f() + * x ? y : f(); // warning, because y has no effect + * (void)x; // no warning to be able to suppress the warning + * This function can NOT be used for an "expression has definitely no effect"- + * analysis. */ static bool expression_has_effect(const expression_t *const expr) { switch (expr->kind) { @@ -5009,9 +5152,11 @@ static bool expression_has_effect(const expression_t *const expr) case EXPR_INVALID: break; case EXPR_REFERENCE: return false; case EXPR_CONST: return false; - case EXPR_CHAR_CONST: return false; + 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_CALL: { const call_expression_t *const call = &expr->call; if (call->function->kind != EXPR_BUILTIN_SYMBOL) @@ -5022,12 +5167,16 @@ static bool expression_has_effect(const expression_t *const expr) 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; return expression_has_effect(cond->true_expression) && expression_has_effect(cond->false_expression); } + case EXPR_SELECT: return false; case EXPR_ARRAY_ACCESS: return false; case EXPR_SIZEOF: return false; @@ -5055,10 +5204,14 @@ static bool expression_has_effect(const expression_t *const expr) 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 */ case EXPR_UNARY_CAST: { - type_t *type = skip_typeref(expr->base.type); + type_t *const type = skip_typeref(expr->base.type); return is_type_atomic(type, ATOMIC_TYPE_VOID); } + case EXPR_UNARY_CAST_IMPLICIT: return true; case EXPR_UNARY_ASSUME: return true; case EXPR_UNARY_BITFIELD_EXTRACT: return false; @@ -5090,8 +5243,14 @@ static bool expression_has_effect(const expression_t *const expr) 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 + * hand side */ case EXPR_BINARY_LOGICAL_AND: case EXPR_BINARY_LOGICAL_OR: + /* Only examine the right hand side of a comma expression, because the left + * hand side has a separate warning */ case EXPR_BINARY_COMMA: return expression_has_effect(expr->binary.right); @@ -5881,7 +6040,6 @@ static statement_t *parse_break(void) */ static bool is_local_var_declaration(const declaration_t *declaration) { switch ((storage_class_tag_t) declaration->storage_class) { - case STORAGE_CLASS_NONE: case STORAGE_CLASS_AUTO: case STORAGE_CLASS_REGISTER: { const type_t *type = skip_typeref(declaration->type); @@ -5900,25 +6058,11 @@ static bool is_local_var_declaration(const declaration_t *declaration) { * Check if a given declaration represents a variable. */ static bool is_var_declaration(const declaration_t *declaration) { - switch ((storage_class_tag_t) declaration->storage_class) { - case STORAGE_CLASS_NONE: - case STORAGE_CLASS_EXTERN: - case STORAGE_CLASS_STATIC: - case STORAGE_CLASS_AUTO: - case STORAGE_CLASS_REGISTER: - case STORAGE_CLASS_THREAD: - case STORAGE_CLASS_THREAD_EXTERN: - case STORAGE_CLASS_THREAD_STATIC: { - const type_t *type = skip_typeref(declaration->type); - if(is_type_function(type)) { - return false; - } else { - return true; - } - } - default: + if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) return false; - } + + const type_t *type = skip_typeref(declaration->type); + return !is_type_function(type); } /**