46 if (
tree_is(decl, eTreeError)) {
return false; }
54 "declaration has an empty name"
62 if (attribs->
link != eLinkModule)
65 "externally visible declaration is anonymous"
72 CTASSERTF(ty != NULL,
"decl `%s` has no type",
id);
77 static void check_global_attribs(
check_t *check,
const tree_t *global)
80 switch (attribs->
link)
86 "global `%s` is marked as imported but has an implementation",
89 msg_note(
id,
"implementation will be ignored");
94 if (attribs->
mangle != NULL)
97 "global `%s` has internal linkage and user defined mangling",
100 msg_note(
id,
"attribute will be ignored");
107 "global `%s` is marked as an entry point but is not a function",
116 static void check_func_has_body(
check_t *check,
const tree_t *fn)
118 if (fn->
body != NULL) {
return; }
121 "function `%s` is an entry point, but has no body",
126 static void check_func_attribs(
check_t *check,
const tree_t *fn)
130 switch (attribs->
link)
133 if (fn->
body != NULL)
136 "function `%s` is marked as imported but has an implementation",
143 if (attribs->
mangle != NULL)
146 "function `%s` has internal linkage and user defined mangling",
149 msg_note(
id,
"attribute will be ignored");
154 check_func_has_body(check, fn);
158 "multiple CLI entry points defined"
168 check_func_has_body(check, fn);
172 "multiple GUI entry points defined"
186 static void check_func_return_equal(
check_t *check,
const tree_t *return_type,
const tree_t *real_type)
191 "return type `%s` does not match function return type `%s`",
197 static void check_deprecated_call(
check_t *check,
const tree_t *expr)
201 if (!
tree_is(fn, eTreeDeclFunction)) {
return; }
208 "call to deprecated function `%s`",
214 static const char *get_fn_name(
const tree_t *fn)
224 static void check_single_expr(
check_t *check,
const tree_t *expr);
226 static void check_params(
check_t *check,
const vector_t *args,
const vector_t *params,
size_t count,
const char *name)
228 for (
size_t i = 0; i < count; i++)
239 check_single_expr(check, arg);
244 "incorrect type for parameter %zu of function `%s`",
258 const char *name = get_fn_name(expr->
callee);
260 if (arg_count != param_count)
263 "incorrect number of parameters to function `%s`",
266 msg_note(
id,
"expected %zu, got %zu", param_count, arg_count);
269 size_t count =
CT_MIN(arg_count, param_count);
271 check_params(check, args, params, count, name);
279 const char *name = get_fn_name(expr->
callee);
281 if (arg_count < param_count)
284 "incorrect number of parameters to variadic function `%s`",
287 msg_note(
id,
"expected at least %zu parameters, only got %zu", param_count, arg_count);
290 size_t count =
CT_MIN(arg_count, param_count);
292 check_params(check, args, params, count, name);
295 static void check_call_arguments(
check_t *check,
const tree_t *expr)
299 if (
tree_is(fn, eTreeExprLoad))
311 check_call_args_fixed(check, expr, fn_args, fn_params);
315 check_call_args_variadic(check, expr, fn_args, fn_params);
319 CT_NEVER(
"invalid arity %d (check-call-arguments)", arity);
323 static const tree_t *get_simple_expr_type(
const tree_t *expr)
328 static bool is_valid_bitcast_type(
const tree_t *type)
330 return tree_is(type, eTreeTypeDigit)
331 ||
tree_is(type, eTreeTypePointer)
332 ||
tree_is(type, eTreeTypeOpaque)
333 ||
tree_is(type, eTreeTypeArray)
334 ||
tree_is(type, eTreeTypeReference);
337 static void check_bitcast_expr(
check_t *check,
const tree_t *expr)
339 const tree_t *dst = get_simple_expr_type(expr);
340 if (!is_valid_bitcast_type(dst))
343 "bitcast to invalid type `%s`",
346 msg_note(msg,
"expected digit, pointer or opaque pointer");
349 const tree_t *src = get_simple_expr_type(expr->
expr);
350 if (!is_valid_bitcast_type(src))
353 "bitcast from invalid type `%s`",
356 msg_note(msg,
"expected digit, pointer or opaque pointer");
360 static void check_signextend_expr(
check_t *check,
const tree_t *expr)
362 const tree_t *dst = get_simple_expr_type(expr);
366 "sign extension of non-integer type `%s`",
371 const tree_t *src = get_simple_expr_type(expr->
expr);
375 "sign extension from non-integer type `%s`",
381 static void check_zeroextend_expr(
check_t *check,
const tree_t *expr)
383 const tree_t *dst = get_simple_expr_type(expr);
387 "zero extension into non-integer type `%s`",
392 const tree_t *src = get_simple_expr_type(expr->
expr);
396 "zero extension of non-integer type `%s`",
402 static bool is_invalid_cast_type(
const tree_t *type)
404 return tree_is(type, eTreeTypeUnit)
405 ||
tree_is(type, eTreeTypeEmpty);
408 static void check_cast_expr(
check_t *check,
const tree_t *expr)
410 const tree_t *dst = get_simple_expr_type(expr);
411 const tree_t *src = get_simple_expr_type(expr->
expr);
412 if (is_invalid_cast_type(src))
415 "invalid cast from type `%s`",
422 if (is_invalid_cast_type(dst))
425 "invalid cast to type `%s`",
435 check_bitcast_expr(check, expr);
437 case eCastSignExtend:
438 check_signextend_expr(check, expr);
440 case eCastZeroExtend:
441 check_zeroextend_expr(check, expr);
448 static bool is_pointer_arithmetic(
const tree_t *lhs,
const tree_t *rhs)
450 return tree_is(lhs, eTreeTypeDigit) &&
tree_is(rhs, eTreeTypePointer);
453 static void check_binary_expr(
check_t *check,
const tree_t *expr)
455 check_single_expr(check, expr->
lhs);
456 check_single_expr(check, expr->
rhs);
458 const tree_t *lhs = get_simple_expr_type(expr->
lhs);
459 const tree_t *rhs = get_simple_expr_type(expr->
rhs);
461 if (!
tree_is(lhs, eTreeTypeDigit) && !
tree_is(rhs, eTreeTypeDigit))
464 "binary operation with non-digit types `%s` and `%s`",
470 if (is_pointer_arithmetic(lhs, rhs) || is_pointer_arithmetic(rhs, lhs))
480 "binary operation with different types `%s` and `%s`",
487 static void check_single_expr(
check_t *check,
const tree_t *expr)
492 check_deprecated_call(check, expr);
493 check_call_arguments(check, expr);
496 case eTreeExprBinary:
497 check_binary_expr(check, expr);
500 case eTreeExprCompare:
501 check_single_expr(check, expr->
lhs);
502 check_single_expr(check, expr->
rhs);
506 check_cast_expr(check, expr);
510 check_single_expr(check, expr->
operand);
513 check_single_expr(check, expr->
load);
516 case eTreeExprOffset:
517 check_single_expr(check, expr->
object);
518 check_single_expr(check, expr->
offset);
524 case eTreeDeclGlobal:
525 case eTreeDeclFunction:
528 case eTreeExprString:
535 check_single_expr(check, expr->
object);
538 case eTreeExprSizeOf:
539 case eTreeExprAlignOf:
540 case eTreeExprAddressOf:
543 case eTreeExprOffsetOf:
544 check_single_expr(check, expr->
object);
559 if ((quals & eQualConst) && !stmt->
init)
562 "assignment to constant `%s`",
571 "assignment to parameter `%s`",
580 if (
tree_is(src_type, eTreeTypeReference))
581 src_type = src_type->
ptr;
583 if (
tree_is(dst_type, eTreeTypeReference))
584 dst_type = dst_type->
ptr;
589 "assignment of type `%s` to `%s`",
596 check_single_expr(check, stmt->
src);
616 case eTreeStmtBranch: {
617 check_func_body(check, return_type, stmt->
then);
619 if (stmt->
other != NULL)
620 check_func_body(check, return_type, stmt->
other);
625 case eTreeStmtAssign:
626 check_assign(check, stmt);
629 case eTreeStmtReturn:
635 case eTreeExprAddressOf:
637 case eTreeExprBinary:
638 case eTreeExprCompare:
640 case eTreeExprOffset:
642 check_single_expr(check, stmt);
650 static bool will_always_return(
const tree_t *stmt)
656 case eTreeStmtReturn:
659 case eTreeStmtBranch: {
661 bool other_returns = stmt->
other != NULL && will_always_return(stmt->
other);
662 return will_always_return(stmt->
then) && other_returns;
666 return will_always_return(stmt->
then);
686 for (
size_t i = 0; i < len; i++)
689 check_simple(check, local);
692 if (
tree_is(type, eTreeTypeUnit))
695 "local `%s` has type `unit`",
699 else if (
tree_is(type, eTreeTypeEmpty))
702 "local `%s` has type `empty`",
709 static void check_function_definition(
check_t *check,
const tree_t *fn)
711 if (fn->
body == NULL) {
return; }
713 check_func_locals(check, fn->
locals);
716 check_func_body(check, return_type, fn->
body);
718 if (!will_always_return(fn->
body))
720 if (
tree_is(return_type, eTreeTypeUnit)) {
return; }
723 "function `%s` may not return a value",
729 static void check_global_recursion(
check_t *check,
const tree_t *global);
731 static void check_expr_recursion(
check_t *check,
const tree_t *tree)
739 case eTreeExprString:
743 check_expr_recursion(check, tree->
load);
746 case eTreeExprCall: {
747 check_expr_recursion(check, tree->
callee);
749 for (
size_t i = 0; i < len; ++i)
752 check_expr_recursion(check, arg);
757 case eTreeExprBinary:
758 check_expr_recursion(check, tree->
lhs);
759 check_expr_recursion(check, tree->
rhs);
763 check_expr_recursion(check, tree->
operand);
767 check_expr_recursion(check, tree->
expr);
770 case eTreeExprCompare:
771 check_expr_recursion(check, tree->
lhs);
772 check_expr_recursion(check, tree->
rhs);
775 case eTreeDeclGlobal:
776 check_global_recursion(check, tree);
782 static void check_global_recursion(
check_t *check,
const tree_t *global)
795 check_expr_recursion(check, global->
initial);
802 "evaluation of `%s` may be infinite",
806 for (
size_t i = 0; i < len; i++)
816 static void check_global_type(
check_t *check,
const tree_t *global)
821 if (
tree_is(ty, eTreeTypeUnit))
824 "global `%s` is of unit type `%s`",
829 else if (
tree_is(ty, eTreeTypeEmpty))
832 "global `%s` is of empty type `%s`",
843 "global value `%s` has invalid storage `%s`",
854 static void check_aggregate_recursion(
check_t *check,
const tree_t *type);
856 static void check_struct_type_recursion(
check_t *check,
const tree_t *type)
866 case eTreeTypePointer:
867 case eTreeTypeOpaque:
868 case eTreeTypeClosure:
873 case eTreeTypeStruct:
875 check_aggregate_recursion(check, type);
882 static void check_aggregate_recursion(
check_t *check,
const tree_t *type)
894 for (
size_t i = 0; i < len; i++)
898 check_struct_type_recursion(check, ty);
905 "size of type `%s` may be infinite",
909 for (
size_t i = 0; i < len; i++)
923 static void check_type_recursion(
check_t *check,
const tree_t *type);
925 static void check_inner_type_recursion(
check_t *check,
const tree_t *type)
935 case eTreeTypeStruct:
938 case eTreeTypeOpaque:
945 case eTreeTypeClosure:
949 for (
size_t i = 0; i < len; i++)
953 check_type_recursion(check, ty);
957 case eTreeTypePointer:
958 case eTreeTypeReference:
960 check_type_recursion(check, type->
ptr);
967 static void check_type_recursion(
check_t *check,
const tree_t *type)
978 check_inner_type_recursion(check, type);
984 "type `%s` contains an impossible type",
988 for (
size_t i = 0; i < len; i++)
998 static void check_any_type_recursion(
check_t *check,
const tree_t *type)
1002 case eTreeTypeUnion:
1003 case eTreeTypeStruct:
1004 check_aggregate_recursion(check, type);
1007 default: check_type_recursion(check, type);
break;
1011 static void check_global_init(
check_t *check,
const tree_t *global)
1015 check_single_expr(check, global->
initial);
1019 static void check_module_valid(
check_t *check,
const tree_t *mod)
1026 for (
size_t i = 0; i < total_modules; i++)
1029 check_module_valid(check, child);
1034 for (
size_t i = 0; i < total_globals; i++)
1038 check_simple(check, global);
1040 check_global_attribs(check, global);
1041 check_global_recursion(check, global);
1042 check_global_type(check, global);
1043 check_global_init(check, global);
1047 size_t total_functions =
vector_len(functions);
1048 for (
size_t i = 0; i < total_functions; i++)
1052 check_simple(check,
function);
1054 check_func_attribs(check,
function);
1055 check_function_definition(check,
function);
1060 for (
size_t i = 0; i < total_types; i++)
1066 check_any_type_recursion(check, type);
1088 for (
size_t i = 0; i < len; i++)
1091 check_module_valid(&check, tree);
CT_PUREFN CT_TREE_API const node_t * tree_get_node(const tree_t *tree)
CT_PUREFN CT_TREE_API tree_kind_t tree_get_kind(const tree_t *tree)
CT_PUREFN CT_TREE_API const char * tree_get_name(const tree_t *tree)
CT_PUREFN CT_TREE_API const char * tree_get_user_name(const tree_t *tree)
CT_PUREFN CT_TREE_API const tree_t * tree_get_type(const tree_t *tree)
CT_PUREFN CT_TREE_API bool tree_is(const tree_t *self, tree_kind_t kind)
CT_TREE_API tree_storage_t tree_get_storage(const tree_t *tree)
CT_PUREFN CT_TREE_API bool tree_is_symbol_anonymous(const tree_t *tree)
CT_TREE_API tree_quals_t tree_get_storage_quals(const tree_t *self)
CT_PUREFN CT_TREE_API tree_arity_t tree_fn_get_arity(const tree_t *self)
CT_TREE_API const char * tree_to_string(const tree_t *self)
CT_PUREFN CT_TREE_API const tree_t * tree_fn_get_return(const tree_t *self)
CT_TREE_API bool tree_has_storage(const tree_t *self)
CT_TREE_API const tree_attribs_t * tree_get_attrib(const tree_t *self)
CT_PUREFN CT_TREE_API const vector_t * tree_fn_get_params(const tree_t *self)
#define STA_DECL
sal2 annotation on function implementations to copy annotations from the declaration
CT_NODISCARD CT_PUREFN CT_BASE_API bool str_equal(const char *lhs, const char *rhs)
compare strings equality
STA_DECL void check_tree(logger_t *reports, vector_t *mods, arena_t *arena)
check the tree form IR all found errors are reported to the reports object
STA_RET_STRING colour_t idx
CT_NODISCARD CT_STD_API vector_t * map_values(map_t *map)
collect all the values from a map into a vector
CT_NODISCARD CT_STD_API set_t * set_new(size_t size, hash_info_t info, arena_t *arena)
create a new set
CT_STD_API const void * set_add(set_t *set, const void *key)
add a key to a set
CT_NODISCARD CT_PUREFN CT_STD_API bool set_contains(const set_t *set, const void *key)
check if a set contains a key
#define CT_UNUSED(x)
mark a variable as unused
CT_NOTIFY_API event_builder_t msg_notify(INOUT_NOTNULL logger_t *logs, const diagnostic_t *diagnostic, const node_t *node, STA_FORMAT_STRING const char *fmt,...)
notify the logger of a new message
CT_NOTIFY_API void msg_append(event_builder_t builder, const node_t *node, STA_FORMAT_STRING const char *fmt,...)
append additional information to a message
CT_NOTIFY_API void msg_note(event_builder_t builder, STA_FORMAT_STRING const char *fmt,...)
add a note to an existing message
#define CT_NEVER(...)
assert that a code path is never reached
#define CTASSERT(expr)
assert a condition, prints the condition as a message
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
CT_BEGIN_API CT_UTIL_API bool util_types_equal(const tree_t *lhs, const tree_t *rhs)
compare two types for strict equality compares two types for exact equality, does not follow typedefs
CT_UTIL_API bool util_type_is_digit(const tree_t *type)
tree_quals_t
all type qualifiers
CT_TREE_API map_t * tree_module_tag(const tree_t *self, size_t tag)
CT_TREE_API const tree_t * tree_follow_type(const tree_t *type)
CT_STD_API const hash_info_t kTypeInfoPtr
type information for a generic pointer this operates on the pointer itself and not the data it points...
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
CT_NODISCARD CT_STD_API vector_t * vector_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
CT_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
CT_STD_API void vector_drop(vector_t *vector)
pop a value from the end of a vector
CT_PUREFN CT_STD_API size_t vector_find(vector_t *vector, const void *element)
find an element in a vector searches via pointer equality
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
an event builder handles adding additional information to an event
const char * mangle
override the mangle of the declaration
const char * deprecated
the reason for deprecation, or NULL if not deprecated
tree_linkage_t link
the link type of the declaration
const tree_t * storage
the underlying storage type
a generic vector of pointers