mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
$is_const is deprecated in favour of @is_const based on $defined.
`$foo` variables could be assigned non-compile time values. `$foo[0] = ...` was incorrectly requiring that the assigned values were compile time constants.
This commit is contained in:
@@ -20,6 +20,12 @@ macro bool @is_vector(#value) @const => types::is_vector($typeof(#value));
|
||||
macro bool @is_same_vector_type(#value1, #value2) @const => types::is_same_vector_type($typeof(#value1), $typeof(#value2));
|
||||
macro bool @assign_to(#value1, #value2) @const => $assignable(#value1, $typeof(#value2));
|
||||
macro bool @is_lvalue(#value) => $defined(#value = #value);
|
||||
macro bool @assignable_to(#foo, $Type) @const @builtin => $defined(*&&($Type){} = #foo);
|
||||
macro bool @is_const(#foo) @const @builtin
|
||||
{
|
||||
var $v;
|
||||
return $defined($v = #foo);
|
||||
}
|
||||
|
||||
macro promote_int(x)
|
||||
{
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
- Formatting option "%h" now supports pointers.
|
||||
- Improve error on unsigned implicit conversion to signed.
|
||||
- Update error message for struct initialization #2286
|
||||
- `$is_const` is deprecated in favour of `@is_const` based on `$defined`.
|
||||
|
||||
### Fixes
|
||||
- mkdir/rmdir would not work properly with substring paths on non-windows platforms.
|
||||
- Hex string formatter check incorrectly rejected slices.
|
||||
@@ -41,6 +43,8 @@
|
||||
- Function pointers are now compile time constants.
|
||||
- Splat 8 arguments can sometimes cause incorrect behaviour in the compiler. #2283
|
||||
- Correctly poison the analysis after a failed $assert or $error. #2284
|
||||
- `$foo` variables could be assigned non-compile time values.
|
||||
- `$foo[0] = ...` was incorrectly requiring that the assigned values were compile time constants.
|
||||
|
||||
### Stdlib changes
|
||||
- Improve contract for readline. #2280
|
||||
|
||||
@@ -1097,7 +1097,7 @@ static Expr *parse_access_expr(ParseContext *c, Expr *left, SourceSpan lhs_start
|
||||
return access_expr;
|
||||
}
|
||||
|
||||
static Expr *parse_ct_ident(ParseContext *c, Expr *left, SourceSpan lhs_span)
|
||||
static Expr *parse_ct_ident(ParseContext *c, Expr *left, SourceSpan lhs_span UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
if (try_consume(c, TOKEN_CT_CONST_IDENT))
|
||||
@@ -1112,7 +1112,7 @@ static Expr *parse_ct_ident(ParseContext *c, Expr *left, SourceSpan lhs_span)
|
||||
}
|
||||
|
||||
|
||||
static Expr *parse_hash_ident(ParseContext *c, Expr *left, SourceSpan lhs_span)
|
||||
static Expr *parse_hash_ident(ParseContext *c, Expr *left, SourceSpan lhs_span UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_HASH_IDENT);
|
||||
@@ -1125,7 +1125,7 @@ static Expr *parse_hash_ident(ParseContext *c, Expr *left, SourceSpan lhs_span)
|
||||
/**
|
||||
* ct_eval ::= CT_EVAL '(' expr ')'
|
||||
*/
|
||||
static Expr *parse_ct_eval(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_eval(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_EVAL);
|
||||
@@ -1138,7 +1138,7 @@ static Expr *parse_ct_eval(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
}
|
||||
|
||||
|
||||
static Expr *parse_ct_defined(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_defined(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *defined = expr_new(EXPR_CT_DEFINED, c->span);
|
||||
@@ -1153,7 +1153,7 @@ static Expr *parse_ct_defined(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
*
|
||||
* Note that this is tranformed to $typeof(expr).sizeof.
|
||||
*/
|
||||
static Expr *parse_ct_sizeof(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_sizeof(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *access = expr_new(EXPR_ACCESS_UNRESOLVED, c->span);
|
||||
@@ -1178,7 +1178,7 @@ static Expr *parse_ct_sizeof(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
/**
|
||||
* ct_is_const ::= CT_IS_CONST '(' expr ')'
|
||||
*/
|
||||
static Expr *parse_ct_is_const(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_is_const(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *checks = expr_new(EXPR_CT_IS_CONST, c->span);
|
||||
@@ -1187,13 +1187,14 @@ static Expr *parse_ct_is_const(ParseContext *c, Expr *left, SourceSpan lhs_start
|
||||
ASSIGN_EXPR_OR_RET(checks->inner_expr, parse_expr(c), poisoned_expr);
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr);
|
||||
RANGE_EXTEND_PREV(checks);
|
||||
SEMA_DEPRECATED(checks, "The $is_const macro is deprecated. Use @is_const(...) instead.");
|
||||
return checks;
|
||||
}
|
||||
|
||||
/**
|
||||
* ct_checks ::= CT_EMBED '(' constant_expr (',' constant_expr)? ')'
|
||||
*/
|
||||
static Expr *parse_ct_embed(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_embed(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *embed = expr_new(EXPR_EMBED, c->span);
|
||||
@@ -1213,7 +1214,7 @@ static Expr *parse_ct_embed(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
* ct_call ::= (CT_ALIGNOF | CT_FEATURE | CT_EXTNAMEOF | CT_OFFSETOF | CT_NAMEOF | CT_QNAMEOF) '(' flat_path ')'
|
||||
* flat_path ::= expr ('.' primary) | '[' expr ']')*
|
||||
*/
|
||||
static Expr *parse_ct_call(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_call(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_CALL);
|
||||
@@ -1230,7 +1231,7 @@ static Expr *parse_ct_call(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_ct_assignable(ParseContext *c, Expr *left, SourceSpan lhs_start)
|
||||
static Expr *parse_ct_assignable(ParseContext *c, Expr *left, SourceSpan lhs_start UNUSED)
|
||||
{
|
||||
ASSERT(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_ASSIGNABLE);
|
||||
|
||||
@@ -92,7 +92,7 @@ static bool sema_expr_check_shift_rhs(SemaContext *context, Expr *expr, Expr *le
|
||||
is_assign);
|
||||
static bool sema_expr_analyse_and_or(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
|
||||
static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool *failed_ref);
|
||||
static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
|
||||
static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
|
||||
static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
|
||||
static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref);
|
||||
static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, BinaryOp operator);
|
||||
@@ -6538,17 +6538,20 @@ bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right)
|
||||
static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right, bool *failed_ref)
|
||||
{
|
||||
// Do regular lvalue evaluation of the identifier
|
||||
if (!sema_analyse_expr_lvalue(context, left, NULL)) return false;
|
||||
ASSERT_SPAN(left, left->resolve_status == RESOLVE_DONE);
|
||||
|
||||
// Evaluate right side to using inference from last type.
|
||||
if (!sema_analyse_inferred_expr(context, left->type, right)) return false;
|
||||
|
||||
if (!expr_is_runtime_const(right))
|
||||
{
|
||||
if (failed_ref) return *failed_ref = true, false;
|
||||
RETURN_SEMA_ERROR(right, "You can only assign constants to a compile time variable.");
|
||||
}
|
||||
Decl *ident = left->ct_ident_expr.decl;
|
||||
|
||||
|
||||
ident->var.init_expr = right;
|
||||
expr_replace(expr, right);
|
||||
ident->type = right->type;
|
||||
@@ -6565,7 +6568,7 @@ static bool sema_expr_analyse_ct_subscript_rhs(SemaContext *context, Decl *ct_va
|
||||
{
|
||||
if (!sema_analyse_expr_rhs(context, type_get_indexed_type(ct_var->type), right, false, NULL, false)) return false;
|
||||
}
|
||||
if (!sema_cast_const(right))
|
||||
if (!expr_is_runtime_const(right))
|
||||
{
|
||||
RETURN_SEMA_ERROR(right, "The argument must be a constant value.");
|
||||
}
|
||||
@@ -6654,7 +6657,7 @@ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *lef
|
||||
{
|
||||
case EXPR_CT_IDENT:
|
||||
// $foo = ...
|
||||
return sema_expr_analyse_ct_identifier_assign(context, expr, left, right);
|
||||
return sema_expr_analyse_ct_identifier_assign(context, expr, left, right, failed_ref);
|
||||
case EXPR_CT_SUBSCRIPT:
|
||||
return sema_expr_analyse_ct_subscript_assign(context, expr, left, right);
|
||||
default:
|
||||
|
||||
20
test/test_suite/compile_time/var_must_be_ct.c3
Normal file
20
test/test_suite/compile_time/var_must_be_ct.c3
Normal file
@@ -0,0 +1,20 @@
|
||||
fn void test1()
|
||||
{
|
||||
int a;
|
||||
var $x;
|
||||
$x = a; // #error: only assign constants to a compile time
|
||||
}
|
||||
fn void test2()
|
||||
{
|
||||
int a;
|
||||
int[2] $x = { 1, 2 };
|
||||
$x[0] = a; // #error: argument must be a constant value
|
||||
}
|
||||
|
||||
int g;
|
||||
fn void test3()
|
||||
{
|
||||
int*[2] $x = { &g + 1, null };
|
||||
int* $y = &g + 1;
|
||||
$x[0] = &g + 1;
|
||||
}
|
||||
Reference in New Issue
Block a user