mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add @safeinfer to allow var to be used locally.
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
- Improve error message for missing `$endif`.
|
||||
- `foo[x][y] = b` now interpreted as `(*&foo[x])[y] = b` which allows overloads to do chained [] accesses.
|
||||
- Error if a stack allocated variable is too big (configurable with `--max-stack-object-size`).
|
||||
- Add `@safeinfer` to allow `var` to be used locally.
|
||||
|
||||
### Fixes
|
||||
- List.remove_at would incorrectly trigger ASAN.
|
||||
|
||||
@@ -466,6 +466,7 @@ typedef struct VarDecl_
|
||||
bool is_temp : 1;
|
||||
bool copy_const : 1;
|
||||
bool defaulted : 1;
|
||||
bool safe_infer : 1;
|
||||
union
|
||||
{
|
||||
Expr *init_expr;
|
||||
|
||||
@@ -307,6 +307,7 @@ typedef enum
|
||||
ATTRIBUTE_PUBLIC,
|
||||
ATTRIBUTE_PURE,
|
||||
ATTRIBUTE_REFLECT,
|
||||
ATTRIBUTE_SAFEINFER,
|
||||
ATTRIBUTE_SAFEMACRO,
|
||||
ATTRIBUTE_SECTION,
|
||||
ATTRIBUTE_STRUCTLIKE,
|
||||
|
||||
@@ -857,7 +857,7 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type)
|
||||
|
||||
bool is_cond;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
|
||||
decl->is_cond = true;
|
||||
decl->is_cond = is_cond;
|
||||
if (tok_is(c, TOKEN_EQ))
|
||||
{
|
||||
if (!decl)
|
||||
@@ -949,6 +949,8 @@ Decl *parse_var_decl(ParseContext *c)
|
||||
// analyser. The runtime variables must have an initializer unlike the CT ones.
|
||||
advance_and_verify(c, TOKEN_VAR);
|
||||
Decl *decl;
|
||||
bool is_cond;
|
||||
SourceSpan span;
|
||||
switch (c->tok)
|
||||
{
|
||||
case TOKEN_CONST_IDENT:
|
||||
@@ -957,6 +959,8 @@ Decl *parse_var_decl(ParseContext *c)
|
||||
case TOKEN_IDENT:
|
||||
decl = decl_new_var_current(c, NULL, VARDECL_LOCAL);
|
||||
advance(c);
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
|
||||
decl->is_cond = is_cond;
|
||||
if (!tok_is(c, TOKEN_EQ))
|
||||
{
|
||||
PRINT_ERROR_HERE("'var' must always have an initial value, or the type cannot be inferred.");
|
||||
@@ -966,16 +970,16 @@ Decl *parse_var_decl(ParseContext *c)
|
||||
ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_expr(c), poisoned_decl);
|
||||
break;
|
||||
case TOKEN_CT_IDENT:
|
||||
decl = decl_new_var_current(c, NULL, VARDECL_LOCAL_CT);
|
||||
advance(c);
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_expr(c), poisoned_decl);
|
||||
}
|
||||
break;
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
decl = decl_new_var_current(c, NULL, VARDECL_LOCAL_CT_TYPE);
|
||||
decl = decl_new_var_current(c, NULL, c->tok == TOKEN_CT_IDENT ? VARDECL_LOCAL_CT : VARDECL_LOCAL_CT_TYPE);
|
||||
advance(c);
|
||||
span = c->span;
|
||||
if (!parse_attributes(c, &decl->attributes, NULL, NULL, &is_cond)) return poisoned_decl;
|
||||
if (is_cond || decl->attributes)
|
||||
{
|
||||
print_error_at(span, "Attributes are not allowed on compile time variables.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_expr(c), poisoned_decl);
|
||||
|
||||
@@ -3055,6 +3055,7 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
|
||||
[ATTRIBUTE_PURE] = ATTR_CALL,
|
||||
[ATTRIBUTE_REFLECT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES,
|
||||
[ATTRIBUTE_SAFEMACRO] = ATTR_MACRO,
|
||||
[ATTRIBUTE_SAFEINFER] = ATTR_GLOBAL | ATTR_LOCAL,
|
||||
[ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL,
|
||||
[ATTRIBUTE_STRUCTLIKE] = ATTR_DISTINCT,
|
||||
[ATTRIBUTE_TAG] = ATTR_BITSTRUCT_MEMBER | ATTR_MEMBER | USER_DEFINED_TYPES | CALLABLE_TYPE,
|
||||
@@ -3421,6 +3422,9 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
|
||||
decl->attr_nopadding = true;
|
||||
decl->attr_compact = true;
|
||||
break;
|
||||
case ATTRIBUTE_SAFEINFER:
|
||||
decl->var.safe_infer = true;
|
||||
break;
|
||||
case ATTRIBUTE_NOINIT:
|
||||
decl->var.no_init = true;
|
||||
break;
|
||||
@@ -4651,9 +4655,9 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
||||
return decl_poison(decl);
|
||||
}
|
||||
ASSERT(!decl->var.no_init);
|
||||
if (kind == VARDECL_LOCAL && !context_is_macro(context) && init_expr->expr_kind != EXPR_LAMBDA)
|
||||
if (kind == VARDECL_LOCAL && !context_is_macro(context) && init_expr->expr_kind != EXPR_LAMBDA && !decl->var.safe_infer)
|
||||
{
|
||||
SEMA_ERROR(decl, "Defining a variable using 'var %s = ...' is only allowed inside a macro, or when defining a lambda.", decl->name);
|
||||
SEMA_ERROR(decl, "Defining a variable using 'var %s = ...' is only allowed inside a macro, or when defining a lambda. You can override this by adding the attribute '@safeinfer' to the declaration.", decl->name);
|
||||
return decl_poison(decl);
|
||||
}
|
||||
if (!sema_analyse_expr(context, init_expr)) return decl_poison(decl);
|
||||
|
||||
@@ -372,6 +372,7 @@ void symtab_init(uint32_t capacity)
|
||||
attribute_list[ATTRIBUTE_PURE] = kw_at_pure;
|
||||
attribute_list[ATTRIBUTE_PUBLIC] = KW_DEF("@public");
|
||||
attribute_list[ATTRIBUTE_REFLECT] = KW_DEF("@reflect");
|
||||
attribute_list[ATTRIBUTE_SAFEINFER] = KW_DEF("@safeinfer");
|
||||
attribute_list[ATTRIBUTE_SAFEMACRO] = KW_DEF("@safemacro");
|
||||
attribute_list[ATTRIBUTE_SECTION] = KW_DEF("@section");
|
||||
attribute_list[ATTRIBUTE_STRUCTLIKE] = KW_DEF("@structlike");
|
||||
|
||||
5
test/test_suite/attributes/safe_infer.c3
Normal file
5
test/test_suite/attributes/safe_infer.c3
Normal file
@@ -0,0 +1,5 @@
|
||||
fn int main(String[] args)
|
||||
{
|
||||
var y @safeinfer = 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import std;
|
||||
fn int main(String[] args)
|
||||
{
|
||||
int[1024 * 1024] x; // #error: The size of this local variable (4096 Kb) exceeds the maximum allowed stack object size (128 Kb)
|
||||
int[1024 * 1024] x; // #error: The size of this local variable (4096 Kb) exceeds the maximum allowed
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user