]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
-fbail-on-werror option
authorWolfgang Bumiller <blub@speed.at>
Thu, 27 Dec 2012 11:46:36 +0000 (12:46 +0100)
committerWolfgang Bumiller <blub@speed.at>
Thu, 27 Dec 2012 11:46:36 +0000 (12:46 +0100)
conout.c
gmqcc.h
opts.c
opts.def
parser.c

index a57881bb4a277c16ea36451c81140a292b65dc08..7c526e184015b3b2f29523230f6f07ded6d83201 100644 (file)
--- a/conout.c
+++ b/conout.c
@@ -384,6 +384,14 @@ void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ..
 size_t compile_errors = 0;
 size_t compile_warnings = 0;
 
+size_t compile_Werrors = 0;
+static lex_ctx first_werror;
+
+void compile_show_werrors()
+{
+    con_cprintmsg((void*)&first_werror, LVL_ERROR, "first warning", "was here");
+}
+
 void vcompile_error(lex_ctx ctx, const char *msg, va_list ap)
 {
     ++compile_errors;
@@ -400,8 +408,9 @@ void compile_error(lex_ctx ctx, const char *msg, ...)
 
 bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap)
 {
-    int lvl = LVL_WARNING;
-    char warn_name[1024];
+    const char *msgtype = "warning";
+    int         lvl     = LVL_WARNING;
+    char        warn_name[1024];
 
     if (!OPTS_WARN(warntype))
         return false;
@@ -410,16 +419,22 @@ bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_
     warn_name[1] = 'W';
     (void)util_strtononcmd(opts_warn_list[warntype].name, warn_name+2, sizeof(warn_name)-2);
 
+    ++compile_warnings;
     if (OPTS_WERROR(warntype)) {
-        ++compile_errors;
+        if (!compile_Werrors)
+            first_werror = ctx;
+        ++compile_Werrors;
+        msgtype = "Werror";
+        if (OPTS_FLAG(BAIL_ON_WERROR)) {
+            msgtype = "error";
+            ++compile_errors;
+        }
         lvl = LVL_ERROR;
     }
-    else
-        ++compile_warnings;
 
-    con_vprintmsg_c(lvl, ctx.file, ctx.line, ((lvl == LVL_ERROR) ? "error" : "warning"), fmt, ap, warn_name);
+    con_vprintmsg_c(lvl, ctx.file, ctx.line, msgtype, fmt, ap, warn_name);
 
-    return OPTS_WERROR(warntype);
+    return OPTS_WERROR(warntype) && OPTS_FLAG(BAIL_ON_WERROR);
 }
 
 bool GMQCC_WARN compile_warning(lex_ctx ctx, int warntype, const char *fmt, ...)
diff --git a/gmqcc.h b/gmqcc.h
index 3a47e74b8e87b532ddced13d6aedd7efbc1264dc..9dc184657ccbb2a810dd7185bb0710d65a68ebe9 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -685,12 +685,14 @@ int  con_out   (const char *, ...);
 
 /* error/warning interface */
 extern size_t compile_errors;
+extern size_t compile_Werrors;
 extern size_t compile_warnings;
 
 void /********/ compile_error   (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, ...);
 void /********/ vcompile_error  (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list ap);
 bool GMQCC_WARN compile_warning (lex_ctx ctx, int warntype, const char *fmt, ...);
 bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap);
+void            compile_show_werrors();
 
 /*===================================================================*/
 /*========================= assembler.c =============================*/
