diff --git a/releasenotes.md b/releasenotes.md index 70d9a7a07..26db6d3dd 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -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. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 36c015ccf..72575983f 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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) { diff --git a/test/test_suite/statements/default_macro_argc.c3t b/test/test_suite/statements/default_macro_argc.c3t new file mode 100644 index 000000000..963fe88c5 --- /dev/null +++ b/test/test_suite/statements/default_macro_argc.c3t @@ -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 +}