+static type_t *make_function_1_type(type_t *result_type, type_t *argument_type)
+{
+ function_parameter_t *parameter
+ = obstack_alloc(type_obst, sizeof(parameter[0]));
+ memset(parameter, 0, sizeof(parameter[0]));
+ parameter->type = argument_type;
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.result_type = result_type;
+ type->function.parameters = parameter;
+
+ type_t *result = typehash_insert(type);
+ if(result != type) {
+ free_type(type);
+ }
+
+ return result;
+}
+
+static type_t *get_builtin_symbol_type(symbol_t *symbol)
+{
+ switch(symbol->ID) {
+ case T___builtin_alloca:
+ return make_function_1_type(type_void_ptr, type_size_t);
+ default:
+ panic("not implemented builtin symbol found");
+ }
+}
+
+/**
+ * performs automatic type cast as described in § 6.3.2.1
+ */
+static type_t *automatic_type_conversion(type_t *type)
+{
+ if(type == NULL)
+ return NULL;
+
+ if(type->type == TYPE_ARRAY) {
+ array_type_t *array_type = &type->array;
+ type_t *element_type = array_type->element_type;
+ unsigned qualifiers = array_type->type.qualifiers;
+
+ return make_pointer_type(element_type, qualifiers);
+ }
+
+ if(type->type == TYPE_FUNCTION) {
+ return make_pointer_type(type, TYPE_QUALIFIER_NONE);
+ }
+
+ return type;
+}
+
+/**
+ * reverts the automatic casts of array to pointer types and function
+ * to function-pointer types as defined § 6.3.2.1
+ */
+type_t *revert_automatic_type_conversion(const expression_t *expression)
+{
+ if(expression->base.datatype == NULL)
+ return NULL;
+
+ switch(expression->type) {
+ case EXPR_REFERENCE: {
+ const reference_expression_t *ref = &expression->reference;
+ return ref->declaration->type;
+ }
+ case EXPR_SELECT: {
+ const select_expression_t *select = &expression->select;
+ return select->compound_entry->type;
+ }
+ case EXPR_UNARY: {
+ const unary_expression_t *unary = &expression->unary;
+ if(unary->type == UNEXPR_DEREFERENCE) {
+ expression_t *value = unary->value;
+ type_t *type = skip_typeref(value->base.datatype);
+ pointer_type_t *pointer_type = &type->pointer;
+
+ return pointer_type->points_to;
+ }
+ break;
+ }
+ case EXPR_BUILTIN_SYMBOL: {
+ const builtin_symbol_expression_t *builtin
+ = &expression->builtin_symbol;
+ return get_builtin_symbol_type(builtin->symbol);
+ }
+ case EXPR_ARRAY_ACCESS: {
+ const array_access_expression_t *array_access
+ = &expression->array_access;
+ const expression_t *array_ref = array_access->array_ref;
+ type_t *type_left = skip_typeref(array_ref->base.datatype);
+ assert(is_type_pointer(type_left));
+ pointer_type_t *pointer_type = &type_left->pointer;
+ return pointer_type->points_to;
+ }
+
+ default:
+ break;
+ }
+
+ return expression->base.datatype;
+}
+