]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.cpp
Just mark LOCAL_RETURN noref instead of checking for '#' in the name
[xonotic/gmqcc.git] / parser.cpp
index fd29f008f8f78876dc2382b9cbedeb0ed2bc6911..e365316f33068520e62e684be39d97aa9fb0f47b 100644 (file)
@@ -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;