diff --git a/src/cc/backend/codegen_expr.c b/src/cc/backend/codegen_expr.c index fc8b52e7b..5fc935c4b 100644 --- a/src/cc/backend/codegen_expr.c +++ b/src/cc/backend/codegen_expr.c @@ -563,14 +563,20 @@ static VReg *gen_comma(Expr *expr) { static VReg *gen_assign_sub(Expr *lhs, Expr *rhs) { VReg *src = gen_expr(rhs); if (lhs->kind == EX_VAR) { + const VarInfo *varinfo = scope_find(lhs->var.scope, lhs->var.name, NULL); + assert(varinfo != NULL); if (is_prim_type(lhs->type) && !is_global_scope(lhs->var.scope)) { - const VarInfo *varinfo = scope_find(lhs->var.scope, lhs->var.name, NULL); if (is_local_storage(varinfo)) { assert(varinfo->local.vreg != NULL); new_ir_mov(varinfo->local.vreg, src, is_unsigned(rhs->type) ? IRF_UNSIGNED : 0); return src; } } + + if ((varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC) { + // Can be omitted. + return src; + } } VReg *dst = gen_lval(lhs); diff --git a/src/wcc/emit_wasm.c b/src/wcc/emit_wasm.c index 89475dcc0..c2cb5f852 100644 --- a/src/wcc/emit_wasm.c +++ b/src/wcc/emit_wasm.c @@ -29,6 +29,7 @@ static void emit_global_number(void *ud, const Type *type, Expr *var, Fixnum off v += get_indirect_function_index(var->var.name); } else { GVarInfo *info = get_gvar_info(var); + assert(info != NULL); assert(!is_prim_type(info->varinfo->type) || (info->varinfo->storage & VS_REF_TAKEN)); v += info->non_prim.address; } @@ -116,6 +117,7 @@ static void emit_number(void *ud, const Type *type, Expr *var, Fixnum offset) { } else { assert(var->kind == EX_VAR); const GVarInfo *info = get_gvar_info(var); + assert(info != NULL); assert(!is_prim_type(info->varinfo->type) || (info->varinfo->storage & VS_REF_TAKEN)); v += info->non_prim.address; diff --git a/src/wcc/gen_wasm.c b/src/wcc/gen_wasm.c index f208ae0bd..ffa997868 100644 --- a/src/wcc/gen_wasm.c +++ b/src/wcc/gen_wasm.c @@ -482,6 +482,7 @@ static void gen_ref_sub(Expr *expr) { ADD_VARUINT32(info->indirect_index); } else { GVarInfo *info = get_gvar_info(expr); + assert(info != NULL); ADD_CODE(OP_I32_CONST); FuncExtra *extra = curfunc->extra; DataStorage *code = extra->code; @@ -554,6 +555,7 @@ static void gen_var(Expr *expr, bool needval) { ADD_ULEB128(vreg->prim.local_index); } else { GVarInfo *info = get_gvar_info(expr); + assert(info != NULL); ADD_CODE(OP_GLOBAL_GET); FuncExtra *extra = curfunc->extra; DataStorage *code = extra->code; @@ -616,6 +618,7 @@ static void gen_set_to_var(Expr *var) { } else { assert(!is_global_datsec_var(varinfo, var->var.scope)); GVarInfo *info = get_gvar_info(var); + assert(info != NULL); ADD_CODE(OP_GLOBAL_SET); FuncExtra *extra = curfunc->extra; DataStorage *code = extra->code; @@ -799,6 +802,7 @@ static void gen_incdec(Expr *expr, bool needval) { } else { assert(!is_global_datsec_var(varinfo, scope)); GVarInfo *info = get_gvar_info(target); + assert(info != NULL); ADD_CODE(OP_GLOBAL_SET); ADD_ULEB128(info->prim.index); if (needval) { @@ -823,6 +827,12 @@ static void gen_assign_sub(Expr *lhs, Expr *rhs) { gen_set_to_var(lhs); break; } + + if ((varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC) { + // Assignment can be omitted. + gen_expr(rhs, false); + return; + } } gen_lval(lhs); gen_expr(rhs, true); diff --git a/src/wcc/traverse.c b/src/wcc/traverse.c index e87109f64..a179b258e 100644 --- a/src/wcc/traverse.c +++ b/src/wcc/traverse.c @@ -157,7 +157,7 @@ GVarInfo *get_gvar_info(Expr *expr) { } assert(varinfo != NULL); GVarInfo *info = get_gvar_info_from_name(name); - if (info == NULL) { + if (info == NULL && (!(varinfo->storage & VS_STATIC) || (varinfo->storage & VS_USED))) { // Returns dummy. info = register_gvar_info(name, varinfo); info->flag |= GVF_UNRESOLVED; @@ -165,7 +165,7 @@ GVarInfo *get_gvar_info(Expr *expr) { return info; } -#define add_global_var(type, name) scope_add(global_scope, name, type, 0) +#define add_global_var(type, name) scope_add(global_scope, name, type, VS_USED) void add_builtin_function(const char *str, Type *type, BuiltinFunctionProc *proc, bool add_to_scope) { @@ -629,7 +629,8 @@ static void traverse_varinfo(VarInfo *varinfo) { if (scope_find(global_scope, varinfo->name, NULL) == NULL) { // Register into global to output linking information. GVarInfo *info = register_gvar_info(varinfo->name, varinfo); - info->flag |= GVF_UNRESOLVED; + if (info != NULL) + info->flag |= GVF_UNRESOLVED; } } if (!(varinfo->storage & (VS_EXTERN | VS_STATIC | VS_ENUM_MEMBER))) @@ -832,6 +833,7 @@ static void add_builtins(int flag) { GVarInfo *info = get_gvar_info_from_name(name); if (info == NULL) info = register_gvar_info(name, varinfo); + assert(info != NULL); info->flag |= GVF_UNRESOLVED; } } @@ -889,7 +891,9 @@ static bool detect_compile_unit_sp(Function *func) { static int detect_compile_unit_memory(void) { for (int i = 0, len = global_scope->vars->len; i < len; ++i) { VarInfo *varinfo = global_scope->vars->data[i]; - if (varinfo->storage & (VS_EXTERN | VS_ENUM_MEMBER) || varinfo->type->kind == TY_FUNC) + if (varinfo->type->kind == TY_FUNC || + (varinfo->storage & (VS_EXTERN | VS_ENUM_MEMBER)) || + (varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC) // Static variable but not used. continue; if (is_global_datsec_var(varinfo, global_scope)) return CUF_LINEAR_MEMORY; @@ -992,8 +996,8 @@ void traverse_ast(Vector *decls) { GVarInfo *info; for (int it = 0; (it = table_iterate(&gvar_info_table, it, &name, (void**)&info)) != -1; ) { const VarInfo *varinfo = info->varinfo; - if (varinfo->storage & VS_ENUM_MEMBER || varinfo->type->kind == TY_FUNC) - continue; + assert(!(varinfo->storage & VS_ENUM_MEMBER || varinfo->type->kind == TY_FUNC)); + assert(!((varinfo->storage & (VS_STATIC | VS_USED)) == VS_STATIC)); if ((k == 0 && !(info->flag & GVF_UNRESOLVED)) || (k != 0 && ((info->flag & GVF_UNRESOLVED) || (varinfo->global.init == NULL) == (k == 1)))) continue; diff --git a/tests/test.sh b/tests/test.sh index 4b2852b69..672a1bb57 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -310,6 +310,12 @@ test_error() { compile_error 'noreturn should not return' 'void sub(void) __attribute__((noreturn));\nvoid sub(void){}\nint main(){ sub(); }' compile_error 'noreturn should be void' '#include \nint sub(void) __attribute__((noreturn));\nint sub(void){exit(0);}\nint main(){ sub(); }' + # Unused check. + compile_error 'unused local variable' 'int main(){ int x = 0; x = 1; return 0; }' + compile_error 'unused static variable' 'int main(){ static int x = 0; x = 1; return 0; }' + compile_error 'unused static global variable' 'static int s = 0; int g; int sub(){g=1; return 2;} int main(){ s = sub(); return g; }' + try_direct 'unused static can run w/o -Werror' 1 'static int s = 0; int g; int sub(){g=1; return 2;} int main(){ s = sub(); return g; } //-WNOERR' + compile_error 'enum and global' 'enum Foo { BAR }; int BAR; int main(){}' compile_error 'global and enum' 'int BAR; enum Foo { BAR }; int main(){}' compile_error 'dup enum elem' 'enum Foo { BAR, BAR }; int main(){}'