mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
IR: re-organize where state goes to prepare for generics
* Rip out legacy code for generics
* put scope in instruction instead of AST nodes
* separate top level decl stuff from AST nodes
- remove the assumption that there is a 1:1 correspondence
between an output instruction and an AST node
- This way we won't have to clone AST nodes for generics.
This commit is contained in:
parent
f6cbb73c74
commit
2f259b8176
@ -20,6 +20,8 @@ struct AstNode;
|
||||
struct ImportTableEntry;
|
||||
struct FnTableEntry;
|
||||
struct Scope;
|
||||
struct ScopeBlock;
|
||||
struct ScopeFnDef;
|
||||
struct TypeTableEntry;
|
||||
struct VariableTableEntry;
|
||||
struct ErrorTableEntry;
|
||||
@ -33,6 +35,13 @@ struct IrInstructionCast;
|
||||
struct IrBasicBlock;
|
||||
struct ScopeDecls;
|
||||
|
||||
struct IrGotoItem {
|
||||
AstNode *source_node;
|
||||
IrBasicBlock *bb;
|
||||
size_t instruction_index;
|
||||
Scope *scope;
|
||||
};
|
||||
|
||||
struct IrExecutable {
|
||||
ZigList<IrBasicBlock *> basic_block_list;
|
||||
size_t mem_slot_count;
|
||||
@ -41,8 +50,9 @@ struct IrExecutable {
|
||||
size_t backward_branch_quota;
|
||||
bool invalid;
|
||||
ZigList<LabelTableEntry *> all_labels;
|
||||
ZigList<AstNode *> goto_list;
|
||||
ZigList<IrGotoItem> goto_list;
|
||||
bool is_inline;
|
||||
FnTableEntry *fn_entry;
|
||||
};
|
||||
|
||||
enum OutType {
|
||||
@ -129,36 +139,62 @@ enum ReturnKnowledge {
|
||||
ReturnKnowledgeSkipDefers,
|
||||
};
|
||||
|
||||
struct StructValExprCodeGen {
|
||||
TypeTableEntry *type_entry;
|
||||
LLVMValueRef ptr;
|
||||
AstNode *source_node;
|
||||
};
|
||||
|
||||
enum VisibMod {
|
||||
VisibModPrivate,
|
||||
VisibModPub,
|
||||
VisibModExport,
|
||||
};
|
||||
|
||||
enum TldId {
|
||||
TldIdVar,
|
||||
TldIdFn,
|
||||
TldIdContainer,
|
||||
TldIdTypeDef,
|
||||
};
|
||||
|
||||
enum TldResolution {
|
||||
TldResolutionUnresolved,
|
||||
TldResolutionInvalid,
|
||||
TldResolutionOk,
|
||||
};
|
||||
|
||||
struct TopLevelDecl {
|
||||
// populated by parser
|
||||
struct Tld {
|
||||
TldId id;
|
||||
Buf *name;
|
||||
VisibMod visib_mod;
|
||||
AstNode *source_node;
|
||||
|
||||
// populated by semantic analyzer
|
||||
ImportTableEntry *import;
|
||||
Scope *parent_scope;
|
||||
// set this flag temporarily to detect infinite loops
|
||||
bool dep_loop_flag;
|
||||
TldResolution resolution;
|
||||
AstNode *parent_decl;
|
||||
IrInstruction *value;
|
||||
Tld *parent_tld;
|
||||
};
|
||||
|
||||
struct TldVar {
|
||||
Tld base;
|
||||
|
||||
VariableTableEntry *var;
|
||||
};
|
||||
|
||||
struct TldFn {
|
||||
Tld base;
|
||||
|
||||
FnTableEntry *fn_entry;
|
||||
};
|
||||
|
||||
struct TldContainer {
|
||||
Tld base;
|
||||
|
||||
ScopeDecls *decls_scope;
|
||||
TypeTableEntry *type_entry;
|
||||
};
|
||||
|
||||
struct TldTypeDef {
|
||||
Tld base;
|
||||
|
||||
TypeTableEntry *type_entry;
|
||||
};
|
||||
|
||||
struct TypeEnumField {
|
||||
@ -223,7 +259,7 @@ struct AstNodeRoot {
|
||||
};
|
||||
|
||||
struct AstNodeFnProto {
|
||||
TopLevelDecl top_level_decl;
|
||||
VisibMod visib_mod;
|
||||
Buf *name;
|
||||
ZigList<AstNode *> params;
|
||||
AstNode *return_type;
|
||||
@ -232,28 +268,12 @@ struct AstNodeFnProto {
|
||||
bool is_inline;
|
||||
bool is_coldcc;
|
||||
bool is_nakedcc;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
|
||||
// the function definition this fn proto is inside. can be null.
|
||||
AstNode *fn_def_node;
|
||||
FnTableEntry *fn_table_entry;
|
||||
bool skip;
|
||||
// computed from params field
|
||||
size_t inline_arg_count;
|
||||
size_t inline_or_var_type_arg_count;
|
||||
// if this is a generic function implementation, this points to the generic node
|
||||
AstNode *generic_proto_node;
|
||||
};
|
||||
|
||||
struct AstNodeFnDef {
|
||||
AstNode *fn_proto;
|
||||
AstNode *body;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *implicit_return_type;
|
||||
Scope *containing_scope;
|
||||
Scope *child_scope;
|
||||
};
|
||||
|
||||
struct AstNodeFnDecl {
|
||||
@ -265,21 +285,10 @@ struct AstNodeParamDecl {
|
||||
AstNode *type;
|
||||
bool is_noalias;
|
||||
bool is_inline;
|
||||
|
||||
// populated by semantic analyzer
|
||||
VariableTableEntry *variable;
|
||||
};
|
||||
|
||||
struct AstNodeBlock {
|
||||
ZigList<AstNode *> statements;
|
||||
|
||||
// populated by semantic analyzer
|
||||
// this one is the scope that the block itself introduces
|
||||
Scope *child_block;
|
||||
// this is the innermost scope created by defers and var decls.
|
||||
// you can follow its parents up to child_block. it will equal
|
||||
// child_block if there are no defers or var decls in the block.
|
||||
Scope *nested_block;
|
||||
};
|
||||
|
||||
enum ReturnKind {
|
||||
@ -298,14 +307,13 @@ struct AstNodeDefer {
|
||||
ReturnKind kind;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
size_t index_in_block;
|
||||
LLVMBasicBlockRef basic_block;
|
||||
Scope *child_block;
|
||||
// temporary data used in IR generation
|
||||
// TODO populate during gen_defer
|
||||
Scope *child_scope;
|
||||
};
|
||||
|
||||
struct AstNodeVariableDeclaration {
|
||||
TopLevelDecl top_level_decl;
|
||||
VisibMod visib_mod;
|
||||
Buf *symbol;
|
||||
bool is_const;
|
||||
bool is_inline;
|
||||
@ -313,28 +321,19 @@ struct AstNodeVariableDeclaration {
|
||||
// one or both of type and expr will be non null
|
||||
AstNode *type;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
VariableTableEntry *variable;
|
||||
};
|
||||
|
||||
struct AstNodeTypeDecl {
|
||||
TopLevelDecl top_level_decl;
|
||||
VisibMod visib_mod;
|
||||
Buf *symbol;
|
||||
AstNode *child_type;
|
||||
|
||||
// populated by semantic analyzer
|
||||
// if this is set, don't process the node; we've already done so
|
||||
// and here is the type (with id TypeTableEntryIdTypeDecl)
|
||||
TypeTableEntry *override_type;
|
||||
TypeTableEntry *child_type_entry;
|
||||
};
|
||||
|
||||
struct AstNodeErrorValueDecl {
|
||||
TopLevelDecl top_level_decl;
|
||||
// always invalid if it's not VisibModPrivate but can be parsed that way
|
||||
VisibMod visib_mod;
|
||||
Buf *name;
|
||||
|
||||
// populated by semantic analyzer
|
||||
ErrorTableEntry *err;
|
||||
};
|
||||
|
||||
@ -388,19 +387,12 @@ struct AstNodeBinOpExpr {
|
||||
AstNode *op1;
|
||||
BinOpType bin_op;
|
||||
AstNode *op2;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
// for when op is BinOpTypeAssign
|
||||
VariableTableEntry *var_entry;
|
||||
};
|
||||
|
||||
struct AstNodeUnwrapErrorExpr {
|
||||
AstNode *op1;
|
||||
AstNode *symbol; // can be null
|
||||
AstNode *op2;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
VariableTableEntry *var;
|
||||
};
|
||||
|
||||
enum CastOp {
|
||||
@ -429,21 +421,11 @@ struct AstNodeFnCallExpr {
|
||||
AstNode *fn_ref_expr;
|
||||
ZigList<AstNode *> params;
|
||||
bool is_builtin;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
BuiltinFnEntry *builtin_fn;
|
||||
FnTableEntry *fn_entry;
|
||||
CastOp cast_op;
|
||||
// if cast_op is CastOpArrayToString, this will be a pointer to
|
||||
// the string struct on the stack
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct AstNodeArrayAccessExpr {
|
||||
AstNode *array_ref_expr;
|
||||
AstNode *subscript;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
};
|
||||
|
||||
struct AstNodeSliceExpr {
|
||||
@ -451,22 +433,11 @@ struct AstNodeSliceExpr {
|
||||
AstNode *start;
|
||||
AstNode *end;
|
||||
bool is_const;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
StructValExprCodeGen resolved_struct_val_expr;
|
||||
};
|
||||
|
||||
struct AstNodeFieldAccessExpr {
|
||||
AstNode *struct_expr;
|
||||
Buf *field_name;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeStructField *type_struct_field;
|
||||
TypeEnumField *type_enum_field;
|
||||
StructValExprCodeGen resolved_struct_val_expr; // for enum values
|
||||
TypeTableEntry *bare_container_type;
|
||||
bool is_member_fn;
|
||||
AstNode *container_init_expr_node;
|
||||
};
|
||||
|
||||
enum PrefixOp {
|
||||
@ -487,24 +458,21 @@ enum PrefixOp {
|
||||
struct AstNodePrefixOpExpr {
|
||||
PrefixOp prefix_op;
|
||||
AstNode *primary_expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeUse {
|
||||
VisibMod visib_mod;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TopLevelDecl top_level_decl;
|
||||
TldResolution resolution;
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct AstNodeIfBoolExpr {
|
||||
AstNode *condition;
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
bool is_inline; // TODO
|
||||
|
||||
// populated by semantic analyzer
|
||||
bool is_inline; // TODO parse inline if
|
||||
};
|
||||
|
||||
struct AstNodeIfVarExpr {
|
||||
@ -512,10 +480,7 @@ struct AstNodeIfVarExpr {
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
bool var_is_ptr;
|
||||
bool is_inline; // TODO
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *type;
|
||||
bool is_inline; // TODO parse inline ?if?
|
||||
};
|
||||
|
||||
struct AstNodeWhileExpr {
|
||||
@ -523,11 +488,6 @@ struct AstNodeWhileExpr {
|
||||
AstNode *continue_expr;
|
||||
AstNode *body;
|
||||
bool is_inline;
|
||||
|
||||
// populated by semantic analyzer
|
||||
bool condition_always_true;
|
||||
bool contains_break;
|
||||
bool contains_continue;
|
||||
};
|
||||
|
||||
struct AstNodeForExpr {
|
||||
@ -537,20 +497,12 @@ struct AstNodeForExpr {
|
||||
AstNode *body;
|
||||
bool elem_is_ptr;
|
||||
bool is_inline;
|
||||
|
||||
// populated by semantic analyzer
|
||||
bool contains_break;
|
||||
bool contains_continue;
|
||||
VariableTableEntry *elem_var;
|
||||
VariableTableEntry *index_var;
|
||||
};
|
||||
|
||||
struct AstNodeSwitchExpr {
|
||||
AstNode *expr;
|
||||
ZigList<AstNode *> prongs;
|
||||
bool is_inline;
|
||||
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeSwitchProng {
|
||||
@ -573,10 +525,6 @@ struct AstNodeLabel {
|
||||
struct AstNodeGoto {
|
||||
Buf *name;
|
||||
bool is_inline;
|
||||
|
||||
// populated by semantic analyzer
|
||||
IrBasicBlock *bb;
|
||||
size_t instruction_index;
|
||||
};
|
||||
|
||||
struct AsmOutput {
|
||||
@ -584,9 +532,6 @@ struct AsmOutput {
|
||||
Buf *constraint;
|
||||
Buf *variable_name;
|
||||
AstNode *return_type; // null unless "=r" and return
|
||||
|
||||
// populated by semantic analyzer
|
||||
VariableTableEntry *variable;
|
||||
};
|
||||
|
||||
struct AsmInput {
|
||||
@ -619,8 +564,6 @@ struct AstNodeAsmExpr {
|
||||
ZigList<AsmOutput*> output_list;
|
||||
ZigList<AsmInput*> input_list;
|
||||
ZigList<Buf*> clobber_list;
|
||||
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
enum ContainerKind {
|
||||
@ -630,23 +573,17 @@ enum ContainerKind {
|
||||
};
|
||||
|
||||
struct AstNodeStructDecl {
|
||||
TopLevelDecl top_level_decl;
|
||||
VisibMod visib_mod;
|
||||
Buf *name;
|
||||
ContainerKind kind;
|
||||
ZigList<AstNode *> generic_params;
|
||||
bool generic_params_is_var_args; // always an error but it can happen from parsing
|
||||
ZigList<AstNode *> fields;
|
||||
ZigList<AstNode *> decls;
|
||||
|
||||
// populated by semantic analyzer
|
||||
ScopeDecls *decls_scope;
|
||||
TypeTableEntry *type_entry;
|
||||
TypeTableEntry *generic_fn_type;
|
||||
bool skip;
|
||||
};
|
||||
|
||||
struct AstNodeStructField {
|
||||
TopLevelDecl top_level_decl;
|
||||
VisibMod visib_mod;
|
||||
Buf *name;
|
||||
AstNode *type;
|
||||
};
|
||||
@ -654,14 +591,10 @@ struct AstNodeStructField {
|
||||
struct AstNodeStringLiteral {
|
||||
Buf *buf;
|
||||
bool c;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
};
|
||||
|
||||
struct AstNodeCharLiteral {
|
||||
uint8_t value;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
};
|
||||
|
||||
struct AstNodeNumberLiteral {
|
||||
@ -670,16 +603,11 @@ struct AstNodeNumberLiteral {
|
||||
// overflow is true if when parsing the number, we discovered it would not
|
||||
// fit without losing data in a uint64_t or double
|
||||
bool overflow;
|
||||
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeStructValueField {
|
||||
Buf *name;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeStructField *type_struct_field;
|
||||
};
|
||||
|
||||
enum ContainerInitKind {
|
||||
@ -691,68 +619,47 @@ struct AstNodeContainerInitExpr {
|
||||
AstNode *type;
|
||||
ZigList<AstNode *> entries;
|
||||
ContainerInitKind kind;
|
||||
|
||||
// populated by semantic analyzer
|
||||
StructValExprCodeGen resolved_struct_val_expr;
|
||||
TypeTableEntry *enum_type;
|
||||
};
|
||||
|
||||
struct AstNodeNullLiteral {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeUndefinedLiteral {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeZeroesLiteral {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeThisLiteral {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeSymbolExpr {
|
||||
Buf *symbol;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeEnumField *enum_field;
|
||||
uint32_t err_value;
|
||||
};
|
||||
|
||||
struct AstNodeBoolLiteral {
|
||||
bool value;
|
||||
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeBreakExpr {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeContinueExpr {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeArrayType {
|
||||
AstNode *size;
|
||||
AstNode *child_type;
|
||||
bool is_const;
|
||||
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeErrorType {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeTypeLiteral {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNodeVarLiteral {
|
||||
// populated by semantic analyzer
|
||||
};
|
||||
|
||||
struct AstNode {
|
||||
@ -761,9 +668,6 @@ struct AstNode {
|
||||
size_t column;
|
||||
uint32_t create_index; // for determinism purposes
|
||||
ImportTableEntry *owner;
|
||||
// the context in which this expression/node is evaluated.
|
||||
// for blocks, this points to the containing scope, not the block's own scope for its children.
|
||||
Scope *scope;
|
||||
union {
|
||||
AstNodeRoot root;
|
||||
AstNodeFnDef fn_def;
|
||||
@ -822,26 +726,12 @@ struct FnTypeParamInfo {
|
||||
TypeTableEntry *type;
|
||||
};
|
||||
|
||||
struct GenericParamValue {
|
||||
TypeTableEntry *type;
|
||||
AstNode *node;
|
||||
size_t impl_index;
|
||||
};
|
||||
|
||||
struct GenericFnTypeId {
|
||||
AstNode *decl_node; // the generic fn or container decl node
|
||||
GenericParamValue *generic_params;
|
||||
size_t generic_param_count;
|
||||
};
|
||||
|
||||
uint32_t generic_fn_type_id_hash(GenericFnTypeId *id);
|
||||
bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b);
|
||||
|
||||
|
||||
struct FnTypeId {
|
||||
TypeTableEntry *return_type;
|
||||
FnTypeParamInfo *param_info;
|
||||
size_t param_count;
|
||||
size_t next_param_index;
|
||||
bool is_var_args;
|
||||
bool is_naked;
|
||||
bool is_cold;
|
||||
@ -945,6 +835,7 @@ struct FnGenParamInfo {
|
||||
|
||||
struct TypeTableEntryFn {
|
||||
FnTypeId fn_type_id;
|
||||
bool is_generic;
|
||||
TypeTableEntry *gen_return_type;
|
||||
size_t gen_param_count;
|
||||
FnGenParamInfo *gen_param_info;
|
||||
@ -955,10 +846,6 @@ struct TypeTableEntryFn {
|
||||
TypeTableEntry *bound_fn_parent;
|
||||
};
|
||||
|
||||
struct TypeTableEntryGenericFn {
|
||||
AstNode *decl_node;
|
||||
};
|
||||
|
||||
struct TypeTableEntryBoundFn {
|
||||
TypeTableEntry *fn_type;
|
||||
};
|
||||
@ -993,7 +880,6 @@ enum TypeTableEntryId {
|
||||
TypeTableEntryIdTypeDecl,
|
||||
TypeTableEntryIdNamespace,
|
||||
TypeTableEntryIdBlock,
|
||||
TypeTableEntryIdGenericFn,
|
||||
TypeTableEntryIdBoundFn,
|
||||
};
|
||||
|
||||
@ -1018,7 +904,6 @@ struct TypeTableEntry {
|
||||
TypeTableEntryUnion unionation;
|
||||
TypeTableEntryFn fn;
|
||||
TypeTableEntryTypeDecl type_decl;
|
||||
TypeTableEntryGenericFn generic_fn;
|
||||
TypeTableEntryBoundFn bound_fn;
|
||||
} data;
|
||||
|
||||
@ -1056,10 +941,9 @@ enum FnAnalState {
|
||||
FnAnalStateReady,
|
||||
FnAnalStateProbing,
|
||||
FnAnalStateComplete,
|
||||
FnAnalStateSkipped,
|
||||
FnAnalStateInvalid,
|
||||
};
|
||||
|
||||
|
||||
enum FnInline {
|
||||
FnInlineAuto,
|
||||
FnInlineAlways,
|
||||
@ -1067,14 +951,18 @@ enum FnInline {
|
||||
};
|
||||
|
||||
struct FnTableEntry {
|
||||
LLVMValueRef fn_value;
|
||||
LLVMValueRef llvm_value;
|
||||
AstNode *proto_node;
|
||||
AstNode *fn_def_node;
|
||||
ScopeFnDef *fndef_scope; // parent should be the top level decls or container decls
|
||||
Scope *child_scope; // parent is scope for last parameter
|
||||
ScopeBlock *def_scope; // parent is child_scope
|
||||
ImportTableEntry *import_entry;
|
||||
Buf symbol_name;
|
||||
TypeTableEntry *type_entry; // function type
|
||||
TypeTableEntry *implicit_return_type;
|
||||
bool internal_linkage;
|
||||
bool is_extern;
|
||||
bool disable_export;
|
||||
bool is_test;
|
||||
FnInline fn_inline;
|
||||
FnAnalState anal_state;
|
||||
@ -1161,11 +1049,10 @@ struct CodeGen {
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
|
||||
HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
|
||||
HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
|
||||
HashMap<GenericFnTypeId *, AstNode *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
|
||||
|
||||
ZigList<ImportTableEntry *> import_queue;
|
||||
size_t import_queue_index;
|
||||
ZigList<AstNode *> resolve_queue;
|
||||
ZigList<Tld *> resolve_queue;
|
||||
size_t resolve_queue_index;
|
||||
ZigList<AstNode *> use_queue;
|
||||
size_t use_queue_index;
|
||||
@ -1249,6 +1136,7 @@ struct CodeGen {
|
||||
// The function definitions this module includes. There must be a corresponding
|
||||
// fn_protos entry.
|
||||
ZigList<FnTableEntry *> fn_defs;
|
||||
size_t fn_defs_index;
|
||||
// The function prototypes this module includes. In the case of external declarations,
|
||||
// there will not be a corresponding fn_defs entry.
|
||||
ZigList<FnTableEntry *> fn_protos;
|
||||
@ -1258,6 +1146,7 @@ struct CodeGen {
|
||||
FnTableEntry *cur_fn;
|
||||
FnTableEntry *main_fn;
|
||||
LLVMValueRef cur_ret_ptr;
|
||||
LLVMValueRef cur_fn_val;
|
||||
ZigList<LLVMBasicBlockRef> break_block_stack;
|
||||
ZigList<LLVMBasicBlockRef> continue_block_stack;
|
||||
bool c_want_stdint;
|
||||
@ -1295,6 +1184,7 @@ struct CodeGen {
|
||||
IrInstruction *invalid_instruction;
|
||||
};
|
||||
|
||||
// TODO after merging IR branch, we can probably delete some of these fields
|
||||
struct VariableTableEntry {
|
||||
Buf name;
|
||||
TypeTableEntry *type;
|
||||
@ -1304,8 +1194,6 @@ struct VariableTableEntry {
|
||||
bool is_inline;
|
||||
// which node is the declaration of the variable
|
||||
AstNode *decl_node;
|
||||
// which node contains the ConstExprValue for this variable's value
|
||||
AstNode *val_node;
|
||||
ZigLLVMDILocalVariable *di_loc_var;
|
||||
size_t src_arg_index;
|
||||
size_t gen_arg_index;
|
||||
@ -1313,10 +1201,10 @@ struct VariableTableEntry {
|
||||
Scope *child_scope;
|
||||
LLVMValueRef param_value_ref;
|
||||
bool force_depends_on_compile_var;
|
||||
ImportTableEntry *import;
|
||||
bool shadowable;
|
||||
size_t mem_slot_index;
|
||||
size_t ref_count;
|
||||
ConstExprValue *value;
|
||||
};
|
||||
|
||||
struct ErrorTableEntry {
|
||||
@ -1339,9 +1227,6 @@ struct Scope {
|
||||
Scope *parent;
|
||||
|
||||
ZigLLVMDIScope *di_scope;
|
||||
|
||||
bool safety_off;
|
||||
AstNode *safety_set_node;
|
||||
};
|
||||
|
||||
// This scope comes from global declarations or from
|
||||
@ -1350,15 +1235,12 @@ struct Scope {
|
||||
struct ScopeDecls {
|
||||
Scope base;
|
||||
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table;
|
||||
};
|
||||
|
||||
// This scope comes from a container declaration such as a struct,
|
||||
// enum, or union.
|
||||
struct ScopeContainer {
|
||||
Scope base;
|
||||
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table;
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;
|
||||
bool safety_off;
|
||||
AstNode *safety_set_node;
|
||||
ImportTableEntry *import;
|
||||
// If this is a scope from a container, this is the type entry, otherwise null
|
||||
TypeTableEntry *container_type;
|
||||
};
|
||||
|
||||
// This scope comes from a block expression in user code.
|
||||
@ -1367,6 +1249,8 @@ struct ScopeBlock {
|
||||
Scope base;
|
||||
|
||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
||||
bool safety_off;
|
||||
AstNode *safety_set_node;
|
||||
};
|
||||
|
||||
// This scope is created from every defer expression.
|
||||
@ -1401,7 +1285,7 @@ struct ScopeLoop {
|
||||
|
||||
// This scope is created for a function definition.
|
||||
// NodeTypeFnDef
|
||||
struct ScopeFnBody {
|
||||
struct ScopeFnDef {
|
||||
Scope base;
|
||||
|
||||
FnTableEntry *fn_entry;
|
||||
@ -1479,6 +1363,7 @@ enum IrInstructionId {
|
||||
|
||||
struct IrInstruction {
|
||||
IrInstructionId id;
|
||||
Scope *scope;
|
||||
AstNode *source_node;
|
||||
ConstExprValue static_value;
|
||||
TypeTableEntry *type_entry;
|
||||
@ -1798,6 +1683,7 @@ struct IrInstructionAsm {
|
||||
// Most information on inline assembly comes from the source node.
|
||||
IrInstruction **input_list;
|
||||
IrInstruction **output_types;
|
||||
VariableTableEntry **output_vars;
|
||||
size_t return_count;
|
||||
bool has_side_effects;
|
||||
};
|
||||
|
||||
1326
src/analyze.cpp
1326
src/analyze.cpp
File diff suppressed because it is too large
Load Diff
@ -22,11 +22,11 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, size_t size_in_bits);
|
||||
TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
|
||||
TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
|
||||
TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type);
|
||||
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info);
|
||||
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
|
||||
TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
|
||||
TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
|
||||
TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
|
||||
TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *context,
|
||||
TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *scope,
|
||||
ContainerKind kind, AstNode *decl_node, const char *name);
|
||||
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
|
||||
TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type);
|
||||
@ -49,9 +49,8 @@ AstNode *first_executing_node(AstNode *node);
|
||||
// TODO move these over, these used to be static
|
||||
bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type);
|
||||
VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
|
||||
AstNode *find_decl(Scope *context, Buf *name);
|
||||
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
|
||||
TopLevelDecl *get_as_top_level_decl(AstNode *node);
|
||||
Tld *find_decl(Scope *scope, Buf *name);
|
||||
void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only);
|
||||
bool type_is_codegen_pointer(TypeTableEntry *type);
|
||||
TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
|
||||
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
|
||||
@ -61,16 +60,21 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
|
||||
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
|
||||
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
|
||||
bool is_container_ref(TypeTableEntry *type_entry);
|
||||
void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node);
|
||||
void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node, Tld *parent_tld);
|
||||
void preview_use_decl(CodeGen *g, AstNode *node);
|
||||
void resolve_use_decl(CodeGen *g, AstNode *node);
|
||||
FnTableEntry *scope_fn_entry(Scope *scope);
|
||||
ImportTableEntry *get_scope_import(Scope *scope);
|
||||
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node,
|
||||
Scope *parent_scope, Tld *parent_tld);
|
||||
VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
|
||||
TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value);
|
||||
|
||||
ScopeDecls *create_decls_scope(AstNode *node, Scope *parent);
|
||||
Scope *create_block_scope(AstNode *node, Scope *parent);
|
||||
Scope *create_defer_scope(AstNode *node, Scope *parent);
|
||||
Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var);
|
||||
Scope *create_cimport_scope(AstNode *node, Scope *parent);
|
||||
Scope *create_loop_scope(AstNode *node, Scope *parent);
|
||||
Scope *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
|
||||
ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry);
|
||||
|
||||
#endif
|
||||
|
||||
@ -377,7 +377,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
break;
|
||||
case NodeTypeFnProto:
|
||||
{
|
||||
const char *pub_str = visib_mod_string(node->data.fn_proto.top_level_decl.visib_mod);
|
||||
const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
|
||||
const char *extern_str = extern_string(node->data.fn_proto.is_extern);
|
||||
const char *inline_str = inline_string(node->data.fn_proto.is_inline);
|
||||
fprintf(ar->f, "%s%s%sfn ", pub_str, inline_str, extern_str);
|
||||
@ -460,7 +460,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
}
|
||||
case NodeTypeVariableDeclaration:
|
||||
{
|
||||
const char *pub_str = visib_mod_string(node->data.variable_declaration.top_level_decl.visib_mod);
|
||||
const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod);
|
||||
const char *extern_str = extern_string(node->data.variable_declaration.is_extern);
|
||||
const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const);
|
||||
fprintf(ar->f, "%s%s%s ", pub_str, extern_str, const_or_var);
|
||||
@ -478,7 +478,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
}
|
||||
case NodeTypeTypeDecl:
|
||||
{
|
||||
const char *pub_str = visib_mod_string(node->data.type_decl.top_level_decl.visib_mod);
|
||||
const char *pub_str = visib_mod_string(node->data.type_decl.visib_mod);
|
||||
const char *var_name = buf_ptr(node->data.type_decl.symbol);
|
||||
fprintf(ar->f, "%stype %s = ", pub_str, var_name);
|
||||
render_node_grouped(ar, node->data.type_decl.child_type);
|
||||
@ -575,7 +575,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
case NodeTypeContainerDecl:
|
||||
{
|
||||
const char *struct_name = buf_ptr(node->data.struct_decl.name);
|
||||
const char *pub_str = visib_mod_string(node->data.struct_decl.top_level_decl.visib_mod);
|
||||
const char *pub_str = visib_mod_string(node->data.struct_decl.visib_mod);
|
||||
const char *container_str = container_string(node->data.struct_decl.kind);
|
||||
fprintf(ar->f, "%s%s %s {\n", pub_str, container_str, struct_name);
|
||||
ar->indent += ar->indent_size;
|
||||
|
||||
286
src/codegen.cpp
286
src/codegen.cpp
@ -60,7 +60,6 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
|
||||
g->primitive_type_table.init(32);
|
||||
g->fn_type_table.init(32);
|
||||
g->error_table.init(16);
|
||||
g->generic_table.init(16);
|
||||
g->is_release_build = false;
|
||||
g->is_test_build = false;
|
||||
g->want_h_file = true;
|
||||
@ -227,13 +226,59 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) {
|
||||
static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
|
||||
static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
|
||||
|
||||
static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
if (fn_table_entry->llvm_value)
|
||||
return fn_table_entry->llvm_value;
|
||||
|
||||
Buf *symbol_name;
|
||||
if (!fn_table_entry->internal_linkage) {
|
||||
symbol_name = &fn_table_entry->symbol_name;
|
||||
} else {
|
||||
symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));
|
||||
}
|
||||
|
||||
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
||||
fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_type->data.fn.raw_type_ref);
|
||||
|
||||
switch (fn_table_entry->fn_inline) {
|
||||
case FnInlineAlways:
|
||||
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMAlwaysInlineAttribute);
|
||||
break;
|
||||
case FnInlineNever:
|
||||
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoInlineAttribute);
|
||||
break;
|
||||
case FnInlineAuto:
|
||||
break;
|
||||
}
|
||||
if (fn_type->data.fn.fn_type_id.is_naked) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNakedAttribute);
|
||||
}
|
||||
|
||||
LLVMSetLinkage(fn_table_entry->llvm_value, fn_table_entry->internal_linkage ?
|
||||
LLVMInternalLinkage : LLVMExternalLinkage);
|
||||
|
||||
if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoReturnAttribute);
|
||||
}
|
||||
LLVMSetFunctionCallConv(fn_table_entry->llvm_value, fn_type->data.fn.calling_convention);
|
||||
if (!fn_type->data.fn.fn_type_id.is_extern) {
|
||||
LLVMAddFunctionAttr(fn_table_entry->llvm_value, LLVMNoUnwindAttribute);
|
||||
}
|
||||
if (!g->is_release_build && fn_table_entry->fn_inline != FnInlineAlways) {
|
||||
ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim", "true");
|
||||
ZigLLVMAddFunctionAttr(fn_table_entry->llvm_value, "no-frame-pointer-elim-non-leaf", nullptr);
|
||||
}
|
||||
|
||||
return fn_table_entry->llvm_value;
|
||||
}
|
||||
|
||||
static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
|
||||
if (scope->di_scope)
|
||||
return scope->di_scope;
|
||||
|
||||
if (scope->node->type == NodeTypeFnDef) {
|
||||
assert(scope->parent);
|
||||
ScopeFnBody *fn_scope = (ScopeFnBody *)scope;
|
||||
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
|
||||
FnTableEntry *fn_table_entry = fn_scope->fn_entry;
|
||||
unsigned line_number = fn_table_entry->proto_node->line + 1;
|
||||
unsigned scope_line = line_number;
|
||||
@ -247,11 +292,13 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
|
||||
is_definition, scope_line, flags, is_optimized, nullptr);
|
||||
|
||||
scope->di_scope = ZigLLVMSubprogramToScope(subprogram);
|
||||
ZigLLVMFnSetSubprogram(fn_table_entry->fn_value, subprogram);
|
||||
} else if (scope->node->type == NodeTypeRoot ||
|
||||
scope->node->type == NodeTypeContainerDecl)
|
||||
{
|
||||
ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram);
|
||||
} else if (scope->node->type == NodeTypeRoot) {
|
||||
scope->di_scope = ZigLLVMFileToScope(scope->node->owner->di_file);
|
||||
} else if (scope->node->type == NodeTypeContainerDecl) {
|
||||
ScopeDecls *decls_scope = (ScopeDecls *)scope;
|
||||
assert(decls_scope->container_type);
|
||||
scope->di_scope = ZigLLVMTypeToScope(decls_scope->container_type->di_type);
|
||||
} else {
|
||||
assert(scope->parent);
|
||||
ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder,
|
||||
@ -265,11 +312,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
|
||||
return scope->di_scope;
|
||||
}
|
||||
|
||||
static void set_debug_source_node(CodeGen *g, AstNode *node) {
|
||||
assert(node->scope);
|
||||
ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, get_di_scope(g, node->scope));
|
||||
}
|
||||
|
||||
static void clear_debug_source_node(CodeGen *g) {
|
||||
ZigLLVMClearCurrentDebugLocation(g->builder);
|
||||
}
|
||||
@ -350,24 +392,25 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntr
|
||||
}
|
||||
}
|
||||
|
||||
static bool want_debug_safety_recursive(CodeGen *g, Scope *context) {
|
||||
if (context->safety_set_node || !context->parent) {
|
||||
return !context->safety_off;
|
||||
}
|
||||
context->safety_off = !want_debug_safety_recursive(g, context->parent);
|
||||
context->safety_set_node = context->parent->safety_set_node;
|
||||
return !context->safety_off;
|
||||
}
|
||||
|
||||
static bool want_debug_safety(CodeGen *g, AstNode *node) {
|
||||
if (g->is_release_build) {
|
||||
return false;
|
||||
}
|
||||
return want_debug_safety_recursive(g, node->scope);
|
||||
}
|
||||
|
||||
static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
|
||||
return want_debug_safety(g, instruction->source_node);
|
||||
if (g->is_release_build)
|
||||
return false;
|
||||
|
||||
// TODO memoize
|
||||
Scope *scope = instruction->scope;
|
||||
while (scope) {
|
||||
if (scope->node->type == NodeTypeBlock) {
|
||||
ScopeBlock *block_scope = (ScopeBlock *)scope;
|
||||
if (block_scope->safety_set_node)
|
||||
return !block_scope->safety_off;
|
||||
} else if (scope->node->type == NodeTypeRoot || scope->node->type == NodeTypeContainerDecl) {
|
||||
ScopeDecls *decls_scope = (ScopeDecls *)scope;
|
||||
if (decls_scope->safety_set_node)
|
||||
return !decls_scope->safety_off;
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void gen_debug_safety_crash(CodeGen *g) {
|
||||
@ -388,10 +431,10 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
|
||||
upper_value = nullptr;
|
||||
}
|
||||
|
||||
LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoundsCheckOk");
|
||||
LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk");
|
||||
LLVMBasicBlockRef lower_ok_block = upper_value ?
|
||||
LLVMAppendBasicBlock(g->cur_fn->fn_value, "FirstBoundsCheckOk") : ok_block;
|
||||
LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block;
|
||||
|
||||
LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, "");
|
||||
LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block);
|
||||
@ -408,7 +451,7 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val,
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type_non_canon,
|
||||
static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type_non_canon,
|
||||
TypeTableEntry *wanted_type_non_canon, LLVMValueRef expr_val)
|
||||
{
|
||||
TypeTableEntry *actual_type = get_underlying_type(actual_type_non_canon);
|
||||
@ -430,13 +473,13 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
|
||||
|
||||
if (actual_bits >= wanted_bits && actual_type->id == TypeTableEntryIdInt &&
|
||||
!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
|
||||
want_debug_safety(g, source_node))
|
||||
want_debug_safety)
|
||||
{
|
||||
LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntSGE, expr_val, zero, "");
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SignCastFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SignCastFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -464,7 +507,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
|
||||
return LLVMBuildFPTrunc(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
} else if (actual_type->id == TypeTableEntryIdInt) {
|
||||
LLVMValueRef trunc_val = LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
if (!want_debug_safety(g, source_node)) {
|
||||
if (!want_debug_safety) {
|
||||
return trunc_val;
|
||||
}
|
||||
LLVMValueRef orig_val;
|
||||
@ -474,8 +517,8 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
|
||||
orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");
|
||||
}
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, expr_val, orig_val, "");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "CastShortenFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "CastShortenFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -502,8 +545,8 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS
|
||||
LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
|
||||
LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
|
||||
LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
|
||||
LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -645,8 +688,8 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
|
||||
}
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -656,11 +699,11 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
|
||||
return result;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
|
||||
static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2,
|
||||
TypeTableEntry *type_entry, bool exact)
|
||||
{
|
||||
|
||||
if (want_debug_safety(g, source_node)) {
|
||||
if (want_debug_safety) {
|
||||
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
|
||||
LLVMValueRef is_zero_bit;
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
@ -670,8 +713,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail");
|
||||
LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -688,7 +731,7 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
|
||||
if (exact) {
|
||||
if (want_debug_safety(g, source_node)) {
|
||||
if (want_debug_safety) {
|
||||
LLVMValueRef remainder_val;
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
|
||||
@ -698,8 +741,8 @@ static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1,
|
||||
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -727,7 +770,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
IrBinOp op_id = bin_op_instruction->op_id;
|
||||
IrInstruction *op1 = bin_op_instruction->op1;
|
||||
IrInstruction *op2 = bin_op_instruction->op2;
|
||||
AstNode *source_node = bin_op_instruction->base.source_node;
|
||||
|
||||
assert(op1->type_entry == op2->type_entry);
|
||||
|
||||
@ -801,7 +843,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildShl(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
|
||||
return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value);
|
||||
} else if (op1->type_entry->data.integral.is_signed) {
|
||||
return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, "");
|
||||
@ -824,7 +866,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
bool is_wrapping = (op_id == IrBinOpSubWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildSub(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
|
||||
return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value);
|
||||
} else if (op1->type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
|
||||
@ -842,7 +884,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
bool is_wrapping = (op_id == IrBinOpMultWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildMul(g->builder, op1_value, op2_value, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
} else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
|
||||
return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value);
|
||||
} else if (op1->type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
|
||||
@ -853,7 +895,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
zig_unreachable();
|
||||
}
|
||||
case IrBinOpDiv:
|
||||
return gen_div(g, source_node, op1_value, op2_value, op1->type_entry, false);
|
||||
return gen_div(g, ir_want_debug_safety(g, &bin_op_instruction->base),
|
||||
op1_value, op2_value, op1->type_entry, false);
|
||||
case IrBinOpMod:
|
||||
if (op1->type_entry->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFRem(g->builder, op1_value, op2_value, "");
|
||||
@ -885,8 +928,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
case CastOpErrToInt:
|
||||
assert(actual_type->id == TypeTableEntryIdErrorUnion);
|
||||
if (!type_has_bits(actual_type->data.error.child_type)) {
|
||||
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
|
||||
g->err_tag_type, wanted_type, expr_val);
|
||||
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
|
||||
g->err_tag_type, wanted_type, expr_val);
|
||||
} else {
|
||||
zig_panic("TODO");
|
||||
}
|
||||
@ -954,7 +997,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
case CastOpPointerReinterpret:
|
||||
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
case CastOpWidenOrShorten:
|
||||
return gen_widen_or_shorten(g, cast_instruction->base.source_node, actual_type, wanted_type, expr_val);
|
||||
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
|
||||
actual_type, wanted_type, expr_val);
|
||||
case CastOpToUnknownSizeArray:
|
||||
{
|
||||
assert(cast_instruction->tmp_ptr);
|
||||
@ -1021,8 +1065,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
|
||||
LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -1087,10 +1131,10 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
|
||||
case CastOpIntToEnum:
|
||||
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
|
||||
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
|
||||
actual_type, wanted_type->data.enumeration.tag_type, expr_val);
|
||||
case CastOpEnumToInt:
|
||||
return gen_widen_or_shorten(g, cast_instruction->base.source_node,
|
||||
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &cast_instruction->base),
|
||||
actual_type->data.enumeration.tag_type, wanted_type, expr_val);
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -1197,8 +1241,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
|
||||
}
|
||||
LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
|
||||
LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
|
||||
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk");
|
||||
LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
|
||||
LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, err_block);
|
||||
@ -1231,8 +1275,8 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
|
||||
cond_val = LLVMBuildLoad(g->builder, maybe_null_ptr, "");
|
||||
}
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
|
||||
LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeNull");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
|
||||
LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeNull");
|
||||
LLVMBuildCondBr(g->builder, cond_val, ok_block, null_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, null_block);
|
||||
@ -1408,7 +1452,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
||||
LLVMValueRef fn_val;
|
||||
TypeTableEntry *fn_type;
|
||||
if (instruction->fn_entry) {
|
||||
fn_val = instruction->fn_entry->fn_value;
|
||||
fn_val = fn_llvm_value(g, instruction->fn_entry);
|
||||
fn_type = instruction->fn_entry->type_entry;
|
||||
} else {
|
||||
assert(instruction->fn_ref);
|
||||
@ -1563,7 +1607,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
|
||||
}
|
||||
|
||||
if (!is_return) {
|
||||
VariableTableEntry *variable = asm_output->variable;
|
||||
VariableTableEntry *variable = instruction->output_vars[i];
|
||||
assert(variable);
|
||||
param_types[param_index] = LLVMTypeOf(variable->value_ref);
|
||||
param_values[param_index] = variable->value_ref;
|
||||
@ -1638,8 +1682,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
|
||||
LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
|
||||
if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
|
||||
LLVMValueRef nonnull_bit = gen_null_bit(g, ptr_type, maybe_ptr);
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapMaybeFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
|
||||
LLVMBuildCondBr(g->builder, nonnull_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
@ -1730,8 +1774,18 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
|
||||
}
|
||||
}
|
||||
|
||||
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
|
||||
AstNode *source_node = instruction->source_node;
|
||||
Scope *scope = instruction->scope;
|
||||
|
||||
assert(source_node);
|
||||
assert(scope);
|
||||
|
||||
ZigLLVMSetCurrentDebugLocation(g->builder, source_node->line + 1, source_node->column + 1, get_di_scope(g, scope));
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
|
||||
set_debug_source_node(g, instruction->source_node);
|
||||
set_debug_location(g, instruction);
|
||||
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -1961,7 +2015,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
|
||||
}
|
||||
}
|
||||
case TypeTableEntryIdFn:
|
||||
return const_val->data.x_fn->fn_value;
|
||||
return fn_llvm_value(g, const_val->data.x_fn);
|
||||
case TypeTableEntryIdPointer:
|
||||
{
|
||||
TypeTableEntry *child_type = type_entry->data.pointer.child_type;
|
||||
@ -2021,7 +2075,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
@ -2107,7 +2160,7 @@ static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {
|
||||
LLVMValueRef name_val = LLVMConstStruct(name_fields, 2, false);
|
||||
LLVMValueRef fields[] = {
|
||||
name_val,
|
||||
fn_entry->fn_value,
|
||||
fn_llvm_value(g, fn_entry),
|
||||
};
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
}
|
||||
@ -2157,7 +2210,7 @@ static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) {
|
||||
assert(executable->basic_block_list.length > 0);
|
||||
for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
|
||||
IrBasicBlock *bb = executable->basic_block_list.at(block_i);
|
||||
bb->llvm_block = LLVMAppendBasicBlock(fn->fn_value, bb->name_hint);
|
||||
bb->llvm_block = LLVMAppendBasicBlock(fn_llvm_value(g, fn), bb->name_hint);
|
||||
}
|
||||
IrBasicBlock *entry_bb = executable->basic_block_list.at(0);
|
||||
LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block);
|
||||
@ -2167,11 +2220,14 @@ static void gen_global_var(CodeGen *g, VariableTableEntry *var, LLVMValueRef ini
|
||||
TypeTableEntry *type_entry)
|
||||
{
|
||||
assert(var->gen_is_const);
|
||||
assert(var->import);
|
||||
assert(type_entry);
|
||||
|
||||
ImportTableEntry *import = get_scope_import(var->parent_scope);
|
||||
assert(import);
|
||||
|
||||
bool is_local_to_unit = true;
|
||||
ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
|
||||
buf_ptr(&var->name), var->import->di_file, var->decl_node->line + 1,
|
||||
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
|
||||
type_entry->di_type, is_local_to_unit, init_val);
|
||||
}
|
||||
|
||||
@ -2187,7 +2243,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
if (var->type->id == TypeTableEntryIdNumLitFloat) {
|
||||
// Generate debug info for it but that's it.
|
||||
ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value;
|
||||
ConstExprValue *const_val = var->value;
|
||||
assert(const_val->special != ConstValSpecialRuntime);
|
||||
TypeTableEntry *var_type = g->builtin_types.entry_f64;
|
||||
LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float);
|
||||
@ -2197,7 +2253,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
if (var->type->id == TypeTableEntryIdNumLitInt) {
|
||||
// Generate debug info for it but that's it.
|
||||
ConstExprValue *const_val = &var->decl_node->data.variable_declaration.top_level_decl.value->static_value;
|
||||
ConstExprValue *const_val = var->value;
|
||||
assert(const_val->special != ConstValSpecialRuntime);
|
||||
TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ?
|
||||
g->builtin_types.entry_isize : g->builtin_types.entry_usize;
|
||||
@ -2222,13 +2278,12 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
LLVMSetLinkage(global_value, LLVMExternalLinkage);
|
||||
} else {
|
||||
IrInstruction *instruction = var->decl_node->data.variable_declaration.top_level_decl.value;
|
||||
render_const_val(g, instruction->type_entry, &instruction->static_value);
|
||||
render_const_val_global(g, instruction->type_entry, &instruction->static_value);
|
||||
global_value = instruction->static_value.llvm_global;
|
||||
render_const_val(g, var->type, var->value);
|
||||
render_const_val_global(g, var->type, var->value);
|
||||
global_value = var->value->llvm_global;
|
||||
// TODO debug info for function pointers
|
||||
if (var->gen_is_const && var->type->id != TypeTableEntryIdFn) {
|
||||
gen_global_var(g, var, instruction->static_value.llvm_value, var->type);
|
||||
gen_global_var(g, var, var->value->llvm_value, var->type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2246,12 +2301,8 @@ static void do_code_gen(CodeGen *g) {
|
||||
// Generate function prototypes
|
||||
for (size_t fn_proto_i = 0; fn_proto_i < g->fn_protos.length; fn_proto_i += 1) {
|
||||
FnTableEntry *fn_table_entry = g->fn_protos.at(fn_proto_i);
|
||||
if (should_skip_fn_codegen(g, fn_table_entry)) {
|
||||
// huge time saver
|
||||
LLVMDeleteFunction(fn_table_entry->fn_value);
|
||||
fn_table_entry->fn_value = nullptr;
|
||||
if (should_skip_fn_codegen(g, fn_table_entry))
|
||||
continue;
|
||||
}
|
||||
|
||||
AstNode *proto_node = fn_table_entry->proto_node;
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
@ -2259,16 +2310,18 @@ static void do_code_gen(CodeGen *g) {
|
||||
|
||||
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
||||
|
||||
LLVMValueRef fn_val = fn_llvm_value(g, fn_table_entry);
|
||||
|
||||
if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
|
||||
// nothing to do
|
||||
} else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {
|
||||
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 0);
|
||||
ZigLLVMAddNonNullAttr(fn_val, 0);
|
||||
} else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&
|
||||
!fn_type->data.fn.fn_type_id.is_extern)
|
||||
{
|
||||
LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
|
||||
LLVMValueRef first_arg = LLVMGetParam(fn_val, 0);
|
||||
LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
|
||||
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 1);
|
||||
ZigLLVMAddNonNullAttr(fn_val, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -2286,7 +2339,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
}
|
||||
|
||||
TypeTableEntry *param_type = info->type;
|
||||
LLVMValueRef argument_val = LLVMGetParam(fn_table_entry->fn_value, gen_index);
|
||||
LLVMValueRef argument_val = LLVMGetParam(fn_val, gen_index);
|
||||
bool param_is_noalias = param_node->data.param_decl.is_noalias;
|
||||
if (param_is_noalias) {
|
||||
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
|
||||
@ -2295,7 +2348,7 @@ static void do_code_gen(CodeGen *g) {
|
||||
LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
|
||||
}
|
||||
if (param_type->id == TypeTableEntryIdPointer) {
|
||||
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, gen_index + 1);
|
||||
ZigLLVMAddNonNullAttr(fn_val, gen_index + 1);
|
||||
}
|
||||
if (is_byval) {
|
||||
// TODO
|
||||
@ -2345,14 +2398,13 @@ static void do_code_gen(CodeGen *g) {
|
||||
// Generate function definitions.
|
||||
for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
|
||||
FnTableEntry *fn_table_entry = g->fn_defs.at(fn_i);
|
||||
if (should_skip_fn_codegen(g, fn_table_entry)) {
|
||||
// huge time saver
|
||||
if (should_skip_fn_codegen(g, fn_table_entry))
|
||||
continue;
|
||||
}
|
||||
|
||||
ImportTableEntry *import = fn_table_entry->import_entry;
|
||||
LLVMValueRef fn = fn_table_entry->fn_value;
|
||||
LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
|
||||
g->cur_fn = fn_table_entry;
|
||||
g->cur_fn_val = fn;
|
||||
if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {
|
||||
g->cur_ret_ptr = LLVMGetParam(fn, 0);
|
||||
} else {
|
||||
@ -2401,7 +2453,18 @@ static void do_code_gen(CodeGen *g) {
|
||||
if (var->is_inline)
|
||||
continue;
|
||||
|
||||
if (var->parent_scope->node->type == NodeTypeFnDef) {
|
||||
if (var->src_arg_index == SIZE_MAX) {
|
||||
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
|
||||
|
||||
|
||||
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
|
||||
LLVMSetAlignment(var->value_ref, align_bytes);
|
||||
|
||||
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
|
||||
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
|
||||
var->type->di_type, !g->strip_debug_symbols, 0);
|
||||
|
||||
} else {
|
||||
assert(var->gen_arg_index != SIZE_MAX);
|
||||
TypeTableEntry *gen_type;
|
||||
if (handle_is_ptr(var->type)) {
|
||||
@ -2417,31 +2480,21 @@ static void do_code_gen(CodeGen *g) {
|
||||
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
|
||||
gen_type->di_type, !g->strip_debug_symbols, 0, var->gen_arg_index + 1);
|
||||
|
||||
} else {
|
||||
var->value_ref = LLVMBuildAlloca(g->builder, var->type->type_ref, buf_ptr(&var->name));
|
||||
|
||||
|
||||
unsigned align_bytes = ZigLLVMGetPrefTypeAlignment(g->target_data_ref, var->type->type_ref);
|
||||
LLVMSetAlignment(var->value_ref, align_bytes);
|
||||
|
||||
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
|
||||
buf_ptr(&var->name), import->di_file, var->decl_node->line + 1,
|
||||
var->type->di_type, !g->strip_debug_symbols, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// create debug variable declarations for parameters
|
||||
// rely on the first variables in the variable_list being parameters.
|
||||
size_t next_var_i = 0;
|
||||
for (size_t param_i = 0; param_i < fn_proto->params.length; param_i += 1) {
|
||||
AstNode *param_decl = fn_proto->params.at(param_i);
|
||||
assert(param_decl->type == NodeTypeParamDecl);
|
||||
|
||||
FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
|
||||
|
||||
if (info->gen_index == SIZE_MAX) {
|
||||
if (info->gen_index == SIZE_MAX)
|
||||
continue;
|
||||
}
|
||||
|
||||
VariableTableEntry *variable = param_decl->data.param_decl.variable;
|
||||
VariableTableEntry *variable = fn_table_entry->variable_list.at(next_var_i);
|
||||
assert(variable->src_arg_index != SIZE_MAX);
|
||||
next_var_i += 1;
|
||||
|
||||
assert(variable);
|
||||
assert(variable->value_ref);
|
||||
|
||||
@ -3308,7 +3361,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
|
||||
zig_panic("TODO");
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
@ -3343,7 +3395,7 @@ void codegen_generate_h_file(CodeGen *g) {
|
||||
assert(proto_node->type == NodeTypeFnProto);
|
||||
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
|
||||
|
||||
if (fn_proto->top_level_decl.visib_mod != VisibModExport)
|
||||
if (fn_proto->visib_mod != VisibModExport)
|
||||
continue;
|
||||
|
||||
FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
|
||||
|
||||
@ -55,7 +55,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
|
||||
zig_panic("TODO");
|
||||
case TypeTableEntryIdBlock:
|
||||
zig_panic("TODO");
|
||||
case TypeTableEntryIdGenericFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
|
||||
1356
src/ir.cpp
1356
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -140,14 +140,6 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
|
||||
fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdGenericFn:
|
||||
{
|
||||
TypeTableEntry *type_entry = const_val->data.x_type;
|
||||
AstNode *decl_node = type_entry->data.generic_fn.decl_node;
|
||||
assert(decl_node->type == NodeTypeFnProto);
|
||||
fprintf(irp->f, "%s", buf_ptr(decl_node->data.fn_proto.name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdBoundFn:
|
||||
{
|
||||
FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn;
|
||||
|
||||
@ -121,7 +121,7 @@ static AstNode *create_typed_var_decl_node(Context *c, bool is_const, const char
|
||||
AstNode *node = create_node(c, NodeTypeVariableDeclaration);
|
||||
node->data.variable_declaration.symbol = buf_create_from_str(var_name);
|
||||
node->data.variable_declaration.is_const = is_const;
|
||||
node->data.variable_declaration.top_level_decl.visib_mod = c->visib_mod;
|
||||
node->data.variable_declaration.visib_mod = c->visib_mod;
|
||||
node->data.variable_declaration.expr = init_node;
|
||||
node->data.variable_declaration.type = type_node;
|
||||
return node;
|
||||
@ -139,16 +139,6 @@ static AstNode *create_prefix_node(Context *c, PrefixOp op, AstNode *child_node)
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *create_struct_field_node(Context *c, const char *name, AstNode *type_node) {
|
||||
assert(type_node);
|
||||
AstNode *node = create_node(c, NodeTypeStructField);
|
||||
node->data.struct_field.name = buf_create_from_str(name);
|
||||
node->data.struct_field.top_level_decl.visib_mod = VisibModPub;
|
||||
node->data.struct_field.type = type_node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *create_param_decl_node(Context *c, const char *name, AstNode *type_node, bool is_noalias) {
|
||||
assert(type_node);
|
||||
AstNode *node = create_node(c, NodeTypeParamDecl);
|
||||
@ -214,15 +204,6 @@ static AstNode *create_num_lit_signed(Context *c, int64_t x) {
|
||||
return create_prefix_node(c, PrefixOpNegation, num_lit_node);
|
||||
}
|
||||
|
||||
static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *child_type_node) {
|
||||
AstNode *node = create_node(c, NodeTypeTypeDecl);
|
||||
node->data.type_decl.symbol = buf_create_from_str(name);
|
||||
node->data.type_decl.top_level_decl.visib_mod = c->visib_mod;
|
||||
node->data.type_decl.child_type = child_type_node;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *make_type_node(Context *c, TypeTableEntry *type_entry) {
|
||||
zig_panic("TODO bypass AST in parseh");
|
||||
}
|
||||
@ -231,7 +212,7 @@ static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_t
|
||||
assert(fn_type->id == TypeTableEntryIdFn);
|
||||
AstNode *node = create_node(c, NodeTypeFnProto);
|
||||
node->data.fn_proto.is_inline = true;
|
||||
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
|
||||
node->data.fn_proto.visib_mod = c->visib_mod;
|
||||
node->data.fn_proto.name = name;
|
||||
node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
|
||||
|
||||
@ -280,25 +261,40 @@ static const char *decl_name(const Decl *decl) {
|
||||
return (const char *)named_decl->getName().bytes_begin();
|
||||
}
|
||||
|
||||
static AstNode *add_typedef_node(Context *c, TypeTableEntry *type_decl) {
|
||||
static void add_typedef_node(Context *c, TypeTableEntry *type_decl) {
|
||||
assert(type_decl);
|
||||
assert(type_decl->id == TypeTableEntryIdTypeDecl);
|
||||
|
||||
AstNode *node = create_type_decl_node(c, buf_ptr(&type_decl->name),
|
||||
make_type_node(c, type_decl->data.type_decl.child_type));
|
||||
node->data.type_decl.override_type = type_decl;
|
||||
ScopeDecls *decls_scope = c->import->decls_scope;
|
||||
TldTypeDef *tld_typedef = allocate<TldTypeDef>(1);
|
||||
init_tld(&tld_typedef->base, TldIdTypeDef, &type_decl->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr);
|
||||
tld_typedef->type_entry = type_decl;
|
||||
|
||||
decls_scope->decl_table.put(&type_decl->name, &tld_typedef->base);
|
||||
c->global_type_table.put(&type_decl->name, type_decl);
|
||||
c->root->data.root.top_level_decls.append(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_entry) {
|
||||
AstNode *node = create_var_decl_node(c, buf_ptr(name), make_type_node(c, type_entry));
|
||||
static void add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_entry) {
|
||||
ScopeDecls *decls_scope = c->import->decls_scope;
|
||||
TldVar *tld_var = allocate<TldVar>(1);
|
||||
init_tld(&tld_var->base, TldIdVar, name, c->visib_mod, c->source_node, &decls_scope->base, nullptr);
|
||||
bool is_const = true;
|
||||
ConstExprValue *init_value = allocate<ConstExprValue>(1);
|
||||
init_value->special = ConstValSpecialStatic;
|
||||
init_value->data.x_type = type_entry;
|
||||
tld_var->var = add_variable(c->codegen, c->source_node, &decls_scope->base, name, type_entry, is_const, init_value);
|
||||
|
||||
decls_scope->decl_table.put(name, &tld_var->base);
|
||||
c->global_type_table.put(name, type_entry);
|
||||
c->root->data.root.top_level_decls.append(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static void add_container_tld(Context *c, TypeTableEntry *type_entry) {
|
||||
ScopeDecls *decls_scope = c->import->decls_scope;
|
||||
TldContainer *tld_container = allocate<TldContainer>(1);
|
||||
init_tld(&tld_container->base, TldIdContainer, &type_entry->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr);
|
||||
tld_container->type_entry = type_entry;
|
||||
|
||||
decls_scope->decl_table.put(&type_entry->name, &tld_container->base);
|
||||
}
|
||||
|
||||
static AstNode *create_ap_num_lit_node(Context *c, const Decl *source_decl,
|
||||
@ -617,7 +613,7 @@ static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const
|
||||
param_info->is_noalias = qt.isRestrictQualified();
|
||||
}
|
||||
|
||||
return get_fn_type(c->codegen, &fn_type_id, true);
|
||||
return get_fn_type(c->codegen, &fn_type_id);
|
||||
}
|
||||
case Type::Record:
|
||||
{
|
||||
@ -724,7 +720,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
|
||||
node->data.fn_proto.name = fn_name;
|
||||
|
||||
node->data.fn_proto.is_extern = fn_type->data.fn.fn_type_id.is_extern;
|
||||
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
|
||||
node->data.fn_proto.visib_mod = c->visib_mod;
|
||||
node->data.fn_proto.is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
|
||||
node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
|
||||
|
||||
@ -939,9 +935,8 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl)
|
||||
static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
|
||||
TypeTableEntry *enum_type = resolve_enum_decl(c, enum_decl);
|
||||
|
||||
if (enum_type->id == TypeTableEntryIdInvalid) {
|
||||
if (enum_type->id == TypeTableEntryIdInvalid)
|
||||
return;
|
||||
}
|
||||
|
||||
// make an alias without the "enum_" prefix. this will get emitted at the
|
||||
// end if it doesn't conflict with anything else
|
||||
@ -951,21 +946,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
|
||||
|
||||
if (enum_type->id == TypeTableEntryIdEnum) {
|
||||
if (enum_type->data.enumeration.complete) {
|
||||
// now create top level decl for the type
|
||||
AstNode *enum_node = create_node(c, NodeTypeContainerDecl);
|
||||
enum_node->data.struct_decl.name = &enum_type->name;
|
||||
enum_node->data.struct_decl.kind = ContainerKindEnum;
|
||||
enum_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
|
||||
enum_node->data.struct_decl.type_entry = enum_type;
|
||||
|
||||
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
|
||||
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
|
||||
AstNode *type_node = make_type_node(c, type_enum_field->type_entry);
|
||||
AstNode *field_node = create_struct_field_node(c, buf_ptr(type_enum_field->name), type_node);
|
||||
enum_node->data.struct_decl.fields.append(field_node);
|
||||
}
|
||||
|
||||
c->root->data.root.top_level_decls.append(enum_node);
|
||||
add_container_tld(c, enum_type);
|
||||
} else {
|
||||
TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&enum_type->name),
|
||||
c->codegen->builtin_types.entry_u8);
|
||||
@ -1127,21 +1108,7 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
|
||||
}
|
||||
|
||||
if (struct_type->data.structure.complete) {
|
||||
// now create a top level decl node for the type
|
||||
AstNode *struct_node = create_node(c, NodeTypeContainerDecl);
|
||||
struct_node->data.struct_decl.name = &struct_type->name;
|
||||
struct_node->data.struct_decl.kind = ContainerKindStruct;
|
||||
struct_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
|
||||
struct_node->data.struct_decl.type_entry = struct_type;
|
||||
|
||||
for (uint32_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
|
||||
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
|
||||
AstNode *type_node = make_type_node(c, type_struct_field->type_entry);
|
||||
AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node);
|
||||
struct_node->data.struct_decl.fields.append(field_node);
|
||||
}
|
||||
|
||||
c->root->data.root.top_level_decls.append(struct_node);
|
||||
add_container_tld(c, struct_type);
|
||||
} else {
|
||||
TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&struct_type->name),
|
||||
c->codegen->builtin_types.entry_u8);
|
||||
|
||||
@ -1501,7 +1501,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, size_t *to
|
||||
|
||||
node->data.variable_declaration.is_inline = is_inline;
|
||||
node->data.variable_declaration.is_const = is_const;
|
||||
node->data.variable_declaration.top_level_decl.visib_mod = visib_mod;
|
||||
node->data.variable_declaration.visib_mod = visib_mod;
|
||||
|
||||
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
|
||||
node->data.variable_declaration.symbol = token_buf(name_token);
|
||||
@ -2079,7 +2079,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
|
||||
}
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFnProto, fn_token);
|
||||
node->data.fn_proto.top_level_decl.visib_mod = visib_mod;
|
||||
node->data.fn_proto.visib_mod = visib_mod;
|
||||
node->data.fn_proto.is_coldcc = is_coldcc;
|
||||
node->data.fn_proto.is_nakedcc = is_nakedcc;
|
||||
|
||||
@ -2144,6 +2144,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, size_t *token_index, bool man
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFnDef, first_token);
|
||||
node->data.fn_def.fn_proto = fn_proto;
|
||||
node->data.fn_def.body = ast_parse_block(pc, token_index, true);
|
||||
fn_proto->data.fn_proto.fn_def_node = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -2193,7 +2194,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
|
||||
*token_index += 1;
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
|
||||
node->data.use.top_level_decl.visib_mod = visib_mod;
|
||||
node->data.use.visib_mod = visib_mod;
|
||||
node->data.use.expr = ast_parse_expression(pc, token_index, true);
|
||||
|
||||
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||
@ -2227,7 +2228,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
|
||||
AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token);
|
||||
node->data.struct_decl.kind = kind;
|
||||
node->data.struct_decl.name = token_buf(struct_name);
|
||||
node->data.struct_decl.top_level_decl.visib_mod = visib_mod;
|
||||
node->data.struct_decl.visib_mod = visib_mod;
|
||||
|
||||
Token *paren_or_brace = &pc->tokens->at(*token_index);
|
||||
if (paren_or_brace->id == TokenIdLParen) {
|
||||
@ -2281,7 +2282,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
|
||||
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
|
||||
*token_index += 1;
|
||||
|
||||
field_node->data.struct_field.top_level_decl.visib_mod = visib_mod;
|
||||
field_node->data.struct_field.visib_mod = visib_mod;
|
||||
field_node->data.struct_field.name = token_buf(token);
|
||||
|
||||
Token *expr_or_comma = &pc->tokens->at(*token_index);
|
||||
@ -2318,7 +2319,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, size_t *token_index
|
||||
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
|
||||
node->data.error_value_decl.top_level_decl.visib_mod = visib_mod;
|
||||
node->data.error_value_decl.visib_mod = visib_mod;
|
||||
node->data.error_value_decl.name = token_buf(name_tok);
|
||||
|
||||
return node;
|
||||
@ -2344,7 +2345,7 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, Visib
|
||||
|
||||
ast_eat_token(pc, token_index, TokenIdSemicolon);
|
||||
|
||||
node->data.type_decl.top_level_decl.visib_mod = visib_mod;
|
||||
node->data.type_decl.visib_mod = visib_mod;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user