diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index d914ec83d..78f907f68 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -944,6 +944,7 @@ enum { ERR_BADPLUSPLUSOPERATOR, ERR_BADNOTTYPE, ERR_BADTYPECAST, + ERR_BADMEMBER, ERR_MULTIPLEDEFAULTS, ERR_CASENOTIMMEDIATE, ERR_BADSWITCHTYPE, diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 3de155c98..234adc004 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -4600,6 +4600,12 @@ QCC_sref_t QCC_PR_StatementFlags ( QCC_opcode_t *op, QCC_sref_t var_a, QCC_sref_ return var_c; } break; + case OP_BITNOT_I64: + op = &pr_opcodes[OP_SUB_I64]; + var_b = var_a; + var_a = QCC_MakeInt64Const(~(longlong)0); + var_a.sym->referenced = true; + break; case OP_BITNOT_F: op = &pr_opcodes[OP_SUB_F]; var_b = var_a; @@ -5905,7 +5911,7 @@ static void QCC_PrecacheFile (const char *n, int ch) static void QCC_VerifyFormatString (const char *funcname, QCC_ref_t **arglist, unsigned int argcount) { - const char *s = "%s"; + const char *s = "%s", *reqtype; int firstarg = 1; const char *s0; char *err; @@ -6072,6 +6078,7 @@ noflags: //case 'll': //long long case 'l': isfloat = 0; break; //long case 'L': isfloat = 0; break; //long double + //case 'q': break; //long long in c case 'j': //[u]intmax_t case 'z': //size_t case 't': //ptrdiff_t @@ -6109,6 +6116,7 @@ nolength: memcpy(formatbuf, s0, s+1-s0); formatbuf[s+1-s0] = 0; + reqtype = NULL; switch(*s) { //fixme: should we validate char ranges? @@ -6123,9 +6131,7 @@ nolength: case ev_variant: break; default: - { - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires float at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); - } + reqtype = "float"; break; } } @@ -6139,7 +6145,7 @@ nolength: case ev_variant: break; default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires pointer at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); + reqtype = "pointer"; break; } } @@ -6156,6 +6162,7 @@ nolength: break; //fallthrough default: + reqtype = "int"; QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires int at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); break; } @@ -6171,12 +6178,12 @@ nolength: case ev_variant: break; default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires vector at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); + reqtype = "vector"; break; } } else - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires intvector at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); + reqtype = "intvector"; break; case 's': case 'S': @@ -6186,7 +6193,7 @@ nolength: case ev_variant: break; default: - QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires string at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); + reqtype = "string"; break; } break; @@ -6194,6 +6201,52 @@ nolength: QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: invalid format string: %s%s%s", funcname, col_name, s0, col_none); return; } + + if (reqtype) + { + QCC_PR_ParseWarning(WARN_FORMATSTRING, "%s: %s%s%s requires %s at arg %i (got %s%s%s)", funcname, col_name, formatbuf, col_none, reqtype, thisarg+1, col_type, TypeName(ARGCTYPE(thisarg), temp, sizeof(temp)), col_none); + switch(ARGCTYPE(thisarg)->type) + { + case ev_string: + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %s or %S for strings"); + break; + case ev_float: + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %g or %f or %hx for floats"); + break; + case ev_vector: + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %v for vectors"); + break; + case ev_entity: + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %i for entities"); + break; + case ev_pointer: + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %p for pointer types"); + break; + case ev_integer: + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %i or %lx for 32bit ints"); + break; + case ev_uint: + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "use %lu or or %lx for 32bit ints"); + break; + + case ev_void: //coder's problem + case ev_field: //cast to int + case ev_function: //cast to int + case ev_variant: //should be accepted by anything... + case ev_int64: //specification problem + case ev_uint64: //specification problem + case ev_double: //specification problem + case ev_struct: //coder's problem + case ev_union: //coder's problem + case ev_accessor: //should be unreachable + case ev_enum: //should be unreachable + case ev_typedef: //should be unreachable + case ev_boolean: //should be unreachable + QCC_PR_Note(WARN_FORMATSTRING, s_filen, pr_source_line, "%s", "cast to something else"); + break; + } + } + s++; break; default: @@ -8963,9 +9016,9 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs) return refbuf; } if (t->parentclass) - QCC_PR_ParseError(ERR_INTERNAL, "%s is not a field of class %s", QCC_GetSRefName(QCC_RefToDef(field, false)), t->name); + QCC_PR_ParseError(ERR_BADMEMBER, "%s is not a field of class %s", QCC_GetSRefName(QCC_RefToDef(field, false)), t->name); else - QCC_PR_ParseError(ERR_INTERNAL, "%s is not a field", QCC_GetSRefName(QCC_RefToDef(field, false))); + QCC_PR_ParseError(ERR_BADMEMBER, "%s is not a field", QCC_GetSRefName(QCC_RefToDef(field, false))); } lhs = QCC_PR_ParseField(refbuf, lhs); @@ -8973,7 +9026,12 @@ static QCC_ref_t *QCC_PR_ParseField(QCC_ref_t *refbuf, QCC_ref_t *lhs) lhs = QCC_PR_ParseRefArrayPointer (refbuf, lhs, false, false); } else - QCC_PR_ParseError(ERR_INTERNAL, "%s is not a member of %s", QCC_PR_ParseName(), t->name); + { + QCC_PR_ParseWarning(ERR_BADMEMBER, "%s is not a member of %s", QCC_PR_ParseName(), t->name); + if (t->filen) + QCC_PR_Note(ERR_BADMEMBER, t->filen, t->line, "%s is defined here", t->name); + return QCC_PR_BuildRef(refbuf, REF_GLOBAL, QCC_MakeIntConst(0), nullsref, type_void, false); + } } else if (flag_qccx && t->type == ev_entity && QCC_PR_CheckToken("[")) { //p[%0] gives a regular array reference. except that p is probably a float, and we're expecting OP_LOAD_F @@ -9383,7 +9441,11 @@ fieldarrayindex: return QCC_PR_ParseRefArrayPointer(retbuf, r, allowarrayassign, makearraypointers); } } - QCC_PR_ParseError(0, "%s is not a member of %s", mname, tname); + + QCC_PR_ParseWarning(ERR_BADMEMBER, "%s is not a member of %s", mname, t->name); + if (t->filen) + QCC_PR_Note(ERR_BADMEMBER, t->filen, t->line, "%s is defined here", t->name); + QCC_PR_ParseError(ERR_BADMEMBER, NULL); } if (!ofs && idx.cast) ; diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 48076f627..e5624f29e 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -4074,11 +4074,14 @@ NORETURN void VARGS QCC_PR_ParseError (int errortype, const char *error, ...) editbadfile(s_filen, pr_source_line); #endif - QCC_PR_PrintScope(); - if (flag_msvcstyle) - externs->Printf ("%s%s(%i) : %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string); - else - externs->Printf ("%s%s:%i: %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string); + if (error) + { + QCC_PR_PrintScope(); + if (flag_msvcstyle) + externs->Printf ("%s%s(%i) : %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string); + else + externs->Printf ("%s%s:%i: %serror%s: %s\n", col_location, s_filen, pr_source_line, col_error, col_none, string); + } longjmp (pr_parse_abort, 1); }