mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Allow splat in initializers.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
## 0.6.5 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Allow splat in initializers.
|
||||
|
||||
### Fixes
|
||||
- Fix bug where `a > 0 ? f() : g()` could cause a compiler crash if both returned `void!`.
|
||||
|
||||
@@ -2290,7 +2290,7 @@ bool sema_analyse_statement(SemaContext *context, Ast *statement);
|
||||
bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right,
|
||||
bool is_unwrapped_var, bool is_declaration);
|
||||
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr);
|
||||
Expr **sema_expand_vasplat_exprs(SemaContext *c, Expr **exprs);
|
||||
Expr **sema_expand_vasplat_exprs(SemaContext *context, Expr **exprs);
|
||||
|
||||
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool optional,
|
||||
bool *no_match_ref);
|
||||
|
||||
@@ -5213,10 +5213,10 @@ static Expr **sema_vasplat_insert(SemaContext *context, Expr **init_expressions,
|
||||
return init_expressions;
|
||||
}
|
||||
|
||||
Expr **sema_expand_vasplat_exprs(SemaContext *c, Expr **exprs)
|
||||
Expr **sema_expand_vasplat_exprs(SemaContext *context, Expr **exprs)
|
||||
{
|
||||
if (!c || !c->current_macro) return exprs;
|
||||
|
||||
if (!context) return exprs;
|
||||
bool in_macro = context->current_macro;
|
||||
unsigned count = vec_size(exprs);
|
||||
bool expand;
|
||||
do
|
||||
@@ -5224,15 +5224,54 @@ Expr **sema_expand_vasplat_exprs(SemaContext *c, Expr **exprs)
|
||||
expand = false;
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
if (exprs[i]->expr_kind == EXPR_VASPLAT)
|
||||
Expr *arg = exprs[i];
|
||||
ExprKind kind = arg->expr_kind;
|
||||
if (in_macro && kind == EXPR_VASPLAT)
|
||||
{
|
||||
exprs = sema_vasplat_insert(c, exprs, exprs[i], i);
|
||||
exprs = sema_vasplat_insert(context, exprs, arg, i);
|
||||
// If we have null back it failed.
|
||||
if (!exprs) return NULL;
|
||||
count = vec_size(exprs);
|
||||
expand = true;
|
||||
break;
|
||||
}
|
||||
if (kind == EXPR_SPLAT)
|
||||
{
|
||||
Expr *inner = arg->inner_expr;
|
||||
if (!sema_analyse_expr(context, inner)) return false;
|
||||
Type *flat = type_flatten(inner->type);
|
||||
switch (flat->type_kind)
|
||||
{
|
||||
case TYPE_VECTOR:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_SLICE:
|
||||
case TYPE_UNTYPED_LIST:
|
||||
// These may be splatted
|
||||
break;
|
||||
default:
|
||||
SEMA_ERROR(arg, "An argument of type %s cannot be splatted.",
|
||||
type_quoted_error_string(inner->type));
|
||||
return NULL;
|
||||
}
|
||||
ArrayIndex len = sema_len_from_expr(inner);
|
||||
if (len == -1)
|
||||
{
|
||||
SEMA_ERROR(arg,
|
||||
"Splat may not be used with if the length is not known, but if you slice it to a constant length it will work (e.g '...val[:2]')");
|
||||
return NULL;
|
||||
}
|
||||
if (len == 0 && !expr_is_const(arg))
|
||||
{
|
||||
SEMA_ERROR(arg, "A non-constant zero size splat is not allowed.");
|
||||
return NULL;
|
||||
}
|
||||
Expr **new_args = sema_splat_arraylike_insert(context, exprs, inner, len, i);
|
||||
if (!new_args) return false;
|
||||
if (!exprs) return NULL;
|
||||
count = vec_size(exprs);
|
||||
expand = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (expand);
|
||||
return exprs;
|
||||
|
||||
40
test/test_suite/functions/splat_init.c3t
Normal file
40
test/test_suite/functions/splat_init.c3t
Normal file
@@ -0,0 +1,40 @@
|
||||
// #target: macos-x64
|
||||
module splat;
|
||||
import std;
|
||||
|
||||
int a = 0;
|
||||
|
||||
fn int[2] test()
|
||||
{
|
||||
a++;
|
||||
return { 2, 3 };
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
int[4] z = { a, ...test(), a };
|
||||
}
|
||||
|
||||
/* #expect: splat.ll
|
||||
|
||||
define void @splat.main() #0 {
|
||||
entry:
|
||||
%z = alloca [4 x i32], align 16
|
||||
%.anon = alloca [2 x i32], align 4
|
||||
%result = alloca [2 x i32], align 4
|
||||
%0 = load i32, ptr @splat.a, align 4
|
||||
store i32 %0, ptr %z, align 4
|
||||
%ptradd = getelementptr inbounds i8, ptr %z, i64 4
|
||||
%1 = call i64 @splat.test()
|
||||
store i64 %1, ptr %result, align 4
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %.anon, ptr align 4 %result, i32 8, i1 false)
|
||||
%2 = load i32, ptr %.anon, align 4
|
||||
store i32 %2, ptr %ptradd, align 4
|
||||
%ptradd1 = getelementptr inbounds i8, ptr %z, i64 8
|
||||
%ptradd2 = getelementptr inbounds i8, ptr %.anon, i64 4
|
||||
%3 = load i32, ptr %ptradd2, align 4
|
||||
store i32 %3, ptr %ptradd1, align 4
|
||||
%ptradd3 = getelementptr inbounds i8, ptr %z, i64 12
|
||||
%4 = load i32, ptr @splat.a, align 4
|
||||
store i32 %4, ptr %ptradd3, align 4
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user