m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+ if (m_flags & AST_FLAG_NOREF)
+ m_ir_v->m_flags |= IR_FLAG_NOREF;
/* initialize */
if (m_hasvalue) {
m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+ if (m_flags & AST_FLAG_NOREF)
+ m_ir_v->m_flags |= IR_FLAG_NOREF;
const size_t namelen = m_name.length();
std::unique_ptr<char[]> name(new char[namelen+16]);
array->m_ir_values[ai]->m_unique_life = true;
array->m_ir_values[ai]->m_locked = true;
if (m_flags & AST_FLAG_INCLUDE_DEF)
- m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
+ array->m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
+ if (m_flags & AST_FLAG_NOREF)
+ array->m_ir_values[ai]->m_flags |= IR_FLAG_NOREF;
}
}
else
m_ir_v = v;
if (m_flags & AST_FLAG_INCLUDE_DEF)
m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
-
if (m_flags & AST_FLAG_ERASEABLE)
m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+ if (m_flags & AST_FLAG_NOREF)
+ m_ir_v->m_flags |= IR_FLAG_NOREF;
}
return true;
}
if (m_flags & AST_FLAG_INCLUDE_DEF)
v->m_flags |= IR_FLAG_INCLUDE_DEF;
if (m_flags & AST_FLAG_ERASEABLE)
- m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+ v->m_flags |= IR_FLAG_ERASABLE;
+ if (m_flags & AST_FLAG_NOREF)
+ v->m_flags |= IR_FLAG_NOREF;
const size_t namelen = m_name.length();
std::unique_ptr<char[]> name(new char[namelen+16]);
m_ir_values[ai]->m_locked = true;
if (m_flags & AST_FLAG_INCLUDE_DEF)
m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
+ if (m_flags & AST_FLAG_NOREF)
+ m_ir_values[ai]->m_flags |= IR_FLAG_NOREF;
}
return v;
v->m_unique_life = true;
v->m_locked = true;
+ if (m_flags & AST_FLAG_NOREF)
+ v->m_flags |= IR_FLAG_NOREF;
+
const size_t namelen = m_name.length();
std::unique_ptr<char[]> name(new char[namelen+16]);
util_strncpy(name.get(), m_name.c_str(), namelen);
}
m_ir_values[ai]->m_context = m_context;
m_ir_values[ai]->m_unique_life = true;
- m_ir_values[ai]->m_locked = true;
+ m_ir_values[ai]->m_locked = true;
+
+ if (m_flags & AST_FLAG_NOREF)
+ m_ir_values[ai]->m_flags |= IR_FLAG_NOREF;
}
}
else
v->m_cvq = m_cvq;
m_ir_v = v;
+ if (m_flags & AST_FLAG_NOREF)
+ m_ir_v->m_flags |= IR_FLAG_NOREF;
+
if (!generateAccessors(func->m_owner))
return false;
return true;
AST_FLAG_COVERAGE = 1 << 12,
AST_FLAG_BLOCK_COVERAGE = 1 << 13,
+ /*
+ * Propagates norefness to the IR so the unused (read/write) check can be
+ * more intelligently done.
+ */
+ AST_FLAG_NOREF = 1 << 14,
+
AST_FLAG_LAST,
AST_FLAG_TYPE_MASK = (AST_FLAG_VARIADIC | AST_FLAG_NORETURN),
AST_FLAG_COVERAGE_MASK = (AST_FLAG_BLOCK_COVERAGE)
*/
std::vector<basic_value_t> m_initlist;
- /* usecount for the parser */
- size_t m_uses = 0;
-
ir_value *m_ir_v = nullptr;
std::vector<ir_value*> m_ir_values;
size_t m_ir_value_count = 0;
for (auto& lp : self->m_locals) {
ir_value *v = lp.get();
- if (v->m_reads.empty() && v->m_writes.size()) {
+ if (v->m_reads.empty() && v->m_writes.size() && !(v->m_flags & IR_FLAG_NOREF)) {
// if it's a vector check to ensure all it's members are unused before
// claiming it's unused, otherwise skip the vector entierly
if (v->m_vtype == TYPE_VECTOR)
IR_FLAG_INCLUDE_DEF = 1 << 3,
IR_FLAG_ERASABLE = 1 << 4,
IR_FLAG_BLOCK_COVERAGE = 1 << 5,
-
- IR_FLAG_SPLIT_VECTOR = 1 << 6,
+ IR_FLAG_NOREF = 1 << 6,
+ IR_FLAG_SPLIT_VECTOR = 1 << 7,
IR_FLAG_LAST,
IR_FLAG_MASK_NO_OVERLAP = (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED),
}
else
{
- if (ast_istype(var, ast_value)) {
- ((ast_value*)var)->m_uses++;
+ // promote these to norefs
+ if (ast_istype(var, ast_value))
+ {
+ ((ast_value *)var)->m_flags |= AST_FLAG_NOREF;
}
- else if (ast_istype(var, ast_member)) {
- ast_member *mem = (ast_member*)var;
+ else if (ast_istype(var, ast_member))
+ {
+ ast_member *mem = (ast_member *)var;
if (ast_istype(mem->m_owner, ast_value))
- ((ast_value*)(mem->m_owner))->m_uses++;
+ ((ast_value *)mem->m_owner)->m_flags |= AST_FLAG_NOREF;
}
}
sy->out.push_back(syexp(parser_ctx(parser), var));
locals = vec_last(parser->_blocklocals);
vec_pop(parser->_blocklocals);
- while (vec_size(parser->_locals) != locals) {
- ast_expression *e = vec_last(parser->_locals);
- ast_value *v = (ast_value*)e;
+ while (vec_size(parser->_locals) != locals)
vec_pop(parser->_locals);
- if (ast_istype(e, ast_value) && !v->m_uses) {
- if (compile_warning(v->m_context, WARN_UNUSED_VARIABLE, "unused variable: `%s`", v->m_name))
- rv = false;
- }
- }
typedefs = vec_last(parser->_blocktypedefs);
while (vec_size(parser->_typedefs) != typedefs) {
/* Deal with end_sys_ vars */
was_end = false;
if (var->m_name == "end_sys_globals") {
- var->m_uses++;
+ var->m_flags |= AST_FLAG_NOREF;
parser->crc_globals = parser->globals.size();
was_end = true;
}
else if (var->m_name == "end_sys_fields") {
- var->m_uses++;
+ var->m_flags |= AST_FLAG_NOREF;
parser->crc_fields = parser->fields.size();
was_end = true;
}
}
}
- /* in a noref section we simply bump the usecount */
if (noref || parser->noref)
- var->m_uses++;
+ var->m_flags |= AST_FLAG_NOREF;
/* Part 2:
* Create the global/local, and deal with vector types.
var->m_cvq = CV_CONST;
}
if (cval == parser->nil)
+ {
var->m_flags |= AST_FLAG_INITIALIZED;
+ var->m_flags |= AST_FLAG_NOREF;
+ }
else
{
var->m_hasvalue = true;
parser->reserved_version->m_cvq = CV_CONST;
parser->reserved_version->m_hasvalue = true;
parser->reserved_version->m_flags |= AST_FLAG_INCLUDE_DEF;
+ parser->reserved_version->m_flags |= AST_FLAG_NOREF;
parser->reserved_version->m_constval.vstring = util_strdup(GMQCC_FULL_VERSION_STRING);
} else {
parser->reserved_version = nullptr;
if (!ast_istype(it, ast_value))
continue;
asvalue = (ast_value*)it;
- if (!asvalue->m_uses && asvalue->m_cvq != CV_CONST && asvalue->m_vtype != TYPE_FUNCTION) {
+ if (!(asvalue->m_flags & AST_FLAG_NOREF) && asvalue->m_cvq != CV_CONST && asvalue->m_vtype != TYPE_FUNCTION) {
retval = retval && !compile_warning(asvalue->m_context, WARN_UNUSED_VARIABLE,
"unused global: `%s`", asvalue->m_name);
}