diff --git a/opts.c b/opts.c
index 269a69d0dc813bfec4b5a07c0e07651aefd37ee9..334186b8cf9a034764d38c53734026d350631f74 100644 (file)
--- a/opts.c
+++ b/opts.c
@@ -59,6 +59,7 @@ static void opts_setdefault() {
     opts_set(opts.flags, FTEPP,                          false);
     opts_set(opts.flags, FTEPP_PREDEFS,                  false);
     opts_set(opts.flags, CORRECT_TERNARY,                true);
+    opts_set(opts.flags, BAIL_ON_WERROR,                 true);
 }
 
 void opts_init(const char *output, int standard, size_t arraysize) {
index f6582efef911e1b14c819d3430bfd112aa1ed9d8..26994c428bdbeb1743109880d716bfdb30f9a25e 100644 (file)
--- a/opts.def
+++ b/opts.def
@@ -45,6 +45,7 @@
     GMQCC_DEFINE_FLAG(TRUE_EMPTY_STRINGS)
     GMQCC_DEFINE_FLAG(FALSE_EMPTY_STRINGS)
     GMQCC_DEFINE_FLAG(UTF8)
+    GMQCC_DEFINE_FLAG(BAIL_ON_WERROR)
 #endif
 
 /* warning flags */
index a11c70955878c248adbef9c0bd7b48307abaafd2..422930d0d8d1ca7612caee58af4e41ac92f2665a 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -76,8 +76,6 @@ typedef struct {
     size_t          *_blocktypedefs;
     lex_ctx         *_block_ctx;
 
-    size_t errors;
-
     /* we store the '=' operator info */
     const oper_info *assign_op;
 
@@ -114,11 +112,8 @@ static ast_expression* parse_expression(parser_t *parser, bool stopatcomma);
 static void parseerror(parser_t *parser, const char *fmt, ...)
 {
     va_list ap;
-
-    parser->errors++;
-
     va_start(ap, fmt);
-    con_vprintmsg(LVL_ERROR, parser->lex->tok.ctx.file, parser->lex->tok.ctx.line, "parse error", fmt, ap);
+    vcompile_error(parser->lex->tok.ctx, fmt, ap);
     va_end(ap);
 }
 
@@ -992,11 +987,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                         field->expression.next->expression.vtype == TYPE_FUNCTION &&
                         exprs[1]->expression.vtype == TYPE_FUNCTION)
                     {
-                        if (parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
-                                         "invalid types in assignment: cannot assign %s to %s", ty2, ty1))
-                        {
-                            parser->errors++;
-                        }
+                        (void)!parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
+                                            "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
                     }
                     else
                         parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
@@ -1026,11 +1018,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                         exprs[0]->expression.vtype == TYPE_FUNCTION &&
                         exprs[1]->expression.vtype == TYPE_FUNCTION)
                     {
-                        if (parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
-                                         "invalid types in assignment: cannot assign %s to %s", ty2, ty1))
-                        {
-                            parser->errors++;
-                        }
+                        (void)!parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
+                                            "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
                     }
                     else
                         parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
@@ -1306,8 +1295,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
             params->exprs = NULL;
             ast_delete(params);
         }
-        if (!ast_call_check_types(call))
-            parser->errors++;
+        (void)!ast_call_check_types(call);
     } else {
         parseerror(parser, "invalid function call");
         return false;
@@ -1873,10 +1861,8 @@ static bool parser_leaveblock(parser_t *parser)
         ast_value      *v = (ast_value*)e;
         vec_pop(parser->_locals);
         if (ast_istype(e, ast_value) && !v->uses) {
-            if (compile_warning(ast_ctx(v), WARN_UNUSED_VARIABLE, "unused variable: `%s`", v->name)) {
-                parser->errors++;
+            if (compile_warning(ast_ctx(v), WARN_UNUSED_VARIABLE, "unused variable: `%s`", v->name))
                 rv = false;
-            }
         }
     }
 
@@ -4742,7 +4728,7 @@ bool parser_compile()
             if (!parser_global_statement(parser)) {
                 if (parser->tok == TOKEN_EOF)
                     parseerror(parser, "unexpected eof");
-                else if (!parser->errors)
+                else if (compile_errors)
                     parseerror(parser, "there have been errors, bailing out");
                 lex_close(parser->lex);
                 parser->lex = NULL;
@@ -4759,7 +4745,7 @@ bool parser_compile()
     lex_close(parser->lex);
     parser->lex = NULL;
 
-    return !parser->errors;
+    return !compile_errors;
 }
 
 bool parser_compile_file(const char *filename)
@@ -4844,133 +4830,138 @@ bool parser_finish(const char *output)
     ir_builder *ir;
     bool retval = true;
 
