feat: complete M5 ownership and cleanup
This commit is contained in:
@@ -63,12 +63,8 @@ VM 안에서 반복해서 물렸던 것들. 어기면 원인 찾기 어려운
|
|||||||
|
|
||||||
## 현재 상태
|
## 현재 상태
|
||||||
|
|
||||||
- M1~M4 완료 및 QEMU/Open Watcom 검증됨.
|
- M1~M5 완료 및 QEMU/Open Watcom 검증됨.
|
||||||
- M5(`^T`, drop, defer, 이동 검사) 진행 중. 남은 것: 모든 경로에서 정확히 1회
|
- 다음은 M6(R1~R8 대여 검사)다. 착수할 때 소유권 로직을 `check.c`/`emit_c.c`에서
|
||||||
cleanup, defer와 drop의 선언 역순 병합, `try` 전파 경로 cleanup, `MaybeMoved`
|
`own.c/h`로 분리한다 (`SPEC.md` §11.3).
|
||||||
런타임 live flag, struct drop과 필드 역순 drop, 분기/루프 상태 합류,
|
|
||||||
누수·이중해제 카운터 harness.
|
|
||||||
- `own.c/h`가 아직 없고 소유권 로직이 `check.c`/`emit_c.c`에 들어가 있다. R1~R8
|
|
||||||
전체를 다루는 **M6 착수 시점에 분리한다** (`SPEC.md` §11.3).
|
|
||||||
- v0.1.6에서 R8(파생 반환), R6(마지막 사용까지 대여), R10(전역 대여 금지)이
|
- v0.1.6에서 R8(파생 반환), R6(마지막 사용까지 대여), R10(전역 대여 금지)이
|
||||||
바뀌었다. 셋 다 own.c의 상태 기계를 건드리므로 분리 이후에 함께 구현한다.
|
바뀌었다. 셋 다 own.c의 상태 기계를 건드리므로 분리 이후에 함께 구현한다.
|
||||||
|
|||||||
+189
-16
@@ -72,7 +72,15 @@ static int is_copy_type(FeType *t)
|
|||||||
static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t)
|
static void mark_moved(FeCheckerState *s, FeNode *n, FeType *t)
|
||||||
{
|
{
|
||||||
FeSym *sym;
|
FeSym *sym;
|
||||||
if (!n || !t || is_copy_type(t) || n->kind!=FE_N_IDENT) return;
|
if (!n || !t || is_copy_type(t)) return;
|
||||||
|
if(n->kind==FE_N_INDEX && t->kind==FE_TYPE_SLICE &&
|
||||||
|
(n->c || !n->b)) return;
|
||||||
|
if(n->kind==FE_N_MEMBER || n->kind==FE_N_INDEX) {
|
||||||
|
err(s->c,n->loc,
|
||||||
|
"cannot move a non-Copy value out of a projection; use mem.replace");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(n->kind!=FE_N_IDENT) return;
|
||||||
sym=find_symbol(s->scope,n->text ? n->text : "");
|
sym=find_symbol(s->scope,n->text ? n->text : "");
|
||||||
if (sym) {
|
if (sym) {
|
||||||
if (s->defer_depth) {
|
if (s->defer_depth) {
|
||||||
@@ -258,6 +266,31 @@ void fe_check_init(FeCheck *c, FeAst *ast, FeDiags *diags,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static FeType *check_expr(FeCheckerState *s, FeNode *n);
|
static FeType *check_expr(FeCheckerState *s, FeNode *n);
|
||||||
|
|
||||||
|
static FeNode *find_method(FeCheck *c, FeType *owner, const char *name)
|
||||||
|
{
|
||||||
|
FeNode *decl;
|
||||||
|
FeNode *method;
|
||||||
|
if(!owner || !name) return 0;
|
||||||
|
for(decl=c->ast->root ? c->ast->root->children : 0; decl; decl=decl->next)
|
||||||
|
if(decl->kind==FE_N_STRUCT && decl->text &&
|
||||||
|
strcmp(decl->text,owner->name)==0)
|
||||||
|
for(method=decl->children; method; method=method->next)
|
||||||
|
if(method->kind==FE_N_FN && method->text &&
|
||||||
|
strcmp(method->text,name)==0) return method;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FeType *method_type(FeCheck *c, FeNode *node, FeType *owner)
|
||||||
|
{
|
||||||
|
if(node && node->kind==FE_N_TYPE && node->text &&
|
||||||
|
strcmp(node->text,"Self")==0) return owner;
|
||||||
|
if(node && node->kind==FE_N_TYPE && node->text &&
|
||||||
|
(strcmp(node->text,"&")==0 || strcmp(node->text,"&mut")==0) &&
|
||||||
|
node->a && node->a->text && strcmp(node->a->text,"Self")==0)
|
||||||
|
return fe_type_ref(&c->types,owner,strcmp(node->text,"&mut")==0);
|
||||||
|
return node_type(c,node);
|
||||||
|
}
|
||||||
static void check_match(FeCheckerState *s, FeNode *n);
|
static void check_match(FeCheckerState *s, FeNode *n);
|
||||||
static void check_stmt(FeCheckerState *s, FeNode *n);
|
static void check_stmt(FeCheckerState *s, FeNode *n);
|
||||||
|
|
||||||
@@ -666,14 +699,44 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
|||||||
return n->sem_type;
|
return n->sem_type;
|
||||||
}
|
}
|
||||||
if (strcmp(n->a->b->text,"create")==0) {
|
if (strcmp(n->a->b->text,"create")==0) {
|
||||||
if (!arg || arg->next || arg->kind!=FE_N_IDENT)
|
if (!arg || arg->next)
|
||||||
err(c,n->loc,"mem.create requires exactly one type argument");
|
err(c,n->loc,"mem.create requires exactly one value");
|
||||||
a=arg && arg->kind==FE_N_IDENT ?
|
a=arg ? check_expr(s,arg) : unknown(c);
|
||||||
fe_type_owned(&c->types,fe_type_intern(&c->types,arg->text)) :
|
if(arg) mark_moved(s,arg,a);
|
||||||
fe_type_owned(&c->types,unknown(c));
|
a=fe_type_owned(&c->types,a);
|
||||||
n->sem_type=fe_type_error_union(&c->types,a);
|
n->sem_type=fe_type_error_union(&c->types,a);
|
||||||
return n->sem_type;
|
return n->sem_type;
|
||||||
}
|
}
|
||||||
|
if (strcmp(n->a->b->text,"alloc_slice")==0) {
|
||||||
|
FeNode *count=arg ? arg->next : 0;
|
||||||
|
FeType *item;
|
||||||
|
if(!arg || arg->kind!=FE_N_IDENT || !count || count->next)
|
||||||
|
err(c,n->loc,"mem.alloc_slice requires a type and length");
|
||||||
|
item=arg && arg->kind==FE_N_IDENT ?
|
||||||
|
fe_type_intern(&c->types,arg->text) : unknown(c);
|
||||||
|
b=count ? check_expr(s,count) : unknown(c);
|
||||||
|
if(known(b) && !fe_type_is_integer(b))
|
||||||
|
err(c,count->loc,"slice length must be an integer");
|
||||||
|
a=fe_type_owned(&c->types,fe_type_slice(&c->types,item));
|
||||||
|
n->sem_type=fe_type_error_union(&c->types,a);
|
||||||
|
return n->sem_type;
|
||||||
|
}
|
||||||
|
if (strcmp(n->a->b->text,"replace")==0) {
|
||||||
|
FeNode *value=arg ? arg->next : 0;
|
||||||
|
if(!arg || !value || value->next)
|
||||||
|
err(c,n->loc,"mem.replace requires destination and value");
|
||||||
|
a=arg ? check_expr(s,arg) : unknown(c);
|
||||||
|
if(!a || a->kind!=FE_TYPE_REF || !a->ref_mut ||
|
||||||
|
!arg->a || !lvalue_writable(s,arg->a))
|
||||||
|
err(c,n->loc,"mem.replace destination must be a mutable place");
|
||||||
|
b=value ? check_expr(s,value) : unknown(c);
|
||||||
|
if(a && a->kind==FE_TYPE_REF && !compatible(a->elem,b,value))
|
||||||
|
err(c,value->loc,"mem.replace value type mismatch");
|
||||||
|
if(value) mark_moved(s,value,b);
|
||||||
|
n->sem_type=a && a->kind==FE_TYPE_REF ? a->elem : unknown(c);
|
||||||
|
fe_type_require_replace(&c->types,n->sem_type);
|
||||||
|
return n->sem_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
if (n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
||||||
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||||
@@ -701,7 +764,39 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
|||||||
n->sem_type=fe_type_intern(&c->types,"usize"); return n->sem_type;
|
n->sem_type=fe_type_intern(&c->types,"usize"); return n->sem_type;
|
||||||
}
|
}
|
||||||
if (n->a && n->a->kind == FE_N_MEMBER) {
|
if (n->a && n->a->kind == FE_N_MEMBER) {
|
||||||
|
FeNode *method;
|
||||||
|
FeNode *self_param;
|
||||||
et=check_expr(s,n->a->a);
|
et=check_expr(s,n->a->a);
|
||||||
|
method=et && et->kind==FE_TYPE_STRUCT ?
|
||||||
|
find_method(c,et,n->a->b ? n->a->b->text : "") : 0;
|
||||||
|
if(method) {
|
||||||
|
self_param=method->a ? method->a->children : 0;
|
||||||
|
if(!self_param) {
|
||||||
|
err(c,n->loc,"method requires self parameter");
|
||||||
|
return unknown(c);
|
||||||
|
}
|
||||||
|
a=method_type(c,self_param->a,et);
|
||||||
|
if(a->kind==FE_TYPE_REF && a->ref_mut &&
|
||||||
|
!lvalue_writable(s,n->a->a))
|
||||||
|
err(c,n->loc,"mutable method requires a mutable receiver");
|
||||||
|
if(a->kind!=FE_TYPE_REF) mark_moved(s,n->a->a,et);
|
||||||
|
param=self_param->next;
|
||||||
|
arg=n->children;
|
||||||
|
while(param && arg) {
|
||||||
|
a=check_expr(s,arg);
|
||||||
|
b=method_type(c,param->a,et);
|
||||||
|
if(!compatible(b,a,arg) && a->kind!=FE_TYPE_UNKNOWN)
|
||||||
|
err(c,arg->loc,"method argument type mismatch");
|
||||||
|
mark_moved(s,arg,a);
|
||||||
|
param=param->next;
|
||||||
|
arg=arg->next;
|
||||||
|
}
|
||||||
|
if(param || arg) err(c,n->loc,"wrong number of method arguments");
|
||||||
|
n->sem_decl=method;
|
||||||
|
n->sem_type=method->b ? method_type(c,method->b,et) :
|
||||||
|
fe_type_intern(&c->types,"void");
|
||||||
|
return n->sem_type;
|
||||||
|
}
|
||||||
variant=et && et->kind==FE_TYPE_ENUM ?
|
variant=et && et->kind==FE_TYPE_ENUM ?
|
||||||
fe_type_variant(et,n->a->b ? n->a->b->text : "") : 0;
|
fe_type_variant(et,n->a->b ? n->a->b->text : "") : 0;
|
||||||
arg=n->children;
|
arg=n->children;
|
||||||
@@ -761,6 +856,13 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
|||||||
n->sem_type=a->elem;
|
n->sem_type=a->elem;
|
||||||
return a->elem;
|
return a->elem;
|
||||||
}
|
}
|
||||||
|
if(a->kind==FE_TYPE_REF && a->elem &&
|
||||||
|
a->elem->kind==FE_TYPE_STRUCT) {
|
||||||
|
field=fe_type_field(a->elem,n->b ? n->b->text : "");
|
||||||
|
if(!field) { err(c,n->loc,"unknown struct field"); return unknown(c); }
|
||||||
|
n->sem_type=field->type;
|
||||||
|
return field->type;
|
||||||
|
}
|
||||||
if (a->kind == FE_TYPE_OWNED && n->b && n->b->text &&
|
if (a->kind == FE_TYPE_OWNED && n->b && n->b->text &&
|
||||||
strcmp(n->b->text,"^")==0) {
|
strcmp(n->b->text,"^")==0) {
|
||||||
n->sem_type=a->elem;
|
n->sem_type=a->elem;
|
||||||
@@ -816,6 +918,15 @@ static FeType *check_lvalue(FeCheckerState *s, FeNode *n, int read)
|
|||||||
n->sem_type=base->elem;
|
n->sem_type=base->elem;
|
||||||
return base->elem;
|
return base->elem;
|
||||||
}
|
}
|
||||||
|
if(base && base->kind==FE_TYPE_REF && base->elem &&
|
||||||
|
base->elem->kind==FE_TYPE_STRUCT) {
|
||||||
|
if(!base->ref_mut)
|
||||||
|
err(s->c,n->loc,"cannot write through shared reference");
|
||||||
|
field=fe_type_field(base->elem,n->b ? n->b->text : "");
|
||||||
|
if(!field) { err(s->c,n->loc,"assignment requires a valid struct field"); return unknown(s->c); }
|
||||||
|
n->sem_type=field->type;
|
||||||
|
return field->type;
|
||||||
|
}
|
||||||
if (base && base->kind == FE_TYPE_OWNED && n->b && n->b->text &&
|
if (base && base->kind == FE_TYPE_OWNED && n->b && n->b->text &&
|
||||||
strcmp(n->b->text,"^")==0) {
|
strcmp(n->b->text,"^")==0) {
|
||||||
n->sem_type=base->elem;
|
n->sem_type=base->elem;
|
||||||
@@ -855,12 +966,17 @@ static void check_match(FeCheckerState *s, FeNode *n)
|
|||||||
FeVariantType *variant;
|
FeVariantType *variant;
|
||||||
int seen[256];
|
int seen[256];
|
||||||
int wildcard=0;
|
int wildcard=0;
|
||||||
|
FeFlowSlot base[64], merged[64], current[64];
|
||||||
|
unsigned flow_count;
|
||||||
|
int have_merged=0;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
for(i=0;i<256U;i++) seen[i]=0;
|
for(i=0;i<256U;i++) seen[i]=0;
|
||||||
value=check_expr(s,n->a);
|
value=check_expr(s,n->a);
|
||||||
if(!value || value->kind!=FE_TYPE_ENUM) { err(s->c,n->loc,"match requires an enum value"); return; }
|
if(!value || value->kind!=FE_TYPE_ENUM) { err(s->c,n->loc,"match requires an enum value"); return; }
|
||||||
|
flow_count=flow_capture(s->scope,base,64);
|
||||||
for(arm=n->children;arm;arm=arm->next) {
|
for(arm=n->children;arm;arm=arm->next) {
|
||||||
FeScope *old=s->scope;
|
FeScope *old=s->scope;
|
||||||
|
flow_restore(base,flow_count);
|
||||||
if(arm->text && strcmp(arm->text,"_")==0) wildcard=1;
|
if(arm->text && strcmp(arm->text,"_")==0) wildcard=1;
|
||||||
else {
|
else {
|
||||||
variant=fe_type_variant(value,arm->text);
|
variant=fe_type_variant(value,arm->text);
|
||||||
@@ -885,7 +1001,19 @@ static void check_match(FeCheckerState *s, FeNode *n)
|
|||||||
if(arm->a && arm->a->kind==FE_N_BLOCK) check_stmt(s,arm->a);
|
if(arm->a && arm->a->kind==FE_N_BLOCK) check_stmt(s,arm->a);
|
||||||
else if(arm->a) check_expr(s,arm->a);
|
else if(arm->a) check_expr(s,arm->a);
|
||||||
s->scope=old;
|
s->scope=old;
|
||||||
|
flow_capture(s->scope,current,flow_count);
|
||||||
|
if(!have_merged) {
|
||||||
|
for(i=0;i<flow_count;++i) merged[i]=current[i];
|
||||||
|
have_merged=1;
|
||||||
|
} else {
|
||||||
|
for(i=0;i<flow_count;++i) {
|
||||||
|
merged[i].moved=merged[i].moved==1 && current[i].moved==1 ? 1 :
|
||||||
|
(merged[i].moved || current[i].moved ? 2 : 0);
|
||||||
|
merged[i].initialized=merged[i].initialized && current[i].initialized;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(have_merged) flow_restore(merged,flow_count);
|
||||||
if(!wildcard) for(i=0;i<value->variant_count && i<256U;i++) if(!seen[i]) err(s->c,n->loc,"non-exhaustive match");
|
if(!wildcard) for(i=0;i<value->variant_count && i<256U;i++) if(!seen[i]) err(s->c,n->loc,"non-exhaustive match");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,12 +1201,12 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
|
|||||||
--s->defer_depth;
|
--s->defer_depth;
|
||||||
break;
|
break;
|
||||||
case FE_N_IF: {
|
case FE_N_IF: {
|
||||||
FeFlowSlot base[128], left[128], right[128];
|
FeFlowSlot base[64], left[64], right[64];
|
||||||
unsigned flow_count;
|
unsigned flow_count;
|
||||||
a = check_expr(s, n->a);
|
a = check_expr(s, n->a);
|
||||||
if (known(a) && a->kind != FE_TYPE_BOOL)
|
if (known(a) && a->kind != FE_TYPE_BOOL)
|
||||||
err(c, n->loc, "if condition must be bool");
|
err(c, n->loc, "if condition must be bool");
|
||||||
flow_count=flow_capture(s->scope,base,128);
|
flow_count=flow_capture(s->scope,base,64);
|
||||||
check_stmt(s, n->b);
|
check_stmt(s, n->b);
|
||||||
flow_capture(s->scope,left,flow_count);
|
flow_capture(s->scope,left,flow_count);
|
||||||
flow_restore(base,flow_count);
|
flow_restore(base,flow_count);
|
||||||
@@ -1092,25 +1220,32 @@ static void check_stmt(FeCheckerState *s, FeNode *n)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FE_N_WHILE: {
|
case FE_N_WHILE: {
|
||||||
FeFlowSlot base[128], body[128];
|
FeFlowSlot base[64], body[64], entry2[64];
|
||||||
unsigned flow_count;
|
unsigned flow_count;
|
||||||
|
unsigned i;
|
||||||
a = check_expr(s, n->a);
|
a = check_expr(s, n->a);
|
||||||
if (known(a) && a->kind != FE_TYPE_BOOL)
|
if (known(a) && a->kind != FE_TYPE_BOOL)
|
||||||
err(c, n->loc, "while condition must be bool");
|
err(c, n->loc, "while condition must be bool");
|
||||||
flow_count=flow_capture(s->scope,base,128);
|
flow_count=flow_capture(s->scope,base,64);
|
||||||
if (s->loop_depth < 255U) ++s->loop_depth;
|
if (s->loop_depth < 255U) ++s->loop_depth;
|
||||||
check_stmt(s, n->b);
|
check_stmt(s, n->b);
|
||||||
if (s->loop_depth) --s->loop_depth;
|
if (s->loop_depth) --s->loop_depth;
|
||||||
flow_capture(s->scope,body,flow_count);
|
flow_capture(s->scope,body,flow_count);
|
||||||
flow_restore(base,flow_count);
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
for (i=0;i<flow_count;++i) {
|
for (i=0;i<flow_count;++i) {
|
||||||
if (body[i].moved) base[i].moved=2;
|
entry2[i]=base[i];
|
||||||
if (!body[i].initialized) base[i].initialized=0;
|
if(body[i].moved!=base[i].moved) entry2[i].moved=2;
|
||||||
|
if(!body[i].initialized) entry2[i].initialized=0;
|
||||||
}
|
}
|
||||||
|
flow_restore(entry2,flow_count);
|
||||||
|
if (s->loop_depth < 255U) ++s->loop_depth;
|
||||||
|
check_stmt(s,n->b);
|
||||||
|
if (s->loop_depth) --s->loop_depth;
|
||||||
|
flow_capture(s->scope,body,flow_count);
|
||||||
|
for(i=0;i<flow_count;++i) {
|
||||||
|
if(body[i].moved) entry2[i].moved=2;
|
||||||
|
if(!body[i].initialized) entry2[i].initialized=0;
|
||||||
}
|
}
|
||||||
flow_restore(base,flow_count);
|
flow_restore(entry2,flow_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FE_N_FOR:
|
case FE_N_FOR:
|
||||||
@@ -1168,6 +1303,28 @@ static void check_fn(FeCheck *c, FeNode *fn, FeScope *globals)
|
|||||||
s.scope = old;
|
s.scope = old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_method(FeCheck *c, FeNode *fn, FeScope *globals,
|
||||||
|
FeType *owner)
|
||||||
|
{
|
||||||
|
FeCheckerState s;
|
||||||
|
FeNode *x;
|
||||||
|
FeType *t;
|
||||||
|
s.c=c;
|
||||||
|
s.globals=globals;
|
||||||
|
s.scope=scope_new(&s,globals);
|
||||||
|
s.ret=fn->b ? method_type(c,fn->b,owner) : fe_type_intern(&c->types,"void");
|
||||||
|
s.loop_depth=0;
|
||||||
|
s.defer_depth=0;
|
||||||
|
fn->sem_type=s.ret;
|
||||||
|
for(x=fn->a ? fn->a->children : 0; x; x=x->next) {
|
||||||
|
t=method_type(c,x->a,owner);
|
||||||
|
x->sem_type=t;
|
||||||
|
add_symbol(&s,s.scope,x->text,t,0,1,1,
|
||||||
|
local_cname(c,x->text ? x->text : "arg"),x);
|
||||||
|
}
|
||||||
|
if(fn->c) check_stmt(&s,fn->c);
|
||||||
|
}
|
||||||
|
|
||||||
int fe_check_program(FeCheck *c)
|
int fe_check_program(FeCheck *c)
|
||||||
{
|
{
|
||||||
FeCheckerState s;
|
FeCheckerState s;
|
||||||
@@ -1189,6 +1346,15 @@ int fe_check_program(FeCheck *c)
|
|||||||
check_type_cycles(c);
|
check_type_cycles(c);
|
||||||
fe_type_layout_all(&c->types);
|
fe_type_layout_all(&c->types);
|
||||||
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next) {
|
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next) {
|
||||||
|
if(n->kind==FE_N_STRUCT) {
|
||||||
|
FeNode *m;
|
||||||
|
char method_name[128];
|
||||||
|
for(m=n->children; m; m=m->next) if(m->kind==FE_N_FN) {
|
||||||
|
sprintf(method_name,"%s_%s",n->text ? n->text : "Type",
|
||||||
|
m->text ? m->text : "method");
|
||||||
|
m->cname=unit_cname(c,method_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (n->kind == FE_N_GLOBAL || n->kind == FE_N_CONST) {
|
if (n->kind == FE_N_GLOBAL || n->kind == FE_N_CONST) {
|
||||||
t = n->a ? node_type(c, n->a) : unknown(c);
|
t = n->a ? node_type(c, n->a) : unknown(c);
|
||||||
add_symbol(&s, s.globals, n->text, t, 0,
|
add_symbol(&s, s.globals, n->text, t, 0,
|
||||||
@@ -1221,6 +1387,13 @@ int fe_check_program(FeCheck *c)
|
|||||||
}
|
}
|
||||||
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next)
|
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next)
|
||||||
if (n->kind == FE_N_FN) check_fn(c, n, s.globals);
|
if (n->kind == FE_N_FN) check_fn(c, n, s.globals);
|
||||||
|
for (n = c->ast->root ? c->ast->root->children : 0; n; n = n->next)
|
||||||
|
if(n->kind==FE_N_STRUCT) {
|
||||||
|
FeNode *m;
|
||||||
|
t=fe_type_intern(&c->types,n->text);
|
||||||
|
for(m=n->children; m; m=m->next)
|
||||||
|
if(m->kind==FE_N_FN) check_method(c,m,s.globals,t);
|
||||||
|
}
|
||||||
fe_type_layout_all(&c->types);
|
fe_type_layout_all(&c->types);
|
||||||
return c->diags->errors == 0;
|
return c->diags->errors == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+157
-32
@@ -63,6 +63,8 @@ static void emit_one_type(FeEmitter *e, FeType *t)
|
|||||||
if (!t || t->emit_state ||
|
if (!t || t->emit_state ||
|
||||||
(t->kind != FE_TYPE_STRUCT && t->kind != FE_TYPE_ENUM &&
|
(t->kind != FE_TYPE_STRUCT && t->kind != FE_TYPE_ENUM &&
|
||||||
t->kind != FE_TYPE_ARRAY && t->kind != FE_TYPE_SLICE &&
|
t->kind != FE_TYPE_ARRAY && t->kind != FE_TYPE_SLICE &&
|
||||||
|
!(t->kind == FE_TYPE_OWNED && t->elem &&
|
||||||
|
t->elem->kind == FE_TYPE_SLICE) &&
|
||||||
t->kind != FE_TYPE_ERROR_UNION) ||
|
t->kind != FE_TYPE_ERROR_UNION) ||
|
||||||
(t->kind == FE_TYPE_ERROR_UNION &&
|
(t->kind == FE_TYPE_ERROR_UNION &&
|
||||||
(!t->error_value || t->error_value->kind == FE_TYPE_VOID))) return;
|
(!t->error_value || t->error_value->kind == FE_TYPE_VOID))) return;
|
||||||
@@ -79,6 +81,15 @@ static void emit_one_type(FeEmitter *e, FeType *t)
|
|||||||
if(!t->ref_mut) fputs("const ",e->out);
|
if(!t->ref_mut) fputs("const ",e->out);
|
||||||
fputs(fe_type_c_name(t->elem,e->pointer_bits),e->out); fputs(" *p; unsigned long n; } ",e->out); fputs(t->cname,e->out); fputs(";\n",e->out);
|
fputs(fe_type_c_name(t->elem,e->pointer_bits),e->out); fputs(" *p; unsigned long n; } ",e->out); fputs(t->cname,e->out); fputs(";\n",e->out);
|
||||||
fprintf(e->out,"static %s %s(%s%s *p, unsigned long n) { %s s; s.p=p; s.n=n; return s; }\n",t->cname,t->maker,t->ref_mut ? "" : "const ",fe_type_c_name(t->elem,e->pointer_bits),t->cname);
|
fprintf(e->out,"static %s %s(%s%s *p, unsigned long n) { %s s; s.p=p; s.n=n; return s; }\n",t->cname,t->maker,t->ref_mut ? "" : "const ",fe_type_c_name(t->elem,e->pointer_bits),t->cname);
|
||||||
|
} else if(t->kind==FE_TYPE_OWNED && t->elem &&
|
||||||
|
t->elem->kind==FE_TYPE_SLICE) {
|
||||||
|
FeType *item=t->elem->elem;
|
||||||
|
fputs("typedef struct { ",e->out);
|
||||||
|
fputs(fe_type_c_name(item,e->pointer_bits),e->out);
|
||||||
|
fputs(" *p; unsigned long n; } ",e->out); fputs(t->cname,e->out);
|
||||||
|
fputs(";\n",e->out);
|
||||||
|
fprintf(e->out,"static %s %s(%s *p, unsigned long n) { %s s; s.p=p; s.n=n; return s; }\n",
|
||||||
|
t->cname,t->maker,fe_type_c_name(item,e->pointer_bits),t->cname);
|
||||||
} else if(t->kind==FE_TYPE_ERROR_UNION) {
|
} else if(t->kind==FE_TYPE_ERROR_UNION) {
|
||||||
fputs(t->cname,e->out); fputs(" { unsigned short e; ",e->out);
|
fputs(t->cname,e->out); fputs(" { unsigned short e; ",e->out);
|
||||||
fputs(fe_type_c_name(t->error_value,e->pointer_bits),e->out);
|
fputs(fe_type_c_name(t->error_value,e->pointer_bits),e->out);
|
||||||
@@ -128,13 +139,21 @@ static void emit_drop_fields(FeEmitter *e, FeType *t)
|
|||||||
if (!type_needs_drop(ft)) continue;
|
if (!type_needs_drop(ft)) continue;
|
||||||
if (ft->kind==FE_TYPE_OWNED) {
|
if (ft->kind==FE_TYPE_OWNED) {
|
||||||
fputs("if (self->",e->out); fputs(t->fields[i-1].name,e->out);
|
fputs("if (self->",e->out); fputs(t->fields[i-1].name,e->out);
|
||||||
|
if(ft->elem && ft->elem->kind==FE_TYPE_SLICE) fputs(".p",e->out);
|
||||||
fputs(") { ",e->out);
|
fputs(") { ",e->out);
|
||||||
if (ft->elem && type_needs_drop(ft->elem) && ft->elem->drop_cname) {
|
if(ft->elem && ft->elem->kind==FE_TYPE_SLICE) {
|
||||||
|
fputs("free(self->",e->out); fputs(t->fields[i-1].name,e->out);
|
||||||
|
fputs(".p); self->",e->out); fputs(t->fields[i-1].name,e->out);
|
||||||
|
fputs(".p=0; ",e->out);
|
||||||
|
} else if (ft->elem && type_needs_drop(ft->elem) && ft->elem->drop_cname) {
|
||||||
fprintf(e->out,"%s(self->%s); ",ft->elem->drop_cname,t->fields[i-1].name);
|
fprintf(e->out,"%s(self->%s); ",ft->elem->drop_cname,t->fields[i-1].name);
|
||||||
}
|
}
|
||||||
|
if(!(ft->elem && ft->elem->kind==FE_TYPE_SLICE)) {
|
||||||
fputs("free(self->",e->out); fputs(t->fields[i-1].name,e->out);
|
fputs("free(self->",e->out); fputs(t->fields[i-1].name,e->out);
|
||||||
fputs("); self->",e->out); fputs(t->fields[i-1].name,e->out);
|
fputs("); self->",e->out); fputs(t->fields[i-1].name,e->out);
|
||||||
fputs("=0; }\n",e->out);
|
fputs("=0; ",e->out);
|
||||||
|
}
|
||||||
|
fputs("}\n",e->out);
|
||||||
} else if (ft->kind==FE_TYPE_STRUCT && ft->drop_cname) {
|
} else if (ft->kind==FE_TYPE_STRUCT && ft->drop_cname) {
|
||||||
fprintf(e->out,"%s(&self->%s);\n",ft->drop_cname,t->fields[i-1].name);
|
fprintf(e->out,"%s(&self->%s);\n",ft->drop_cname,t->fields[i-1].name);
|
||||||
} else if (ft->kind==FE_TYPE_ARRAY && ft->drop_cname) {
|
} else if (ft->kind==FE_TYPE_ARRAY && ft->drop_cname) {
|
||||||
@@ -147,7 +166,10 @@ static void emit_drop_helpers(FeEmitter *e)
|
|||||||
{
|
{
|
||||||
FeType *t;
|
FeType *t;
|
||||||
FeNode *method;
|
FeNode *method;
|
||||||
FeNode *param;
|
for (t=e->check->types.types; t; t=t->next)
|
||||||
|
if(t->kind==FE_TYPE_STRUCT && (method=find_drop_method(e,t->name))!=0)
|
||||||
|
fprintf(e->out,"void %s(%s *self);\n",
|
||||||
|
cname(method,"fe_drop_method"),t->cname);
|
||||||
for (t=e->check->types.types; t; t=t->next)
|
for (t=e->check->types.types; t; t=t->next)
|
||||||
if ((t->kind==FE_TYPE_STRUCT || t->kind==FE_TYPE_ARRAY) &&
|
if ((t->kind==FE_TYPE_STRUCT || t->kind==FE_TYPE_ARRAY) &&
|
||||||
type_needs_drop(t) && t->drop_cname)
|
type_needs_drop(t) && t->drop_cname)
|
||||||
@@ -157,10 +179,7 @@ static void emit_drop_helpers(FeEmitter *e)
|
|||||||
fprintf(e->out,"static void %s(%s *self) {\n",t->drop_cname,t->cname);
|
fprintf(e->out,"static void %s(%s *self) {\n",t->drop_cname,t->cname);
|
||||||
method=find_drop_method(e,t->name);
|
method=find_drop_method(e,t->name);
|
||||||
if (method) {
|
if (method) {
|
||||||
param=method->a ? method->a->children : 0;
|
fprintf(e->out,"%s(self);\n",cname(method,"fe_drop_method"));
|
||||||
if (param) param->cname="self";
|
|
||||||
if (method->c) emit_block(e,method->c);
|
|
||||||
fputc('\n',e->out);
|
|
||||||
}
|
}
|
||||||
emit_drop_fields(e,t);
|
emit_drop_fields(e,t);
|
||||||
fputs("}\n",e->out);
|
fputs("}\n",e->out);
|
||||||
@@ -189,14 +208,29 @@ static void emit_type_helpers(FeEmitter *e)
|
|||||||
t->error_value->kind!=FE_TYPE_VOID) {
|
t->error_value->kind!=FE_TYPE_VOID) {
|
||||||
fprintf(e->out,"static %s %s(unsigned short e, %s v) { %s r; r.e=e; r.v=v; return r; }\n",
|
fprintf(e->out,"static %s %s(unsigned short e, %s v) { %s r; r.e=e; r.v=v; return r; }\n",
|
||||||
t->cname,t->maker,fe_type_c_name(t->error_value,e->pointer_bits),t->cname);
|
t->cname,t->maker,fe_type_c_name(t->error_value,e->pointer_bits),t->cname);
|
||||||
if (t->error_value->kind==FE_TYPE_OWNED)
|
if (t->error_value->kind==FE_TYPE_OWNED &&
|
||||||
fprintf(e->out,"static %s %s(void) { %s r; r.v=(%s)malloc(sizeof(%s)); r.e=r.v ? 0 : 1; return r; }\n",
|
t->error_value->elem &&
|
||||||
|
t->error_value->elem->kind==FE_TYPE_SLICE) {
|
||||||
|
FeType *item=t->error_value->elem->elem;
|
||||||
|
fprintf(e->out,"static %s %s(unsigned long n) { %s r; r.v.p=(%s*)malloc(sizeof(%s)*n); r.v.n=n; r.e=(r.v.p || !n) ? 0 : 1; return r; }\n",
|
||||||
t->cname,t->alloc_cname,t->cname,
|
t->cname,t->alloc_cname,t->cname,
|
||||||
|
fe_type_c_name(item,e->pointer_bits),
|
||||||
|
fe_type_c_name(item,e->pointer_bits));
|
||||||
|
} else if (t->error_value->kind==FE_TYPE_OWNED) {
|
||||||
|
fprintf(e->out,"static %s %s(%s v) { %s r; r.v=(%s)malloc(sizeof(%s)); if(r.v) *r.v=v; r.e=r.v ? 0 : 1; return r; }\n",
|
||||||
|
t->cname,t->alloc_cname,
|
||||||
|
fe_type_c_name(t->error_value->elem,e->pointer_bits),t->cname,
|
||||||
fe_type_c_name(t->error_value,e->pointer_bits),
|
fe_type_c_name(t->error_value,e->pointer_bits),
|
||||||
fe_type_c_name(t->error_value->elem,e->pointer_bits));
|
fe_type_c_name(t->error_value->elem,e->pointer_bits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for(t=e->check->types.types;t;t=t->next) {
|
for(t=e->check->types.types;t;t=t->next) {
|
||||||
|
if(t->replace_cname) {
|
||||||
|
const char *ct=fe_type_c_name(t,e->pointer_bits);
|
||||||
|
fprintf(e->out,"static %s %s(%s *dst, %s value) { %s old=*dst; *dst=value; return old; }\n",
|
||||||
|
ct,t->replace_cname,ct,ct,ct);
|
||||||
|
}
|
||||||
if(t->kind==FE_TYPE_STRUCT && t->maker) {
|
if(t->kind==FE_TYPE_STRUCT && t->maker) {
|
||||||
fprintf(e->out,"static %s %s(",t->cname,t->maker);
|
fprintf(e->out,"static %s %s(",t->cname,t->maker);
|
||||||
for(i=0;i<t->field_count;i++) { if(i) fputs(", ",e->out); fputs(fe_type_c_name(t->fields[i].type,e->pointer_bits),e->out); fprintf(e->out," p%u",i); }
|
for(i=0;i<t->field_count;i++) { if(i) fputs(", ",e->out); fputs(fe_type_c_name(t->fields[i].type,e->pointer_bits),e->out); fprintf(e->out," p%u",i); }
|
||||||
@@ -599,6 +633,10 @@ static void emit_lvalue(FeEmitter *e, FeNode *n)
|
|||||||
} else if (n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_OWNED &&
|
} else if (n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_OWNED &&
|
||||||
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
|
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
|
||||||
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
|
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
|
||||||
|
} else if(n->a && n->a->sem_type &&
|
||||||
|
n->a->sem_type->kind==FE_TYPE_REF) {
|
||||||
|
emit_expr(e,n->a); fputs("->",e->out);
|
||||||
|
fputs(n->b ? n->b->text : "member",e->out);
|
||||||
} else { emit_lvalue(e,n->a); fputc('.',e->out); fputs(n->b ? n->b->text : "member",e->out); }
|
} else { emit_lvalue(e,n->a); fputc('.',e->out); fputs(n->b ? n->b->text : "member",e->out); }
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -612,10 +650,17 @@ static void emit_lvalue(FeEmitter *e, FeNode *n)
|
|||||||
|
|
||||||
static void emit_destroy_expr(FeEmitter *e, FeNode *n)
|
static void emit_destroy_expr(FeEmitter *e, FeNode *n)
|
||||||
{
|
{
|
||||||
fputs("(free(",e->out); emit_expr(e,n); fputs(")",e->out);
|
fputs("(free(",e->out); emit_expr(e,n);
|
||||||
|
if(n && n->sem_type && n->sem_type->kind==FE_TYPE_OWNED &&
|
||||||
|
n->sem_type->elem && n->sem_type->elem->kind==FE_TYPE_SLICE)
|
||||||
|
fputs(".p",e->out);
|
||||||
|
fputs(")",e->out);
|
||||||
if (n && n->kind==FE_N_IDENT) {
|
if (n && n->kind==FE_N_IDENT) {
|
||||||
fputs(", ",e->out); emit_lvalue(e,n);
|
fputs(", ",e->out); emit_lvalue(e,n);
|
||||||
fputs("=0, fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
if(n->sem_type && n->sem_type->elem &&
|
||||||
|
n->sem_type->elem->kind==FE_TYPE_SLICE) fputs(".p=0",e->out);
|
||||||
|
else fputs("=0",e->out);
|
||||||
|
fputs(", fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
||||||
fputs("=0",e->out);
|
fputs("=0",e->out);
|
||||||
} else {
|
} else {
|
||||||
fputs(", ",e->out); emit_lvalue(e,n); fputs("=0",e->out);
|
fputs(", ",e->out); emit_lvalue(e,n); fputs("=0",e->out);
|
||||||
@@ -698,7 +743,12 @@ static void emit_expr(FeEmitter *e, FeNode *n)
|
|||||||
}
|
}
|
||||||
switch (n->kind) {
|
switch (n->kind) {
|
||||||
case FE_N_IDENT:
|
case FE_N_IDENT:
|
||||||
fputs(cname(n, "fe_missing"), e->out);
|
if((n->flags & 0x100U) && n->sem_type &&
|
||||||
|
type_needs_drop(n->sem_type)) {
|
||||||
|
fputs("(fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
||||||
|
fputs("=0, ",e->out); fputs(cname(n,"fe_missing"),e->out);
|
||||||
|
fputc(')',e->out);
|
||||||
|
} else fputs(cname(n, "fe_missing"), e->out);
|
||||||
break;
|
break;
|
||||||
case FE_N_LITERAL:
|
case FE_N_LITERAL:
|
||||||
if (n->text && strcmp(n->text, "true") == 0) fputs("1", e->out);
|
if (n->text && strcmp(n->text, "true") == 0) fputs("1", e->out);
|
||||||
@@ -760,7 +810,7 @@ static void emit_expr(FeEmitter *e, FeNode *n)
|
|||||||
if (strcmp(op, "not") == 0) fputs("(!", e->out);
|
if (strcmp(op, "not") == 0) fputs("(!", e->out);
|
||||||
else {
|
else {
|
||||||
fputc('(', e->out);
|
fputc('(', e->out);
|
||||||
fputs(op, e->out);
|
fputs(strcmp(op,"&mut")==0 ? "&" : op, e->out);
|
||||||
}
|
}
|
||||||
emit_expr(e, n->a);
|
emit_expr(e, n->a);
|
||||||
fputc(')', e->out);
|
fputc(')', e->out);
|
||||||
@@ -801,19 +851,55 @@ static void emit_expr(FeEmitter *e, FeNode *n)
|
|||||||
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||||
strcmp(n->a->a->text,"mem")==0 && n->a->b &&
|
strcmp(n->a->a->text,"mem")==0 && n->a->b &&
|
||||||
n->a->b->text && strcmp(n->a->b->text,"create")==0 &&
|
n->a->b->text && strcmp(n->a->b->text,"create")==0 &&
|
||||||
n->children && n->children->kind==FE_N_IDENT) {
|
n->children) {
|
||||||
FeType *created=fe_type_intern(&e->check->types,n->children->text);
|
FeType *created=n->children->sem_type;
|
||||||
FeType *owned=fe_type_owned(&e->check->types,created);
|
FeType *owned=fe_type_owned(&e->check->types,created);
|
||||||
FeType *result=fe_type_error_union(&e->check->types,owned);
|
FeType *result=fe_type_error_union(&e->check->types,owned);
|
||||||
if (result->alloc_cname) fputs(result->alloc_cname,e->out);
|
if (result->alloc_cname) fputs(result->alloc_cname,e->out);
|
||||||
else fputs("fe_bad_alloc",e->out);
|
else fputs("fe_bad_alloc",e->out);
|
||||||
fputs("()",e->out);
|
fputc('(',e->out); emit_expr(e,n->children); fputc(')',e->out);
|
||||||
|
special=1;
|
||||||
|
}
|
||||||
|
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
||||||
|
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||||
|
strcmp(n->a->a->text,"mem")==0 && n->a->b &&
|
||||||
|
n->a->b->text && strcmp(n->a->b->text,"alloc_slice")==0 &&
|
||||||
|
n->children && n->children->next) {
|
||||||
|
FeType *result=n->sem_type;
|
||||||
|
if(result && result->alloc_cname) fputs(result->alloc_cname,e->out);
|
||||||
|
else fputs("fe_bad_slice_alloc",e->out);
|
||||||
|
fputc('(',e->out); emit_expr(e,n->children->next); fputc(')',e->out);
|
||||||
|
special=1;
|
||||||
|
}
|
||||||
|
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
||||||
|
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||||
|
strcmp(n->a->a->text,"mem")==0 && n->a->b &&
|
||||||
|
n->a->b->text && strcmp(n->a->b->text,"replace")==0 &&
|
||||||
|
n->children && n->children->next && n->sem_type) {
|
||||||
|
fputs(n->sem_type->replace_cname ? n->sem_type->replace_cname :
|
||||||
|
"fe_bad_replace",e->out);
|
||||||
|
fputc('(',e->out); emit_expr(e,n->children); fputs(", ",e->out);
|
||||||
|
emit_expr(e,n->children->next); fputc(')',e->out);
|
||||||
special=1;
|
special=1;
|
||||||
}
|
}
|
||||||
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
||||||
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||||
strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
|
strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
|
||||||
strcmp(n->a->b->text,"null_writer")==0) { fputs("fe_m4_null_writer()",e->out); special=1; }
|
strcmp(n->a->b->text,"null_writer")==0) { fputs("fe_m4_null_writer()",e->out); special=1; }
|
||||||
|
else if(n->a && n->a->kind==FE_N_MEMBER && n->sem_decl &&
|
||||||
|
n->sem_decl->kind==FE_N_FN) {
|
||||||
|
FeNode *mp=n->sem_decl->a ? n->sem_decl->a->children : 0;
|
||||||
|
FeNode *ma;
|
||||||
|
fputs(cname(n->sem_decl,"fe_method"),e->out); fputc('(',e->out);
|
||||||
|
if(mp && mp->sem_type && mp->sem_type->kind==FE_TYPE_REF) {
|
||||||
|
fputc('&',e->out); emit_lvalue(e,n->a->a);
|
||||||
|
} else emit_expr(e,n->a->a);
|
||||||
|
for(ma=n->children; ma; ma=ma->next) {
|
||||||
|
fputs(", ",e->out); emit_expr(e,ma);
|
||||||
|
}
|
||||||
|
fputc(')',e->out);
|
||||||
|
special=1;
|
||||||
|
}
|
||||||
else if(!n->a && n->text && strcmp(n->text,"@size_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%lu",fe_type_size(fe_type_intern(&e->check->types,n->children->text))); special=1; }
|
else if(!n->a && n->text && strcmp(n->text,"@size_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%lu",fe_type_size(fe_type_intern(&e->check->types,n->children->text))); special=1; }
|
||||||
else if(!n->a && n->text && strcmp(n->text,"@align_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%u",fe_type_align(fe_type_intern(&e->check->types,n->children->text))); special=1; }
|
else if(!n->a && n->text && strcmp(n->text,"@align_of")==0 && n->children && n->children->kind==FE_N_IDENT) { fprintf(e->out,"%u",fe_type_align(fe_type_intern(&e->check->types,n->children->text))); special=1; }
|
||||||
else if (n->a && n->a->kind==FE_N_MEMBER && n->a->a && n->a->a->sem_type && n->a->a->sem_type->kind==FE_TYPE_ENUM) {
|
else if (n->a && n->a->kind==FE_N_MEMBER && n->a->a && n->a->a->sem_type && n->a->a->sem_type->kind==FE_TYPE_ENUM) {
|
||||||
@@ -860,7 +946,10 @@ static void emit_expr(FeEmitter *e, FeNode *n)
|
|||||||
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
|
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
|
||||||
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
|
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
|
||||||
} else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_ENUM) { v=fe_type_variant(n->a->sem_type,n->b ? n->b->text : ""); if(v) fputs(v->maker,e->out); else fputs("0",e->out); if(v)fputs("()",e->out); }
|
} else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_ENUM) { v=fe_type_variant(n->a->sem_type,n->b ? n->b->text : ""); if(v) fputs(v->maker,e->out); else fputs("0",e->out); if(v)fputs("()",e->out); }
|
||||||
else { emit_expr(e, n->a); fputc('.', e->out); if (n->b) fputs(n->b->text ? n->b->text : "member", e->out); }
|
else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_REF) {
|
||||||
|
emit_expr(e,n->a); fputs("->",e->out);
|
||||||
|
if(n->b) fputs(n->b->text ? n->b->text : "member",e->out);
|
||||||
|
} else { emit_expr(e, n->a); fputc('.', e->out); if (n->b) fputs(n->b->text ? n->b->text : "member", e->out); }
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -887,7 +976,7 @@ static void emit_decl(FeEmitter *e, FeNode *n)
|
|||||||
}
|
}
|
||||||
fputs(";\n", e->out);
|
fputs(";\n", e->out);
|
||||||
if ((n->kind==FE_N_LET || n->kind==FE_N_VAR) && n->sem_type &&
|
if ((n->kind==FE_N_LET || n->kind==FE_N_VAR) && n->sem_type &&
|
||||||
n->sem_type->kind==FE_TYPE_OWNED) {
|
type_needs_drop(n->sem_type)) {
|
||||||
pad(e); fputs("unsigned char fe_live_",e->out);
|
pad(e); fputs("unsigned char fe_live_",e->out);
|
||||||
fputs(cname(n,"owned"),e->out); fputs("=0;\n",e->out);
|
fputs(cname(n,"owned"),e->out); fputs("=0;\n",e->out);
|
||||||
}
|
}
|
||||||
@@ -895,7 +984,7 @@ static void emit_decl(FeEmitter *e, FeNode *n)
|
|||||||
|
|
||||||
static void emit_owned_live(FeEmitter *e, FeNode *n, int value)
|
static void emit_owned_live(FeEmitter *e, FeNode *n, int value)
|
||||||
{
|
{
|
||||||
if (n && n->sem_type && n->sem_type->kind==FE_TYPE_OWNED) {
|
if (n && n->sem_type && type_needs_drop(n->sem_type)) {
|
||||||
pad(e); fputs("fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
pad(e); fputs("fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
||||||
fprintf(e->out,"=%d;\n",value);
|
fprintf(e->out,"=%d;\n",value);
|
||||||
}
|
}
|
||||||
@@ -909,14 +998,21 @@ static void emit_value_drop(FeEmitter *e, FeNode *n)
|
|||||||
if (t->kind==FE_TYPE_OWNED) {
|
if (t->kind==FE_TYPE_OWNED) {
|
||||||
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
||||||
fputs(") { ",e->out);
|
fputs(") { ",e->out);
|
||||||
if (t->elem && type_needs_drop(t->elem) && t->elem->drop_cname) {
|
if(t->elem && t->elem->kind==FE_TYPE_SLICE) {
|
||||||
fprintf(e->out,"%s(%s); ",t->elem->drop_cname,cname(n,"owned"));
|
|
||||||
}
|
|
||||||
fputs("free(",e->out); fputs(cname(n,"owned"),e->out);
|
fputs("free(",e->out); fputs(cname(n,"owned"),e->out);
|
||||||
fputs("); fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
fputs(".p); ",e->out);
|
||||||
|
} else if (t->elem && type_needs_drop(t->elem) && t->elem->drop_cname) {
|
||||||
|
fprintf(e->out,"%s(%s); ",t->elem->drop_cname,cname(n,"owned"));
|
||||||
|
fputs("free(",e->out); fputs(cname(n,"owned"),e->out); fputs("); ",e->out);
|
||||||
|
} else {
|
||||||
|
fputs("free(",e->out); fputs(cname(n,"owned"),e->out); fputs("); ",e->out);
|
||||||
|
}
|
||||||
|
fputs("fe_live_",e->out); fputs(cname(n,"owned"),e->out);
|
||||||
fputs("=0; }\n",e->out);
|
fputs("=0; }\n",e->out);
|
||||||
} else if (t->drop_cname) {
|
} else if (t->drop_cname) {
|
||||||
pad(e); fprintf(e->out,"%s(&%s);\n",t->drop_cname,cname(n,"local"));
|
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n,"local"),e->out);
|
||||||
|
fprintf(e->out,") { %s(&%s); fe_live_",t->drop_cname,cname(n,"local"));
|
||||||
|
fputs(cname(n,"local"),e->out); fputs("=0; }\n",e->out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1006,7 +1102,7 @@ static void emit_block(FeEmitter *e, FeNode *n)
|
|||||||
if (e->current_fn && e->current_fn->c==n && e->current_fn->a) {
|
if (e->current_fn && e->current_fn->c==n && e->current_fn->a) {
|
||||||
FeNode *param;
|
FeNode *param;
|
||||||
for (param=e->current_fn->a->children; param; param=param->next)
|
for (param=e->current_fn->a->children; param; param=param->next)
|
||||||
if (param->sem_type && param->sem_type->kind==FE_TYPE_OWNED) {
|
if (param->sem_type && type_needs_drop(param->sem_type)) {
|
||||||
pad(e); fputs("unsigned char fe_live_",e->out);
|
pad(e); fputs("unsigned char fe_live_",e->out);
|
||||||
fputs(cname(param,"owned"),e->out); fputs("=1;\n",e->out);
|
fputs(cname(param,"owned"),e->out); fputs("=1;\n",e->out);
|
||||||
}
|
}
|
||||||
@@ -1126,12 +1222,26 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
|
|||||||
n->a->sem_type->kind==FE_TYPE_OWNED) {
|
n->a->sem_type->kind==FE_TYPE_OWNED) {
|
||||||
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
|
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
|
||||||
fputs(") { ",e->out);
|
fputs(") { ",e->out);
|
||||||
if (n->a->sem_type->elem && type_needs_drop(n->a->sem_type->elem) &&
|
if(n->a->sem_type->elem &&
|
||||||
|
n->a->sem_type->elem->kind==FE_TYPE_SLICE) {
|
||||||
|
fputs("free(",e->out); fputs(cname(n->a,"owned"),e->out);
|
||||||
|
fputs(".p); ",e->out);
|
||||||
|
} else if (n->a->sem_type->elem && type_needs_drop(n->a->sem_type->elem) &&
|
||||||
n->a->sem_type->elem->drop_cname)
|
n->a->sem_type->elem->drop_cname)
|
||||||
fprintf(e->out,"%s(%s); ",n->a->sem_type->elem->drop_cname,cname(n->a,"owned"));
|
fprintf(e->out,"%s(%s); ",n->a->sem_type->elem->drop_cname,cname(n->a,"owned"));
|
||||||
fputs("free(",e->out); fputs(cname(n->a,"owned"),e->out);
|
if(!(n->a->sem_type->elem &&
|
||||||
fputs("); fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
|
n->a->sem_type->elem->kind==FE_TYPE_SLICE)) {
|
||||||
|
fputs("free(",e->out); fputs(cname(n->a,"owned"),e->out); fputs("); ",e->out);
|
||||||
|
}
|
||||||
|
fputs("fe_live_",e->out); fputs(cname(n->a,"owned"),e->out);
|
||||||
fputs("=0; }\n",e->out);
|
fputs("=0; }\n",e->out);
|
||||||
|
} else if(n->a && n->a->kind==FE_N_IDENT && n->a->sem_type &&
|
||||||
|
type_needs_drop(n->a->sem_type) &&
|
||||||
|
n->a->sem_type->drop_cname) {
|
||||||
|
pad(e); fputs("if (fe_live_",e->out); fputs(cname(n->a,"local"),e->out);
|
||||||
|
fprintf(e->out,") { %s(&%s); fe_live_",
|
||||||
|
n->a->sem_type->drop_cname,cname(n->a,"local"));
|
||||||
|
fputs(cname(n->a,"local"),e->out); fputs("=0; }\n",e->out);
|
||||||
}
|
}
|
||||||
pad(e);
|
pad(e);
|
||||||
emit_lvalue(e, n->a);
|
emit_lvalue(e, n->a);
|
||||||
@@ -1153,12 +1263,12 @@ static void emit_stmt(FeEmitter *e, FeNode *n)
|
|||||||
pad(e);
|
pad(e);
|
||||||
if (n->a && n->a->kind==FE_N_UNARY && n->a->text &&
|
if (n->a && n->a->kind==FE_N_UNARY && n->a->text &&
|
||||||
strcmp(n->a->text,"try")==0 && n->a->a) {
|
strcmp(n->a->text,"try")==0 && n->a->a) {
|
||||||
fputs("if ((fe_m4_error = ",e->out);
|
fputs("if ((fe_error_temp = ",e->out);
|
||||||
emit_expr(e,n->a->a);
|
emit_expr(e,n->a->a);
|
||||||
fputs(") != 0) {\n",e->out);
|
fputs(") != 0) {\n",e->out);
|
||||||
++e->indent;
|
++e->indent;
|
||||||
emit_cleanup_all(e);
|
emit_cleanup_all(e);
|
||||||
pad(e); fputs("return fe_m4_error;\n",e->out);
|
pad(e); fputs("return fe_error_temp;\n",e->out);
|
||||||
--e->indent;
|
--e->indent;
|
||||||
pad(e); fputs("}\n",e->out);
|
pad(e); fputs("}\n",e->out);
|
||||||
} else {
|
} else {
|
||||||
@@ -1275,7 +1385,8 @@ static void emit_fn(FeEmitter *e, FeNode *fn, int prototype)
|
|||||||
if (!p) fputs("void", e->out);
|
if (!p) fputs("void", e->out);
|
||||||
while (p) {
|
while (p) {
|
||||||
if (p != fn->a->children) fputs(", ", e->out);
|
if (p != fn->a->children) fputs(", ", e->out);
|
||||||
fputs(ctype(e, p->a), e->out);
|
fputs(p->sem_type ? fe_type_c_name(p->sem_type,e->pointer_bits) :
|
||||||
|
ctype(e,p->a),e->out);
|
||||||
fputc(' ', e->out);
|
fputc(' ', e->out);
|
||||||
fputs(cname(p, "fe_arg"), e->out);
|
fputs(cname(p, "fe_arg"), e->out);
|
||||||
p = p->next;
|
p = p->next;
|
||||||
@@ -1343,7 +1454,7 @@ void fe_emit_c_program(FeEmitter *e)
|
|||||||
fputs("typedef char fe_assert_usize[(sizeof(unsigned short)==2) ? 1 : -1];\n",e->out);
|
fputs("typedef char fe_assert_usize[(sizeof(unsigned short)==2) ? 1 : -1];\n",e->out);
|
||||||
else
|
else
|
||||||
fputs("typedef char fe_assert_usize[(sizeof(unsigned long)==4) ? 1 : -1];\n",e->out);
|
fputs("typedef char fe_assert_usize[(sizeof(unsigned long)==4) ? 1 : -1];\n",e->out);
|
||||||
fputs("static void fe_trap_bounds(void) { abort(); }\n\n", e->out);
|
fputs("static void fe_trap_bounds(void) { abort(); }\nstatic unsigned short fe_error_temp;\n\n", e->out);
|
||||||
emit_type_defs(e);
|
emit_type_defs(e);
|
||||||
if (need_m4) emit_m4_runtime(e);
|
if (need_m4) emit_m4_runtime(e);
|
||||||
emit_type_helpers(e);
|
emit_type_helpers(e);
|
||||||
@@ -1373,10 +1484,24 @@ void fe_emit_c_program(FeEmitter *e)
|
|||||||
emit_fn(e, n, 1);
|
emit_fn(e, n, 1);
|
||||||
if (n->text && strcmp(n->text, "main") == 0) main_fn = n;
|
if (n->text && strcmp(n->text, "main") == 0) main_fn = n;
|
||||||
}
|
}
|
||||||
|
for (n = e->check->ast->root ? e->check->ast->root->children : 0;
|
||||||
|
n; n = n->next) if(n->kind==FE_N_STRUCT) {
|
||||||
|
FeNode *m;
|
||||||
|
for(m=n->children; m; m=m->next)
|
||||||
|
if(m->kind==FE_N_FN)
|
||||||
|
emit_fn(e,m,1);
|
||||||
|
}
|
||||||
fputc('\n', e->out);
|
fputc('\n', e->out);
|
||||||
for (n = e->check->ast->root ? e->check->ast->root->children : 0;
|
for (n = e->check->ast->root ? e->check->ast->root->children : 0;
|
||||||
n; n = n->next)
|
n; n = n->next)
|
||||||
if (n->kind == FE_N_FN) emit_fn(e, n, 0);
|
if (n->kind == FE_N_FN) emit_fn(e, n, 0);
|
||||||
|
for (n = e->check->ast->root ? e->check->ast->root->children : 0;
|
||||||
|
n; n = n->next) if(n->kind==FE_N_STRUCT) {
|
||||||
|
FeNode *m;
|
||||||
|
for(m=n->children; m; m=m->next)
|
||||||
|
if(m->kind==FE_N_FN)
|
||||||
|
emit_fn(e,m,0);
|
||||||
|
}
|
||||||
if (main_fn) {
|
if (main_fn) {
|
||||||
fputc('\n', e->out);
|
fputc('\n', e->out);
|
||||||
emit_main_wrapper(e, main_fn);
|
emit_main_wrapper(e, main_fn);
|
||||||
|
|||||||
+14
-1
@@ -21,6 +21,7 @@ static FeType *new_type(FeTypeCtx *ctx, const char *name, FeTypeKind kind)
|
|||||||
t->tail_slicer = 0;
|
t->tail_slicer = 0;
|
||||||
t->drop_cname = 0;
|
t->drop_cname = 0;
|
||||||
t->alloc_cname = 0;
|
t->alloc_cname = 0;
|
||||||
|
t->replace_cname = 0;
|
||||||
t->bits = 0;
|
t->bits = 0;
|
||||||
t->is_unsigned = 0;
|
t->is_unsigned = 0;
|
||||||
t->packed = 0;
|
t->packed = 0;
|
||||||
@@ -200,6 +201,10 @@ FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem)
|
|||||||
if(t->kind==FE_TYPE_UNKNOWN) {
|
if(t->kind==FE_TYPE_UNKNOWN) {
|
||||||
t->kind=FE_TYPE_OWNED;
|
t->kind=FE_TYPE_OWNED;
|
||||||
t->elem=elem;
|
t->elem=elem;
|
||||||
|
if(elem && elem->kind==FE_TYPE_SLICE) {
|
||||||
|
t->cname=generated_name(ctx,"fe_owned_slice_","type");
|
||||||
|
t->maker=generated_name(ctx,"fe_make_owned_slice_","type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
@@ -222,6 +227,12 @@ FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value)
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fe_type_require_replace(FeTypeCtx *ctx, FeType *type)
|
||||||
|
{
|
||||||
|
if(type && !type->replace_cname)
|
||||||
|
type->replace_cname=generated_name(ctx,"fe_replace_","type");
|
||||||
|
}
|
||||||
|
|
||||||
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed)
|
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed)
|
||||||
{
|
{
|
||||||
FeType *t;
|
FeType *t;
|
||||||
@@ -410,7 +421,9 @@ static void layout_type(FeTypeCtx *ctx, FeType *t)
|
|||||||
t->cycle_state = 2; return;
|
t->cycle_state = 2; return;
|
||||||
}
|
}
|
||||||
if (t->kind == FE_TYPE_OWNED) {
|
if (t->kind == FE_TYPE_OWNED) {
|
||||||
t->size = ctx->pointer_bits == 16 ? 2UL : 4UL;
|
t->size = t->elem && t->elem->kind==FE_TYPE_SLICE ?
|
||||||
|
(ctx->pointer_bits == 16 ? 4UL : 8UL) :
|
||||||
|
(ctx->pointer_bits == 16 ? 2UL : 4UL);
|
||||||
t->align = ctx->pointer_bits == 16 ? 1U : 4U;
|
t->align = ctx->pointer_bits == 16 ? 1U : 4U;
|
||||||
t->cycle_state = 2; return;
|
t->cycle_state = 2; return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ struct FeType {
|
|||||||
char *tail_slicer;
|
char *tail_slicer;
|
||||||
char *drop_cname;
|
char *drop_cname;
|
||||||
char *alloc_cname;
|
char *alloc_cname;
|
||||||
|
char *replace_cname;
|
||||||
unsigned bits;
|
unsigned bits;
|
||||||
int is_unsigned;
|
int is_unsigned;
|
||||||
int packed;
|
int packed;
|
||||||
@@ -77,6 +78,7 @@ FeType *fe_type_mut_slice(FeTypeCtx *ctx, FeType *elem);
|
|||||||
FeType *fe_type_ref(FeTypeCtx *ctx, FeType *elem, int mutable);
|
FeType *fe_type_ref(FeTypeCtx *ctx, FeType *elem, int mutable);
|
||||||
FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem);
|
FeType *fe_type_owned(FeTypeCtx *ctx, FeType *elem);
|
||||||
FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value);
|
FeType *fe_type_error_union(FeTypeCtx *ctx, FeType *value);
|
||||||
|
void fe_type_require_replace(FeTypeCtx *ctx, FeType *type);
|
||||||
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed);
|
FeType *fe_type_declare_struct(FeTypeCtx *ctx, const FeNode *node, int packed);
|
||||||
FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node);
|
FeType *fe_type_declare_enum(FeTypeCtx *ctx, const FeNode *node);
|
||||||
FeType *fe_type_declare_error(FeTypeCtx *ctx, const FeNode *node);
|
FeType *fe_type_declare_error(FeTypeCtx *ctx, const FeNode *node);
|
||||||
|
|||||||
+4
-2
@@ -1,8 +1,10 @@
|
|||||||
unit mem;
|
unit mem;
|
||||||
|
|
||||||
pub fn create(T: type) -> !^T;
|
pub fn create(value: T) -> !^T;
|
||||||
pub fn destroy(p: *void);
|
pub fn destroy(p: *void);
|
||||||
pub fn copy(dst: []u8, src: []u8);
|
pub fn alloc_slice(T: type, n: usize) -> !^[]T;
|
||||||
|
pub fn replace(dst: &mut T, value: T) -> T;
|
||||||
|
pub fn copy(dst: []mut u8, src: []u8);
|
||||||
pub struct Arena {
|
pub struct Arena {
|
||||||
ptr: *void,
|
ptr: *void,
|
||||||
pub fn init() -> Arena { return Arena{ ptr: null }; }
|
pub fn init() -> Arena { return Arena{ ptr: null }; }
|
||||||
|
|||||||
+9
-3
@@ -259,14 +259,20 @@ fec.exe --target=bits32 --emit-c TESTS\M5\BAD-DBL.FE -o TESTS\M5\BAD-DBL.C > nul
|
|||||||
if not errorlevel 1 goto test_fail
|
if not errorlevel 1 goto test_fail
|
||||||
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-COND.FE -o TESTS\M5\BAD-COND.C > nul
|
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-COND.FE -o TESTS\M5\BAD-COND.C > nul
|
||||||
if not errorlevel 1 goto test_fail
|
if not errorlevel 1 goto test_fail
|
||||||
if exist TESTS\M5\RUNTIME-G.C del TESTS\M5\RUNTIME-G.C
|
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-PROJ.FE -o TESTS\M5\BAD-PROJ.C > nul
|
||||||
|
if not errorlevel 1 goto test_fail
|
||||||
|
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-CLOS.FE -o TESTS\M5\BAD-CLOS.C > nul
|
||||||
|
if not errorlevel 1 goto test_fail
|
||||||
|
fec.exe --target=bits32 --emit-c TESTS\M5\BAD-LOOP.FE -o TESTS\M5\BAD-LOOP.C > nul
|
||||||
|
if not errorlevel 1 goto test_fail
|
||||||
|
if exist TESTS\M5\RUNT-G.C del TESTS\M5\RUNT-G.C
|
||||||
if exist TESTS\M5\RUNTIME.O del TESTS\M5\RUNTIME.O
|
if exist TESTS\M5\RUNTIME.O del TESTS\M5\RUNTIME.O
|
||||||
if exist TESTS\M5\RUNTIME.EXE del TESTS\M5\RUNTIME.EXE
|
if exist TESTS\M5\RUNTIME.EXE del TESTS\M5\RUNTIME.EXE
|
||||||
fec.exe --target=bits32 --emit-c TESTS\M5\RUNTIME.FE -o TESTS\M5\RUNTIME-G.C > nul
|
fec.exe --target=bits32 --emit-c TESTS\M5\RUNTIME.FE -o TESTS\M5\RUNT-G.C > nul
|
||||||
if errorlevel 1 goto test_fail
|
if errorlevel 1 goto test_fail
|
||||||
rem Compile generated source and the C89 runtime harness in one WCL386 invocation
|
rem Compile generated source and the C89 runtime harness in one WCL386 invocation
|
||||||
rem so both objects use the same DOS/4GW startup and runtime library.
|
rem so both objects use the same DOS/4GW startup and runtime library.
|
||||||
wcl386 -q -za -bt=dos -dmalloc=m5_malloc -dfree=m5_free -fe=TESTS\M5\RUNTIME.EXE TESTS\M5\RUNTIME-G.C TESTS\M5\RUNTIME.C
|
wcl386 -q -za -bt=dos -dmalloc=m5_malloc -dfree=m5_free -fe=TESTS\M5\RUNTIME.EXE TESTS\M5\RUNT-G.C TESTS\M5\RUNTIME.C
|
||||||
if errorlevel 1 goto test_fail
|
if errorlevel 1 goto test_fail
|
||||||
TESTS\M5\RUNTIME.EXE
|
TESTS\M5\RUNTIME.EXE
|
||||||
if errorlevel 1 goto test_fail
|
if errorlevel 1 goto test_fail
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
unit m5_bad_consuming_close;
|
||||||
|
|
||||||
|
struct FileLike {
|
||||||
|
handle: i32,
|
||||||
|
fn close(self: Self) -> !void { self.handle = 0; }
|
||||||
|
fn drop(self: &mut Self) { self.handle = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad() -> !void {
|
||||||
|
let file: FileLike = FileLike{ handle: 7 };
|
||||||
|
try file.close();
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
unit m5_bad_loop_move;
|
||||||
|
|
||||||
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
|
|
||||||
|
fn bad(p: ^i32, again: bool) -> void {
|
||||||
|
while again { take(p); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
unit m5_bad_projection_move;
|
||||||
|
|
||||||
|
struct Holder { p: ^i32 }
|
||||||
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
|
|
||||||
|
fn bad(h: Holder) -> void {
|
||||||
|
take(h.p);
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
unit m5_owned;
|
unit m5_owned;
|
||||||
|
|
||||||
fn main() -> void {
|
fn main() -> void {
|
||||||
var p: ^i32 = try mem.create(i32);
|
var p: ^i32 = try mem.create(0);
|
||||||
p = try mem.create(i32);
|
p = try mem.create(0);
|
||||||
p.^ = 7;
|
p.^ = 7;
|
||||||
let value: i32 = p.^;
|
let value: i32 = p.^;
|
||||||
defer { mem.destroy(p); }
|
defer { mem.destroy(p); }
|
||||||
|
|||||||
+55
-9
@@ -4,21 +4,43 @@
|
|||||||
#undef malloc
|
#undef malloc
|
||||||
#undef free
|
#undef free
|
||||||
|
|
||||||
|
extern void *malloc(size_t size);
|
||||||
|
extern void free(void *p);
|
||||||
|
|
||||||
extern long fe_m5_runtime_run(long mode);
|
extern long fe_m5_runtime_run(long mode);
|
||||||
extern void fe_m5_runtime_conditional(unsigned char flag);
|
extern unsigned short fe_m5_runtime_conditional(unsigned char flag);
|
||||||
extern void fe_m5_runtime_argument_cleanup(void);
|
extern unsigned short fe_m5_runtime_argument_cleanup(void);
|
||||||
|
extern unsigned short fe_m5_runtime_owned_slice(unsigned long n);
|
||||||
|
extern unsigned short fe_m5_runtime_replace_field(void);
|
||||||
|
extern unsigned short fe_m5_runtime_loop_cleanup(void);
|
||||||
|
extern unsigned short fe_m5_runtime_try_cleanup(void);
|
||||||
|
extern unsigned short fe_m5_runtime_field_order(void);
|
||||||
|
extern unsigned short fe_m5_runtime_defer_order(void);
|
||||||
|
extern unsigned short fe_m5_runtime_match_cleanup(unsigned char flag);
|
||||||
|
extern unsigned short fe_m5_runtime_close_once(void);
|
||||||
|
extern unsigned short fe_m5_runtime_reassign_struct(void);
|
||||||
|
|
||||||
static void *live_ptrs[64];
|
static void *live_ptrs[64];
|
||||||
static unsigned live_count;
|
static unsigned live_count;
|
||||||
static unsigned alloc_count;
|
static unsigned alloc_count;
|
||||||
static unsigned free_count;
|
static unsigned free_count;
|
||||||
static unsigned double_free_count;
|
static unsigned double_free_count;
|
||||||
|
static long fail_after = -1;
|
||||||
|
static unsigned malloc_attempts;
|
||||||
|
static int track_order;
|
||||||
|
static void *order_ptrs[2];
|
||||||
|
static unsigned order_allocs;
|
||||||
|
static unsigned order_frees;
|
||||||
|
static unsigned order_bad;
|
||||||
|
|
||||||
void *m5_malloc(size_t size)
|
void *m5_malloc(size_t size)
|
||||||
{
|
{
|
||||||
void *p = malloc(size);
|
void *p;
|
||||||
|
if (fail_after >= 0 && (long)malloc_attempts++ == fail_after) return 0;
|
||||||
|
p = malloc(size);
|
||||||
if (p && live_count < 64) live_ptrs[live_count++] = p;
|
if (p && live_count < 64) live_ptrs[live_count++] = p;
|
||||||
if (p) ++alloc_count;
|
if (p) ++alloc_count;
|
||||||
|
if (p && track_order && order_allocs < 2) order_ptrs[order_allocs++] = p;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +50,9 @@ void m5_free(void *p)
|
|||||||
if (!p) return;
|
if (!p) return;
|
||||||
for (i = 0; i < live_count; ++i) {
|
for (i = 0; i < live_count; ++i) {
|
||||||
if (live_ptrs[i] == p) {
|
if (live_ptrs[i] == p) {
|
||||||
|
if (track_order && order_frees < 2 &&
|
||||||
|
p != order_ptrs[1-order_frees]) ++order_bad;
|
||||||
|
if (track_order && order_frees < 2) ++order_frees;
|
||||||
live_ptrs[i] = live_ptrs[--live_count];
|
live_ptrs[i] = live_ptrs[--live_count];
|
||||||
++free_count;
|
++free_count;
|
||||||
free(p);
|
free(p);
|
||||||
@@ -42,11 +67,32 @@ int main(void)
|
|||||||
if (fe_m5_runtime_run(0) != 0) return 1;
|
if (fe_m5_runtime_run(0) != 0) return 1;
|
||||||
if (fe_m5_runtime_run(1) != 9) return 2;
|
if (fe_m5_runtime_run(1) != 9) return 2;
|
||||||
if (fe_m5_runtime_run(2) != 0) return 3;
|
if (fe_m5_runtime_run(2) != 0) return 3;
|
||||||
fe_m5_runtime_conditional(0);
|
if (fe_m5_runtime_conditional(0) != 0) return 4;
|
||||||
fe_m5_runtime_conditional(1);
|
if (fe_m5_runtime_conditional(1) != 0) return 5;
|
||||||
fe_m5_runtime_argument_cleanup();
|
if (fe_m5_runtime_argument_cleanup() != 0) return 6;
|
||||||
if (double_free_count != 0) return 4;
|
if (fe_m5_runtime_owned_slice(17) != 0) return 7;
|
||||||
if (live_count != 0) return 5;
|
if (fe_m5_runtime_replace_field() != 0) return 8;
|
||||||
if (alloc_count != free_count) return 6;
|
if (fe_m5_runtime_loop_cleanup() != 0) return 9;
|
||||||
|
fail_after=1;
|
||||||
|
malloc_attempts=0;
|
||||||
|
if (fe_m5_runtime_try_cleanup() == 0) return 10;
|
||||||
|
fail_after=-1;
|
||||||
|
track_order=1;
|
||||||
|
order_allocs=order_frees=order_bad=0;
|
||||||
|
if (fe_m5_runtime_field_order() != 0) return 11;
|
||||||
|
track_order=0;
|
||||||
|
if (order_allocs != 2 || order_frees != 2 || order_bad != 0) return 12;
|
||||||
|
track_order=1;
|
||||||
|
order_allocs=order_frees=order_bad=0;
|
||||||
|
if (fe_m5_runtime_defer_order() != 0) return 13;
|
||||||
|
track_order=0;
|
||||||
|
if (order_allocs != 2 || order_frees != 2 || order_bad != 0) return 14;
|
||||||
|
if (fe_m5_runtime_match_cleanup(0) != 0) return 15;
|
||||||
|
if (fe_m5_runtime_match_cleanup(1) != 0) return 16;
|
||||||
|
if (fe_m5_runtime_close_once() != 0) return 17;
|
||||||
|
if (fe_m5_runtime_reassign_struct() != 0) return 18;
|
||||||
|
if (double_free_count != 0) return 19;
|
||||||
|
if (live_count != 0) return 20;
|
||||||
|
if (alloc_count != free_count) return 21;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-6
@@ -3,11 +3,11 @@ unit m5_runtime;
|
|||||||
fn take(p: ^i32) -> void { mem.destroy(p); }
|
fn take(p: ^i32) -> void { mem.destroy(p); }
|
||||||
|
|
||||||
pub fn run(mode: i32) -> i32 {
|
pub fn run(mode: i32) -> i32 {
|
||||||
var p: ^i32 = try mem.create(i32);
|
var p: ^i32 = try mem.create(0);
|
||||||
defer { mem.destroy(p); }
|
defer { mem.destroy(p); }
|
||||||
p.^ = 7;
|
p.^ = 7;
|
||||||
if mode == 1 {
|
if mode == 1 {
|
||||||
p = try mem.create(i32);
|
p = try mem.create(0);
|
||||||
p.^ = 9;
|
p.^ = 9;
|
||||||
return p.^;
|
return p.^;
|
||||||
}
|
}
|
||||||
@@ -16,12 +16,85 @@ pub fn run(mode: i32) -> i32 {
|
|||||||
return p.^ - 7;
|
return p.^ - 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn conditional(flag: bool) -> void {
|
pub fn conditional(flag: bool) -> !void {
|
||||||
var p: ^i32 = try mem.create(i32);
|
var p: ^i32 = try mem.create(0);
|
||||||
if flag { take(p); }
|
if flag { take(p); }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn argument_cleanup() -> void {
|
pub fn argument_cleanup() -> !void {
|
||||||
let p: ^i32 = try mem.create(i32);
|
let p: ^i32 = try mem.create(0);
|
||||||
take(p);
|
take(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn owned_slice(n: usize) -> !void {
|
||||||
|
let bytes: ^[]u8 = try mem.alloc_slice(u8, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Holder { p: ^i32 }
|
||||||
|
|
||||||
|
pub fn replace_field() -> !void {
|
||||||
|
let first: ^i32 = try mem.create(1);
|
||||||
|
var h: Holder = Holder{ p: first };
|
||||||
|
let second: ^i32 = try mem.create(2);
|
||||||
|
let old: ^i32 = mem.replace(&mut h.p, second);
|
||||||
|
mem.destroy(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loop_cleanup() -> !void {
|
||||||
|
var i: i32 = 0;
|
||||||
|
while i < 2 {
|
||||||
|
let p: ^i32 = try mem.create(i);
|
||||||
|
i += 1;
|
||||||
|
if i == 1 { continue; }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_cleanup() -> !void {
|
||||||
|
let first: ^i32 = try mem.create(1);
|
||||||
|
let second: ^i32 = try mem.create(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PairOwners { first: ^i32, second: ^i32 }
|
||||||
|
|
||||||
|
pub fn field_order() -> !void {
|
||||||
|
let first: ^i32 = try mem.create(1);
|
||||||
|
let second: ^i32 = try mem.create(2);
|
||||||
|
let pair: PairOwners = PairOwners{ first: first, second: second };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn defer_order() -> !void {
|
||||||
|
let first: ^i32 = try mem.create(1);
|
||||||
|
defer { mem.destroy(first); }
|
||||||
|
let second: ^i32 = try mem.create(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Choice { A, B }
|
||||||
|
|
||||||
|
pub fn match_cleanup(flag: bool) -> !void {
|
||||||
|
var choice: Choice = Choice.A;
|
||||||
|
if flag { choice = Choice.B; }
|
||||||
|
let p: ^i32 = try mem.create(1);
|
||||||
|
match choice {
|
||||||
|
A => { take(p); }
|
||||||
|
B => { take(p); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileLike {
|
||||||
|
handle: i32,
|
||||||
|
fn close(self: Self) -> !void { self.handle = 0; }
|
||||||
|
fn drop(self: &mut Self) { self.handle = 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_once() -> !void {
|
||||||
|
let file: FileLike = FileLike{ handle: 7 };
|
||||||
|
try file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reassign_struct() -> !void {
|
||||||
|
let first: ^i32 = try mem.create(1);
|
||||||
|
var owner: Holder = Holder{ p: first };
|
||||||
|
let second: ^i32 = try mem.create(2);
|
||||||
|
owner = Holder{ p: second };
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user