Files
c3c/src/compiler/sema_internal.h

246 lines
11 KiB
C

#pragma once
// Copyright (c) 2020 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by a LGPLv3.0
// a copy of which can be found in the LICENSE file.
#include "compiler_internal.h"
#define INT5_MAX 15
#define INT12_MAX 2047
#define INT20_MAX 524287
#define INT5_MIN -16
#define INT12_MIN -2048
#define INT20_MIN (-INT20_MAX-1)
#define UINT5_MAX 31
#define UINT12_MAX 4095
#define UINT20_MAX 1048575U
#define SEMA_WARN(_node, ...) (sema_warn_at(context, (_node)->span, __VA_ARGS__))
#define SEMA_ERROR(_node, ...) sema_error_at(context, (_node)->span, __VA_ARGS__)
#define RETURN_SEMA_ERROR(_node, ...) do { sema_error_at(context, (_node)->span, __VA_ARGS__); return false; } while (0)
#define RETURN_NULL_SEMA_ERROR(_node, ...) do { sema_error_at(context, (_node)->span, __VA_ARGS__); return NULL; } while (0)
#define RETURN_SEMA_ERROR_AT(span__, ...) do { sema_error_at(context, span__, __VA_ARGS__); return false; } while (0)
#define SCOPE_OUTER_START do { DynamicScope stored_scope = context->active_scope; context_change_scope_with_flags(context, SCOPE_NONE);
#define SCOPE_OUTER_END ASSERT(context->active_scope.defer_last == context->active_scope.defer_start); context->active_scope = stored_scope; } while(0)
#define SCOPE_START SCOPE_START_WITH_FLAGS(SCOPE_NONE)
#define SCOPE_START_WITH_FLAGS(flags) do { DynamicScope old_scope = context->active_scope; context_change_scope_with_flags(context, flags);
#define SCOPE_START_WITH_LABEL(label) do { DynamicScope old_scope = context->active_scope; context_change_scope_for_label(context, label);
#define SCOPE_END ASSERT(context->active_scope.defer_last == context->active_scope.defer_start); context->active_scope = old_scope; } while(0)
#define SCOPE_POP_ERROR() ((bool)(context->active_scope = old_scope, false))
#define SCOPE_ERROR_END_OUTER() do { context->active_scope = stored_scope; } while(0)
#define PUSH_X(ast, X) AstId _old_##X##_defer = context->X##_defer; Ast *_old_##X = context->X##_target; context->X##_target = ast; context->X##_defer = context->active_scope.defer_last
#define POP_X(X) context->X##_target = _old_##X; context->X##_defer = _old_##X##_defer
#define PUSH_CONTINUE(ast) PUSH_X(ast, continue)
#define POP_CONTINUE() POP_X(continue)
#define PUSH_BREAK(ast) PUSH_X(ast, break)
#define POP_BREAK() POP_X(break)
#define PUSH_NEXT(ast, sast) PUSH_X(ast, next); Ast *_old_next_switch = context->next_switch; context->next_switch = sast
#define POP_NEXT() POP_X(next); context->next_switch = _old_next_switch
#define PUSH_BREAKCONT(ast) PUSH_CONTINUE(ast); PUSH_BREAK(ast)
#define POP_BREAKCONT() POP_CONTINUE(); POP_BREAK()
Decl **global_context_acquire_locals_list(void);
void generic_context_release_locals_list(Decl **);
const char *context_filename(SemaContext *context);
AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bottom, bool is_success);
void context_pop_defers(SemaContext *context, AstId *next);
void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast);
void context_change_scope_for_label(SemaContext *context, DeclId label);
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags);
SemaContext *context_transform_for_eval(SemaContext *context, SemaContext *temp_context, CompilationUnit *eval_unit);
TokenType sema_splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref);
void sema_print_inline(SemaContext *context);
void sema_error_at(SemaContext *context, SourceSpan span, const char *message, ...);
bool sema_warn_at(SemaContext *context, SourceSpan span, const char *message, ...);
void sema_context_init(SemaContext *context, CompilationUnit *unit);
void sema_context_destroy(SemaContext *context);
unsigned sema_context_push_ct_stack(SemaContext *context);
void sema_context_pop_ct_stack(SemaContext *context, unsigned old_state);
bool sema_analyse_function_body(SemaContext *context, Decl *func);
bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts, SourceSpan span, bool *has_ensures);
void sema_append_contract_asserts(AstId assert_first, Ast* compound_stmt);
Decl *sema_create_runner_main(SemaContext *context, Decl *decl);
void sema_analyse_pass_top(Module *module);
void sema_analyse_pass_module_hierarchy(Module *module);
void sema_analysis_pass_process_imports(Module *module);
void sema_analysis_pass_register_global_declarations(Module *module);
void sema_analysis_pass_process_includes(Module *module);
void sema_analysis_pass_register_conditional_units(Module *module);
void sema_analysis_pass_register_conditional_declarations(Module *module);
void sema_analysis_pass_process_methods(Module *module, bool process_generic);
void sema_analysis_pass_decls(Module *module);
void sema_analysis_pass_ct_assert(Module *module);
void sema_analysis_pass_ct_echo(Module *module);
void sema_analysis_pass_functions(Module *module);
void sema_analysis_pass_interface(Module *module);
void sema_analysis_pass_lambda(Module *module);
void sema_analyze_stage(Module *module, AnalysisStage stage);
void sema_trace_liveness(void);
Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing);
bool sema_analyse_expr_address(SemaContext *context, Expr *expr);
bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr, bool *failed_ref);
bool sema_analyse_expr_value(SemaContext *context, Expr *expr);
Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl);
bool sema_analyse_ct_expr(SemaContext *context, Expr *expr);
Decl *sema_find_typed_operator(SemaContext *context, OperatorOverload operator_overload, Expr *lhs, Expr *rhs, Decl **ambiguous_ref, bool *reverse);
Decl *sema_find_untyped_operator(SemaContext *context, Type *type, OperatorOverload operator_overload, Decl *skipped);
bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments, bool reverse_overload);
bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr);
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool call_var_optional, bool *no_match_ref);
Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr, unsigned *index_ref);
Expr *sema_ct_eval_expr(SemaContext *context, bool is_type_eval, Expr *inner, bool report_missing);
Expr *sema_resolve_string_ident(SemaContext *context, Expr *inner, bool report_missing);
bool sema_analyse_asm(SemaContext *context, AsmInlineBlock *block, Ast *asm_stmt);
bool sema_bit_assignment_check(SemaContext *context, Expr *right, Decl *member);
CondResult sema_check_comp_time_bool(SemaContext *context, Expr *expr);
bool sema_expr_check_assign(SemaContext *context, Expr *expr, bool *failed_ref);
bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, TypeInfo *parent, CallABI abi, Signature *signature);
Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Expr **exprs);
ConstInitializer *sema_merge_bitstruct_const_initializers(ConstInitializer *lhs, ConstInitializer *rhs, BinaryOp op);
void sema_invert_bitstruct_const_initializer(ConstInitializer *initializer);
ArrayIndex sema_len_from_const(Expr *expr);
void cast_promote_vararg(Expr *arg);
Type *cast_numeric_arithmetic_promotion(Type *type);
void cast_to_int_to_max_bit_size(Expr *lhs, Expr *rhs, Type *left_type, Type *right_type);
bool sema_decl_if_cond(SemaContext *context, Decl *decl);
Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, const char *name, SourceSpan span,
Expr **params, bool *was_recursive_ref);
bool sema_parameterized_type_is_found(SemaContext *context, Path *decl_path, const char *name, SourceSpan span);
Type *sema_resolve_type_get_func(Signature *signature, CallABI abi);
INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result);
INLINE bool sema_set_alloca_alignment(SemaContext *context, Type *type, AlignSize *result);
INLINE void sema_display_deprecated_warning_on_use(Decl *decl, SourceSpan span);
bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *left, Expr *right);
INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result)
{
if (type_is_func_ptr(type))
{
*result = type_abi_alignment(type_voidptr);
return true;
}
if (!sema_resolve_type_decl(context, type)) return false;
*result = type_abi_alignment(type);
return true;
}
INLINE bool sema_set_alloca_alignment(SemaContext *context, Type *type, AlignSize *result)
{
if (!sema_resolve_type_decl(context, type)) return false;
*result = type_alloca_alignment(type);
return true;
}
INLINE Attr* attr_find_kind(Attr **attrs, AttributeType attr_type)
{
FOREACH(Attr *, attr, attrs)
{
if (attr->attr_kind == attr_type) return attr;
}
return NULL;
}
INLINE void sema_display_deprecated_warning_on_use(Decl *decl, SourceSpan span)
{
ASSERT(decl->resolve_status == RESOLVE_DONE);
if (!decl->resolved_attributes || !decl->attrs_resolved || !decl->attrs_resolved->deprecated) return;
const char *msg = decl->attrs_resolved->deprecated;
// Prevent multiple reports
decl->attrs_resolved->deprecated = NULL;
if (compiler.build.silence_deprecation) return;
if (msg[0])
{
sema_warning_at(span, "'%s' is deprecated: %s.", decl->name, msg);
return;
}
sema_warning_at(span, "'%s' is deprecated.", decl->name);
}
static inline IndexDiff range_const_len(Range *range)
{
switch (range->range_type)
{
case RANGE_CONST_LEN:
return range->const_end;
case RANGE_CONST_END:
return -1;
case RANGE_CONST_RANGE:
return range->len_index;
case RANGE_DYNAMIC:
break;
}
Expr *start = exprptr(range->start);
Expr *end = exprptrzero(range->end);
if (!end || !expr_is_const_int(end)) return -1;
if (!int_fits(end->const_expr.ixx, TYPE_I32)) return -1;
IndexDiff end_val = (IndexDiff)int_to_i64(end->const_expr.ixx);
if (range->is_len) return end_val;
if (!expr_is_const_int(start)) return -1;
if (!int_fits(start->const_expr.ixx, TYPE_I32)) return -1;
IndexDiff start_val = (IndexDiff)int_to_i64(start->const_expr.ixx);
if (range->start_from_end && range->end_from_end) return start_val - end_val + 1;
if (range->start_from_end != range->end_from_end) return -1;
return end_val - start_val + 1;
}
static inline StorageType sema_resolve_storage_type(SemaContext *context, Type *type)
{
if (!type) return STORAGE_NORMAL;
bool is_distinct = false;
RETRY:
if (type == type_wildcard_optional) return STORAGE_WILDCARD;
switch (type->type_kind)
{
case TYPE_VOID:
return is_distinct ? STORAGE_UNKNOWN : STORAGE_VOID;
case TYPE_WILDCARD:
return STORAGE_WILDCARD;
case TYPE_MEMBER:
case TYPE_UNTYPED_LIST:
case TYPE_TYPEINFO:
case TYPE_FUNC_RAW:
return STORAGE_COMPILE_TIME;
case TYPE_OPTIONAL:
type = type->optional;
goto RETRY;
case TYPE_TYPEDEF:
if (!sema_analyse_decl(context, type->decl)) return false;
type = type->canonical;
goto RETRY;
case TYPE_DISTINCT:
is_distinct = true;
if (!sema_analyse_decl(context, type->decl)) return false;
type = type->decl->distinct->type;
goto RETRY;
default:
return STORAGE_NORMAL;
}
}
static inline TypeProperty type_property_by_name(const char *name)
{
for (unsigned i = 0; i < NUMBER_OF_TYPE_PROPERTIES; i++)
{
if (type_property_list[i] == name) return (TypeProperty)i;
}
return TYPE_PROPERTY_NONE;
}