mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Struct constants stored in globals.
This commit is contained in:
committed by
Christoffer Lerno
parent
d070a5e7ff
commit
9709cb61a4
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
*.ll
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
|
||||
86
README.md
86
README.md
@@ -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.
|
||||
- Data is inert.
|
||||
- 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?
|
||||
@@ -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
|
||||
|
||||
|
||||
#### What's currently missing
|
||||
#### Todo / done
|
||||
|
||||
- `asm` sections.
|
||||
- bitstructs
|
||||
- array range initializers e.g. `{ [1..2] = 2 }`
|
||||
- `assert` - with compiler hint
|
||||
- `$switch` `$for` - compile time iteration / switch
|
||||
- Pre/post conditions
|
||||
- `generic` - explicit overloading
|
||||
- `malloc` / `free`
|
||||
- `string` not fully implemented
|
||||
- vararrays, e.g. `int[*]` not working
|
||||
- `unreachable` for compiler hinting
|
||||
- Generic modules
|
||||
- Stdlib not linked.
|
||||
|
||||
Also see: https://github.com/c3lang/c3c/issues
|
||||
|
||||
#### What's working?
|
||||
|
||||
- Lexing/parsing/semantic analysis/codegen.
|
||||
- "Regular code" should mostly work.
|
||||
- You can use any C function by declaring it as a normal C3 function with external
|
||||
- [x] For/while/do
|
||||
- [x] `if`/ternary
|
||||
- [x] Structs
|
||||
- [x] Union
|
||||
- [x] Enums
|
||||
- [x] Value methods
|
||||
- [x] Compound literals
|
||||
- [x] Designated initalizers
|
||||
- [x] Slicing syntax
|
||||
- [x] Arrays and subarrays
|
||||
- [x] Modules
|
||||
- [x] `$unreachable`
|
||||
- [x] Compile time assert with `$assert`
|
||||
- [x] Compiler guiding `assert`
|
||||
- [x] C code calling by declaring methods `extern`
|
||||
- [x] Compile time variables
|
||||
- [x] Basic macros
|
||||
- [x] 4cc, 8cc, 2cc
|
||||
- [x] Enum type inference in switch/assignment
|
||||
- [x] Integer type inference
|
||||
- [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?
|
||||
|
||||
|
||||
51
resources/testfragments/struct_ref.c3
Normal file
51
resources/testfragments/struct_ref.c3
Normal 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 };
|
||||
}
|
||||
@@ -166,7 +166,9 @@ typedef enum
|
||||
|
||||
typedef struct _DesignatedPath
|
||||
{
|
||||
DesignatedPathKind kind;
|
||||
DesignatedPathKind kind : 3;
|
||||
bool constant : 1;
|
||||
bool pure : 1;
|
||||
struct _DesignatedPath *sub_path;
|
||||
Type *type;
|
||||
union
|
||||
@@ -623,7 +625,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
DesignatedPath *path;
|
||||
Expr* value;
|
||||
Expr *value;
|
||||
} ExprDesignatedInit;
|
||||
|
||||
typedef struct
|
||||
@@ -1585,4 +1587,11 @@ static inline void advance_and_verify(Context *context, TokenType token_type)
|
||||
assert(context->tok.type == token_type);
|
||||
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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -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)
|
||||
{
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
if (is_error) TODO
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
#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 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_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)
|
||||
|
||||
|
||||
@@ -937,54 +937,6 @@ static inline void insert_access_deref(Expr *expr)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Expr *parent = expr->access_expr.parent;
|
||||
@@ -1211,7 +1186,6 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
|
||||
}
|
||||
goto NO_MATCH;
|
||||
case TYPE_ENUM:
|
||||
return sema_expr_analyse_method(context, expr, type->decl, is_pointer);
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
@@ -1222,10 +1196,14 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (is_pointer)
|
||||
@@ -1270,6 +1248,8 @@ static DesignatedPath *sema_analyse_init_identifier_string(Context *context, Des
|
||||
sub_path->kind = DESIGNATED_IDENT;
|
||||
sub_path->index = i;
|
||||
parent_path->sub_path = sub_path;
|
||||
sub_path->pure = true;
|
||||
sub_path->constant = true;
|
||||
*has_found_match = true;
|
||||
return sub_path;
|
||||
}
|
||||
@@ -1284,6 +1264,11 @@ static DesignatedPath *sema_analyse_init_access(Context *context, DesignatedPath
|
||||
if (!last_path) return NULL;
|
||||
DesignatedPath *path = sema_analyse_init_identifier_string(context, last_path,
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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->kind = DESIGNATED_SUBSCRIPT;
|
||||
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;
|
||||
bool is_structlike = type_is_structlike(assigned->canonical);
|
||||
|
||||
// TODO purity const
|
||||
initializer->pure = false;
|
||||
initializer->constant = false;
|
||||
initializer->pure = true;
|
||||
initializer->constant = true;
|
||||
VECEACH(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;
|
||||
DesignatedPath path = { .type = assigned };
|
||||
path.pure = true;
|
||||
path.constant = true;
|
||||
bool has_reported_error = false;
|
||||
bool has_found_match = false;
|
||||
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;
|
||||
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->designated_init_expr.path = path.sub_path;
|
||||
expr->designated_init_expr.value = value;
|
||||
expr->failable |= value->failable;
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
initializer->pure &= expr->pure;
|
||||
initializer->constant &= expr->constant;
|
||||
}
|
||||
initializer->expr_initializer.init_type = INITIALIZER_DESIGNATED;
|
||||
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)
|
||||
{
|
||||
// TODO purity const
|
||||
initializer->pure = false;
|
||||
initializer->constant = false;
|
||||
initializer->pure = true;
|
||||
initializer->constant = true;
|
||||
|
||||
Expr **elements = initializer->expr_initializer.initializer_expr;
|
||||
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.
|
||||
// This way we can check the other elements which might help the
|
||||
// user pinpoint where they put the double elements.
|
||||
Expr *element = elements[i];
|
||||
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;
|
||||
}
|
||||
// 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;
|
||||
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.
|
||||
@@ -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)
|
||||
{
|
||||
// TODO purity const
|
||||
initializer->pure = false;
|
||||
initializer->constant = false;
|
||||
initializer->pure = true;
|
||||
initializer->constant = true;
|
||||
|
||||
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)
|
||||
{
|
||||
Expr *element = elements[i];
|
||||
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;
|
||||
}
|
||||
if (!sema_analyse_expr_of_required_type(context, inner_type, elements[i], true)) return false;
|
||||
initializer->failable |= elements[i]->failable;
|
||||
if (!sema_analyse_expr_of_required_type(context, inner_type, element, true)) return false;
|
||||
initializer->failable |= element->failable;
|
||||
initializer->pure &= element->pure;
|
||||
initializer->constant &= element->constant;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user