mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-18 14:21:36 +00:00
Merge branch 'arithmetic_exceptions' into cooking
Conflicts: doc/gmqcc.1 gmqcc.ini.example opts.def parser.c
This commit is contained in:
commit
53e9ed0d96
23 changed files with 908 additions and 83 deletions
|
@ -11,8 +11,6 @@ GITINFO :=
|
|||
GITINFO != git describe --always
|
||||
.endif
|
||||
|
||||
CFLAGS += -Wall -Wextra -Werror -Wstrict-aliasing -Wno-attributes
|
||||
|
||||
.if $(CC) == clang
|
||||
CFLAGS += -Weverything\
|
||||
-Wno-padded\
|
||||
|
@ -22,6 +20,7 @@ CFLAGS += -Wall -Wextra -Werror -Wstrict-aliasing -Wno-attributes
|
|||
-Wno-float-equal\
|
||||
-Wno-unknown-warning-option\
|
||||
-Wno-cast-align\
|
||||
-Wno-assign-enum\
|
||||
-pedantic-errors
|
||||
.else
|
||||
. if $(CC) != g++
|
||||
|
|
4
Makefile
4
Makefile
|
@ -4,8 +4,7 @@ UNAME ?= $(shell uname)
|
|||
CYGWIN = $(findstring CYGWIN, $(UNAME))
|
||||
MINGW = $(findstring MINGW, $(UNAME))
|
||||
|
||||
CFLAGS += -Wall -Wextra -Werror -Wstrict-aliasing -Wno-attributes
|
||||
#turn on tons of warnings if clang is present
|
||||
# turn on tons of warnings if clang is present
|
||||
# but also turn off the STUPID ONES
|
||||
ifeq ($(CC), clang)
|
||||
CFLAGS += \
|
||||
|
@ -17,6 +16,7 @@ ifeq ($(CC), clang)
|
|||
-Wno-float-equal \
|
||||
-Wno-unknown-warning-option \
|
||||
-Wno-cast-align \
|
||||
-Wno-assign-enum \
|
||||
-pedantic-errors
|
||||
else
|
||||
ifneq ($(CC), g++)
|
||||
|
|
1
ast.c
1
ast.c
|
@ -360,6 +360,7 @@ ast_value* ast_value_new(lex_ctx_t ctx, const char *name, int t)
|
|||
self->cvq = CV_NONE;
|
||||
self->hasvalue = false;
|
||||
self->isimm = false;
|
||||
self->inexact = false;
|
||||
self->uses = 0;
|
||||
memset(&self->constval, 0, sizeof(self->constval));
|
||||
self->initlist = NULL;
|
||||
|
|
1
ast.h
1
ast.h
|
@ -216,6 +216,7 @@ struct ast_value_s
|
|||
bool isfield; /* this declares a field */
|
||||
bool isimm; /* an immediate, not just const */
|
||||
bool hasvalue;
|
||||
bool inexact; /* inexact coming from folded expression */
|
||||
basic_value_t constval;
|
||||
/* for TYPE_ARRAY we have an optional vector
|
||||
* of constants when an initializer list
|
||||
|
|
|
@ -349,6 +349,10 @@ will search its intrinsics table for something that matches that
|
|||
function name by appending "__builtin_" to it. This behaviour may
|
||||
be unexpected, so enabling this will produce a diagnostic when
|
||||
such a function is resolved to a builtin.
|
||||
.It Fl W Ns Cm inexact-compares
|
||||
When comparing an inexact value such as `1.0/3.0' the result is
|
||||
pathologically wrong. Enabling this will trigger a compiler warning
|
||||
on such expressions.
|
||||
.El
|
||||
.Sh COMPILE FLAGS
|
||||
.Bl -tag -width Ds
|
||||
|
@ -587,6 +591,11 @@ Emulate OP_STATE operations in code rather than using the instruction.
|
|||
The desired fps can be set via -state-fps=NUM, defaults to 10.
|
||||
Specifying \-state-fps implicitly sets this flag. Defaults to off in all
|
||||
standards.
|
||||
.It Fl f Ns Cm arithmetic-exceptions
|
||||
Turn on arithmetic exception tests in the compiler. In constant expressions
|
||||
which trigger exceptions like division by zero, overflow, underflow, etc,
|
||||
the following flag will produce diagnostics for what triggered that
|
||||
exception.
|
||||
.El
|
||||
.Sh OPTIMIZATIONS
|
||||
.Bl -tag -width Ds
|
||||
|
|
4
exec.c
4
exec.c
|
@ -950,7 +950,7 @@ static void prog_main_setparams(qc_program_t *prog) {
|
|||
}
|
||||
}
|
||||
|
||||
void prog_disasm_function(qc_program_t *prog, size_t id);
|
||||
static void prog_disasm_function(qc_program_t *prog, size_t id);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
size_t i;
|
||||
|
@ -1265,7 +1265,7 @@ int main(int argc, char **argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void prog_disasm_function(qc_program_t *prog, size_t id) {
|
||||
static void prog_disasm_function(qc_program_t *prog, size_t id) {
|
||||
prog_section_function_t *fdef = prog->functions + id;
|
||||
prog_section_statement_t *st;
|
||||
|
||||
|
|
|
@ -316,6 +316,12 @@
|
|||
EMULATE_STATE = false
|
||||
|
||||
|
||||
#Turn on arithmetic exception tests in the compiler. In constant expressions
|
||||
#which trigger exceptions like division by zero, overflow, underflow, etc,
|
||||
#the following flag will produce diagnostics for what triggered that
|
||||
#exception.
|
||||
ARITHMETIC_EXCEPTIONS = false
|
||||
|
||||
[warnings]
|
||||
#Generate a warning about variables which are declared but never
|
||||
#used. This can be avoided by adding the ‘noref’ keyword in front
|
||||
|
@ -573,6 +579,12 @@
|
|||
BUILTINS = true
|
||||
|
||||
|
||||
#When comparing an inexact value such as `1.0/3.0' the result is
|
||||
#pathologically wrong. Enabling this will trigger a compiler warning
|
||||
#on such expressions.
|
||||
INEXACT_COMPARES = true
|
||||
|
||||
|
||||
[optimizations]
|
||||
#Some general peephole optimizations. For instance the code `a = b
|
||||
#+ c` typically generates 2 instructions, an ADD and a STORE. This
|
||||
|
|
15
include.mk
15
include.mk
|
@ -5,6 +5,9 @@ BINDIR := $(PREFIX)/bin
|
|||
DATADIR := $(PREFIX)/share
|
||||
MANDIR := $(DATADIR)/man
|
||||
|
||||
# default flags
|
||||
CFLAGS += -Wall -Wextra -Werror -Wstrict-aliasing -Wno-attributes -O2
|
||||
|
||||
# compiler
|
||||
CC ?= clang
|
||||
|
||||
|
@ -101,7 +104,12 @@ SPLINTFLAGS = \
|
|||
-observertrans \
|
||||
-abstract \
|
||||
-statictrans \
|
||||
-castfcnptr
|
||||
-castfcnptr \
|
||||
-shiftimplementation \
|
||||
-shiftnegative \
|
||||
-boolcompare \
|
||||
-infloops \
|
||||
-sysunrecog
|
||||
|
||||
#always the right rule
|
||||
default: all
|
||||
|
@ -118,13 +126,16 @@ uninstall:
|
|||
#style rule
|
||||
STYLE_MATCH = \( -name '*.[ch]' -or -name '*.def' -or -name '*.qc' \)
|
||||
|
||||
# splint cannot parse the MSVC source
|
||||
SPLINT_MATCH = \( -name '*.[ch]' -and ! -name 'msvc.c' -and ! -path './doc/*' \)
|
||||
|
||||
style:
|
||||
find . -type f $(STYLE_MATCH) -exec sed -i 's/ *$$//' '{}' ';'
|
||||
find . -type f $(STYLE_MATCH) -exec sed -i -e '$$a\' '{}' ';'
|
||||
find . -type f $(STYLE_MATCH) -exec sed -i 's/\t/ /g' '{}' ';'
|
||||
|
||||
splint:
|
||||
@splint $(SPLINTFLAGS) *.c *.h
|
||||
@splint $(SPLINTFLAGS) `find . -type f $(SPLINT_MATCH)`
|
||||
|
||||
gource:
|
||||
@gource $(GOURCEFLAGS)
|
||||
|
|
8
intrin.c
8
intrin.c
|
@ -422,7 +422,7 @@ static ast_expression *intrin_atanh(intrin_t *intrin) {
|
|||
(ast_expression*)ast_binary_new(
|
||||
intrin_ctx(intrin),
|
||||
INSTR_MUL_F,
|
||||
(ast_expression*)fold_constgen_float(intrin->fold, 0.5),
|
||||
(ast_expression*)fold_constgen_float(intrin->fold, 0.5, false),
|
||||
(ast_expression*)calllog
|
||||
)
|
||||
);
|
||||
|
@ -496,7 +496,7 @@ static ast_expression *intrin_exp(intrin_t *intrin) {
|
|||
intrin_ctx(intrin),
|
||||
INSTR_LT,
|
||||
(ast_expression*)i,
|
||||
(ast_expression*)fold_constgen_float(intrin->fold, 200.0f)
|
||||
(ast_expression*)fold_constgen_float(intrin->fold, 200.0f, false)
|
||||
),
|
||||
false,
|
||||
NULL,
|
||||
|
@ -1027,7 +1027,7 @@ static ast_expression *intrin_pow(intrin_t *intrin) {
|
|||
intrin_ctx(intrin),
|
||||
INSTR_GT,
|
||||
(ast_expression*)callfabs,
|
||||
(ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON)
|
||||
(ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON, false)
|
||||
),
|
||||
/* pre not */
|
||||
false,
|
||||
|
@ -1911,7 +1911,7 @@ static ast_expression *intrin_log_variant(intrin_t *intrin, const char *name, fl
|
|||
vec_push(value->expression.params, arg1);
|
||||
|
||||
vec_push(callln->params, (ast_expression*)arg1);
|
||||
vec_push(callln->params, (ast_expression*)fold_constgen_float(intrin->fold, base));
|
||||
vec_push(callln->params, (ast_expression*)fold_constgen_float(intrin->fold, base, false));
|
||||
|
||||
vec_push(body->exprs,
|
||||
(ast_expression*)ast_return_new(
|
||||
|
|
1
opts.c
1
opts.c
|
@ -93,6 +93,7 @@ static void opts_setdefault(void) {
|
|||
opts_set(opts.warn, WARN_CONST_OVERWRITE, true);
|
||||
opts_set(opts.warn, WARN_DIRECTIVE_INMACRO, true);
|
||||
opts_set(opts.warn, WARN_BUILTINS, true);
|
||||
opts_set(opts.warn, WARN_INEXACT_COMPARES, true);
|
||||
|
||||
/* flags */
|
||||
opts_set(opts.flags, ADJUST_VECTOR_FIELDS, true);
|
||||
|
|
2
opts.def
2
opts.def
|
@ -57,6 +57,7 @@
|
|||
GMQCC_DEFINE_FLAG(TYPELESS_STORES)
|
||||
GMQCC_DEFINE_FLAG(SORT_OPERANDS)
|
||||
GMQCC_DEFINE_FLAG(EMULATE_STATE)
|
||||
GMQCC_DEFINE_FLAG(ARITHMETIC_EXCEPTIONS)
|
||||
#endif
|
||||
|
||||
/* warning flags */
|
||||
|
@ -99,6 +100,7 @@
|
|||
GMQCC_DEFINE_FLAG(CONST_OVERWRITE)
|
||||
GMQCC_DEFINE_FLAG(DIRECTIVE_INMACRO)
|
||||
GMQCC_DEFINE_FLAG(BUILTINS)
|
||||
GMQCC_DEFINE_FLAG(INEXACT_COMPARES)
|
||||
#endif
|
||||
|
||||
#ifdef GMQCC_TYPE_OPTIMIZATIONS
|
||||
|
|
62
parser.c
62
parser.c
|
@ -1293,7 +1293,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
|
|||
if ((fun->flags & AST_FLAG_VARIADIC) &&
|
||||
!(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin))
|
||||
{
|
||||
call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount);
|
||||
call->va_count = (ast_expression*)fold_constgen_float(parser->fold, (qcfloat_t)paramcount, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1548,14 +1548,14 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
|
|||
return true;
|
||||
}
|
||||
else if (parser->tok == TOKEN_FLOATCONST) {
|
||||
ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f));
|
||||
ast_expression *val = fold_constgen_float(parser->fold, (parser_token(parser)->constval.f), false);
|
||||
if (!val)
|
||||
return false;
|
||||
vec_push(sy->out, syexp(parser_ctx(parser), val));
|
||||
return true;
|
||||
}
|
||||
else if (parser->tok == TOKEN_INTCONST || parser->tok == TOKEN_CHARCONST) {
|
||||
ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i));
|
||||
ast_expression *val = fold_constgen_float(parser->fold, (qcfloat_t)(parser_token(parser)->constval.i), false);
|
||||
if (!val)
|
||||
return false;
|
||||
vec_push(sy->out, syexp(parser_ctx(parser), val));
|
||||
|
@ -4043,7 +4043,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
|
|||
self_think = (ast_expression*)ast_entfield_new(ctx, gbl_self, fld_think);
|
||||
|
||||
time_plus_1 = (ast_expression*)ast_binary_new(ctx, INSTR_ADD_F,
|
||||
gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta));
|
||||
gbl_time, (ast_expression*)fold_constgen_float(parser->fold, frame_delta, false));
|
||||
|
||||
if (!self_frame || !self_nextthink || !self_think || !time_plus_1) {
|
||||
if (self_frame) ast_delete(self_frame);
|
||||
|
@ -4169,7 +4169,7 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
|
|||
goto enderrfn;
|
||||
}
|
||||
func->varargs = varargs;
|
||||
func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params));
|
||||
func->fixedparams = (ast_value*)fold_constgen_float(parser->fold, vec_size(var->expression.params), false);
|
||||
}
|
||||
|
||||
parser->function = func;
|
||||
|
@ -4227,7 +4227,7 @@ static ast_expression *array_accessor_split(
|
|||
|
||||
cmp = ast_binary_new(ctx, INSTR_LT,
|
||||
(ast_expression*)index,
|
||||
(ast_expression*)fold_constgen_float(parser->fold, middle));
|
||||
(ast_expression*)fold_constgen_float(parser->fold, middle, false));
|
||||
if (!cmp) {
|
||||
ast_delete(left);
|
||||
ast_delete(right);
|
||||
|
@ -4260,7 +4260,7 @@ static ast_expression *array_setter_node(parser_t *parser, ast_value *array, ast
|
|||
if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
|
||||
assignop = INSTR_STORE_V;
|
||||
|
||||
subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
|
||||
subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
|
||||
if (!subscript)
|
||||
return NULL;
|
||||
|
||||
|
@ -4326,7 +4326,7 @@ static ast_expression *array_field_setter_node(
|
|||
if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR)
|
||||
assignop = INSTR_STOREP_V;
|
||||
|
||||
subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
|
||||
subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
|
||||
if (!subscript)
|
||||
return NULL;
|
||||
|
||||
|
@ -4389,7 +4389,7 @@ static ast_expression *array_getter_node(parser_t *parser, ast_value *array, ast
|
|||
ast_return *ret;
|
||||
ast_array_index *subscript;
|
||||
|
||||
subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from));
|
||||
subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)fold_constgen_float(parser->fold, from, false));
|
||||
if (!subscript)
|
||||
return NULL;
|
||||
|
||||
|
@ -5160,6 +5160,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
|
|||
bool wasarray = false;
|
||||
|
||||
ast_member *me[3] = { NULL, NULL, NULL };
|
||||
ast_member *last_me[3] = { NULL, NULL, NULL };
|
||||
|
||||
if (!localblock && is_static)
|
||||
parseerror(parser, "`static` qualifier is not supported in global scope");
|
||||
|
@ -5623,6 +5624,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
|
|||
}
|
||||
}
|
||||
}
|
||||
memcpy(last_me, me, sizeof(me));
|
||||
me[0] = me[1] = me[2] = NULL;
|
||||
cleanvar = false;
|
||||
/* Part 2.2
|
||||
|
@ -5830,15 +5832,44 @@ skipvar:
|
|||
} else {
|
||||
ast_expression *cexp;
|
||||
ast_value *cval;
|
||||
bool folded_const = false;
|
||||
|
||||
cexp = parse_expression_leave(parser, true, false, false);
|
||||
if (!cexp)
|
||||
break;
|
||||
cval = ast_istype(cexp, ast_value) ? (ast_value*)cexp : NULL;
|
||||
|
||||
if (!localblock || is_static) {
|
||||
cval = (ast_value*)cexp;
|
||||
/* deal with foldable constants: */
|
||||
if (localblock &&
|
||||
var->cvq == CV_CONST && cval && cval->hasvalue && cval->cvq == CV_CONST && !cval->isfield)
|
||||
{
|
||||
/* remove it from the current locals */
|
||||
if (isvector) {
|
||||
for (i = 0; i < 3; ++i) {
|
||||
vec_pop(parser->_locals);
|
||||
vec_pop(localblock->collect);
|
||||
}
|
||||
}
|
||||
/* do sanity checking, this function really needs refactoring */
|
||||
if (vec_last(parser->_locals) != (ast_expression*)var)
|
||||
parseerror(parser, "internal error: unexpected change in local variable handling");
|
||||
else
|
||||
vec_pop(parser->_locals);
|
||||
if (vec_last(localblock->locals) != var)
|
||||
parseerror(parser, "internal error: unexpected change in local variable handling (2)");
|
||||
else
|
||||
vec_pop(localblock->locals);
|
||||
/* push it to the to-be-generated globals */
|
||||
vec_push(parser->globals, (ast_expression*)var);
|
||||
if (isvector)
|
||||
for (i = 0; i < 3; ++i)
|
||||
vec_push(parser->globals, (ast_expression*)last_me[i]);
|
||||
folded_const = true;
|
||||
}
|
||||
|
||||
if (folded_const || !localblock || is_static) {
|
||||
if (cval != parser->nil &&
|
||||
(!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
|
||||
(!cval || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
|
||||
)
|
||||
{
|
||||
parseerror(parser, "initializer is non constant");
|
||||
|
@ -5886,6 +5917,13 @@ skipvar:
|
|||
vec_free(sy.argc);
|
||||
var->cvq = cvq;
|
||||
}
|
||||
/* a constant initialized to an inexact value should be marked inexact:
|
||||
* const float x = <inexact>; should propagate the inexact flag
|
||||
*/
|
||||
if (var->cvq == CV_CONST && var->expression.vtype == TYPE_FLOAT) {
|
||||
if (cval && cval->hasvalue && cval->cvq == CV_CONST)
|
||||
var->inexact = cval->inexact;
|
||||
}
|
||||
}
|
||||
|
||||
another:
|
||||
|
|
2
parser.h
2
parser.h
|
@ -127,7 +127,7 @@ ast_expression *parser_find_global(parser_t *parser, const char *name);
|
|||
/* fold.c */
|
||||
fold_t *fold_init (parser_t *);
|
||||
void fold_cleanup (fold_t *);
|
||||
ast_expression *fold_constgen_float (fold_t *, qcfloat_t);
|
||||
ast_expression *fold_constgen_float (fold_t *, qcfloat_t, bool);
|
||||
ast_expression *fold_constgen_vector(fold_t *, vec3_t);
|
||||
ast_expression *fold_constgen_string(fold_t *, const char *, bool);
|
||||
bool fold_generate (fold_t *, ir_builder *);
|
||||
|
|
5
test.c
5
test.c
|
@ -1100,6 +1100,7 @@ static size_t task_schedualize(size_t *pad) {
|
|||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
size_t failed = 0;
|
||||
int status = 0;
|
||||
|
||||
util_snprintf(space[0], sizeof(space[0]), "%d", (int)vec_size(task_tasks));
|
||||
|
||||
|
@ -1167,7 +1168,9 @@ static size_t task_schedualize(size_t *pad) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (task_pclose(task_tasks[i].runhandles) != EXIT_SUCCESS && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
|
||||
status = task_pclose(task_tasks[i].runhandles);
|
||||
if ((!strcmp(task_tasks[i].tmpl->proceduretype, "-fail") && status == EXIT_SUCCESS)
|
||||
|| ( strcmp(task_tasks[i].tmpl->proceduretype, "-fail") && status == EXIT_FAILURE)) {
|
||||
con_out("failure: `%s` %*s %*s\n",
|
||||
task_tasks[i].tmpl->description,
|
||||
(pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
|
||||
|
|
13
tests/arithexcept.qc
Normal file
13
tests/arithexcept.qc
Normal file
|
@ -0,0 +1,13 @@
|
|||
const float huge = 340282346638528859811704183484516925440.000000; // FLT_MAX
|
||||
|
||||
#ifdef DIVBYZERO
|
||||
const float a = 1.0 / 0.0;
|
||||
#endif
|
||||
|
||||
#ifdef OVERFLOW
|
||||
const float a = huge * huge;
|
||||
#endif
|
||||
|
||||
#ifdef UNDERFLOW
|
||||
const float a = 1 / huge;
|
||||
#endif
|
4
tests/arithexcept.tmpl
Normal file
4
tests/arithexcept.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: arithexcept.qc
|
||||
D: arithmetic exceptions (divide by zero)
|
||||
T: -fail
|
||||
C: -std=fteqcc -farithmetic-exceptions -DDIVBYZERO
|
4
tests/arithexcept_of.tmpl
Normal file
4
tests/arithexcept_of.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: arithexcept.qc
|
||||
D: arithmetic exceptions (overflow)
|
||||
T: -fail
|
||||
C: -std=ftqcc -farithmetic-exceptions -DOVERFLOW
|
4
tests/arithexcept_uf.tmpl
Normal file
4
tests/arithexcept_uf.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: arithexcept.qc
|
||||
D: arithmetic exceptions (underflow)
|
||||
T: -fail
|
||||
C: -std=ftqcc -farithmetic-exceptions -DUNDERFLOW
|
7
tests/inexact-local.qc
Normal file
7
tests/inexact-local.qc
Normal file
|
@ -0,0 +1,7 @@
|
|||
void main() {
|
||||
const float a = 1.0 / 3.0;
|
||||
const float b = 0.33333333333;
|
||||
if (a == b) {
|
||||
// Should trigger warning
|
||||
}
|
||||
}
|
4
tests/inexact-local.tmpl
Normal file
4
tests/inexact-local.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: inexact-local.qc
|
||||
D: inexact comparisons
|
||||
T: -fail
|
||||
C: -std=gmqcc -Winexact-compares -Wall -Werror
|
8
tests/inexact.qc
Normal file
8
tests/inexact.qc
Normal file
|
@ -0,0 +1,8 @@
|
|||
const float a = 1.0 / 3.0;
|
||||
const float b = 0.33333333333;
|
||||
|
||||
void main() {
|
||||
if (a == b) {
|
||||
// Should trigger warning
|
||||
}
|
||||
}
|
4
tests/inexact.tmpl
Normal file
4
tests/inexact.tmpl
Normal file
|
@ -0,0 +1,4 @@
|
|||
I: inexact.qc
|
||||
D: inexact comparisons
|
||||
T: -fail
|
||||
C: -std=gmqcc -Winexact-compares -Wall -Werror
|
Loading…
Reference in a new issue