-    if (!parser->errors)
-    {
-        ir = ir_builder_new("gmqcc_out");
-        if (!ir) {
-            con_out("failed to allocate builder\n");
+    if (compile_errors) {
+        con_out("*** there were compile errors\n");
+        return false;
+    }
+
+    ir = ir_builder_new("gmqcc_out");
+    if (!ir) {
+        con_out("failed to allocate builder\n");
+        return false;
+    }
+
+    for (i = 0; i < vec_size(parser->fields); ++i) {
+        ast_value *field;
+        bool hasvalue;
+        if (!ast_istype(parser->fields[i], ast_value))
+            continue;
+        field = (ast_value*)parser->fields[i];
+        hasvalue = field->hasvalue;
+        field->hasvalue = false;
+        if (!ast_global_codegen((ast_value*)field, ir, true)) {
+            con_out("failed to generate field %s\n", field->name);
+            ir_builder_delete(ir);
             return false;
         }
-
-        for (i = 0; i < vec_size(parser->fields); ++i) {
-            ast_value *field;
-            bool hasvalue;
-            if (!ast_istype(parser->fields[i], ast_value))
-                continue;
-            field = (ast_value*)parser->fields[i];
-            hasvalue = field->hasvalue;
-            field->hasvalue = false;
-            if (!ast_global_codegen((ast_value*)field, ir, true)) {
-                con_out("failed to generate field %s\n", field->name);
-                ir_builder_delete(ir);
-                return false;
-            }
-            if (hasvalue) {
-                ir_value *ifld;
-                ast_expression *subtype;
-                field->hasvalue = true;
-                subtype = field->expression.next;
-                ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype);
-                if (subtype->expression.vtype == TYPE_FIELD)
-                    ifld->fieldtype = subtype->expression.next->expression.vtype;
-                else if (subtype->expression.vtype == TYPE_FUNCTION)
-                    ifld->outtype = subtype->expression.next->expression.vtype;
-                (void)!ir_value_set_field(field->ir_v, ifld);
-            }
-        }
-        for (i = 0; i < vec_size(parser->globals); ++i) {
-            ast_value *asvalue;
-            if (!ast_istype(parser->globals[i], ast_value))
-                continue;
-            asvalue = (ast_value*)(parser->globals[i]);
-            if (!asvalue->uses && !asvalue->hasvalue && 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, false)) {
-                con_out("failed to generate global %s\n", asvalue->name);
-                ir_builder_delete(ir);
-                return false;
-            }
+        if (hasvalue) {
+            ir_value *ifld;
+            ast_expression *subtype;
+            field->hasvalue = true;
+            subtype = field->expression.next;
+            ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype);
+            if (subtype->expression.vtype == TYPE_FIELD)
+                ifld->fieldtype = subtype->expression.next->expression.vtype;
+            else if (subtype->expression.vtype == TYPE_FUNCTION)
+                ifld->outtype = subtype->expression.next->expression.vtype;
+            (void)!ir_value_set_field(field->ir_v, ifld);
         }
-        for (i = 0; i < vec_size(parser->imm_float); ++i) {
-            if (!ast_global_codegen(parser->imm_float[i], ir, false)) {
-                con_out("failed to generate global %s\n", parser->imm_float[i]->name);
-                ir_builder_delete(ir);
-                return false;
-            }
+    }
+    for (i = 0; i < vec_size(parser->globals); ++i) {
+        ast_value *asvalue;
+        if (!ast_istype(parser->globals[i], ast_value))
+            continue;
+        asvalue = (ast_value*)(parser->globals[i]);
+        if (!asvalue->uses && !asvalue->hasvalue && 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, false)) {
+            con_out("failed to generate global %s\n", asvalue->name);
+            ir_builder_delete(ir);
+            return false;
         }
-        for (i = 0; i < vec_size(parser->imm_string); ++i) {
-            if (!ast_global_codegen(parser->imm_string[i], ir, false)) {
-                con_out("failed to generate global %s\n", parser->imm_string[i]->name);
-                ir_builder_delete(ir);
-                return false;
-            }
+    }
+    for (i = 0; i < vec_size(parser->imm_float); ++i) {
+        if (!ast_global_codegen(parser->imm_float[i], ir, false)) {
+            con_out("failed to generate global %s\n", parser->imm_float[i]->name);
+            ir_builder_delete(ir);
+            return false;
         }
-        for (i = 0; i < vec_size(parser->imm_vector); ++i) {
-            if (!ast_global_codegen(parser->imm_vector[i], ir, false)) {
-                con_out("failed to generate global %s\n", parser->imm_vector[i]->name);
-                ir_builder_delete(ir);
-                return false;
-            }
+    }
+    for (i = 0; i < vec_size(parser->imm_string); ++i) {
+        if (!ast_global_codegen(parser->imm_string[i], ir, false)) {
+            con_out("failed to generate global %s\n", parser->imm_string[i]->name);
+            ir_builder_delete(ir);
+            return false;
         }
-        for (i = 0; i < vec_size(parser->globals); ++i) {
-            ast_value *asvalue;
-            if (!ast_istype(parser->globals[i], ast_value))
-                continue;
-            asvalue = (ast_value*)(parser->globals[i]);
-            if (!ast_generate_accessors(asvalue, ir)) {
-                ir_builder_delete(ir);
-                return false;
-            }
+    }
+    for (i = 0; i < vec_size(parser->imm_vector); ++i) {
+        if (!ast_global_codegen(parser->imm_vector[i], ir, false)) {
+            con_out("failed to generate global %s\n", parser->imm_vector[i]->name);
+            ir_builder_delete(ir);
+            return false;
         }
-        for (i = 0; i < vec_size(parser->fields); ++i) {
-            ast_value *asvalue;
-            asvalue = (ast_value*)(parser->fields[i]->expression.next);
+    }
+    for (i = 0; i < vec_size(parser->globals); ++i) {
+        ast_value *asvalue;
+        if (!ast_istype(parser->globals[i], ast_value))
+            continue;
+        asvalue = (ast_value*)(parser->globals[i]);
+        if (!ast_generate_accessors(asvalue, ir)) {
+            ir_builder_delete(ir);
+            return false;
+        }
+    }
+    for (i = 0; i < vec_size(parser->fields); ++i) {
+        ast_value *asvalue;
+        asvalue = (ast_value*)(parser->fields[i]->expression.next);
 
-            if (!ast_istype((ast_expression*)asvalue, ast_value))
-                continue;
-            if (asvalue->expression.vtype != TYPE_ARRAY)
-                continue;
-            if (!ast_generate_accessors(asvalue, ir)) {
-                ir_builder_delete(ir);
-                return false;
-            }
+        if (!ast_istype((ast_expression*)asvalue, ast_value))
+            continue;
+        if (asvalue->expression.vtype != TYPE_ARRAY)
+            continue;
+        if (!ast_generate_accessors(asvalue, ir)) {
+            ir_builder_delete(ir);
+            return false;
         }
-        for (i = 0; i < vec_size(parser->functions); ++i) {
-            if (!ast_function_codegen(parser->functions[i], ir)) {
-                con_out("failed to generate function %s\n", parser->functions[i]->name);
-                ir_builder_delete(ir);
-                return false;
-            }
+    }
+    for (i = 0; i < vec_size(parser->functions); ++i) {
+        if (!ast_function_codegen(parser->functions[i], ir)) {
+            con_out("failed to generate function %s\n", parser->functions[i]->name);
+            ir_builder_delete(ir);
+            return false;
         }
-        if (opts.dump)
-            ir_builder_dump(ir, con_out);
-        for (i = 0; i < vec_size(parser->functions); ++i) {
-            if (!ir_function_finalize(parser->functions[i]->ir_func)) {
-                con_out("failed to finalize function %s\n", parser->functions[i]->name);
-                ir_builder_delete(ir);
-                return false;
-            }
+    }
+    if (opts.dump)
+        ir_builder_dump(ir, con_out);
+    for (i = 0; i < vec_size(parser->functions); ++i) {
+        if (!ir_function_finalize(parser->functions[i]->ir_func)) {
+            con_out("failed to finalize function %s\n", parser->functions[i]->name);
+            ir_builder_delete(ir);
+            return false;
         }
+    }
 
-        if (retval) {
-            if (opts.dumpfin)
-                ir_builder_dump(ir, con_out);
+    if (compile_Werrors) {
+        con_out("*** there were warnings treated as errors\n");
+        compile_show_werrors();
+        retval = false;
+    }
 
-            generate_checksum(parser);
+    if (retval) {
+        if (opts.dumpfin)
+            ir_builder_dump(ir, con_out);
 
-            if (!ir_builder_generate(ir, output)) {
-                con_out("*** failed to generate output file\n");
-                ir_builder_delete(ir);
-                return false;
-            }
-        }
+        generate_checksum(parser);
 
-        ir_builder_delete(ir);
-        return retval;
+        if (!ir_builder_generate(ir, output)) {
+            con_out("*** failed to generate output file\n");
+            ir_builder_delete(ir);
+            return false;
+        }
     }
 
-    con_out("*** there were compile errors\n");
-    return false;
+    ir_builder_delete(ir);
+    return retval;
 }