Struct constants stored in globals.

This commit is contained in:
Christoffer Lerno
2020-08-06 16:03:46 +02:00
committed by Christoffer Lerno
parent d070a5e7ff
commit 9709cb61a4
7 changed files with 339 additions and 98 deletions

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@
*.ko *.ko
*.obj *.obj
*.elf *.elf
*.ll
# Linker output # Linker output
*.ilk *.ilk

View File

@@ -13,7 +13,7 @@ C3 tries to be an alternative in the the C/C++ niche: fast and close to the meta
- Learning C3 should be easy for a C programmer. - Learning C3 should be easy for a C programmer.
- Data is inert. - Data is inert.
- Avoid "big ideas" & the "more is better" fallacy. - Avoid "big ideas" & the "more is better" fallacy.
- Dare introducing some conveniences not "close to metal" if the value is great. - Introduce some higher level conveniences where the value is great.
### In what ways do C3 differ from C? ### In what ways do C3 differ from C?
@@ -42,29 +42,69 @@ developer of Judge0.
Design work is still being done in the design draft here: https://c3lang.github.io/c3docs/. If you have suggestions, send a mail to [christoffer@aegik.com](mailto:christoffer@aegik.com), [file an issue](https://github.com/c3lang/c3c/issues) or discuss C3 on the r/ProgrammingLanguages Discord server: https://discord.gg/cfu4wdk Design work is still being done in the design draft here: https://c3lang.github.io/c3docs/. If you have suggestions, send a mail to [christoffer@aegik.com](mailto:christoffer@aegik.com), [file an issue](https://github.com/c3lang/c3c/issues) or discuss C3 on the r/ProgrammingLanguages Discord server: https://discord.gg/cfu4wdk
#### What's currently missing #### Todo / done
- `asm` sections. - [x] For/while/do
- bitstructs - [x] `if`/ternary
- array range initializers e.g. `{ [1..2] = 2 }` - [x] Structs
- `assert` - with compiler hint - [x] Union
- `$switch` `$for` - compile time iteration / switch - [x] Enums
- Pre/post conditions - [x] Value methods
- `generic` - explicit overloading - [x] Compound literals
- `malloc` / `free` - [x] Designated initalizers
- `string` not fully implemented - [x] Slicing syntax
- vararrays, e.g. `int[*]` not working - [x] Arrays and subarrays
- `unreachable` for compiler hinting - [x] Modules
- Generic modules - [x] `$unreachable`
- Stdlib not linked. - [x] Compile time assert with `$assert`
- [x] Compiler guiding `assert`
Also see: https://github.com/c3lang/c3c/issues - [x] C code calling by declaring methods `extern`
- [x] Compile time variables
#### What's working? - [x] Basic macros
- [x] 4cc, 8cc, 2cc
- Lexing/parsing/semantic analysis/codegen. - [x] Enum type inference in switch/assignment
- "Regular code" should mostly work. - [x] Integer type inference
- You can use any C function by declaring it as a normal C3 function with external - [x] Error type
- [x] Failable error handling
- [x] `try` for conditional execution
- [x] `catch` for error handling
- [x] Implicit unwrap after `catch`
- [x] `sizeof`
- [x] `typeof`
- [x] 2s complement wrapping operators
- [x] Labelled break / continue
- [x] `next` statement
- [x] Expression blocks
- [x] Do-without-while
- [ ] Foreach statement
- [ ] All attributes
- [ ] Associative array literals
- [ ] CT type constants
- [ ] Reflection methods
- [ ] Anonymous structs
- [ ] Distinct types
- [ ] LTO/ThinLTO setup
- [ ] Built-in linking
- [ ] `global` / `shared` for globals
- [ ] Complex macros
- [ ] CT only macros evaluating to constants
- [ ] Escape macros
- [ ] Implicit capturing macros
- [ ] Trailing body macros
- [ ] Subarray initializers
- [ ] slice initializers e.g. `{ [1..2] = 2 }`
- [ ] Bitstructs
- [ ] `asm` section
- [ ] `$switch`
- [ ] `$for`
- [ ] Pre-post conditions
- [ ] Stdlib inclusion
- [ ] Generic modules
- [ ] String functions
- [ ] Vararrays e.g. `int[*]`
- [ ] Compile time incremental arrays
- [ ] Complete C ABI conformance
- [ ] Generic functions
#### What can you help with? #### What can you help with?

