+ if (old_storage_class == STORAGE_CLASS_EXTERN &&
+ new_storage_class == STORAGE_CLASS_EXTERN) {
+warn_redundant_declaration:
+ if (warning.redundant_decls) {
+ warningf(declaration->source_position, "redundant declaration for '%Y'", symbol);
+ warningf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ }
+ } else if (current_function == NULL) {
+ if (old_storage_class != STORAGE_CLASS_STATIC &&
+ new_storage_class == STORAGE_CLASS_STATIC) {
+ errorf(declaration->source_position, "static declaration of '%Y' follows non-static declaration", symbol);
+ errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ } else {
+ if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
+ goto warn_redundant_declaration;
+ }
+ if (new_storage_class == STORAGE_CLASS_NONE) {
+ previous_declaration->storage_class = STORAGE_CLASS_NONE;
+ }
+ }
+ } else {
+ if (old_storage_class == new_storage_class) {
+ errorf(declaration->source_position, "redeclaration of '%Y'", symbol);
+ } else {
+ errorf(declaration->source_position, "redeclaration of '%Y' with different linkage", symbol);
+ }
+ errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ }
+ }
+ return previous_declaration;
+ }
+ } else if (is_function_definition) {
+ if (declaration->storage_class != STORAGE_CLASS_STATIC) {
+ if (warning.missing_prototypes && !is_sym_main(symbol)) {
+ warningf(declaration->source_position, "no previous prototype for '%#T'", orig_type, symbol);
+ } else if (warning.missing_declarations && !is_sym_main(symbol)) {
+ warningf(declaration->source_position, "no previous declaration for '%#T'", orig_type, symbol);
+ }
+ }
+ } else if (warning.missing_declarations &&
+ scope == global_scope &&
+ !is_type_function(type) && (
+ declaration->storage_class == STORAGE_CLASS_NONE ||
+ declaration->storage_class == STORAGE_CLASS_THREAD
+ )) {
+ warningf(declaration->source_position, "no previous declaration for '%#T'", orig_type, symbol);
+ }
+
+ assert(declaration->parent_scope == NULL);
+ assert(declaration->symbol != NULL);
+ assert(scope != NULL);
+
+ declaration->parent_scope = scope;
+
+ environment_push(declaration);
+ return append_declaration(declaration);
+}
+
+static declaration_t *record_declaration(declaration_t *declaration)
+{
+ return internal_record_declaration(declaration, false);
+}
+
+static declaration_t *record_function_definition(declaration_t *declaration)
+{
+ return internal_record_declaration(declaration, true);
+}
+
+static void parser_error_multiple_definition(declaration_t *declaration,
+ const source_position_t source_position)
+{
+ errorf(source_position, "multiple definition of symbol '%Y'",
+ declaration->symbol);
+ errorf(declaration->source_position,
+ "this is the location of the previous definition.");
+}
+
+static bool is_declaration_specifier(const token_t *token,
+ bool only_type_specifiers)
+{
+ switch(token->type) {
+ TYPE_SPECIFIERS
+ return true;
+ case T_IDENTIFIER:
+ return is_typedef_symbol(token->v.symbol);
+
+ case T___extension__:
+ STORAGE_CLASSES
+ TYPE_QUALIFIERS
+ return !only_type_specifiers;
+
+ default:
+ return false;
+ }
+}
+
+static void parse_init_declarator_rest(declaration_t *declaration)
+{
+ eat('=');
+
+ type_t *orig_type = declaration->type;
+ type_t *type = 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 == NULL) {
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+
+ cnst->base.datatype = type_size_t;
+
+ switch (initializer->kind) {
+ case INITIALIZER_LIST: {
+ cnst->conste.v.int_value = initializer->list.len;
+ break;
+ }
+
+ case INITIALIZER_STRING: {
+ cnst->conste.v.int_value = initializer->string.string.size;
+ break;
+ }