diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index d397b426a..50cd0d882 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -138,9 +138,13 @@ struct AnonStruct int x; } + func void testAnonStruct() { + AnonStruct s = { b2 = 3, b1 = 7, sune.b = 1 }; + AnonStruct foo; + s.sune.b = 1; s.b1 = 2; s.b2 = 3; @@ -153,6 +157,9 @@ func void testUnion() SimpleUnion s; s.a = 1; s.f = 1.0; + s = { 1 }; + int x = 2; + s = { (x = 2) }; //s = { f = 1.0 }; TestUnion tu = { e = TestStruct2 { c = 1 } }; tu.e = TestStruct2 { c = 1 }; @@ -168,6 +175,7 @@ func TestStruct2 structTest(int i) TestStruct2 bar2 = { b.a = x, a.a = x + 1 }; return bar2; } + func void enumInferenceTest() { OtherError e = OtherError.FOO_BAR; diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 657a2cb18..46c466f84 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -560,6 +560,10 @@ void fprint_expr_recursive(FILE *file, Expr *expr, int indent) fprint_expr_common(file, expr, indent + 1); fprint_type_info_recursive(file, expr->type_expr.type, indent + 1); break; + case EXPR_GROUP: + fprintf_indented(file, indent, "(group\n"); + fprint_expr_recursive(file, expr->group_expr, indent + 1); + break; case EXPR_CALL: fprintf_indented(file, indent, "(call\n"); fprint_expr_common(file, expr, indent + 1); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index ddce8d6a3..bccdbd7d0 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -844,6 +844,7 @@ typedef struct _Context Decl **ct_ifs; Ast **defers; Decl *active_function_for_analysis; + Decl *active_type_for_analysis; Decl **last_local; Ast **labels; Ast **gotos; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 0940beec4..67656e9c6 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -220,6 +220,7 @@ typedef enum EXPR_IDENTIFIER, EXPR_TYPE_ACCESS, EXPR_CALL, + EXPR_GROUP, EXPR_SIZEOF, EXPR_SUBSCRIPT, EXPR_ACCESS, @@ -229,7 +230,6 @@ typedef enum EXPR_SCOPED_EXPR, EXPR_MACRO_EXPR, EXPR_EXPR_BLOCK, - EXPR_DESIGNATED_INIT, } ExprKind; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index d9e5239d4..467242eca 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -31,20 +31,17 @@ static inline LLVMValueRef gencontext_emit_sub_int(GenContext *context, Type *ty ? LLVMBuildNUWSub(context->builder, left, right, "usub") : LLVMBuildNSWSub(context->builder, left, right, "sub"); } - -static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr) +static inline LLVMValueRef gencontext_emit_subscript_addr_from_value(GenContext *context, LLVMValueRef parent, Type *parent_type, Expr *index_expr) { - LLVMValueRef index = gencontext_emit_expr(context, expr->subscript_expr.index); - Type *type = expr->subscript_expr.expr->type->canonical; - switch (type->type_kind) + assert(parent_type->canonical == parent_type); + LLVMValueRef index = gencontext_emit_expr(context, index_expr); + switch (parent_type->type_kind) { - case TYPE_ARRAY: - TODO case TYPE_POINTER: return LLVMBuildGEP2(context->builder, - llvm_type(type->pointer), - gencontext_emit_expr(context, expr->subscript_expr.expr), - &index, 1, "[]"); + llvm_type(parent_type->pointer), + parent, &index, 1, "[]"); + case TYPE_ARRAY: case TYPE_VARARRAY: case TYPE_SUBARRAY: case TYPE_STRING: @@ -52,6 +49,12 @@ static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, E default: UNREACHABLE } + +} +static inline LLVMValueRef gencontext_emit_subscript_addr(GenContext *context, Expr *expr) +{ + LLVMValueRef parent = gencontext_emit_expr(context, expr->subscript_expr.expr); + return gencontext_emit_subscript_addr_from_value(context, parent, expr->subscript_expr.expr->type->canonical, expr->subscript_expr.index); } static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRef value, Decl *parent, Decl *member) @@ -76,10 +79,12 @@ static LLVMValueRef gencontext_emit_member_addr(GenContext *context, LLVMValueRe if (current_parent->decl_kind == DECL_UNION) { - return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), ""); + return LLVMBuildBitCast(context->builder, value, LLVMPointerType(llvm_type(member->type), 0), "unionref"); } - return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, ""); + return LLVMBuildStructGEP2(context->builder, llvm_type(current_parent->type), value, index, "structref"); } + + static inline LLVMValueRef gencontext_emit_access_addr(GenContext *context, Expr *expr) { Expr *parent = expr->access_expr.parent; @@ -119,6 +124,8 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr) return gencontext_emit_subscript_addr(context, expr); case EXPR_SCOPED_EXPR: return gencontext_emit_scoped_expr_address(context, expr); + case EXPR_GROUP: + return gencontext_emit_address(context, expr->group_expr); case EXPR_CONST: case EXPR_TYPE: case EXPR_POISONED: @@ -204,6 +211,28 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr * LLVMValueRef rhs = gencontext_emit_expr(context, expr->cast_expr.expr); return gencontext_emit_cast(context, expr->cast_expr.kind, rhs, expr->type->canonical, expr->cast_expr.expr->type->canonical); } +static inline LLVMValueRef gencontext_emit_designated_initializer(GenContext *context, Type *parent_type, LLVMValueRef parent, Expr *expr) +{ + assert(parent_type == parent_type->canonical); + switch (expr->expr_kind) + { + case EXPR_SUBSCRIPT: + if (expr->subscript_expr.expr) + { + parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->subscript_expr.expr); + parent_type = expr->subscript_expr.expr->type->canonical; + } + return gencontext_emit_subscript_addr_from_value(context, parent, parent_type, expr->subscript_expr.index); + case EXPR_ACCESS: + parent = gencontext_emit_designated_initializer(context, parent_type, parent, expr->access_expr.parent); + parent_type = expr->subscript_expr.expr->type->canonical; + return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->access_expr.ref); + case EXPR_IDENTIFIER: + return gencontext_emit_member_addr(context, parent, parent_type->decl, expr->identifier_expr.decl); + default: + UNREACHABLE + } +} static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *context, Expr *expr) { @@ -225,7 +254,14 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con bool is_union = expr->type->canonical->type_kind == TYPE_UNION; if (expr->expr_initializer.init_type == INITIALIZER_NORMAL) { - assert(!is_union); + if (is_union) + { + assert(vec_size(elements) == 1); + LLVMValueRef init_value = gencontext_emit_expr(context, elements[0]); + LLVMValueRef u = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(elements[0]->type->canonical), 0), ""); + LLVMBuildStore(context->builder, init_value, u); + return ref; + } VECEACH(elements, i) { Expr *element = elements[i]; @@ -245,27 +281,10 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr(GenContext *con VECEACH(elements, i) { Expr *element = elements[i]; - LLVMValueRef sub_value = gencontext_emit_expr(context, element->designated_init_expr.value); - Decl *parent = expr->type->decl; - DesignatedInitPath *path = &element->designated_init_expr.path; - LLVMValueRef subref = ref; - assert(element->expr_kind == EXPR_DESIGNATED_INIT); - // If this is a union, we down a step to begin with. - if (is_union) - { - subref = LLVMBuildBitCast(context->builder, ref, LLVMPointerType(llvm_type(path->decl->type), 0), "unioncast"); - parent = path->decl; - path = path->sub_path; - } - while (path) - { - subref = LLVMBuildStructGEP2(context->builder, llvm_type(parent->type), subref, path->decl->var.id, "access"); - parent = path->decl; - path = path->sub_path; - } - LLVMBuildStore(context->builder, sub_value, subref); + LLVMValueRef sub_value = gencontext_emit_expr(context, element->binary_expr.right); + LLVMValueRef sub_ref = gencontext_emit_designated_initializer(context, expr->type->canonical, ref, element->binary_expr.left); + LLVMBuildStore(context->builder, sub_value, sub_ref); } - return ref; } @@ -828,8 +847,6 @@ static inline LLVMValueRef gencontext_emit_expression_list_expr(GenContext *cont } - - static inline LLVMValueRef gencontext_emit_expr_block(GenContext *context, Expr *expr) { LLVMValueRef old_ret_out = context->return_out; @@ -896,6 +913,8 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr) return gencontext_load_expr(context, gencontext_emit_address(context, expr)); case EXPR_CALL: return gencontext_emit_call_expr(context, expr); + case EXPR_GROUP: + return gencontext_emit_expr(context, expr->group_expr); case EXPR_ACCESS: return gencontext_emit_access_expr(context, expr); case EXPR_INITIALIZER_LIST: diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 2632df310..bb05e6890 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -208,10 +208,12 @@ static Expr *parse_ternary_expr(Context *context, Expr *left_side) static Expr *parse_grouping_expr(Context *context, Expr *left) { assert(!left && "Unexpected left hand side"); + Expr *expr = expr_new(EXPR_GROUP, context->tok.span); advance_and_verify(context, TOKEN_LPAREN); - Expr *right = TRY_EXPR_OR(parse_expr(context), &poisoned_expr); + expr->group_expr = TRY_EXPR_OR(parse_expr(context), &poisoned_expr); CONSUME_OR(TOKEN_RPAREN, &poisoned_expr); - return right; + RANGE_EXTEND_PREV(expr); + return expr; } /** diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index efae32883..8894fca68 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -49,6 +49,8 @@ static bool expr_is_ltype(Expr *expr) return expr->unary_expr.operator == UNARYOP_DEREF; case EXPR_ACCESS: return expr_is_ltype(expr->access_expr.parent); + case EXPR_GROUP: + return expr_is_ltype(expr->group_expr); case EXPR_SUBSCRIPT: return true; default: @@ -172,7 +174,6 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr Decl *ambiguous_decl; Decl *decl = sema_resolve_symbol(context, expr->identifier_expr.identifier, expr->identifier_expr.path, &ambiguous_decl); - if (!decl && !expr->identifier_expr.path && to) { if (find_possible_inferred_identifier(to, expr)) return true; @@ -353,6 +354,13 @@ static Decl *strukt_recursive_search_member(Decl *strukt, const char *name) return NULL; } +static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr) +{ + if (!sema_analyse_expr(context, to, expr->group_expr)) return false; + *expr = *expr->group_expr; + return true; +} + static inline bool sema_expr_analyse_access(Context *context, Type *to, Expr *expr) { @@ -482,10 +490,12 @@ static Decl *sema_analyse_init_identifier(Context *context, Decl *strukt, Expr * { assert(expr->resolve_status == RESOLVE_NOT_DONE); expr->resolve_status = RESOLVE_RUNNING; - expr->identifier_expr.decl = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier); + Decl *res = sema_analyse_init_identifier_string(context, strukt, expr->identifier_expr.identifier); + if (!res) return NULL; + expr->identifier_expr.decl = res; expr->resolve_status = RESOLVE_DONE; - expr->type = expr->identifier_expr.decl->type; - return expr->identifier_expr.decl; + expr->type = res->type; + return res; } static Decl *sema_analyse_init_access(Context *context, Decl *strukt, Expr *access_expr) @@ -528,190 +538,92 @@ static Decl *sema_analyse_init_path(Context *context, Decl *strukt, Expr *expr) } } -static bool sema_expr_analyse_designated_init(Context *context, DesignatedInitPath *path, Decl *top, Expr *path_expr); - -static bool sema_expr_analyse_designated_init_ident(Context *context, DesignatedInitPath *path, Decl *top, const char *name) +static bool sema_expr_analyse_struct_designated_initializer(Context *context, Decl *assigned, Expr *initializer) { - // 3. Loop through the members. - Decl **members = top->strukt.members; - VECEACH(members, i) + Expr **init_expressions = initializer->expr_initializer.initializer_expr; + + VECEACH(init_expressions, i) { - Decl *member = members[i]; - if (member->name == name) + Expr *expr = init_expressions[i]; + + // 1. Ensure that're seeing expr = expr on the top level. + if (expr->expr_kind != EXPR_BINARY || expr->binary_expr.operator != BINARYOP_ASSIGN) { - // 4. If found, set this to the current path. - (*path) = (DesignatedInitPath) { .decl = member, .sub_path = NULL }; - - // 5. And we're done! - return true; - } - // 6. We might encounter anonymous members. Treat this as a possible "match" - if (!member->name) - { - DesignatedInitPath anon_path; - bool found = sema_expr_analyse_designated_init_ident(context, &anon_path, member, name); - if (found) - { - // 7. If found, create a copy path. - DesignatedInitPath *path_copy = malloc_arena(sizeof(DesignatedInitPath)); - *path_copy = anon_path; - (*path) = (DesignatedInitPath) { .decl = member, .sub_path = path_copy }; - return true; - } - } - } - return false; - -} -static bool sema_expr_analyse_designated_init(Context *context, DesignatedInitPath *path, Decl *top, Expr *path_expr) -{ - // Our expression will look like this for a.b[3].c = ... - // access(subscript(access(identifier))), now we need to reverse that. - switch (path_expr->expr_kind) - { - case EXPR_IDENTIFIER: - - // Resolving for an identifier: - // 1. Can't be a path attached. - if (path_expr->identifier_expr.path) return false; - - // 2. Ensure it's a union or struct - if (!decl_is_struct_type(top)) return false; - - return sema_expr_analyse_designated_init_ident(context, path, top, path_expr->identifier_expr.identifier); - - case EXPR_ACCESS: - - // Resolve for access: - - // 1. Resolve the parent path: - if (!sema_expr_analyse_designated_init(context, path, top, path_expr->access_expr.parent)) return false; - - // 2. Our new top is now lowest init path. - while (path->sub_path) - { - path = path->sub_path; - } - top = path->decl; - - // 3. Do an analysis with the identifier: - path->sub_path = malloc_arena(sizeof(DesignatedInitPath)); - return sema_expr_analyse_designated_init_ident(context, - path->sub_path, - top->type->decl, - path_expr->access_expr.sub_element.string); - case EXPR_SUBSCRIPT: - - // Resolve for subscript: - - // 1. Resolve the parent path: - if (!sema_expr_analyse_designated_init(context, path, top, path_expr->subscript_expr.expr)) return false; - - // 2. Our new top is now lowest init path. - while (path->sub_path) - { - path = path->sub_path; - } - top = path->decl; - - TODO // Analyse index etc. - default: + SEMA_ERROR(expr, "Expected an initializer on the format 'foo = 123' here."); + return false; + } + Expr *path = expr->binary_expr.left; + if (!sema_analyse_init_path(context, assigned, path)) + { + SEMA_ERROR(path, "This is not a valid member of '%s'.", type_to_error_string(assigned->type)); return false; - } -} - -static bool sema_expr_analyse_struct_designated_initializer_list(Context *context, Decl *assigned, Expr *expr_list) -{ - assert(expr_list->expr_initializer.init_type == INITIALIZER_UNKNOWN); - VECEACH(expr_list->expr_initializer.initializer_expr, i) - { - Expr *expr = expr_list->expr_initializer.initializer_expr[i]; - if (expr->expr_kind != EXPR_BINARY && expr->binary_expr.operator != BINARYOP_ASSIGN) - { - if (i != 0) - { - SEMA_ERROR(expr, "Named and non-named initializers are not allowed together, please choose one or the other."); - return false; - } - // If there is an unexpected expression and no previous element then this is a normal initializer list. - expr_list->expr_initializer.init_type = INITIALIZER_NORMAL; - return true; } - Expr *path_expr = expr->binary_expr.left; Expr *value = expr->binary_expr.right; - DesignatedInitPath path; - if (!sema_expr_analyse_designated_init(context, &path, assigned, path_expr)) - { - if (i != 0) - { - SEMA_ERROR(path_expr, "Unexpected element when initializing '%s', did you get the name right?", assigned->name); - return false; - } - expr_list->expr_initializer.init_type = INITIALIZER_NORMAL; - return true; - } - // Walk down to the last decl. - DesignatedInitPath *init_path = &path; - while (init_path->sub_path) init_path = init_path->sub_path; - - if (!sema_analyse_expr_of_required_type(context, init_path->decl->type, value)) return false; - - // Destruct the expression and replace. - expr->designated_init_expr.value = value; // Do this first! - expr->resolve_status = RESOLVE_DONE; - expr->designated_init_expr.path = path; - expr->expr_kind = EXPR_DESIGNATED_INIT; - expr->type = init_path->decl->type; + if (!sema_analyse_expr_of_required_type(context, path->type, value)) return false; + expr->type = path->type; } - expr_list->expr_initializer.init_type = INITIALIZER_DESIGNATED; + initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED; return true; } -static inline bool sema_expr_analyse_struct_initializer_list(Context *context, Type *assigned, Expr *expr) +static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer) +{ + Expr **elements = initializer->expr_initializer.initializer_expr; + Decl **members = assigned->strukt.members; + initializer->expr_initializer.init_type = INITIALIZER_NORMAL; + unsigned size = vec_size(elements); + unsigned expected_members = vec_size(members); + + // For struct number of members must be the same as the size of the struct. + + assert(size > 0); + if (expected_members == 0) + { + SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty."); + return false; + } + + bool is_union = assigned->decl_kind == DECL_UNION; + expected_members = is_union ? 1 : expected_members; + VECEACH(elements, i) + { + if (i >= expected_members) + { + SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members); + return false; + } + if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i])) return false; + } + if (expected_members > size) + { + SEMA_ERROR(elements[size - 1], "Few elements in initializer, there should be elements after this one."); + return false; + } + return true; +} + +static inline bool sema_expr_analyse_struct_initializer(Context *context, Type *assigned, Expr *expr) { expr->type = assigned; - Decl **members = assigned->decl->strukt.members; - unsigned size = vec_size(members); + Expr **init_expressions = expr->expr_initializer.initializer_expr; - // Zero size init will initialize to empty. - if (size == 0) + // 1. Zero size init will initialize to empty. + if (vec_size(init_expressions) == 0) { expr->expr_initializer.init_type = INITIALIZER_ZERO; return true; } - if (!sema_expr_analyse_struct_designated_initializer_list(context, assigned->decl, expr)) return false; - - // If we already parsed this. - if (expr->expr_initializer.init_type == INITIALIZER_DESIGNATED) return true; - - Expr **elements = expr->expr_initializer.initializer_expr; - - assert(expr->expr_initializer.init_type == INITIALIZER_NORMAL); - - if (assigned->type_kind == TYPE_UNION) + // 2. Check if we might have a designated initializer + // this means that in this case we're actually not resolving macros here. + if (init_expressions[0]->expr_kind == EXPR_BINARY && init_expressions[0]->binary_expr.operator == BINARYOP_ASSIGN) { - SEMA_ERROR(elements[0], "Initializer list for unions must use named initializers, e.g. { a = 4 }"); - return false; + return sema_expr_analyse_struct_designated_initializer(context, assigned->decl, expr); } - VECEACH(elements, i) - { - if (i >= size) - { - SEMA_ERROR(elements[size], "Too many elements in initializer, expected only %d.", size); - return false; - } - if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i])) return false; - } - - if (size > vec_size(elements)) - { - SEMA_ERROR(elements[vec_size(elements) - 1], "Too few elements in initializer, expected %d.", size); - return false; - } - return true; + // 3. Otherwise use the plain initializer. + return sema_expr_analyse_struct_plain_initializer(context, assigned->decl, expr); } static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr) @@ -723,7 +635,9 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to { case TYPE_STRUCT: case TYPE_UNION: - if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer_list(context, assigned, expr); + if (decl_is_struct_type(assigned->decl)) return sema_expr_analyse_struct_initializer(context, + assigned, + expr); break; case TYPE_ARRAY: TODO @@ -2127,6 +2041,9 @@ static Expr *expr_copy_from_macro(Context *context, Expr *macro, Expr *source_ex EXPR_COPY(expr->subscript_expr.expr); EXPR_COPY(expr->subscript_expr.index); return expr; + case EXPR_GROUP: + EXPR_COPY(expr->group_expr->group_expr); + return expr; case EXPR_ACCESS: EXPR_COPY(expr->access_expr.parent); return expr; @@ -2562,6 +2479,8 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr * return sema_expr_analyse_sizeof(context, to, expr); case EXPR_SUBSCRIPT: return sema_expr_analyse_subscript(context, to, expr); + case EXPR_GROUP: + return sema_expr_analyse_group(context, to, expr); case EXPR_ACCESS: return sema_expr_analyse_access(context, to, expr); case EXPR_INITIALIZER_LIST: diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index e87ba53db..015eac40c 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -20,7 +20,7 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags) context->current_scope->local_decl_start = context->last_local; context->current_scope->defers.start = parent_defer; context->current_scope->defers.end = parent_defer; - if (flags & (SCOPE_DEFER | SCOPE_EXPR_BLOCK)) + if (flags & (SCOPE_DEFER | SCOPE_EXPR_BLOCK | SCOPE_NEXT)) { context->current_scope->flags = flags; }