mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Unions and structs, including setting them should now work.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user