View File

@@ -0,0 +1,51 @@
struct Foo
{
int x;
struct b
{
int y;
int z;
}
struct
{
int g;
}
union
{
usize x1;
int z2;
}
}
func void Foo.xy(Foo* f, int y)
{
f.b.y = y;
}
extern func void printf(char*c , ...);
struct SimpleStruct
{
int a;
double b;
}
func void main()
{
Foo z;
z.x = 2;
z.b.z = 3;
z.g = 4;
printf("z.x = %d\n", z.x);
printf("z.b.z = %d\n", z.b.z);
printf("z.g = %d\n", z.g);
z.xy(100);
printf("z.b.y = %d\n", z.b.y);
SimpleStruct s = { a = 3, b = 33.3 };
int[2] fe = { 1, 2 };
//Foo f = { x = 2, b.z = 3, z2 = -2 };
Foo f = { x = 2, b.z = 3, z2 = -2, b = { 1, 4 } };
int[3] fo = { [1] = 2 };
//byte[7] fo = { [1..4] = 3 };
}

View File

@@ -166,7 +166,9 @@ typedef enum
typedef struct _DesignatedPath typedef struct _DesignatedPath
{ {
DesignatedPathKind kind; DesignatedPathKind kind : 3;
bool constant : 1;
bool pure : 1;
struct _DesignatedPath *sub_path; struct _DesignatedPath *sub_path;
Type *type; Type *type;
union union
@@ -623,7 +625,7 @@ typedef struct
typedef struct typedef struct
{ {
DesignatedPath *path; DesignatedPath *path;
Expr* value; Expr *value;
} ExprDesignatedInit; } ExprDesignatedInit;
typedef struct typedef struct
@@ -1585,4 +1587,11 @@ static inline void advance_and_verify(Context *context, TokenType token_type)
assert(context->tok.type == token_type); assert(context->tok.type == token_type);
advance(context); advance(context);
} }
#define TRY_AST_OR(_ast_stmt, _res) ({ Ast* _ast = (_ast_stmt); if (!ast_ok(_ast)) return _res; _ast; })
#define TRY_EXPR_OR(_expr_stmt, _res) ({ Expr* _expr = (_expr_stmt); if (!expr_ok(_expr)) return _res; _expr; })
#define TRY_TYPE_OR(_type_stmt, _res) ({ TypeInfo* _type = (_type_stmt); if (!type_info_ok(_type)) return _res; _type; })
#define TRY_TYPE_REAL_OR(_type_stmt, _res) ({ Type* _type = (_type_stmt); if (!type_ok(_type)) return _res; _type; })
#define TRY_DECL_OR(_decl_stmt, _res) ({ Decl* _decl = (_decl_stmt); if (!decl_ok(_decl)) return _res; _decl; })
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@@ -369,8 +369,141 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
return gencontext_emit_cast(context, expr->cast_expr.kind, rhs, expr->type->canonical, expr->cast_expr.expr->type->canonical); return gencontext_emit_cast(context, expr->cast_expr.kind, rhs, expr->type->canonical, expr->cast_expr.expr->type->canonical);
} }
static LLVMValueRef gencontext_emit_initializer_list_expr_const(GenContext *context, Expr *expr);
static LLVMValueRef gencontext_construct_const_value(GenContext *context, Expr *expr)
{
NESTED_RETRY:
if (expr->expr_kind == EXPR_COMPOUND_LITERAL)
{
expr = expr->expr_compound_literal.initializer;
goto NESTED_RETRY;
}
if (expr->expr_kind == EXPR_INITIALIZER_LIST)
{
return gencontext_emit_initializer_list_expr_const(context, expr);
}
return gencontext_emit_expr(context, expr);
}
static LLVMValueRef gencontext_construct_const_union_struct(GenContext *context, Type *canonical, Expr *value)
{
LLVMValueRef values[2];
values[0] = gencontext_construct_const_value(context, value);
unsigned size_diff = type_size(canonical) - type_size(value->type);
if (size_diff > 0)
{
LLVMTypeRef size = LLVMArrayType(llvm_type(type_char), size_diff);
values[1] = LLVMConstNull(size);
}
return LLVMConstStructInContext(context->context, values, size_diff > 0 ? 2 : 1, false);
}
static LLVMValueRef gencontext_recursive_set_const_value(GenContext *context, DesignatedPath *path, LLVMValueRef parent, Type *parent_type, Expr *value)
{
switch (path->kind)
{
case DESIGNATED_IDENT:
if (!path->sub_path)
{
if (parent_type->canonical->type_kind == TYPE_UNION)
{
return gencontext_construct_const_union_struct(context, parent_type, value);
}
return LLVMConstInsertValue(parent, gencontext_construct_const_value(context, value), &path->index, 1);
}
else
{
parent_type = path->type;
return LLVMConstInsertValue(parent,
gencontext_recursive_set_const_value(context,
path->sub_path,
LLVMConstExtractValue(parent,
&path->index,
1),
parent_type,
value), &path->index, 1);
}
case DESIGNATED_SUBSCRIPT:
{
// TODO range, more arrays
assert(path->index_expr->expr_kind == EXPR_CONST);
unsigned int index = (unsigned int)bigint_as_unsigned(&path->index_expr->const_expr.i);
if (!path->sub_path)
{
LLVMValueRef res = gencontext_construct_const_value(context, value);
return LLVMConstInsertValue(parent, res, &index, 1);
}
parent_type = path->type;
return LLVMConstInsertValue(parent,
gencontext_recursive_set_const_value(context,
path->sub_path,
LLVMConstExtractValue(parent, &index, 1),
parent_type,
value), &index, 1);
}
default:
UNREACHABLE;
}
}
static LLVMValueRef gencontext_emit_initializer_list_expr_const(GenContext *context, Expr *expr)
{
Type *canonical = expr->type->canonical;
LLVMTypeRef type = llvm_type(canonical);
if (expr->expr_initializer.init_type == INITIALIZER_ZERO)
{
return LLVMConstNull(type);
}
bool is_error = expr->type->canonical->type_kind == TYPE_ERRTYPE;
if (is_error)
{
TODO
}
Expr **elements = expr->expr_initializer.initializer_expr;
bool is_union = expr->type->canonical->type_kind == TYPE_UNION;
if (expr->expr_initializer.init_type == INITIALIZER_NORMAL && is_union)
{
assert(vec_size(elements) == 1);
return gencontext_construct_const_union_struct(context, canonical, elements[0]);
}
if (expr->expr_initializer.init_type == INITIALIZER_NORMAL)
{
LLVMValueRef value = LLVMGetUndef(type);
VECEACH(elements, i)
{
Expr *element = elements[i];
if (element->expr_kind == EXPR_CONST)
{
}
value = LLVMConstInsertValue(value, gencontext_emit_expr(context, element), &i, 1);
}
return value;
}
LLVMValueRef value = LLVMConstNull(type);
VECEACH(elements, i)
{
Expr *element = elements[i];
DesignatedPath *path = element->designated_init_expr.path;
Type *parent_type = expr->type->canonical;
value = gencontext_recursive_set_const_value(context,
path,
value,
parent_type,
element->designated_init_expr.value);
}
return value;
}
/** /**
* Emit a Foo { .... } literal. * Emit a Foo { .... } literal.
@@ -380,6 +513,19 @@ static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *
*/ */
static inline LLVMValueRef gencontext_emit_initializer_list_expr_addr(GenContext *context, Expr *expr, LLVMValueRef optional_ref) static inline LLVMValueRef gencontext_emit_initializer_list_expr_addr(GenContext *context, Expr *expr, LLVMValueRef optional_ref)
{ {
if (expr->constant && type_size(expr->type) <= type_size(type_voidptr) * 4)
{
LLVMTypeRef type = llvm_type(expr->type);
LLVMValueRef val = gencontext_emit_initializer_list_expr_const(context, expr);
LLVMValueRef ref = LLVMAddGlobal(context->module, type, "");
LLVMSetInitializer(ref, val);
LLVMSetGlobalConstant(ref, true);
if (optional_ref)
{
LLVMBuildMemCpy(context->builder, optional_ref, LLVMGetAlignment(optional_ref), ref, LLVMGetAlignment(ref), LLVMSizeOf(type));
}
return ref;
}
LLVMTypeRef type = llvm_type(expr->type); LLVMTypeRef type = llvm_type(expr->type);
LLVMValueRef ref = optional_ref ?: gencontext_emit_alloca(context, type, "literal"); LLVMValueRef ref = optional_ref ?: gencontext_emit_alloca(context, type, "literal");
@@ -426,6 +572,7 @@ static inline LLVMValueRef gencontext_emit_initializer_list_expr_addr(GenContext
return ref; return ref;
} }
VECEACH(elements, i) VECEACH(elements, i)
{ {
if (is_error) TODO if (is_error) TODO

View File

@@ -15,11 +15,7 @@
#define TRY_CONSUME_EOS() TRY_CONSUME_EOS_OR(poisoned_ast) #define TRY_CONSUME_EOS() TRY_CONSUME_EOS_OR(poisoned_ast)
#define RETURN_AFTER_EOS(_ast) extend_ast_with_prev_token(context, ast); TRY_CONSUME_EOS_OR(poisoned_ast); return _ast #define RETURN_AFTER_EOS(_ast) extend_ast_with_prev_token(context, ast); TRY_CONSUME_EOS_OR(poisoned_ast); return _ast
#define TRY_AST_OR(_ast_stmt, _res) ({ Ast* _ast = (_ast_stmt); if (!ast_ok(_ast)) return _res; _ast; })
#define TRY_AST(_ast_stmt) TRY_AST_OR(_ast_stmt, poisoned_ast) #define TRY_AST(_ast_stmt) TRY_AST_OR(_ast_stmt, poisoned_ast)
#define TRY_EXPR_OR(_expr_stmt, _res) ({ Expr* _expr = (_expr_stmt); if (!expr_ok(_expr)) return _res; _expr; })
#define TRY_TYPE_OR(_type_stmt, _res) ({ TypeInfo* _type = (_type_stmt); if (!type_info_ok(_type)) return _res; _type; })
#define TRY_DECL_OR(_decl_stmt, _res) ({ Decl* _decl = (_decl_stmt); if (!decl_ok(_decl)) return _res; _decl; })
#define CHECK_EXPR(_expr) do { if (!expr_ok(_expr)) return _expr; } while(0) #define CHECK_EXPR(_expr) do { if (!expr_ok(_expr)) return _expr; } while(0)

View File

@@ -937,54 +937,6 @@ static inline void insert_access_deref(Expr *expr)
expr->access_expr.parent = deref; expr->access_expr.parent = deref;
} }
static inline bool sema_expr_analyse_method(Context *context, Expr *expr, Decl *decl, bool is_pointer)
{
const char *name = TOKSTR(expr->access_expr.sub_element);
VECEACH(decl->methods, i)
{
Decl *function = decl->methods[i];
if (function->name == name)
{
if (is_pointer)
{
insert_access_deref(expr);
}
expr->access_expr.ref = function;
expr->type = function->type;
return true;
}
}
if (decl_is_struct_type(decl))
{
SEMA_ERROR(expr, "There is no element or method '%s.%s'.", decl->name, name);
}
else
{
SEMA_ERROR(expr, "Cannot find method '%s.%s'", decl->name, name);
}
return false;
}
static Decl *strukt_recursive_search_member(Decl *strukt, const char *name)
{
VECEACH(strukt->strukt.members, i)
{
Decl *member = strukt->strukt.members[i];
if (member->name == name) return member;
if (decl_is_struct_type(member) && !member->name)
{
Decl *result = strukt_recursive_search_member(member, name);
if (result)
{
return result;
}
}
}
return NULL;
}
static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr) static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr)
{ {
if (!sema_analyse_expr(context, NULL, expr->group_expr)) return false; if (!sema_analyse_expr(context, NULL, expr->group_expr)) return false;
@@ -1162,6 +1114,29 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr)
*/ */
static void add_members_to_context(Context *context, Decl *decl)
{
if (decl_is_struct_type(decl))
{
Decl **members = decl->strukt.members;
VECEACH(members, i)
{
Decl *member = members[i];
if (member->name == NULL)
{
add_members_to_context(context, member);
continue;
}
sema_add_member(context, member);
}
}
VECEACH(decl->methods, i)
{
Decl *func = decl->methods[i];
sema_add_member(context, func);
}
}
static inline bool sema_expr_analyse_access(Context *context, Expr *expr) static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
{ {
Expr *parent = expr->access_expr.parent; Expr *parent = expr->access_expr.parent;
@@ -1211,7 +1186,6 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
} }
goto NO_MATCH; goto NO_MATCH;
case TYPE_ENUM: case TYPE_ENUM:
return sema_expr_analyse_method(context, expr, type->decl, is_pointer);
case TYPE_ERRTYPE: case TYPE_ERRTYPE:
case TYPE_STRUCT: case TYPE_STRUCT:
case TYPE_UNION: case TYPE_UNION:
@@ -1222,10 +1196,14 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
return false; return false;
} }
Decl *decl = type->decl; Decl *decl = type->decl;
Decl *member = strukt_recursive_search_member(decl, TOKSTR(expr->access_expr.sub_element)); context_push_scope(context);
add_members_to_context(context, decl);
Decl *member = sema_resolve_symbol_in_current_dynamic_scope(context, kw);
context_pop_scope(context);
if (!member) if (!member)
{ {
return sema_expr_analyse_method(context, expr, decl, is_pointer); SEMA_ERROR(expr, "There is no element or method '%s.%s'.", decl->name, kw);
return false; return false;
} }
if (is_pointer) if (is_pointer)
@@ -1270,6 +1248,8 @@ static DesignatedPath *sema_analyse_init_identifier_string(Context *context, Des
sub_path->kind = DESIGNATED_IDENT; sub_path->kind = DESIGNATED_IDENT;
sub_path->index = i; sub_path->index = i;
parent_path->sub_path = sub_path; parent_path->sub_path = sub_path;
sub_path->pure = true;
sub_path->constant = true;
*has_found_match = true; *has_found_match = true;
return sub_path; return sub_path;
} }
@@ -1284,6 +1264,11 @@ static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath
if (!last_path) return NULL; if (!last_path) return NULL;
DesignatedPath *path = sema_analyse_init_identifier_string(context, last_path, DesignatedPath *path = sema_analyse_init_identifier_string(context, last_path,
TOKSTR(access_expr->access_expr.sub_element), has_found_match, has_reported_error); TOKSTR(access_expr->access_expr.sub_element), has_found_match, has_reported_error);
if (path)
{
path->pure = true;
path->constant = true;
}
if (!path && has_found_match && !has_reported_error) if (!path && has_found_match && !has_reported_error)
{ {
SEMA_TOKID_ERROR(access_expr->access_expr.sub_element, "'%s' is not a valid sub member.", TOKSTR(access_expr->access_expr.sub_element)); SEMA_TOKID_ERROR(access_expr->access_expr.sub_element, "'%s' is not a valid sub member.", TOKSTR(access_expr->access_expr.sub_element));
@@ -1341,6 +1326,11 @@ static DesignatedPath *sema_analyse_init_subscript(Context *context, DesignatedP
DesignatedPath *sub_path = CALLOCS(DesignatedPath); DesignatedPath *sub_path = CALLOCS(DesignatedPath);
path->sub_path = sub_path; path->sub_path = sub_path;
sub_path->pure = index->pure;
sub_path->constant = index->constant;
path->constant &= index->pure;
path->pure &= index->pure;
sub_path->type = inner_type; sub_path->type = inner_type;
sub_path->kind = DESIGNATED_SUBSCRIPT; sub_path->kind = DESIGNATED_SUBSCRIPT;
sub_path->index_expr = index; sub_path->index_expr = index;
@@ -1370,9 +1360,8 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
Expr **init_expressions = initializer->expr_initializer.initializer_expr; Expr **init_expressions = initializer->expr_initializer.initializer_expr;
bool is_structlike = type_is_structlike(assigned->canonical); bool is_structlike = type_is_structlike(assigned->canonical);
// TODO purity const initializer->pure = true;
initializer->pure = false; initializer->constant = true;
initializer->constant = false;
VECEACH(init_expressions, i) VECEACH(init_expressions, i)
{ {
Expr *expr = init_expressions[i]; Expr *expr = init_expressions[i];
@@ -1391,6 +1380,8 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
} }
Expr *init_expr = expr->binary_expr.left; Expr *init_expr = expr->binary_expr.left;
DesignatedPath path = { .type = assigned }; DesignatedPath path = { .type = assigned };
path.pure = true;
path.constant = true;
bool has_reported_error = false; bool has_reported_error = false;
bool has_found_match = false; bool has_found_match = false;
DesignatedPath *last_path = sema_analyse_init_path(context, &path, init_expr, &has_found_match, &has_reported_error); DesignatedPath *last_path = sema_analyse_init_path(context, &path, init_expr, &has_found_match, &has_reported_error);
@@ -1401,11 +1392,15 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
} }
Expr *value = expr->binary_expr.right; Expr *value = expr->binary_expr.right;
if (!sema_analyse_expr_of_required_type(context, last_path->type, value, true)) return false; if (!sema_analyse_expr_of_required_type(context, last_path->type, value, true)) return false;
expr->pure = value->pure & last_path->pure;
expr->constant = value->constant & last_path->constant;
expr->expr_kind = EXPR_DESIGNATED_INITIALIZER; expr->expr_kind = EXPR_DESIGNATED_INITIALIZER;
expr->designated_init_expr.path = path.sub_path; expr->designated_init_expr.path = path.sub_path;
expr->designated_init_expr.value = value; expr->designated_init_expr.value = value;
expr->failable |= value->failable; expr->failable |= value->failable;
expr->resolve_status = RESOLVE_DONE; expr->resolve_status = RESOLVE_DONE;
initializer->pure &= expr->pure;
initializer->constant &= expr->constant;
} }
initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED; initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED;
return true; return true;
@@ -1417,9 +1412,8 @@ static bool sema_expr_analyse_designated_initializer(Context *context, Type *ass
*/ */
static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer) static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, Decl *assigned, Expr *initializer)
{ {
// TODO purity const initializer->pure = true;
initializer->pure = false; initializer->constant = true;
initializer->constant = false;
Expr **elements = initializer->expr_initializer.initializer_expr; Expr **elements = initializer->expr_initializer.initializer_expr;
Decl **members = assigned->strukt.members; Decl **members = assigned->strukt.members;
@@ -1448,14 +1442,17 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
// 4. Check if we exceeded the list of elements in the struct/union. // 4. Check if we exceeded the list of elements in the struct/union.
// This way we can check the other elements which might help the // This way we can check the other elements which might help the
// user pinpoint where they put the double elements. // user pinpoint where they put the double elements.
Expr *element = elements[i];
if (i >= expected_members) if (i >= expected_members)
{ {
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members); SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members);
return false; return false;
} }
// 5. We know the required type, so resolve the expression. // 5. We know the required type, so resolve the expression.
if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i], 0)) return false; if (!sema_analyse_expr_of_required_type(context, members[i]->type, elements[i], 0)) return false;
initializer->failable = elements[i]->failable; initializer->pure &= element->pure;
initializer->constant &= element->constant;
initializer->failable |= element->failable;
} }
// 6. There's the case of too few values as well. Mark the last element as wrong. // 6. There's the case of too few values as well. Mark the last element as wrong.
@@ -1476,9 +1473,8 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context,
*/ */
static inline bool sema_expr_analyse_array_plain_initializer(Context *context, Type *assigned, Expr *initializer) static inline bool sema_expr_analyse_array_plain_initializer(Context *context, Type *assigned, Expr *initializer)
{ {
// TODO purity const initializer->pure = true;
initializer->pure = false; initializer->constant = true;
initializer->constant = false;
Expr **elements = initializer->expr_initializer.initializer_expr; Expr **elements = initializer->expr_initializer.initializer_expr;
@@ -1502,13 +1498,16 @@ static inline bool sema_expr_analyse_array_plain_initializer(Context *context, T
VECEACH(elements, i) VECEACH(elements, i)
{ {
Expr *element = elements[i];
if (i >= expected_members) if (i >= expected_members)
{ {
SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", expected_members); SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members);
return false; return false;
} }
if (!sema_analyse_expr_of_required_type(context, inner_type, elements[i], true)) return false; if (!sema_analyse_expr_of_required_type(context, inner_type, element, true)) return false;
initializer->failable |= elements[i]->failable; initializer->failable |= element->failable;
initializer->pure &= element->pure;
initializer->constant &= element->constant;
} }
if (expected_members > size) if (expected_members > size)
@@ -1546,10 +1545,8 @@ static inline bool sema_expr_analyse_initializer(Context *context, Type *assigne
{ {
return sema_expr_analyse_array_plain_initializer(context, assigned, expr); return sema_expr_analyse_array_plain_initializer(context, assigned, expr);
} }
else
{ return sema_expr_analyse_struct_plain_initializer(context, assigned->decl, expr);
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) static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to, Expr *expr)