X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.cpp;h=e365316f33068520e62e684be39d97aa9fb0f47b;hp=fd29f008f8f78876dc2382b9cbedeb0ed2bc6911;hb=c285eb385d628e89f98f6d2552f6abc3f23b8a3c;hpb=45236a644fb45ac9f61c3ef38bcab17b5004b095 diff --git a/parser.cpp b/parser.cpp index fd29f00..e365316 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1668,13 +1668,16 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) } 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)); @@ -2020,15 +2023,8 @@ static bool parser_leaveblock(parser_t *parser) 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) { @@ -2523,8 +2519,7 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou parseerror(parser, "expected for-loop condition"); goto onerr; } - } - else if (!parser_next(parser)) { + } else if (!parser_next(parser)) { parseerror(parser, "expected for-loop condition"); goto onerr; } @@ -2535,7 +2530,6 @@ static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **ou if (!cond) goto onerr; } - /* move on to incrementor */ if (parser->tok != ';') { parseerror(parser, "expected semicolon after for-loop initializer"); @@ -2636,6 +2630,7 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou retval = new ast_value(ctx, "#LOCAL_RETURN", TYPE_VOID); retval->adoptType(*expected->m_next); parser->function->m_return_value = retval; + parser->function->m_return_value->m_flags |= AST_FLAG_NOREF; } if (!exp->compareType(*retval)) { @@ -3122,6 +3117,52 @@ static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression * return false; } swcase.m_value = parse_expression_leave(parser, false, false, false); + + if (!operand->compareType(*swcase.m_value)) { + char ty1[1024]; + char ty2[1024]; + + ast_type_to_string(swcase.m_value, ty1, sizeof ty1); + ast_type_to_string(operand, ty2, sizeof ty2); + + auto fnLiteral = [](ast_expression *expression) -> char* { + if (!ast_istype(expression, ast_value)) + return nullptr; + ast_value *value = (ast_value *)expression; + if (!value->m_hasvalue) + return nullptr; + char *string = nullptr; + basic_value_t *constval = &value->m_constval; + switch (value->m_vtype) + { + case TYPE_FLOAT: + util_asprintf(&string, "%.2f", constval->vfloat); + return string; + case TYPE_VECTOR: + util_asprintf(&string, "'%.2f %.2f %.2f'", + constval->vvec.x, + constval->vvec.y, + constval->vvec.z); + return string; + case TYPE_STRING: + util_asprintf(&string, "\"%s\"", constval->vstring); + return string; + default: + break; + } + return nullptr; + }; + + char *literal = fnLiteral(swcase.m_value); + if (literal) + compile_error(parser_ctx(parser), "incompatible type `%s` for switch case `%s` expected `%s`", ty1, literal, ty2); + else + compile_error(parser_ctx(parser), "incompatible type `%s` for switch case expected `%s`", ty1, ty2); + mem_d(literal); + delete switchnode; + return false; + } + if (!swcase.m_value) { delete switchnode; parseerror(parser, "expected expression for case"); @@ -5188,12 +5229,12 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* 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; } @@ -5353,9 +5394,8 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } } - /* 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. @@ -5756,7 +5796,10 @@ skipvar: 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; @@ -6031,6 +6074,7 @@ parser_t *parser_create() 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; @@ -6215,12 +6259,12 @@ bool parser_finish(parser_t *parser, const char *output) ast_expression *subtype; field->m_hasvalue = true; subtype = field->m_next; - ifld = ir_builder_create_field(ir, field->m_name, subtype->m_vtype); + ifld = ir->createField(field->m_name, subtype->m_vtype); if (subtype->m_vtype == TYPE_FIELD) ifld->m_fieldtype = subtype->m_next->m_vtype; else if (subtype->m_vtype == TYPE_FUNCTION) ifld->m_outtype = subtype->m_next->m_vtype; - (void)!ir_value_set_field(field->m_ir_v, ifld); + (void)!field->m_ir_v->setField(ifld); } } for (auto &it : parser->globals) { @@ -6228,7 +6272,7 @@ bool parser_finish(parser_t *parser, const char *output) if (!ast_istype(it, ast_value)) continue; asvalue = (ast_value*)it; - if (!asvalue->m_uses && !asvalue->m_hasvalue && 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); } @@ -6316,7 +6360,7 @@ bool parser_finish(parser_t *parser, const char *output) generate_checksum(parser, ir); if (OPTS_OPTION_BOOL(OPTION_DUMP)) - ir_builder_dump(ir, con_out); + ir->dump(con_out); for (auto &it : parser->functions) { if (!ir_function_finalize(it->m_ir_func)) { con_out("failed to finalize function %s\n", it->m_name.c_str()); @@ -6326,21 +6370,28 @@ bool parser_finish(parser_t *parser, const char *output) } parser_remove_ast(parser); - if (compile_Werrors) { - con_out("*** there were warnings treated as errors\n"); - compile_show_werrors(); - retval = false; - } + auto fnCheckWErrors = [&retval]() { + if (compile_Werrors) { + con_out("*** there were warnings treated as errors\n"); + compile_show_werrors(); + retval = false; + } + }; + + fnCheckWErrors(); if (retval) { if (OPTS_OPTION_BOOL(OPTION_DUMPFIN)) - ir_builder_dump(ir, con_out); + ir->dump(con_out); - if (!ir_builder_generate(ir, output)) { + if (!ir->generate(output)) { con_out("*** failed to generate output file\n"); delete ir; return false; } + + // ir->generate can generate compiler warnings + fnCheckWErrors(); } delete ir; return retval;