+static type_t *make_function_1_type(type_t *result_type, type_t *argument_type)
+{
+ function_parameter_t *parameter = allocate_type_zero(sizeof(parameter[0]));
+ parameter->type = argument_type;
+
+ function_type_t *type = allocate_type_zero(sizeof(type[0]));
+ type->type.type = TYPE_FUNCTION;
+ type->result_type = result_type;
+ type->parameters = parameter;
+
+ type_t *result = typehash_insert((type_t*) type);
+ if(result != (type_t*) 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 = (array_type_t*) type;
+ 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->datatype == NULL)
+ return NULL;
+
+ switch(expression->type) {
+ case EXPR_REFERENCE: {
+ const reference_expression_t *ref
+ = (const reference_expression_t*) expression;
+ return ref->declaration->type;
+ }
+ case EXPR_SELECT: {
+ const select_expression_t *select
+ = (const select_expression_t*) expression;
+ return select->compound_entry->type;
+ }
+ case EXPR_UNARY: {
+ const unary_expression_t *unary
+ = (const unary_expression_t*) expression;
+ if(unary->type == UNEXPR_DEREFERENCE) {
+ expression_t *value = unary->value;
+ type_t *type = skip_typeref(value->datatype);
+ pointer_type_t *pointer_type = (pointer_type_t*) type;
+
+ return pointer_type->points_to;
+ }
+ break;
+ }
+ case EXPR_BUILTIN_SYMBOL: {
+ const builtin_symbol_expression_t *builtin
+ = (const builtin_symbol_expression_t*) expression;
+ return get_builtin_symbol_type(builtin->symbol);
+ }
+ case EXPR_ARRAY_ACCESS: {
+ const array_access_expression_t *array_access
+ = (const array_access_expression_t*) expression;
+ type_t *type_left = skip_typeref(array_access->array_ref->datatype);
+ assert(is_type_pointer(type_left));
+ pointer_type_t *pointer_type = (pointer_type_t*) type_left;
+ return pointer_type->points_to;
+ }
+
+ default:
+ break;
+ }
+
+ return expression->datatype;
+}
+