aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/all_types.hpp2
-rw-r--r--src/analyze.cpp20
-rw-r--r--src/ir.cpp56
-rw-r--r--src/parser.cpp14
4 files changed, 69 insertions, 23 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp
index a5b0804985..6e1bfb5ad5 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -1006,6 +1006,7 @@ struct AstNodeStructField {
// populated if the "align(A)" is present
AstNode *align_expr;
Buf doc_comments;
+ Token *comptime_token;
};
struct AstNodeStringLiteral {
@@ -1263,6 +1264,7 @@ struct TypeStructField {
uint32_t bit_offset_in_host; // offset from the memory at gen_index
uint32_t host_int_bytes; // size of host integer
uint32_t align;
+ bool is_comptime;
};
enum ResolveStatus {
diff --git a/src/analyze.cpp b/src/analyze.cpp
index c3e24ecb46..cf7296a9f8 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2736,6 +2736,16 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
field_node = decl_node->data.container_decl.fields.at(i);
type_struct_field->name = field_node->data.struct_field.name;
type_struct_field->decl_node = field_node;
+ if (field_node->data.struct_field.comptime_token != nullptr) {
+ if (field_node->data.struct_field.value == nullptr) {
+ add_token_error(g, field_node->owner,
+ field_node->data.struct_field.comptime_token,
+ buf_sprintf("comptime struct field missing initialization value"));
+ struct_type->data.structure.resolve_status = ResolveStatusInvalid;
+ return ErrorSemanticAnalyzeFail;
+ }
+ type_struct_field->is_comptime = true;
+ }
if (field_node->data.struct_field.type == nullptr) {
add_node_error(g, field_node, buf_sprintf("struct field missing type"));
@@ -2788,6 +2798,9 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
type_struct_field->src_index = i;
type_struct_field->gen_index = SIZE_MAX;
+ if (type_struct_field->is_comptime)
+ continue;
+
switch (type_val_resolve_requires_comptime(g, field_type_val)) {
case ReqCompTimeYes:
struct_type->data.structure.requires_comptime = true;
@@ -7987,8 +8000,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
// inserting padding bytes where LLVM would do it automatically.
size_t llvm_struct_abi_align = 0;
for (size_t i = 0; i < field_count; i += 1) {
- ZigType *field_type = struct_type->data.structure.fields[i]->type_entry;
- if (!type_has_bits(field_type))
+ TypeStructField *field = struct_type->data.structure.fields[i];
+ ZigType *field_type = field->type_entry;
+ if (field->is_comptime || !type_has_bits(field_type))
continue;
LLVMTypeRef field_llvm_type = get_llvm_type(g, field_type);
size_t llvm_field_abi_align = LLVMABIAlignmentOfType(g->target_data_ref, field_llvm_type);
@@ -7999,7 +8013,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
TypeStructField *field = struct_type->data.structure.fields[i];
ZigType *field_type = field->type_entry;
- if (!type_has_bits(field_type)) {
+ if (field->is_comptime || !type_has_bits(field_type)) {
field->gen_index = SIZE_MAX;
continue;
}
diff --git a/src/ir.cpp b/src/ir.cpp
index 9b99fed42c..cd9d895fd4 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -655,6 +655,10 @@ static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) {
if (isf != nullptr) {
TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name);
assert(field != nullptr);
+ if (field->is_comptime) {
+ assert(field->init_val != nullptr);
+ return field->init_val;
+ }
assert(const_val->data.x_ptr.special == ConstPtrSpecialRef);
ZigValue *struct_val = const_val->data.x_ptr.data.ref.pointee;
return struct_val->data.x_struct.fields[field->src_index];
@@ -17373,6 +17377,13 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
field->type_val = create_const_type(ira->codegen, field->type_entry);
field->src_index = old_field_count;
field->decl_node = uncasted_value->source_node;
+ if (instr_is_comptime(uncasted_value)) {
+ ZigValue *uncasted_val = ir_resolve_const(ira, uncasted_value, UndefOk);
+ field->is_comptime = true;
+ field->init_val = create_const_vals(1);
+ copy_const_val(field->init_val, uncasted_val);
+ return ir_const_void(ira, source_instr);
+ }
ZigType *struct_ptr_type = get_pointer_to_type(ira->codegen, isf->inferred_struct_type, false);
IrInstruction *casted_ptr;
@@ -19503,6 +19514,18 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
return ira->codegen->invalid_instruction;
}
+static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field) {
+ if (field->init_val != nullptr) return;
+ if (field->decl_node->type != NodeTypeStructField) return;
+ AstNode *init_node = field->decl_node->data.struct_field.value;
+ if (init_node == nullptr) return;
+ // scope is not the scope of the struct init, it's the scope of the struct type decl
+ Scope *analyze_scope = &get_container_scope(container_type)->base;
+ // memoize it
+ field->init_val = analyze_const_value(codegen, analyze_scope, init_node,
+ field->type_entry, nullptr, UndefOk);
+}
+
static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr,
TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing)
{
@@ -19510,6 +19533,12 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction
ZigType *field_type = resolve_struct_field_type(ira->codegen, field);
if (field_type == nullptr)
return ira->codegen->invalid_instruction;
+ if (field->is_comptime) {
+ IrInstruction *elem = ir_const(ira, source_instr, field_type);
+ memoize_field_init_val(ira->codegen, struct_type, field);
+ copy_const_val(elem->value, field->init_val);
+ return ir_get_ref(ira, source_instr, elem, true, false);
+ }
switch (type_has_one_possible_value(ira->codegen, field_type)) {
case OnePossibleValueInvalid:
return ira->codegen->invalid_instruction;
@@ -21540,25 +21569,12 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
// look for a default field value
TypeStructField *field = container_type->data.structure.fields[i];
+ memoize_field_init_val(ira->codegen, container_type, field);
if (field->init_val == nullptr) {
- // it's not memoized. time to go analyze it
- AstNode *init_node;
- if (field->decl_node->type == NodeTypeStructField) {
- init_node = field->decl_node->data.struct_field.value;
- } else {
- init_node = nullptr;
- }
- if (init_node == nullptr) {
- ir_add_error_node(ira, instruction->source_node,
- buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name)));
- any_missing = true;
- continue;
- }
- // scope is not the scope of the struct init, it's the scope of the struct type decl
- Scope *analyze_scope = &get_container_scope(container_type)->base;
- // memoize it
- field->init_val = analyze_const_value(ira->codegen, analyze_scope, init_node,
- field->type_entry, nullptr, UndefOk);
+ ir_add_error_node(ira, instruction->source_node,
+ buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i]->name)));
+ any_missing = true;
+ continue;
}
if (type_is_invalid(field->init_val->type))
return ira->codegen->invalid_instruction;
@@ -21716,6 +21732,10 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
for (size_t i = 0; i < const_ptrs.length; i += 1) {
IrInstruction *elem_result_loc = const_ptrs.at(i);
assert(elem_result_loc->value->special == ConstValSpecialStatic);
+ if (elem_result_loc->value->type->data.pointer.inferred_struct_field != nullptr) {
+ // This field will be generated comptime; no need to do this.
+ continue;
+ }
IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc, nullptr);
elem_result_loc->value->special = ConstValSpecialRuntime;
ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref, false);
diff --git a/src/parser.cpp b/src/parser.cpp
index 665e048a89..1786e38d4b 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -536,8 +536,8 @@ static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) {
// <- TestDecl ContainerMembers
// / TopLevelComptime ContainerMembers
// / KEYWORD_pub? TopLevelDecl ContainerMembers
-// / ContainerField COMMA ContainerMembers
-// / ContainerField
+// / KEYWORD_comptime? ContainerField COMMA ContainerMembers
+// / KEYWORD_comptime? ContainerField
// /
static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
AstNodeContainerDecl res = {};
@@ -574,10 +574,13 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
ast_error(pc, peek_token(pc), "expected function or variable declaration after pub");
}
+ Token *comptime_token = eat_token_if(pc, TokenIdKeywordCompTime);
+
AstNode *container_field = ast_parse_container_field(pc);
if (container_field != nullptr) {
assert(container_field->type == NodeTypeStructField);
container_field->data.struct_field.doc_comments = doc_comment_buf;
+ container_field->data.struct_field.comptime_token = comptime_token;
res.fields.append(container_field);
if (eat_token_if(pc, TokenIdComma) != nullptr) {
continue;
@@ -612,6 +615,13 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) {
if (comptime == nullptr)
return nullptr;
+ // 1 token lookahead because it could be a comptime struct field
+ Token *lbrace = peek_token(pc);
+ if (lbrace->id != TokenIdLBrace) {
+ put_back_token(pc);
+ return nullptr;
+ }
+
AstNode *block = ast_expect(pc, ast_parse_block_expr);
AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime);
res->data.comptime_expr.expr = block;