mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Support int $foo... arguments. #2601
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
- Deprecate `--test-nocapture` in favour of `--test-show-output` #2588.
|
||||
- Xtensa target no longer enabled by default on LLVM 22, Compile with `-DXTENSA_ENABLE` to enable it instead
|
||||
- Add `float[<3>] x = { .xy = 1.2, .z = 3.3 }` swizzle initialization for vectors. #2599
|
||||
- Support `int $foo...` arguments. #2601
|
||||
|
||||
### Fixes
|
||||
- `Foo.is_eq` would return false if the type was a `typedef` and had an overload, but the underlying type was not comparable.
|
||||
|
||||
@@ -1583,12 +1583,20 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Variadic *variadic, i
|
||||
// We reserve upper case constants for globals.
|
||||
PRINT_ERROR_HERE("Parameter names may not be all uppercase.");
|
||||
return false;
|
||||
case TOKEN_CT_IDENT:
|
||||
// ct_var $foo
|
||||
name = symstr(c);
|
||||
advance_and_verify(c, TOKEN_CT_IDENT);
|
||||
param_kind = VARDECL_PARAM_CT;
|
||||
goto CHECK_ELLIPSIS;
|
||||
break;
|
||||
case TOKEN_IDENT:
|
||||
// normal "foo"
|
||||
name = symstr(c);
|
||||
param_kind = VARDECL_PARAM;
|
||||
advance_and_verify(c, TOKEN_IDENT);
|
||||
// Check for "foo..." which defines an implicit "any" vararg
|
||||
CHECK_ELLIPSIS:
|
||||
if (try_consume(c, TOKEN_ELLIPSIS))
|
||||
{
|
||||
// Did we get Foo... foo...
|
||||
@@ -1606,7 +1614,12 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Variadic *variadic, i
|
||||
// Did we get Foo foo...? If so then that's an error.
|
||||
if (type)
|
||||
{
|
||||
PRINT_ERROR_LAST("For typed varargs '...', needs to appear after the type.");
|
||||
PRINT_ERROR_LAST("For typed vaargs '...', needs to appear after the type.");
|
||||
return false;
|
||||
}
|
||||
else if (param_kind == VARDECL_PARAM_CT)
|
||||
{
|
||||
PRINT_ERROR_LAST("Untyped constant vaargs are not supported. Use raw macro vaargs instead.");
|
||||
return false;
|
||||
}
|
||||
// This is "foo..."
|
||||
@@ -1615,18 +1628,6 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Variadic *variadic, i
|
||||
type = type_info_new_base(type_any, c->span);
|
||||
}
|
||||
break;
|
||||
case TOKEN_CT_IDENT:
|
||||
// ct_var $foo
|
||||
name = symstr(c);
|
||||
advance_and_verify(c, TOKEN_CT_IDENT);
|
||||
// This will catch Type... $foo and $foo..., neither is allowed.
|
||||
if (ellipsis || tok_is(c, TOKEN_ELLIPSIS))
|
||||
{
|
||||
PRINT_ERROR_LAST("Compile time parameters may not be varargs, use untyped macro varargs '...' instead.");
|
||||
return false;
|
||||
}
|
||||
param_kind = VARDECL_PARAM_CT;
|
||||
break;
|
||||
case TOKEN_AMP:
|
||||
// reference &foo
|
||||
advance_and_verify(c, TOKEN_AMP);
|
||||
@@ -1659,7 +1660,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Variadic *variadic, i
|
||||
advance_and_verify(c, TOKEN_HASH_IDENT);
|
||||
if (ellipsis || tok_is(c, TOKEN_ELLIPSIS))
|
||||
{
|
||||
PRINT_ERROR_LAST("Expression parameters may not be varargs, use untyped macro varargs '...' instead.");
|
||||
PRINT_ERROR_LAST("Expression parameters may not be vaargs, use untyped macro vaargs '...' instead.");
|
||||
return false;
|
||||
}
|
||||
param_kind = VARDECL_PARAM_EXPR;
|
||||
@@ -1670,7 +1671,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Variadic *variadic, i
|
||||
advance_and_verify(c, TOKEN_CT_TYPE_IDENT);
|
||||
if (ellipsis || tok_is(c, TOKEN_ELLIPSIS))
|
||||
{
|
||||
PRINT_ERROR_LAST("Expression parameters may not be varargs, use untyped macro varargs '...' instead.");
|
||||
PRINT_ERROR_LAST("Expression parameters may not be vaargs, use untyped macro vaargs '...' instead.");
|
||||
return false;
|
||||
}
|
||||
param_kind = VARDECL_PARAM_CT_TYPE;
|
||||
|
||||
@@ -1411,7 +1411,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
|
||||
}
|
||||
if (param->var.vararg)
|
||||
{
|
||||
if (var_kind != VARDECL_PARAM)
|
||||
if (var_kind != VARDECL_PARAM && var_kind != VARDECL_PARAM_CT)
|
||||
{
|
||||
SEMA_ERROR(param, "Only regular parameters may be vararg.");
|
||||
return decl_poison(param);
|
||||
|
||||
@@ -2025,7 +2025,18 @@ INLINE bool sema_call_evaluate_arguments(SemaContext *context, CalledDecl *calle
|
||||
if (type_is_arraylike(inner->type))
|
||||
{
|
||||
inner_new = expr_copy(inner);
|
||||
expr_insert_addr(inner_new);
|
||||
if (sema_cast_const(inner_new) && expr_is_const_initializer(inner_new))
|
||||
{
|
||||
ConstInitializer *initializer = inner_new->const_expr.initializer;
|
||||
inner_new->const_expr.const_kind = CONST_SLICE;
|
||||
inner_new->type = type_get_slice(inner_new->type->array.base);
|
||||
inner_new->const_expr.slice_init = initializer;
|
||||
initializer->type = inner_new->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
expr_insert_addr(inner_new);
|
||||
}
|
||||
}
|
||||
if (!cast_implicit_silent(context, inner_new, variadic_slot_type, false)) goto SPLAT_NORMAL;
|
||||
if (inner != inner_new) expr_replace(inner, inner_new);
|
||||
@@ -2218,6 +2229,33 @@ SPLAT_NORMAL:;
|
||||
if (!sema_analyse_parameter(context, arg, params[i], callee->definition, optional, no_match_ref, callee->macro, callee->struct_var && i == 0)) return false;
|
||||
actual_args[i] = arg;
|
||||
}
|
||||
if (call->call_expr.varargs && variadic != VARIADIC_RAW)
|
||||
{
|
||||
Decl *param = params[vaarg_index];
|
||||
if (param->var.kind == VARDECL_PARAM_CT)
|
||||
{
|
||||
if (call->call_expr.va_is_splat)
|
||||
{
|
||||
if (!expr_is_runtime_const(call->call_expr.vasplat))
|
||||
{
|
||||
SEMA_ERROR(call->call_expr.vasplat, "The splat must be a compile time value.");
|
||||
RETURN_NOTE_FUNC_DEFINITION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FOREACH(Expr *, ct_param, call->call_expr.varargs)
|
||||
{
|
||||
if (!expr_is_runtime_const(ct_param))
|
||||
{
|
||||
SEMA_ERROR(ct_param, "All vaargs must be contant values.");
|
||||
RETURN_NOTE_FUNC_DEFINITION;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_args) last = args[num_args - 1];
|
||||
call->call_expr.arguments = args;
|
||||
// 17. Set default values.
|
||||
|
||||
6
test/test_suite/functions/const_vaarg_untyped.c3
Normal file
6
test/test_suite/functions/const_vaarg_untyped.c3
Normal file
@@ -0,0 +1,6 @@
|
||||
macro foo2(int $a, $i...) // #error: Untyped constant vaargs are not supported. Use raw macro vaargs instead
|
||||
{
|
||||
$foreach $ab : $i:
|
||||
$echo $ab;
|
||||
$endforeach
|
||||
}
|
||||
4
test/test_suite/functions/expr_vaarg_untyped.c3
Normal file
4
test/test_suite/functions/expr_vaarg_untyped.c3
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
macro @foo3(int $a, int #i...) // #error: Expression parameters may not be vaargs, use untyped macro vaargs '...' instead
|
||||
{
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: macos-x64
|
||||
fn void test1()
|
||||
{
|
||||
int x;
|
||||
|
||||
35
test/test_suite/functions/splat_const_vaarg.c3t
Normal file
35
test/test_suite/functions/splat_const_vaarg.c3t
Normal file
@@ -0,0 +1,35 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
macro foo(int $a, int... $i)
|
||||
{
|
||||
$foreach $ab : $i:
|
||||
{
|
||||
int x = $ab;
|
||||
}
|
||||
$endforeach
|
||||
}
|
||||
fn int main()
|
||||
{
|
||||
foo(3, 1, 2);
|
||||
int[3] $x = { 1, 2, 3 };
|
||||
foo(3, ...$x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%x1 = alloca i32, align 4
|
||||
%x2 = alloca i32, align 4
|
||||
%x3 = alloca i32, align 4
|
||||
%x4 = alloca i32, align 4
|
||||
store i32 1, ptr %x, align 4
|
||||
store i32 2, ptr %x1, align 4
|
||||
store i32 1, ptr %x2, align 4
|
||||
store i32 2, ptr %x3, align 4
|
||||
store i32 3, ptr %x4, align 4
|
||||
ret i32 0
|
||||
}
|
||||
17
test/test_suite/functions/splat_const_vaarg_fail.c3
Normal file
17
test/test_suite/functions/splat_const_vaarg_fail.c3
Normal file
@@ -0,0 +1,17 @@
|
||||
module test;
|
||||
|
||||
macro foo(int $a, int... $i)
|
||||
{
|
||||
$foreach $ab : $i:
|
||||
$echo $ab;
|
||||
$endforeach
|
||||
}
|
||||
fn int main()
|
||||
{
|
||||
int a;
|
||||
foo(3, 1, 2, a); // #error: All vaargs must be contant values
|
||||
int[3] x = { 1, 2, 3 };
|
||||
foo(3, ...x); // #error: The splat must be a compile time value
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user