Files
c3c/src/compiler/sema_internal.h
Christoffer Lerno 4899ee14e2 Resolving &X.b when X is a const incorrectly checked for runtime constness #2842
Creating a generic instance fails if it is created after interface checking #2840
2026-01-25 21:24:27 +01:00

303 lines
14 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_VAL_SEMA_ERROR(val__, _node, ...) do { sema_error_at(context, (_node)->span, __VA_ARGS__); return (val__); } 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(span__) do { DynamicScope stored_scope = context->active_scope; context_change_scope_with_flags(context, SCOPE_NONE, span__);
#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(span__) SCOPE_START_WITH_FLAGS(SCOPE_NONE, span__)
#define SCOPE_START_WITH_FLAGS(flags, span__) do { DynamicScope old_scope = context->active_scope; context_change_scope_with_flags(context, flags, span__);
#define SCOPE_START_WITH_LABEL(label, span__) do { DynamicScope old_scope = context->active_scope; context_change_scope_for_label(context, label, span__);
#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_Y(ast, X) JumpTarget _old_##X = context->X##_jump; context->X##_jump = (JumpTarget) { ast, context->active_scope.defer_last }
#define POP_Y(X) context->X##_jump = _old_##X;
#define PUSH_CONTINUE(ast) PUSH_Y(ast, continue)
#define POP_CONTINUE() POP_Y(continue)
#define PUSH_BREAK(ast) PUSH_Y(ast, break)
#define POP_BREAK() POP_Y(break)
#define PUSH_NEXT(ast, sast) PUSH_Y(ast, next); Ast *_old_next_switch = context->next_switch; context->next_switch = sast
#define POP_NEXT() POP_Y(next); context->next_switch = _old_next_switch
#define PUSH_BREAKCONT(ast) PUSH_CONTINUE(ast); PUSH_BREAK(ast)
#define POP_BREAKCONT() POP_CONTINUE(); POP_BREAK()
#define CHECK_ON_DEFINED(ref__) do { if (!ref__) break; *ref__ = true; return false; } while(0)
#define SET_JUMP_END(context__, node__) do { (context__)->active_scope.end_jump = (EndJump) { true, (node__)->span }; } while(0)
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_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, SourceSpan span);
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags, SourceSpan span);
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, SourceSpan span_original);
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_lvalue(SemaContext *context, Expr *expr, bool *failed_ref);
bool sema_analyse_expr(SemaContext *context, Expr *expr);
Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl);
void expr_set_to_ref(Expr *expr);
bool sema_analyse_ct_expr(SemaContext *context, Expr *expr);
Decl *sema_find_typed_operator(SemaContext *context, OperatorOverload operator_overload, SourceSpan span, Expr *lhs, Expr *rhs, bool *reverse);
OverloadMatch sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overload_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref);
BoolErr sema_type_has_equality_overload(SemaContext *context, Type *type);
BoolErr sema_type_can_check_equality_with_overload(SemaContext *context, Type *type);
Decl *sema_find_untyped_operator(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);
void sema_add_methods_to_decl_stack(SemaContext *context, Decl *decl);
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, CtEvalKind eval_kind, 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_expr_analyse_sprintf(SemaContext *context, Expr *expr, Expr *format_string, Expr **args, unsigned num_args);
bool sema_check_swizzle_string(SemaContext *context, Expr *expr, const char *kw, unsigned len, unsigned vec_len, bool *is_overlapping_ref, int *index_ref);
bool sema_kw_is_swizzle(const char *kw, unsigned len);
bool sema_bit_assignment_check(SemaContext *context, Expr *right, Decl *member, bool *failed_ref);
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_generate_parameterized_identifier(SemaContext *context, Decl *generic, Decl *alias, Expr **params,
Decl **param_decls, const char *suffix, const char *csuffix, SourceSpan invocation_span, SourceSpan span);
Decl *sema_analyse_parameterized_identifier(SemaContext *context, Path *decl_path, const char *name, SourceSpan span,
Expr **params, bool *was_recursive_ref, SourceSpan invocation_span);
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_alignment(SemaContext *context, Type *type, AlignSize *result, bool is_alloca);
INLINE bool sema_set_alloca_alignment(SemaContext *context, Type *type, AlignSize *result);
INLINE void sema_display_deprecated_warning_on_use(SemaContext *context, Decl *decl, SourceSpan span);
bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *left, Expr *right, bool *failed_ref);
bool sema_analyse_const_enum_constant_val(SemaContext *context, Decl *decl);
bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr **attrs, AttributeDomain domain, bool *erase_decl);
void unit_register_optional_global_decl(CompilationUnit *unit, Decl *decl);
bool analyse_func_body(SemaContext *context, Decl *decl);
bool sema_check_interfaces(SemaContext *context, Decl *decl);
INLINE bool sema_analyse_stmt_chain(SemaContext *context, Ast *statement)
{
if (!ast_ok(statement)) return false;
AstId current = astid(statement);
Ast *ast = NULL;
bool all_ok = true;
while (current)
{
ast = ast_next(&current);
if (!sema_analyse_statement(context, ast))
{
ast_poison(ast);
all_ok = false;
}
}
return all_ok;
}
INLINE bool sema_analyse_func_macro(SemaContext *context, Decl *decl, AttributeDomain domain, bool *erase_decl)
{
assert((domain & CALLABLE_TYPE) == domain);
if (!sema_analyse_attributes(context, decl, decl->attributes, domain,
erase_decl)) return decl_poison(decl);
return true;
}
INLINE bool sema_check_left_right_const(SemaContext *context, Expr *left, Expr *right)
{
if (!sema_cast_const(left)) RETURN_SEMA_ERROR(left, "Expected this to evaluate to a constant value.");
if (!sema_cast_const(right)) RETURN_SEMA_ERROR(right, "Expected this to evaluate to a constant value.");
return true;
}
INLINE bool sema_set_alignment(SemaContext *context, Type *type, AlignSize *result, bool is_alloca)
{
type = type->canonical;
if (type_is_func_ptr(type))
{
*result = type_abi_alignment(type_voidptr);
return true;
}
if (!sema_resolve_type_decl(context, type)) return false;
*result = is_alloca ? type_alloca_alignment(type) : 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(SemaContext *context, Decl *decl, SourceSpan span)
{
ASSERT(decl->resolve_status == RESOLVE_DONE);
if (!decl_is_deprecated(decl)) return;
if (context->call_env.ignore_deprecation) 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_SINGLE_ELEMENT:
UNREACHABLE;
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_ALIAS:
if (!sema_analyse_decl(context, type->decl)) return false;
type = type->canonical;
goto RETRY;
case TYPE_TYPEDEF:
is_distinct = true;
if (!sema_analyse_decl(context, type->decl)) return false;
type = type->decl->distinct->type;
goto RETRY;
case TYPE_FLEXIBLE_ARRAY:
return STORAGE_UNKNOWN;
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;
}