Macros with default arguments to &, # and type parameters didn't work as expected. #1754.

This commit is contained in:
Christoffer Lerno
2025-01-01 17:52:32 +01:00
parent 99c350fc43
commit 7c45ae24ae
3 changed files with 368 additions and 14 deletions

View File

@@ -41,6 +41,7 @@
- Fix bug when including compile time parameters in trailing body more than once.
- Fix issue with compiling a constant struct containing a string array in a local context.
- Fix error where panic would not properly stop the program when stacktrace couldn't be printed #1751.
- Macros with default arguments to `&`, `#` and type parameters didn't work as expected. #1754.
### Stdlib changes
- Increase BitWriter.write_bits limit up to 32 bits.

View File

@@ -1267,7 +1267,6 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param,
{
VarDeclKind kind = param->var.kind;
Type *type = param->type;
// 16. Analyse a regular argument.
switch (kind)
{
@@ -1403,7 +1402,7 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param,
case VARDECL_ERASE:
UNREACHABLE
}
if (param && type_len_is_inferred(type))
if (type_len_is_inferred(type))
{
param->type = type_no_optional(arg->type);
}
@@ -1417,6 +1416,7 @@ INLINE bool sema_set_default_argument(SemaContext *context, CalledDecl *callee,
Expr *init_expr = param->var.init_expr;
if (!init_expr) return true;
Expr *arg = copy_expr_single(init_expr);
bool parameter_checked = false;
if (arg->resolve_status != RESOLVE_DONE)
{
SemaContext default_context;
@@ -1436,20 +1436,20 @@ INLINE bool sema_set_default_argument(SemaContext *context, CalledDecl *callee,
{
RETURN_NOTE_FUNC_DEFINITION;
}
if (!success) return false;
parameter_checked = true;
}
if (sema_cast_const(arg))
switch (param->var.kind)
{
switch (param->var.kind)
{
case VARDECL_PARAM_CT:
case VARDECL_PARAM_CT_TYPE:
case VARDECL_PARAM_EXPR:
*expr_ref = arg;
return sema_analyse_parameter(context, arg, param, callee->definition, optional, no_match_ref,
callee->macro, false);
default:
break;
}
case VARDECL_PARAM_CT:
case VARDECL_PARAM_CT_TYPE:
case VARDECL_PARAM_EXPR:
*expr_ref = arg;
if (parameter_checked) return true;
return sema_analyse_parameter(context, arg, param, callee->definition, optional, no_match_ref,
callee->macro, false);
default:
break;
}
Expr *function_scope_arg = expr_new(EXPR_DEFAULT_ARG, arg->span);
function_scope_arg->resolve_status = RESOLVE_DONE;
@@ -1457,6 +1457,7 @@ INLINE bool sema_set_default_argument(SemaContext *context, CalledDecl *callee,
function_scope_arg->default_arg_expr.inner = arg;
function_scope_arg->default_arg_expr.loc = callee->call_location;
*expr_ref = function_scope_arg;
if (parameter_checked) return true;
return sema_analyse_parameter(context, function_scope_arg, param, callee->definition, optional, no_match_ref,
callee->macro, false);
}
@@ -9784,6 +9785,10 @@ bool sema_analyse_expr(SemaContext *context, Expr *expr)
bool sema_cast_const(Expr *expr)
{
if (expr->resolve_status != RESOLVE_DONE)
{
puts("Tesst");
}
ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_DONE);
switch (expr->expr_kind)
{

View File

@@ -0,0 +1,348 @@
module test;
import std, test2;
int[2] x;
macro @test2(&a = x[1])
{
*a = 123;
}
macro test($Type = int) { io::printn($Type.nameof); }
fn void testme() { io::printn("Testme"); }
macro @test3(#foo = testme()) => #foo;
fn void main()
{
test();
@test2();
@test3();
io::printn(x);
test2::test();
test2::@test2();
test2::@test3();
io::printn(test2::x);
}
module test2;
import std;
int[2] x;
macro @test2(&a = x[1])
{
*a = 12;
}
macro test($Type = double) { io::printn($Type.nameof); }
fn void testme() { io::printn("Testme2"); }
macro @test3(#foo = testme()) => #foo;
/* #expect: test.ll
define void @test.main() #0 {
entry:
%len = alloca i64, align 8
%error_var = alloca i64, align 8
%retparam = alloca i64, align 8
%taddr = alloca %"char[]", align 8
%error_var2 = alloca i64, align 8
%error_var8 = alloca i64, align 8
%x = alloca [2 x i32], align 4
%x14 = alloca [2 x i32], align 4
%len15 = alloca i64, align 8
%error_var16 = alloca i64, align 8
%x17 = alloca [2 x i32], align 4
%varargslots = alloca [1 x %any], align 8
%retparam19 = alloca i64, align 8
%taddr20 = alloca %any, align 8
%taddr21 = alloca %"char[]", align 8
%taddr22 = alloca %"any[]", align 8
%error_var28 = alloca i64, align 8
%error_var34 = alloca i64, align 8
%len42 = alloca i64, align 8
%error_var43 = alloca i64, align 8
%retparam45 = alloca i64, align 8
%taddr46 = alloca %"char[]", align 8
%error_var52 = alloca i64, align 8
%error_var58 = alloca i64, align 8
%x66 = alloca [2 x i32], align 4
%x67 = alloca [2 x i32], align 4
%len68 = alloca i64, align 8
%error_var69 = alloca i64, align 8
%x70 = alloca [2 x i32], align 4
%varargslots72 = alloca [1 x %any], align 8
%retparam74 = alloca i64, align 8
%taddr75 = alloca %any, align 8
%taddr76 = alloca %"char[]", align 8
%taddr77 = alloca %"any[]", align 8
%error_var83 = alloca i64, align 8
%error_var89 = alloca i64, align 8
%0 = call ptr @std.io.stdout()
store %"char[]" { ptr @.str.1, i64 3 }, ptr %taddr, align 8
%1 = load [2 x i64], ptr %taddr, align 8
%2 = call i64 @std.io.File.write(ptr %retparam, ptr %0
%not_err = icmp eq i64 %2, 0
%3 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %3, label %after_check, label %assign_optional
assign_optional: ; preds = %entry
store i64 %2, ptr %error_var, align 8
br label %guard_block
after_check: ; preds = %entry
br label %noerr_block
guard_block: ; preds = %assign_optional
br label %voiderr
noerr_block: ; preds = %after_check
%4 = load i64, ptr %retparam, align 8
store i64 %4, ptr %len, align 8
%5 = call i64 @std.io.File.write_byte(ptr %0, i8 10)
%not_err3 = icmp eq i64 %5, 0
%6 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
br i1 %6, label %after_check5, label %assign_optional4
assign_optional4: ; preds = %noerr_block
store i64 %5, ptr %error_var2, align 8
br label %guard_block6
after_check5: ; preds = %noerr_block
br label %noerr_block7
guard_block6: ; preds = %assign_optional4
br label %voiderr
noerr_block7: ; preds = %after_check5
%7 = call i64 @std.io.File.flush(ptr %0)
%not_err9 = icmp eq i64 %7, 0
%8 = call i1 @llvm.expect.i1(i1 %not_err9, i1 true)
br i1 %8, label %after_check11, label %assign_optional10
assign_optional10: ; preds = %noerr_block7
store i64 %7, ptr %error_var8, align 8
br label %guard_block12
after_check11: ; preds = %noerr_block7
br label %noerr_block13
guard_block12: ; preds = %assign_optional10
br label %voiderr
noerr_block13: ; preds = %after_check11
%9 = load i64, ptr %len, align 8
%add = add i64 %9, 1
br label %voiderr
voiderr: ; preds = %noerr_block13, %guard_block12, %guard_block6, %guard_block
store i32 123, ptr getelementptr inbounds (i8, ptr @test.x, i64 4), align 4
call void @test.testme()
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x, ptr align 4 @test.x, i32 8, i1 false)
%10 = call ptr @std.io.stdout()
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x14, ptr align 4 %x, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x17, ptr align 4 %x14, i32 8, i1 false)
%11 = insertvalue %any undef, ptr %10, 0
%12 = insertvalue %any %11, i64 ptrtoint (ptr @"$ct.std.io.File" to i64), 1
%13 = insertvalue %any undef, ptr %x17, 0
%14 = insertvalue %any %13, i64 ptrtoint (ptr @"$ct.a2$int" to i64), 1
store %any %14, ptr %varargslots, align 8
%15 = insertvalue %"any[]" undef, ptr %varargslots, 0
%"$$temp" = insertvalue %"any[]" %15, i64 1, 1
store %any %12, ptr %taddr20, align 8
%16 = load [2 x i64], ptr %taddr20, align 8
store %"char[]" { ptr @.str.2, i64 2 }, ptr %taddr21, align 8
%17 = load [2 x i64], ptr %taddr21, align 8
store %"any[]" %"$$temp", ptr %taddr22, align 8
%18 = load [2 x i64], ptr %taddr22, align 8
%19 = call i64 @std.io.fprintf(ptr %retparam19
%not_err23 = icmp eq i64 %19, 0
%20 = call i1 @llvm.expect.i1(i1 %not_err23, i1 true)
br i1 %20, label %after_check25, label %assign_optional24
assign_optional24: ; preds = %voiderr
store i64 %19, ptr %error_var16, align 8
br label %guard_block26
after_check25: ; preds = %voiderr
br label %noerr_block27
guard_block26: ; preds = %assign_optional24
br label %voiderr41
noerr_block27: ; preds = %after_check25
%21 = load i64, ptr %retparam19, align 8
store i64 %21, ptr %len15, align 8
%22 = call i64 @std.io.File.write_byte(ptr %10, i8 10)
%not_err29 = icmp eq i64 %22, 0
%23 = call i1 @llvm.expect.i1(i1 %not_err29, i1 true)
br i1 %23, label %after_check31, label %assign_optional30
assign_optional30: ; preds = %noerr_block27
store i64 %22, ptr %error_var28, align 8
br label %guard_block32
after_check31: ; preds = %noerr_block27
br label %noerr_block33
guard_block32: ; preds = %assign_optional30
br label %voiderr41
noerr_block33: ; preds = %after_check31
%24 = call i64 @std.io.File.flush(ptr %10)
%not_err35 = icmp eq i64 %24, 0
%25 = call i1 @llvm.expect.i1(i1 %not_err35, i1 true)
br i1 %25, label %after_check37, label %assign_optional36
assign_optional36: ; preds = %noerr_block33
store i64 %24, ptr %error_var34, align 8
br label %guard_block38
after_check37: ; preds = %noerr_block33
br label %noerr_block39
guard_block38: ; preds = %assign_optional36
br label %voiderr41
noerr_block39: ; preds = %after_check37
%26 = load i64, ptr %len15, align 8
%add40 = add i64 %26, 1
br label %voiderr41
voiderr41: ; preds = %noerr_block39, %guard_block38, %guard_block32, %guard_block26
%27 = call ptr @std.io.stdout()
store %"char[]" { ptr @.str.3, i64 6 }, ptr %taddr46, align 8
%28 = load [2 x i64], ptr %taddr46, align 8
%29 = call i64 @std.io.File.write(ptr %retparam45
%not_err47 = icmp eq i64 %29, 0
%30 = call i1 @llvm.expect.i1(i1 %not_err47, i1 true)
br i1 %30, label %after_check49, label %assign_optional48
assign_optional48: ; preds = %voiderr41
store i64 %29, ptr %error_var43, align 8
br label %guard_block50
after_check49: ; preds = %voiderr41
br label %noerr_block51
guard_block50: ; preds = %assign_optional48
br label %voiderr65
noerr_block51: ; preds = %after_check49
%31 = load i64, ptr %retparam45, align 8
store i64 %31, ptr %len42, align 8
%32 = call i64 @std.io.File.write_byte(ptr %27, i8 10)
%not_err53 = icmp eq i64 %32, 0
%33 = call i1 @llvm.expect.i1(i1 %not_err53, i1 true)
br i1 %33, label %after_check55, label %assign_optional54
assign_optional54: ; preds = %noerr_block51
store i64 %32, ptr %error_var52, align 8
br label %guard_block56
after_check55: ; preds = %noerr_block51
br label %noerr_block57
guard_block56: ; preds = %assign_optional54
br label %voiderr65
noerr_block57: ; preds = %after_check55
%34 = call i64 @std.io.File.flush(ptr %27)
%not_err59 = icmp eq i64 %34, 0
%35 = call i1 @llvm.expect.i1(i1 %not_err59, i1 true)
br i1 %35, label %after_check61, label %assign_optional60
assign_optional60: ; preds = %noerr_block57
store i64 %34, ptr %error_var58, align 8
br label %guard_block62
after_check61: ; preds = %noerr_block57
br label %noerr_block63
guard_block62: ; preds = %assign_optional60
br label %voiderr65
noerr_block63: ; preds = %after_check61
%36 = load i64, ptr %len42, align 8
%add64 = add i64 %36, 1
br label %voiderr65
voiderr65: ; preds = %noerr_block63, %guard_block62, %guard_block56, %guard_block50
store i32 12, ptr getelementptr inbounds
call void @test2.testme()
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x66, ptr align 4 @test2.x, i32 8, i1 false)
%37 = call ptr @std.io.stdout()
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x67, ptr align 4 %x66, i32 8, i1 false)
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %x70, ptr align 4 %x67, i32 8, i1 false)
%38 = insertvalue %any undef, ptr %37, 0
%39 = insertvalue %any %38, i64 ptrtoint (ptr @"$ct.std.io.File" to i64), 1
%40 = insertvalue %any undef, ptr %x70, 0
%41 = insertvalue %any %40, i64 ptrtoint (ptr @"$ct.a2$int" to i64), 1
store %any %41, ptr %varargslots72, align 8
%42 = insertvalue %"any[]" undef, ptr %varargslots72, 0
%"$$temp73" = insertvalue %"any[]" %42, i64 1, 1
store %any %39, ptr %taddr75, align 8
%43 = load [2 x i64], ptr %taddr75, align 8
store %"char[]" { ptr @.str.4, i64 2 }, ptr %taddr76, align 8
%44 = load [2 x i64], ptr %taddr76, align 8
store %"any[]" %"$$temp73", ptr %taddr77, align 8
%45 = load [2 x i64], ptr %taddr77, align 8
%46 = call i64 @std.io.fprintf(ptr %retparam74
%not_err78 = icmp eq i64 %46, 0
%47 = call i1 @llvm.expect.i1(i1 %not_err78, i1 true)
br i1 %47, label %after_check80, label %assign_optional79
assign_optional79: ; preds = %voiderr65
store i64 %46, ptr %error_var69, align 8
br label %guard_block81
after_check80: ; preds = %voiderr65
br label %noerr_block82
guard_block81: ; preds = %assign_optional79
br label %voiderr96
noerr_block82: ; preds = %after_check80
%48 = load i64, ptr %retparam74, align 8
store i64 %48, ptr %len68, align 8
%49 = call i64 @std.io.File.write_byte(ptr %37, i8 10)
%not_err84 = icmp eq i64 %49, 0
%50 = call i1 @llvm.expect.i1(i1 %not_err84, i1 true)
br i1 %50, label %after_check86, label %assign_optional85
assign_optional85: ; preds = %noerr_block82
store i64 %49, ptr %error_var83, align 8
br label %guard_block87
after_check86: ; preds = %noerr_block82
br label %noerr_block88
guard_block87: ; preds = %assign_optional85
br label %voiderr96
noerr_block88: ; preds = %after_check86
%51 = call i64 @std.io.File.flush(ptr %37)
%not_err90 = icmp eq i64 %51, 0
%52 = call i1 @llvm.expect.i1(i1 %not_err90, i1 true)
br i1 %52, label %after_check92, label %assign_optional91
assign_optional91: ; preds = %noerr_block88
store i64 %51, ptr %error_var89, align 8
br label %guard_block93
after_check92: ; preds = %noerr_block88
br label %noerr_block94
guard_block93: ; preds = %assign_optional91
br label %voiderr96
noerr_block94: ; preds = %after_check92
%53 = load i64, ptr %len68, align 8
%add95 = add i64 %53, 1
br label %voiderr96
voiderr96: ; preds = %noerr_block94, %guard_block93, %guard_block87, %guard_block81
ret void
}