MEM_VEC_FUNCTIONS(parser_t, varentry_t, locals)
MEM_VEC_FUNCTIONS(parser_t, ast_function*, functions)
-static void parser_pop_local(parser_t *parser);
+static bool GMQCC_WARN parser_pop_local(parser_t *parser);
static bool parser_variable(parser_t *parser, ast_block *localblock);
static ast_block* parser_parse_block(parser_t *parser, bool warnreturn);
static bool parser_parse_block_into(parser_t *parser, ast_block *block, bool warnreturn);
static ast_expression* parser_expression_leave(parser_t *parser, bool stopatcomma);
static ast_expression* parser_expression(parser_t *parser, bool stopatcomma);
-void parseerror(parser_t *parser, const char *fmt, ...)
+static void parseerror(parser_t *parser, const char *fmt, ...)
{
va_list ap;
}
/* returns true if it counts as an error */
-bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char *fmt, ...)
+static bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char *fmt, ...)
{
va_list ap;
int lvl = LVL_WARNING;
return opts_werror;
}
+static bool GMQCC_WARN genwarning(lex_ctx ctx, int warntype, const char *fmt, ...)
+{
+ va_list ap;
+ int lvl = LVL_WARNING;
+
+ if (!OPTS_WARN(warntype))
+ return false;
+
+ if (opts_werror)
+ lvl = LVL_ERROR;
+
+ va_start(ap, fmt);
+ vprintmsg(lvl, ctx.file, ctx.line, "warning", fmt, ap);
+ va_end(ap);
+
+ return opts_werror;
+}
+
/**********************************************************************
* some maths used for constant folding
*/
if (opts_standard == COMPILER_GMQCC)
{
if (fval)
- parseerror(parser, "too %s parameters for call to %s: expected %i, got %i", fewmany,
- fval->name, (int)fun->expression.params_count, paramcount);
+ parseerror(parser, "too %s parameters for call to %s: expected %i, got %i\n"
+ " -> `%s` has been declared here: %s:%i",
+ fewmany, fval->name, (int)fun->expression.params_count, (int)paramcount,
+ fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line);
else
- parseerror(parser, "too %s parameters for function call: expected %i, got %i", fewmany,
- (int)fun->expression.params_count, paramcount);
+ parseerror(parser, "too %s parameters for function call: expected %i, got %i\n"
+ " -> `%s` has been declared here: %s:%i",
+ fewmany, fval->name, (int)fun->expression.params_count, (int)paramcount,
+ fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line);
return false;
}
else
{
if (fval)
return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS,
- "too %s parameters for call to %s: expected %i, got %i", fewmany,
- fval->name, (int)fun->expression.params_count, paramcount);
+ "too %s parameters for call to %s: expected %i, got %i\n"
+ " -> `%s` has been declared here: %s:%i",
+ fewmany, fval->name, (int)fun->expression.params_count, (int)paramcount,
+ fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line);
else
return !parsewarning(parser, WARN_TOO_FEW_PARAMETERS,
- "too %s parameters for function call: expected %i, got %i", fewmany,
- (int)fun->expression.params_count, paramcount);
+ "too %s parameters for function call: expected %i, got %i\n"
+ " -> `%s` has been declared here: %s:%i",
+ fewmany, fval->name, (int)fun->expression.params_count, (int)paramcount,
+ fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line);
}
}
}
parseerror(parser, "unexpected ident: %s", parser_tokval(parser));
goto onerr;
}
+ if (ast_istype(var, ast_value))
+ ((ast_value*)var)->uses++;
if (!shunt_out_add(&sy, syexp(parser_ctx(parser), var))) {
parseerror(parser, "out of memory");
goto onerr;
ast_loop *aloop;
ast_expression *initexpr, *cond, *increment, *ontrue;
size_t oldblocklocal;
+ bool retval = true;
lex_ctx ctx = parser_ctx(parser);
increment = parser_expression_leave(parser, false);
if (!increment)
goto onerr;
+ if (!ast_istype(increment, ast_store) &&
+ !ast_istype(increment, ast_call) &&
+ !ast_istype(increment, ast_binstore))
+ {
+ if (genwarning(ast_ctx(increment), WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
+ goto onerr;
+ }
}
/* closing paren */
*out = (ast_expression*)aloop;
while (parser->locals_count > parser->blocklocal)
- parser_pop_local(parser);
+ retval = retval && parser_pop_local(parser);
parser->blocklocal = oldblocklocal;
- return true;
+ return retval;
onerr:
if (initexpr) ast_delete(initexpr);
if (cond) ast_delete(cond);
if (increment) ast_delete(increment);
while (parser->locals_count > parser->blocklocal)
- parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
parser->blocklocal = oldblocklocal;
return false;
}
if (!exp)
return false;
*out = exp;
+ if (!ast_istype(exp, ast_store) &&
+ !ast_istype(exp, ast_call) &&
+ !ast_istype(exp, ast_binstore))
+ {
+ if (genwarning(ast_ctx(exp), WARN_EFFECTLESS_STATEMENT, "statement has no effect"))
+ return false;
+ }
return true;
}
}
-static void parser_pop_local(parser_t *parser)
+static bool GMQCC_WARN parser_pop_local(parser_t *parser)
{
+ varentry_t *ve;
parser->locals_count--;
+
+ ve = &parser->locals[parser->locals_count];
+ if (ast_istype(ve->var, ast_value) && !(((ast_value*)(ve->var))->uses)) {
+ if (parsewarning(parser, WARN_UNUSED_VARIABLE, "unused variable: `%s`", ve->name))
+ return false;
+ }
mem_d(parser->locals[parser->locals_count].name);
+ return true;
}
static bool parser_parse_block_into(parser_t *parser, ast_block *block, bool warnreturn)
{
size_t oldblocklocal;
+ bool retval = true;
oldblocklocal = parser->blocklocal;
parser->blocklocal = parser->locals_count;
cleanup:
while (parser->locals_count > parser->blocklocal)
- parser_pop_local(parser);
+ retval = retval && parser_pop_local(parser);
parser->blocklocal = oldblocklocal;
return !!block;
}
bool hadproto;
bool isparam;
+ bool retval = true;
+
int basetype = parser_token(parser)->constval.t;
if (!parser_next(parser)) {
!ast_block_collect(localblock, vy.var) ||
!ast_block_collect(localblock, vz.var))
{
- parser_pop_local(parser);
- parser_pop_local(parser);
- parser_pop_local(parser);
- parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
ast_value_delete(var);
ast_value_delete(typevar);
return false;
}
if (localblock && !ast_block_locals_add(localblock, var))
{
- parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
ast_value_delete(var);
ast_value_delete(typevar);
return false;
!ast_block_collect(block, vy.var) ||
!ast_block_collect(block, vz.var) )
{
- parser_pop_local(parser);
- parser_pop_local(parser);
- parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
+ (void)!parser_pop_local(parser);
ast_block_delete(block);
ast_value_delete(typevar);
return false;
}
parser->function = old;
while (parser->locals_count)
- parser_pop_local(parser);
+ retval = retval && parser_pop_local(parser);
if (!block) {
ast_value_delete(typevar);
else if (opts_standard == COMPILER_QCC)
parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)");
ast_value_delete(typevar);
- return true;
+ return retval;
} else {
ast_expression *cexp;
ast_value *cval;
{
size_t i;
ir_builder *ir;
+ bool retval = true;
if (!parser->errors)
{
}
}
for (i = 0; i < parser->globals_count; ++i) {
+ ast_value *asvalue;
if (!ast_istype(parser->globals[i].var, ast_value))
continue;
- if (!ast_global_codegen((ast_value*)(parser->globals[i].var), ir)) {
+ asvalue = (ast_value*)(parser->globals[i].var);
+ if (!asvalue->uses && !asvalue->isconst && asvalue->expression.vtype != TYPE_FUNCTION) {
+ retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE,
+ "unused global: `%s`", asvalue->name);
+ }
+ if (!ast_global_codegen(asvalue, ir)) {
printf("failed to generate global %s\n", parser->globals[i].name);
ir_builder_delete(ir);
return false;
}
}
- if (opts_dump)
- ir_builder_dump(ir, printf);
+ if (retval) {
+ if (opts_dump)
+ ir_builder_dump(ir, printf);
- if (!ir_builder_generate(ir, output)) {
- printf("*** failed to generate output file\n");
- ir_builder_delete(ir);
- return false;
+ if (!ir_builder_generate(ir, output)) {
+ printf("*** failed to generate output file\n");
+ ir_builder_delete(ir);
+ return false;
+ }
}
ir_builder_delete(ir);
- return true;
+ return retval;
}
printf("*** there were compile errors\n");