+static declaration_t *internal_record_declaration(
+ declaration_t *const declaration,
+ const bool is_function_definition)
+{
+ const symbol_t *const symbol = declaration->symbol;
+ const namespace_t namespc = (namespace_t)declaration->namespc;
+
+ const type_t *const type = skip_typeref(declaration->type);
+ if (is_type_function(type) && type->function.unspecified_parameters) {
+ warningf(declaration->source_position,
+ "function declaration '%#T' is not a prototype",
+ type, declaration->symbol);
+ }
+
+ declaration_t *const previous_declaration = get_declaration(symbol, namespc);
+ assert(declaration != previous_declaration);
+ if (previous_declaration != NULL
+ && previous_declaration->parent_context == context) {
+ /* can happen for K&R style declarations */
+ if(previous_declaration->type == NULL) {
+ previous_declaration->type = declaration->type;
+ }
+
+ const type_t *const prev_type = skip_typeref(previous_declaration->type);
+ if (!types_compatible(type, prev_type)) {
+ errorf(declaration->source_position,
+ "declaration '%#T' is incompatible with previous declaration '%#T'",
+ type, symbol, previous_declaration->type, symbol);
+ errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ } else {
+ unsigned old_storage_class = previous_declaration->storage_class;
+ unsigned new_storage_class = declaration->storage_class;
+
+ /* pretend no storage class means extern for function declarations
+ * (except if the previous declaration is neither none nor extern) */
+ if (is_type_function(type)) {
+ switch (old_storage_class) {
+ case STORAGE_CLASS_NONE:
+ old_storage_class = STORAGE_CLASS_EXTERN;
+
+ case STORAGE_CLASS_EXTERN:
+ if (new_storage_class == STORAGE_CLASS_NONE && !is_function_definition) {
+ new_storage_class = STORAGE_CLASS_EXTERN;
+ }
+ break;
+
+ default: break;
+ }
+ }
+
+ if (old_storage_class == STORAGE_CLASS_EXTERN &&
+ new_storage_class == STORAGE_CLASS_EXTERN) {
+warn_redundant_declaration:
+ 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;
+ }
+
+ assert(declaration->parent_context == NULL);
+ assert(declaration->symbol != NULL);
+ assert(context != NULL);
+
+ declaration->parent_context = context;
+
+ environment_push(declaration);
+ return append_declaration(declaration);
+}
+
+/**
+ * Check if a given type is a vilid array type.
+ */
+static bool is_valid_array_type(const type_t *type) {
+ if (type->kind == TYPE_ARRAY) {
+ const array_type_t *array = &type->array;
+ const type_t *etype = skip_typeref(array->element_type);
+
+ if (! is_valid_array_type(etype))
+ return false;
+
+ if (etype->kind == TYPE_ATOMIC) {
+ const atomic_type_t *atype = &etype->atomic;
+
+ if (atype->akind == ATOMIC_TYPE_VOID) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static declaration_t *record_declaration(declaration_t *declaration)
+{
+ declaration = internal_record_declaration(declaration, false);
+ const type_t *type = skip_typeref(declaration->type);
+
+ /* check the type here for several not allowed combinations */
+ if (type->kind == TYPE_FUNCTION) {
+ const function_type_t* function_type = &type->function;
+ const type_t* ret_type = skip_typeref(function_type->return_type);
+
+ if (ret_type->kind == TYPE_FUNCTION) {
+ errorf(declaration->source_position, "'%Y' declared as function returning a function",
+ declaration->symbol);
+ declaration->type = type_error_type;
+ } else if (ret_type->kind == TYPE_ARRAY) {
+ errorf(declaration->source_position, "'%Y' declared as function returning an array",
+ declaration->symbol);
+ declaration->type = type_error_type;
+ }
+ }
+ if (! is_valid_array_type(type)) {
+ errorf(declaration->source_position, "declaration of '%Y' as array of voids",
+ declaration->symbol);
+ declaration->type = type_error_type;
+ }