static ir_type *create_method_type(const function_type_t *function_type)
{
- type_t *result_type = function_type->result_type;
+ type_t *return_type = function_type->return_type;
ident *id = unique_ident("functiontype");
int n_parameters = count_parameters(function_type);
- int n_results = result_type == type_void ? 0 : 1;
+ int n_results = return_type == type_void ? 0 : 1;
ir_type *irtype = new_type_method(id, n_parameters, n_results);
- if(result_type != type_void) {
- ir_type *restype = get_ir_type(result_type);
+ if(return_type != type_void) {
+ ir_type *restype = get_ir_type(return_type);
set_method_res_type(irtype, 0, restype);
}
case T___builtin_nand: {
/* Ignore string for now... */
assert(function_type->type == TYPE_FUNCTION);
- ir_mode *mode = get_ir_mode(function_type->function.result_type);
+ ir_mode *mode = get_ir_mode(function_type->function.return_type);
tarval *tv = get_mode_NAN(mode);
ir_node *res = new_d_Const(dbgi, mode, tv);
return res;
ir_node *mem = new_d_Proj(dbgi, node, mode_M, pn_Call_M_regular);
set_store(mem);
- type_t *result_type = skip_typeref(function_type->result_type);
+ type_t *return_type = skip_typeref(function_type->return_type);
ir_node *result = NULL;
- if(!is_type_atomic(result_type, ATOMIC_TYPE_VOID)) {
+ if(!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
ir_mode *mode;
- if(is_type_scalar(result_type)) {
- mode = get_ir_mode(result_type);
+ if(is_type_scalar(return_type)) {
+ mode = get_ir_mode(return_type);
} else {
mode = mode_P_data;
}
if(get_cur_block() != NULL) {
assert(declaration->type->type == TYPE_FUNCTION);
const function_type_t* const func_type = &declaration->type->function;
- const type_t *result_type = skip_typeref(func_type->result_type);
+ const type_t *return_type = skip_typeref(func_type->return_type);
ir_node *ret;
- if (is_type_atomic(result_type, ATOMIC_TYPE_VOID)) {
+ if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
ret = new_Return(get_store(), 0, NULL);
} else {
ir_mode *mode;
- if(is_type_scalar(result_type)) {
- mode = get_ir_mode(func_type->result_type);
+ if(is_type_scalar(return_type)) {
+ mode = get_ir_mode(func_type->return_type);
} else {
mode = mode_P_data;
}
return true;
}
- /* shortcur, same types are always compatible */
- if(declaration->type == previous->type)
- return true;
-
- if (declaration->type->type == TYPE_FUNCTION &&
- previous->type->type == TYPE_FUNCTION) {
- function_type_t* const prev_func = &previous->type->function;
- function_type_t* const decl_func = &declaration->type->function;
-
- /* 1 of the 2 declarations might have unspecified parameters */
- if(decl_func->unspecified_parameters) {
- return true;
- } else if(prev_func->unspecified_parameters) {
- declaration->type = previous->type;
- return true;
- }
- }
+ type_t *type1 = skip_typeref(declaration->type);
+ type_t *type2 = skip_typeref(previous->type);
- /* TODO: not correct/complete yet */
- return false;
+ return types_compatible(type1, type2);
}
static declaration_t *get_declaration(symbol_t *symbol, namespace_t namespc)
&& previous_declaration->parent_context == context) {
if(!is_compatible_declaration(declaration, previous_declaration)) {
parser_print_error_prefix_pos(declaration->source_position);
- fprintf(stderr, "definition of symbol %s%s with type ",
+ fprintf(stderr, "definition of symbol '%s%s' with type ",
get_namespace_prefix(namespc), symbol->string);
print_type_quoted(declaration->type);
fputc('\n', stderr);
points_to_left = skip_typeref(points_to_left);
points_to_right = skip_typeref(points_to_right);
- if(!is_type_atomic(points_to_left, ATOMIC_TYPE_VOID)
- && !is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)
- && !types_compatible(points_to_left, points_to_right)) {
- goto incompatible_assign_types;
- }
-
/* the left type has all qualifiers from the right type */
unsigned missing_qualifiers
= points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
return;
}
+ points_to_left = get_unqualified_type(points_to_left);
+ points_to_right = get_unqualified_type(points_to_right);
+
+ if(!is_type_atomic(points_to_left, ATOMIC_TYPE_VOID)
+ && !is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)
+ && !types_compatible(points_to_left, points_to_right)) {
+ goto incompatible_assign_types;
+ }
+
*right = create_implicit_cast(*right, type_left);
return;
}
return declarations;
}
+static void semantic_parameter(declaration_t *declaration)
+{
+ /* TODO: improve error messages */
+
+ if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
+ parse_error("typedef not allowed in parameter list");
+ } else if(declaration->storage_class != STORAGE_CLASS_NONE
+ && declaration->storage_class != STORAGE_CLASS_REGISTER) {
+ parse_error("parameter may only have none or register storage class");
+ }
+
+ type_t *orig_type = declaration->type;
+ if(orig_type == NULL)
+ return;
+ type_t *type = skip_typeref(orig_type);
+
+ /* Array as last part of a paramter type is just syntactic sugar. Turn it
+ * into a pointer. ยง 6.7.5.3 (7) */
+ if (type->type == TYPE_ARRAY) {
+ const array_type_t *arr_type = &type->array;
+ type_t *element_type = arr_type->element_type;
+
+ type = make_pointer_type(element_type, type->base.qualifiers);
+
+ declaration->type = type;
+ }
+
+ if(is_type_incomplete(type)) {
+ parser_print_error_prefix();
+ fprintf(stderr, "incomplete type (");
+ print_type_quoted(orig_type);
+ fprintf(stderr, ") not allowed for parameter '%s'\n",
+ declaration->symbol->string);
+ }
+}
+
static declaration_t *parse_parameter(void)
{
declaration_specifiers_t specifiers;
declaration_t *declaration = parse_declarator(&specifiers, true);
- /* TODO check declaration constraints for parameters */
- if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
- parse_error("typedef not allowed in parameter list");
- }
-
- /* Array as last part of a paramter type is just syntactic sugar. Turn it
- * into a pointer */
- if (declaration->type->type == TYPE_ARRAY) {
- const array_type_t *const arr_type = &declaration->type->array;
- type_t *element_type = arr_type->element_type;
- declaration->type = make_pointer_type(element_type, TYPE_QUALIFIER_NONE);
- }
+ semantic_parameter(declaration);
return declaration;
}
type_t *function_type = construct_function_type->function_type;
- function_type->function.result_type = type;
+ function_type->function.return_type = type;
type = function_type;
break;
#endif
}
+ semantic_parameter(parameter_declaration);
+
function_parameter_t *function_parameter
= obstack_alloc(type_obst, sizeof(function_parameter[0]));
memset(function_parameter, 0, sizeof(function_parameter[0]));
const source_position_t source_position)
{
type_t *ntype = allocate_type_zero(TYPE_FUNCTION);
- ntype->function.result_type = type_int;
+ ntype->function.return_type = type_int;
ntype->function.unspecified_parameters = true;
type_t *type = typehash_insert(ntype);
return declaration;
}
-static type_t *make_function_1_type(type_t *result_type, type_t *argument_type)
+static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
{
function_parameter_t *parameter
= obstack_alloc(type_obst, sizeof(parameter[0]));
parameter->type = argument_type;
type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.result_type = result_type;
+ type->function.return_type = return_type;
type->function.parameters = parameter;
type_t *result = typehash_insert(type);
type_t *type_left = left->base.datatype;
type_t *type_inside = inside->base.datatype;
- type_t *result_type = NULL;
+ type_t *return_type = NULL;
if(type_left != NULL && type_inside != NULL) {
type_left = skip_typeref(type_left);
if(is_type_pointer(type_left)) {
pointer_type_t *pointer = &type_left->pointer;
- result_type = pointer->points_to;
+ return_type = pointer->points_to;
array_access->array_ref = left;
array_access->index = inside;
} else if(is_type_pointer(type_inside)) {
pointer_type_t *pointer = &type_inside->pointer;
- result_type = pointer->points_to;
+ return_type = pointer->points_to;
array_access->array_ref = inside;
array_access->index = left;
array_access->flipped = true;
}
next_token();
- result_type = automatic_type_conversion(result_type);
- array_access->expression.datatype = result_type;
+ return_type = automatic_type_conversion(return_type);
+ array_access->expression.datatype = return_type;
return (expression_t*) array_access;
}
if (type->type == TYPE_FUNCTION) {
function_type = &type->function;
- call->expression.datatype = function_type->result_type;
+ call->expression.datatype = function_type->return_type;
}
}
if(function_type == NULL) {
assert(current_function->type->type == TYPE_FUNCTION);
function_type_t *function_type = ¤t_function->type->function;
- type_t *return_type = function_type->result_type;
+ type_t *return_type = function_type->return_type;
expression_t *return_value = NULL;
if(token.type != ';') {
{
print_type_qualifiers(type->type.qualifiers);
- intern_print_type_pre(type->result_type);
+ intern_print_type_pre(type->return_type);
/* TODO: don't emit braces if we're the toplevel type... */
fputc('(', out);
const context_t *context)
{
/* TODO: don't emit braces if we're the toplevel type... */
- intern_print_type_post(type->result_type);
+ intern_print_type_post(type->return_type);
fputc(')', out);
fputc('(', out);
}
}
+static size_t get_type_size(type_t *type)
+{
+ switch(type->type) {
+ case TYPE_ATOMIC: return sizeof(atomic_type_t);
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION: return sizeof(compound_type_t);
+ case TYPE_ENUM: return sizeof(enum_type_t);
+ case TYPE_FUNCTION: return sizeof(function_type_t);
+ case TYPE_POINTER: return sizeof(pointer_type_t);
+ case TYPE_ARRAY: return sizeof(array_type_t);
+ case TYPE_BUILTIN: return sizeof(builtin_type_t);
+ case TYPE_TYPEDEF: return sizeof(typedef_type_t);
+ case TYPE_TYPEOF: return sizeof(typeof_type_t);
+ case TYPE_INVALID: panic("invalid type found");
+ }
+ panic("unknown type found");
+}
+
+/**
+ * duplicates a type
+ * note that this does not produce a deep copy!
+ */
+type_t *duplicate_type(type_t *type)
+{
+ size_t size = get_type_size(type);
+
+ type_t *copy = obstack_alloc(type_obst, size);
+ memcpy(copy, type, size);
+
+ return copy;
+}
+
+type_t *get_unqualified_type(type_t *type)
+{
+ if(type->base.qualifiers == TYPE_QUALIFIER_NONE)
+ return type;
+
+ type_t *unqualified_type = duplicate_type(type);
+ unqualified_type->base.qualifiers = TYPE_QUALIFIER_NONE;
+
+ type_t *result = typehash_insert(unqualified_type);
+ if(result != unqualified_type) {
+ obstack_free(type_obst, unqualified_type);
+ }
+
+ return result;
+}
+
bool type_valid(const type_t *type)
{
return type->type != TYPE_INVALID;
panic("invalid type found");
}
+static bool function_types_compatible(const function_type_t *func1,
+ const function_type_t *func2)
+{
+ if(!types_compatible(func1->return_type, func2->return_type))
+ return false;
+
+ /* can parameters be compared? */
+ if(func1->unspecified_parameters || func2->unspecified_parameters)
+ return true;
+
+ if(func1->variadic != func2->variadic)
+ return false;
+
+ /* TODO: handling of unspecified parameters not correct yet */
+
+ /* all argument types must be compatible */
+ function_parameter_t *parameter1 = func1->parameters;
+ function_parameter_t *parameter2 = func2->parameters;
+ for( ; parameter1 != NULL && parameter2 != NULL;
+ parameter1 = parameter1->next, parameter2 = parameter2->next) {
+ type_t *parameter1_type = skip_typeref(parameter1->type);
+ type_t *parameter2_type = skip_typeref(parameter2->type);
+
+ parameter1_type = get_unqualified_type(parameter1_type);
+ parameter2_type = get_unqualified_type(parameter2_type);
+
+ if(!types_compatible(parameter1_type, parameter2_type))
+ return false;
+ }
+ /* same number of arguments? */
+ if(parameter1 != NULL || parameter2 != NULL)
+ return false;
+
+ return true;
+}
+
+static bool array_types_compatible(const array_type_t *array1,
+ const array_type_t *array2)
+{
+ type_t *element_type1 = skip_typeref(array1->element_type);
+ type_t *element_type2 = skip_typeref(array2->element_type);
+ if(!types_compatible(element_type1, element_type2))
+ return false;
+
+ if(array1->size != NULL && array2->size != NULL) {
+ /* TODO: check if size expression evaulate to the same value
+ * if they are constant */
+ }
+
+ return true;
+}
+
bool types_compatible(const type_t *type1, const type_t *type2)
{
assert(!is_typeref(type1));
assert(!is_typeref(type2));
- /* TODO: really incomplete */
+ /* shortcut: the same type is always compatible */
if(type1 == type2)
return true;
- if(type1->type == TYPE_ATOMIC && type2->type == TYPE_ATOMIC) {
+ if(type1->base.qualifiers != type2->base.qualifiers)
+ return false;
+ if(type1->type != type2->type)
+ return false;
+
+ switch(type1->type) {
+ case TYPE_FUNCTION:
+ return function_types_compatible(&type1->function, &type2->function);
+ case TYPE_ATOMIC:
return type1->atomic.atype == type2->atomic.atype;
+ case TYPE_ARRAY:
+ return array_types_compatible(&type1->array, &type2->array);
+ case TYPE_POINTER:
+ return types_compatible(type1->pointer.points_to,
+ type2->pointer.points_to);
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION:
+ case TYPE_ENUM:
+ case TYPE_BUILTIN:
+ /* TODO: not implemented */
+ break;
+
+ case TYPE_INVALID:
+ panic("invalid type found in compatible types");
+ case TYPE_TYPEDEF:
+ case TYPE_TYPEOF:
+ panic("typerefs not skipped in compatible types?!?");
}
+ /* TODO: incomplete */
return false;
}
return true;
}
-static size_t get_type_size(type_t *type)
-{
- switch(type->type) {
- case TYPE_ATOMIC: return sizeof(atomic_type_t);
- case TYPE_COMPOUND_STRUCT:
- case TYPE_COMPOUND_UNION: return sizeof(compound_type_t);
- case TYPE_ENUM: return sizeof(enum_type_t);
- case TYPE_FUNCTION: return sizeof(function_type_t);
- case TYPE_POINTER: return sizeof(pointer_type_t);
- case TYPE_ARRAY: return sizeof(array_type_t);
- case TYPE_BUILTIN: return sizeof(builtin_type_t);
- case TYPE_TYPEDEF: return sizeof(typedef_type_t);
- case TYPE_TYPEOF: return sizeof(typeof_type_t);
- case TYPE_INVALID: panic("invalid type found");
- }
- panic("unknown type found");
-}
-
-/**
- * duplicates a type
- * note that this does not produce a deep copy!
- */
-type_t *duplicate_type(type_t *type)
-{
- size_t size = get_type_size(type);
-
- type_t *copy = obstack_alloc(type_obst, size);
- memcpy(copy, type, size);
-
- return copy;
-}
-
type_t *skip_typeref(type_t *type)
{
unsigned qualifiers = type->base.qualifiers;
bool pointers_compatible(const type_t *type1, const type_t *type2);
+type_t *get_unqualified_type(type_t *type);
type_t *skip_typeref(type_t *type);
#endif
static unsigned hash_function_type(const function_type_t *type)
{
- unsigned result = hash_ptr(type->result_type);
+ unsigned result = hash_ptr(type->return_type);
function_parameter_t *parameter = type->parameters;
while(parameter != NULL) {
static bool function_types_equal(const function_type_t *type1,
const function_type_t *type2)
{
- if(type1->result_type != type2->result_type)
+ if(type1->return_type != type2->return_type)
return false;
if(type1->variadic != type2->variadic)
return false;
struct function_type_t {
type_base_t type;
- type_t *result_type;
+ type_t *return_type;
function_parameter_t *parameters;
unsigned variadic : 1;
unsigned unspecified_parameters : 1;
}
fprintf(out, ") : ");
- write_type(type->result_type);
+ write_type(type->return_type);
fprintf(out, ")");
}
}
fprintf(out, ")");
- const type_t *result_type = function_type->result_type;
- if(result_type->type != TYPE_ATOMIC ||
- ((const atomic_type_t*) result_type)->atype != ATOMIC_TYPE_VOID) {
+ const type_t *return_type = function_type->return_type;
+ if(!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
fprintf(out, " : ");
- write_type(result_type);
+ write_type(return_type);
}
fputc('\n', out);
}