1
0
Fork 0
forked from fte/fteqw

Make class parsing more c++-like, fix some issues with uninitialised variables not getting detected properly.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@6322 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2023-01-09 05:13:12 +00:00
parent 6700dfd289
commit ed63b7435e
5 changed files with 557 additions and 349 deletions

View file

@ -3253,6 +3253,7 @@ void DecompileProgsDat(char *name, void *buf, size_t bufsize)
type_bint = type_integer;
type_variant = QCC_PR_NewType("variant", ev_variant, true);
type_variant = QCC_PR_NewType("__variant", ev_variant, true);
type_invalid = QCC_PR_NewType("invalid", ev_void, false);
DecompileReadData(name, buf, bufsize);
DecompileDecompileFunctions(c);

View file

@ -508,7 +508,7 @@ extern int QCC_packid;
extern const unsigned int type_size[];
//extern QCC_def_t *def_for_type[9];
extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_integer, *type_uint, *type_int64, *type_uint64, *type_variant, *type_floatfield;
extern QCC_type_t *type_void, *type_string, *type_float, *type_double, *type_vector, *type_entity, *type_field, *type_function, *type_floatfunction, *type_pointer, *type_floatpointer, *type_intpointer, *type_bint, *type_bfloat, *type_integer, *type_uint, *type_int64, *type_uint64, *type_invalid, *type_variant, *type_floatfield;
extern char *basictypenames[];
struct QCC_function_s
@ -819,7 +819,7 @@ enum {
WARN_BADPRAGMA,
WARN_NOTUTF8,
WARN_HANGINGSLASHR,
WARN_NOTDEFINED,
WARN_MEMBERNOTDEFINED,
WARN_NOTCONSTANT,
WARN_SWITCHTYPEMISMATCH,
WARN_CONFLICTINGUNIONMEMBER,
@ -1095,7 +1095,7 @@ void QCC_PR_EmitArrayGetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char
void QCC_PR_EmitArraySetFunction(QCC_def_t *defscope, QCC_def_t *thearray, char *arrayname);
void QCC_PR_EmitClassFromFunction(QCC_def_t *defscope, QCC_type_t *basetype);
void QCC_PR_ParseDefs (char *classname, pbool fatal);
void QCC_PR_ParseDefs (const char *classname, pbool fatal);
QCC_def_t *QCC_PR_DummyDef(QCC_type_t *type, const char *name, QCC_function_t *scope, int arraysize, QCC_def_t *rootsymbol, unsigned int ofs, int referable, unsigned int flags);
void QCC_PR_ParseInitializerDef(QCC_def_t *def, unsigned int flags);
void QCC_PR_FinaliseFunctions(void);

View file

@ -10524,8 +10524,54 @@ static QCC_ref_t *QCC_PR_RefTerm (QCC_ref_t *retbuf, unsigned int exprflags)
return QCC_DefToRef(retbuf, QCC_MakeIntConst(sz));
}
}
/*if (QCC_PR_CheckKeyword(keyword_new, "new"))
{ //note: C++ requires struct-based classes rather than entity ones.
const char *cname = QCC_PR_ParseName();
QCC_type_t *rettype = QCC_TypeForName(cname);
QCC_sref_t result, func;
if (!rettype || rettype->type != ev_entity)
QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "new %s() unsupported argument type for intrinsic", cname);
e = QCC_PR_GetSRef(NULL, "spawn", NULL, 0, 0, 0);
if (!e.cast)
QCC_PR_ParseError (ERR_TYPEMISMATCHPARM, "new %s() spawn builtin not defined", cname);
result = QCC_PR_GenerateFunctionCallRef(nullsref, e, NULL,0);
result.cast = rettype;
if (QCC_PR_CheckToken("("))
{ //arglist is optional, apparently
char genfunc[256];
//do field assignments.
while(QCC_PR_CheckToken(","))
{
QCC_sref_t f, p, v;
f = QCC_PR_ParseValue(rettype, false, false, true);
if (f.cast->type != ev_field)
QCC_PR_ParseError(0, "Named field is not a field.");
if (QCC_PR_CheckToken("=")) //allow : or = as a separator, but throw a warning for =
QCC_PR_ParseWarning(0, "That = should be a :"); //rejecting = helps avoid qcc bugs. :P
else
QCC_PR_Expect(":");
v = QCC_PR_Expression(TOP_PRIORITY, EXPR_DISALLOW_COMMA);
p = QCC_PR_StatementFlags(&pr_opcodes[OP_ADDRESS], result, f, NULL, STFL_PRESERVEA);
if (v.cast->size == 3)
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STOREP_V], v, p, NULL));
else
QCC_FreeTemp(QCC_PR_Statement(&pr_opcodes[OP_STOREP_F], v, p, NULL));
}
QCC_PR_Expect(")");
QC_snprintfz(genfunc, sizeof(genfunc), "spawnfunc_%s", rettype->name);
func = QCC_PR_GetSRef(type_function, genfunc, NULL, true, 0, GDF_CONST);
func.sym->referenced = true;
QCC_UnFreeTemp(result);
QCC_FreeTemp(QCC_PR_GenerateFunctionCallRef(result, func, NULL, 0));
result.cast = rettype;
}
return QCC_DefToRef(retbuf, result);
}*/
if (QCC_PR_CheckKeyword(true, "_length"))
{ //for compat with gmqcc
{ //for compat with gmqcc. use array.length in fte instead.
pbool bracket = QCC_PR_CheckToken("(");
/*QCC_type_t *t;
t = QCC_PR_ParseType(false, true);
@ -15047,8 +15093,27 @@ void QCC_CommonSubExpressionRemoval(int first, int last)
//follow branches (by recursing).
//stop on first read(error, return statement) or write(no error, return -1)
//end-of-block returns 0, done/return/goto returns -2
static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_def_t *def, unsigned int min, unsigned int max)
static int QCC_CheckOneUninitialised(int firststatement, int laststatement, union QCC_eval_basic_s *min, union QCC_eval_basic_s *max)
{
#define SPLIT \
if (!(ofs > max || ofs+sz <= min)) \
{ \
if (min < ofs) \
{ /*keep checking before*/ \
ret = QCC_CheckOneUninitialised(i + 1, laststatement, min, ofs); \
if (ret > 0) \
return ret; \
} \
if (ofs+sz < max) \
{ /*keep checking after*/ \
ret = QCC_CheckOneUninitialised(i + 1, laststatement, ofs+sz, max); \
if (ret > 0) \
return ret; \
} \
if (iswrite) \
return -1; /*okay, we wrote it all*/ \
return i; /*an error when its a read*/ \
}
int ret;
int i;
QCC_statement_t *st;
@ -15059,46 +15124,44 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
if (st->op == OP_DONE || st->op == OP_RETURN)
{
if (st->a.sym && st->a.sym->symbolheader == def && st->a.ofs >= min && st->a.ofs < max)
return i;
if (st->a.cast && st->a.sym)
{
union QCC_eval_basic_s *ofs = st->a.sym->symboldata+st->a.ofs;
int sz = st->a.cast->size;
if (!(ofs > max || ofs+sz < min))
return i;
}
return -2;
}
if (st->op == OP_GLOBALADDRESS && st->a.sym && (st->a.sym->symbolheader == def || (st->a.sym->symbolheader == def)))
return -1; //assume taking a pointer to it is an initialisation.
// this code catches gotos, but can cause issues with while statements.
// if (st->op == OP_GOTO && (int)st->a < 1)
// return -2;
if (pr_opcodes[st->op].type_a)
if (pr_opcodes[st->op].type_a && st->a.sym)
{
if (st->a.sym && st->a.sym->symbolheader == def && st->a.ofs >= min && st->a.ofs < max)
{
if (OpAssignsToA(st->op))
return -1;
union QCC_eval_basic_s *ofs = st->a.sym->symboldata+st->a.ofs;
int sz = st->a.cast->size;
pbool iswrite = OpAssignsToA(st->op) || st->op == OP_GLOBALADDRESS; /* address-of counts as a write here, because we're too dumb to track when/if that is assigned to.*/
return i;
}
SPLIT
}
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->a.ofs > 0 && !st->a.sym)
{
int jump = i + (int)st->a.ofs;
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);
ret = QCC_CheckOneUninitialised(i + 1, jump, min, max);
if (ret > 0)
return ret;
i = jump-1;
}
if (pr_opcodes[st->op].type_b)
if (pr_opcodes[st->op].type_b && st->b.sym)
{
if (st->b.sym && st->b.sym->symbolheader == def && st->b.ofs >= min && st->b.ofs < max)
{
if (OpAssignsToB(st->op))
return -1;
union QCC_eval_basic_s *ofs = st->b.sym->symboldata+st->b.ofs;
int sz = st->b.cast->size;
pbool iswrite = OpAssignsToB(st->op);
return i;
}
SPLIT
}
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->b.ofs > 0 && !st->b.sym && !(st->flags & STF_LOGICOP))
{
@ -15108,10 +15171,10 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
if (st->op == OP_GOTO && (int)st->a.ofs > 0)
{
int jump2 = jump-1 + st->a.ofs;
int rett = QCC_CheckOneUninitialised(i + 1, jump - 1, def, min, max);
int rett = QCC_CheckOneUninitialised(i + 1, jump - 1, min, max);
if (rett > 0)
return rett;
ret = QCC_CheckOneUninitialised(jump, jump2, def, min, max);
ret = QCC_CheckOneUninitialised(jump, jump2, min, max);
if (ret > 0)
return ret;
if (rett < 0 && ret < 0)
@ -15120,7 +15183,7 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
}
else
{
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);
ret = QCC_CheckOneUninitialised(i + 1, jump, min, max);
if (ret > 0)
return ret;
i = jump-1;
@ -15128,17 +15191,18 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
continue;
}
if (pr_opcodes[st->op].type_c && st->c.sym && st->c.sym->symbolheader == def && st->c.ofs >= min && st->c.ofs < max)
if (pr_opcodes[st->op].type_c && st->c.sym)
{
if (OpAssignsToC(st->op))
return -1;
union QCC_eval_basic_s *ofs = st->c.sym->symboldata+st->c.ofs;
int sz = st->c.cast->size;
pbool iswrite = OpAssignsToC(st->op);
return i;
SPLIT
}
else if (pr_opcodes[st->op].associative == ASSOC_RIGHT && (int)st->c.ofs > 0 && !st->c.sym)
{
int jump = i + (int)st->c.ofs;
ret = QCC_CheckOneUninitialised(i + 1, jump, def, min, max);
ret = QCC_CheckOneUninitialised(i + 1, jump, min, max);
if (ret > 0)
return ret;
i = jump-1;
@ -15148,11 +15212,12 @@ static int QCC_CheckOneUninitialised(int firststatement, int laststatement, QCC_
}
return 0;
#undef SPLIT
}
static pbool QCC_CheckUninitialised(int firststatement, int laststatement)
{
QCC_def_t *local;
QCC_def_t *local, *c, *uninit;
unsigned int i;
pbool result = false;
unsigned int paramend = FIRST_LOCAL;
@ -15180,11 +15245,33 @@ static pbool QCC_CheckUninitialised(int firststatement, int laststatement)
continue;
if (local->arraysize)
continue; //probably indexed. we won't detect things properly. its the user's resposibility to check. :(
err = QCC_CheckOneUninitialised(firststatement, laststatement, local, local->ofs, local->ofs + local->type->size * (local->arraysize?local->arraysize:1));
err = QCC_CheckOneUninitialised(firststatement, laststatement, local->symboldata, local->symboldata + local->type->size * (local->arraysize?local->arraysize:1));
if (err > 0)
{
QCC_PR_Warning(WARN_UNINITIALIZED, s_filen, statements[err].linenum, "Potentially uninitialised variable %s%s%s", col_symbol,local->name,col_none);
{ //try to refine it to a single component if we can.
uninit = NULL;
for (c = local; ; c = c->next)
{
if (c != local)
{
err = QCC_CheckOneUninitialised(firststatement, laststatement, c->symboldata, c->symboldata + c->type->size * (c->arraysize?c->arraysize:1));
if (err > 0)
{
if (uninit)
{
uninit = NULL;
break;
}
uninit = c;
}
}
if (c == local->deftail)
break; //that was the last of them.
}
if (!uninit) //otherwise give up and print the whole struct.
uninit = local;
QCC_PR_Warning(WARN_UNINITIALIZED, s_filen, statements[err].linenum, "Potentially uninitialised variable %s%s%s", col_symbol,uninit->name,col_none);
result = true;
// break;
}
}
@ -17989,7 +18076,7 @@ PR_ParseDefs
Called at the outer layer and when a local statement is hit
================
*/
void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
void QCC_PR_ParseDefs (const char *classname, pbool fatal_unused)
{
char *name;
QCC_type_t *basetype, *type, *defclass;
@ -18416,17 +18503,29 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
// QCC_PR_ParseError (WARN_TYPEWITHNONAME, "type (%s) with no name", type->name);
return;
}
else
if (!istypedef && !classname && type->typedefed && QCC_PR_CheckToken("::"))
{
while (QCC_PR_CheckToken ("*"))
type = QCC_PointerTypeTo(type);
name = QCC_PR_ParseName ();
classname = type->name; //FIXME: doesn't work with commas...
type = type_invalid;
}
else while (QCC_PR_CheckToken ("*"))
type = QCC_PointerTypeTo(type);
name = QCC_PR_ParseName ();
if (!istypedef && !classname && QCC_PR_CheckToken("::"))
{
classname = name; //FIXME: doesn't work with commas...
name = QCC_PR_ParseName();
}
if (!istypedef && QCC_PR_CheckToken("::") && !classname)
if (type == type_invalid)
{
classname = name;
name = QCC_PR_ParseName();
type = type_void;
if (!strcmp(classname, name))
; //constructor. allowed.
else
QCC_PR_ParseWarning(ERR_NOTATYPE, "no type specified for %s::%s. this is only allowed for constructors", classname, name);
}
//check for an array
@ -18527,6 +18626,7 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
name = qccHunkAlloc(strlen(classname) + strlen(name) + 3);
sprintf(name, "%s::%s", classname, membername);
defclass = QCC_TypeForName(classname);
allocatenew = (dynlength.cast || aliasof)?false:2;
if (defclass && defclass->type == ev_struct)
allocatenew = false;
else if (!defclass || !defclass->parentclass)
@ -18630,6 +18730,15 @@ void QCC_PR_ParseDefs (char *classname, pbool fatal_unused)
def->referenced = true;
def = QCC_PR_DummyDef(type, name, pr_scope, arraysize, def, 0, true, gd_flags);
}
else if (allocatenew != 1)
{ //we always allocate here, because it lets us handle syntax errors a little more gracefully, but an error is still an error and will be fatal later.
def = QCC_PR_GetDef (type, name, pr_scope, false, arraysize, gd_flags);
if (!def)
{
QCC_PR_ParseWarning(allocatenew?WARN_MEMBERNOTDEFINED:ERR_NOTDEFINED, "%s is not part of class %s", name, classname);
def = QCC_PR_GetDef (type, name, pr_scope, true, arraysize, gd_flags);
}
}
else
def = QCC_PR_GetDef (type, name, pr_scope, allocatenew, arraysize, gd_flags);
}

View file

@ -98,6 +98,7 @@ QCC_type_t *type_uint; //uint32
QCC_type_t *type_int64; //int64
QCC_type_t *type_uint64; //uint64
QCC_type_t *type_variant; //__variant
QCC_type_t *type_invalid; //technically void, but shouldn't really ever be used.
QCC_type_t *type_floatpointer; //float *
QCC_type_t *type_intpointer; //int *
QCC_type_t *type_bint; //int (0 or 1)
@ -3047,6 +3048,7 @@ void QCC_PR_PreProcessor_Define(pbool append)
s++; //skip the \ char
if (*s == '\r' && s[1] == '\n')
s++; //skip the \r. the \n will become part of the macro.
s++; //skip the \n
QCC_PR_NewLine(true);
/*
@ -3524,7 +3526,7 @@ static pbool QCC_PR_ExpandPreProcessorMacro(CompilerConstant_t *c, char **buffer
QCC_PR_ExpandStrCat(buffer,bufferlen,buffermax, "#", 1);
QCC_PR_ExpandStrCat(buffer,bufferlen,buffermax, qcc_token, strlen(qcc_token));
if (!c->evil)
QCC_PR_ParseWarning(0, "'#' is not followed by a macro parameter in %s", c->name);
QCC_PR_ParseWarning(0, "'#%s' is not a macro parameter in %s", qcc_token, c->name);
}
continue; //already did this one
}
@ -5643,7 +5645,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
return newt;
}
if (QCC_PR_CheckKeyword (keyword_class, "class"))
if (flag_qcfuncs && QCC_PR_CheckKeyword (keyword_class, "class"))
{
// int parms;
QCC_type_t *fieldtype;
@ -5658,6 +5660,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
int basicindex;
QCC_def_t *d;
QCC_type_t *pc;
QCC_type_t *basetype;
pbool found = false;
int assumevirtual = 0; //0=erk, 1=yes, -1=no
@ -5718,11 +5721,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
{
unsigned int gdf_flags;
pbool havebody = false;
pbool isnull = false;
pbool isvirt = false;
pbool isnonvirt = false;
pbool isstatic = false;
pbool wasvirt = false;
pbool wasnonvirt = false;
pbool wasstatic = false;
pbool isconst = false;
pbool isvar = false;
pbool isignored = false;
@ -5732,18 +5733,34 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
// pbool ispublic = false;
// pbool isprivate = false;
// pbool isprotected = false;
pbool firstkeyword = true;
while(1)
{
if (QCC_PR_CheckKeyword(1, "nonvirtual"))
isnonvirt = true;
{
if (firstkeyword && QCC_PR_CheckToken(":"))
{ //fteqcc-specific
assumevirtual = -1;
continue;
}
wasnonvirt = true;
}
else if (QCC_PR_CheckKeyword(1, "static"))
isstatic = true;
wasstatic = true;
else if (QCC_PR_CheckKeyword(1, "const"))
isconst = isstatic = true;
isconst = wasstatic = true;
else if (QCC_PR_CheckKeyword(1, "var"))
isvar = true;
else if (QCC_PR_CheckKeyword(1, "virtual"))
isvirt = true;
{
if (firstkeyword && QCC_PR_CheckToken(":"))
{ //fteqcc-specific
assumevirtual = 1;
continue;
}
wasvirt = true;
}
else if (QCC_PR_CheckKeyword(1, "ignore"))
isignored = true;
else if (QCC_PR_CheckKeyword(1, "strip"))
@ -5754,339 +5771,384 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
isget = true;
else if (QCC_PR_CheckKeyword(1, "set"))
isset = true;
else if (QCC_PR_CheckKeyword(1, "public"))
/*ispublic = true*/;
else if (QCC_PR_CheckKeyword(1, "private"))
/*isprivate = true*/;
else if (QCC_PR_CheckKeyword(1, "protected"))
/*isprotected = true*/;
else if (firstkeyword && QCC_PR_CheckKeyword(1, "public"))
{
/*ispublic = true;*/
QCC_PR_Expect(":");
continue;
}
else if (firstkeyword && QCC_PR_CheckKeyword(1, "private"))
{
QCC_PR_Expect(":");
/*isprivate = true; */
continue;
}
else if (firstkeyword && QCC_PR_CheckKeyword(1, "protected"))
{
QCC_PR_Expect(":");
/*isprotected = true;*/ QCC_PR_Expect(":");
continue;
}
else
break;
}
if (QCC_PR_CheckToken(":"))
{
if (isvirt && !isnonvirt)
assumevirtual = 1;
else if (isnonvirt && !isvirt)
assumevirtual = -1;
continue;
firstkeyword = false;
}
if (isget || isset)
{
if (isvirt)
if (wasvirt)
QCC_PR_ParseWarning(ERR_INTERNAL, "virtual accessors are not supported at this time");
if (isstatic)
if (wasstatic)
QCC_PR_ParseError(ERR_INTERNAL, "static accessors are not supported");
QCC_PR_ParseAccessorMember(newt, isinline, isset);
QCC_PR_CheckToken(";");
continue;
}
newparm = QCC_PR_ParseType(false, false);
basetype = QCC_PR_ParseType(false, false);
if (!newparm)
if (!basetype)
QCC_PR_ParseError(ERR_INTERNAL, "In class %s, expected type, found %s", classname, pr_token);
if (newparm->type == ev_struct || newparm->type == ev_union) //we wouldn't be able to handle it.
if (basetype->type == ev_struct || basetype->type == ev_union) //we wouldn't be able to handle it.
QCC_PR_ParseError(ERR_INTERNAL, "Struct or union in class %s", classname);
parmname = QCC_PR_ParseName();
if (QCC_PR_CheckToken("["))
{
arraysize = QCC_PR_IntConstExpr();
QCC_PR_Expect("]");
}
else
arraysize = 0;
if (newparm->type == ev_function)
for (;basetype;)
{
if (isstatic)
{
isstatic = false;
isnonvirt = true;
// QCC_PR_ParseError(ERR_INTERNAL, "%s::%s static member functions are not supported at this time.", classname, parmname);
pbool havebody = false;
pbool isnull = false;
pbool isstatic = wasstatic;
pbool isvirt = wasvirt;
pbool isnonvirt = wasnonvirt;
if (flag_qcfuncs && basetype->type == ev_function && basetype->aux_type == newt && QCC_PR_PeekToken(";"))
{ //C++ style constructor (ie: missing return type followed by class name)
//swap the class out for the appropriate function type...
newparm = QCC_PR_GenFunctionType(type_void, basetype->params, basetype->num_parms);
parmname = classname;
}
if (!strcmp(classname, parmname))
else if (!flag_qcfuncs && basetype == newt && QCC_PR_CheckToken("("))
{
if (isstatic)
QCC_PR_ParseError(ERR_INTERNAL, "Constructor %s::%s may not be static.", classname, pr_token);
if (!isvirt)
isnonvirt = true;//silently promote constructors to static
}
else if (!isvirt && !isnonvirt && !isstatic)
{
if (assumevirtual == 1)
isvirt = true;
else if (assumevirtual == -1)
isnonvirt = true;
else
{
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "%s::%s was not qualified. Assuming non-virtual.", classname, parmname);
isnonvirt = true;
}
}
if (isvirt+isnonvirt+isstatic != 1)
QCC_PR_ParseError(ERR_INTERNAL, "Multiple conflicting qualifiers on %s::%s.", classname, pr_token);
}
else
{
if (isvirt||isnonvirt)
QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function");
if (isinline)
QCC_Error(ERR_INTERNAL, "inline keyword on member that is not a function");
}
if (QCC_PR_CheckToken("="))
havebody = true;
else if (newparm->type == ev_function && pr_token[0] == '{')
havebody = true;
if (isinline && (!havebody || isvirt))
QCC_Error(ERR_INTERNAL, "inline keyword on function prototype or virtual function");
gdf_flags = 0;
if ((newparm->type == ev_function && !arraysize && !isvar) || isconst)
gdf_flags = GDF_CONST;
if (havebody)
{
QCC_def_t *def;
if (pr_scope)
QCC_Error(ERR_INTERNAL, "Nested function declaration");
isnull = (QCC_PR_CheckImmediate("0") || QCC_PR_CheckImmediate("0i"));
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
if (isnull)
{
if (isignored)
def = NULL;
else
{
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
def->symboldata[def->ofs].function = 0;
def->initialized = 1;
}
newparm = QCC_PR_ParseFunctionType(false, type_void);
parmname = classname;
}
else
{
if (isignored)
def = NULL;
else
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
if (newparm->type != ev_function && !isstatic)
QCC_Error(ERR_INTERNAL, "Can only initialise member functions");
else
parmname = QCC_PR_ParseName();
if (QCC_PR_CheckToken("["))
{
if (autoprototype || isignored)
{
if (QCC_PR_CheckToken("["))
{
while (!QCC_PR_CheckToken("]"))
{
if (pr_token_type == tt_eof)
break;
QCC_PR_Lex();
}
}
QCC_PR_Expect("{");
arraysize = QCC_PR_IntConstExpr();
QCC_PR_Expect("]");
}
else
arraysize = 0;
{
int blev = 1;
//balance out the { and }
while(blev)
{
if (pr_token_type == tt_eof)
break;
if (QCC_PR_CheckToken("{"))
blev++;
else if (QCC_PR_CheckToken("}"))
blev--;
else
QCC_PR_Lex(); //ignore it.
}
}
}
if (QCC_PR_CheckToken("("))
{
//int fnc(), fld; is valid.
newparm = QCC_PR_ParseFunctionType(false, basetype);
}
else
newparm = basetype;
}
if (newparm->type == ev_function)
{
if (!strcmp(classname, parmname))
{
if (isstatic)
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "Constructor %s::%s should not be static.", classname, pr_token);
if (!isvirt)
isnonvirt = true;//silently promote constructors to static
if (newparm->aux_type->type != ev_void)
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "Constructor %s::%s does not return void.", classname, pr_token);
if (newparm->num_parms != 0 || newparm->vargs)
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "Constructor arguments are not supported at this time %s::%s. Use named fields instead.", classname, pr_token);
}
else if (!isvirt && !isnonvirt && !isstatic)
{
if (assumevirtual == 1)
isvirt = true;
else if (assumevirtual == -1)
isnonvirt = true;
else
{
pr_classtype = newt;
QCC_PR_ParseInitializerDef(def, 0);
pr_classtype = NULL;
/*
f = QCC_PR_ParseImmediateStatements (def, newparm);
pr_classtype = NULL;
pr_scope = NULL;
def->symboldata[def->ofs].function = f - functions;
f->def = def;
def->initialized = 1;*/
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "%s::%s was not qualified. Assuming non-virtual.", classname, parmname);
isnonvirt = true;
}
}
}
if (def)
QCC_FreeDef(def);
else if (isvirt+isnonvirt+isstatic != 1)
QCC_PR_ParseError(ERR_INTERNAL, "Multiple conflicting qualifiers on %s::%s.", classname, pr_token);
if (!isvirt && !isignored)
{
QCC_def_t *fdef;
QCC_type_t *pc;
unsigned int i;
for (pc = newt->parentclass; pc; pc = pc->parentclass)
{
for (i = 0; i < pc->num_parms; i++)
{
if (!strcmp(pc->params[i].paramname, parmname))
{
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class '%s'. Did you forget the 'virtual' keyword?", newt->name, parmname, pc->name);
break;
}
}
if (i < pc->num_parms)
break;
if (isstatic)
{ //static and non-virtual functions differ only in that static should not have a 'this' available. however there's no hiding 'self' for calling in to other functions.
isstatic = false;
isnonvirt = true;
// QCC_PR_ParseError(ERR_INTERNAL, "%s::%s static member functions are not supported at this time.", classname, parmname);
}
if (!pc)
{
fdef = QCC_PR_GetDef(NULL, parmname, NULL, false, 0, GDF_CONST);
if (fdef && fdef->type->type == ev_field)
{
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class 'entity'. Did you forget the 'virtual' keyword?", newt->name, parmname);
QCC_PR_ParsePrintDef(0, fdef);
}
else if (fdef)
{
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s shadows a global", newt->name, parmname);
QCC_PR_ParsePrintDef(0, fdef);
}
if (fdef)
QCC_FreeDef(fdef);
}
}
}
QCC_PR_Expect(";");
if (isignored) //member doesn't really exist
continue;
//static members are technically just funny-named globals, and do not generate fields.
if (isnonvirt || isstatic || (newparm->type == ev_function && !arraysize))
{
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
QCC_FreeDef(QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags));
if (isnonvirt || isstatic)
continue;
}
fieldtype = QCC_PR_NewType(parmname, ev_field, false);
fieldtype->aux_type = newparm;
fieldtype->size = newparm->size;
parms = realloc(parms, sizeof(*parms) * (numparms+1));
parms[numparms].ofs = 0;
parms[numparms].out = false;
parms[numparms].optional = false;
parms[numparms].isvirtual = isvirt;
parms[numparms].paramname = parmname;
parms[numparms].arraysize = arraysize;
parms[numparms].type = newparm;
parms[numparms].defltvalue.cast = NULL;
basicindex = 0;
found = false;
for(pc = newt; pc && !found; pc = pc->parentclass)
{
struct QCC_typeparam_s *pp;
int numpc;
int i;
if (pc == newt)
{
pp = parms;
numpc = numparms;
}
else
{
pp = pc->params;
numpc = pc->num_parms;
if (isvirt||isnonvirt)
QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function");
if (isinline)
QCC_Error(ERR_INTERNAL, "inline keyword on member that is not a function");
}
for (i = 0; i < numpc; i++)
if (QCC_PR_CheckToken("="))
havebody = true;
else if (newparm->type == ev_function && QCC_PR_PeekToken("{"))
havebody = true;
if (isinline && (!havebody || isvirt))
QCC_Error(ERR_INTERNAL, "inline keyword on function prototype or virtual function");
gdf_flags = 0;
if ((newparm->type == ev_function && !arraysize && !isvar) || isconst)
gdf_flags = GDF_CONST;
if (havebody)
{
if (pp[i].type->type == newparm->type)
QCC_def_t *def;
if (pr_scope)
QCC_Error(ERR_INTERNAL, "Nested function declaration");
isnull = (QCC_PR_CheckImmediate("0") || QCC_PR_CheckImmediate("0i"));
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
if (isnull)
{
if (!strcmp(pp[i].paramname, parmname))
if (isignored)
def = NULL;
else
{
if (typecmp(pp[i].type, newparm))
{
char bufc[256];
char bufp[256];
TypeName(pp[i].type, bufp, sizeof(bufp));
TypeName(newparm, bufc, sizeof(bufc));
QCC_PR_ParseError(0, "%s defined as %s in %s, but %s in %s\n", parmname, bufc, newt->name, bufp, pc->name);
}
basicindex = pp[i].ofs;
found = true;
break;
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
def->symboldata[def->ofs].function = 0;
def->initialized = 1;
}
if ((unsigned int)basicindex < pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1)) //if we found one with the index
basicindex = pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1); //make sure we don't union it.
}
}
}
parms[numparms].ofs = basicindex; //ulp, its new
numparms++;
if (found)
continue;
if (!*basictypes[newparm->type])
QCC_PR_ParseError(0, "members of type %s are not supported (%s::%s)\n", basictypenames[newparm->type], classname, parmname);
//make sure the union is okay
d = QCC_PR_GetDef(NULL, parmname, NULL, 0, 0, GDF_CONST);
if (d)
basicindex = 0;
else
{ //don't go all weird with unioning generic fields
QC_snprintfz(membername, sizeof(membername), "::*%s", basictypenames[newparm->type]);
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
if (!d)
{
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST|GDF_POSTINIT|GDF_USED);
// for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
// d->symboldata[i]._int = pr.size_fields+i;
// pr.size_fields += i;
d->used = true;
d->referenced = true; //always referenced, so you can inherit safely.
}
if (d->arraysize < basicindex+(arraysize?arraysize:1))
{
if (d->symboldata)
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
else
{
int newsize = basicindex+(arraysize?arraysize:1);
if (d->type->type == ev_union || d->type->type == ev_struct)
d->arraysize = newsize;
else while(d->arraysize < newsize)
if (isignored)
def = NULL;
else
def = QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags);
if (newparm->type != ev_function && !isstatic)
QCC_Error(ERR_INTERNAL, "Can only initialise member functions");
else
{
QC_snprintfz(membername, sizeof(membername), "::%s[%i]", basictypenames[newparm->type], d->arraysize/d->type->size);
QCC_PR_DummyDef(d->type, membername, d->scope, 0, d, d->arraysize, true, GDF_CONST);
d->arraysize+=d->type->size;
if (autoprototype || isignored)
{
if (QCC_PR_CheckToken("["))
{
while (!QCC_PR_CheckToken("]"))
{
if (pr_token_type == tt_eof)
break;
QCC_PR_Lex();
}
}
QCC_PR_Expect("{");
{
int blev = 1;
//balance out the { and }
while(blev)
{
if (pr_token_type == tt_eof)
break;
if (QCC_PR_CheckToken("{"))
blev++;
else if (QCC_PR_CheckToken("}"))
blev--;
else
QCC_PR_Lex(); //ignore it.
}
}
}
else
{
pr_classtype = newt;
QCC_PR_ParseInitializerDef(def, 0);
pr_classtype = NULL;
/*
f = QCC_PR_ParseImmediateStatements (def, newparm);
pr_classtype = NULL;
pr_scope = NULL;
def->symboldata[def->ofs].function = f - functions;
f->def = def;
def->initialized = 1;*/
}
}
}
if (def)
QCC_FreeDef(def);
if (!isvirt && !isignored)
{
QCC_def_t *fdef;
QCC_type_t *pc;
unsigned int i;
for (pc = newt->parentclass; pc; pc = pc->parentclass)
{
for (i = 0; i < pc->num_parms; i++)
{
if (!strcmp(pc->params[i].paramname, parmname))
{
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class '%s'. Did you forget the 'virtual' keyword?", newt->name, parmname, pc->name);
break;
}
}
if (i < pc->num_parms)
break;
}
if (!pc)
{
fdef = QCC_PR_GetDef(NULL, parmname, NULL, false, 0, GDF_CONST);
if (fdef && fdef->type->type == ev_field)
{
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s is virtual inside parent class 'entity'. Did you forget the 'virtual' keyword?", newt->name, parmname);
QCC_PR_ParsePrintDef(0, fdef);
}
else if (fdef)
{
QCC_PR_ParseWarning(WARN_DUPLICATEDEFINITION, "%s::%s shadows a global", newt->name, parmname);
QCC_PR_ParsePrintDef(0, fdef);
}
if (fdef)
QCC_FreeDef(fdef);
}
}
}
}
QCC_FreeDef(d);
//and make sure we can do member::__fname
//actually, that seems pointless.
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, classname, parmname);
// externs->Printf("define %s -> %s\n", membername, d->name);
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, arraysize, d, basicindex, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
d->referenced = true; //always referenced, so you can inherit safely.
if (!QCC_PR_CheckToken(","))
{
QCC_PR_Expect(";");
basetype = NULL;
}
if (isignored) //member doesn't really exist
continue;
//static members are technically just funny-named globals, and do not generate fields.
if (isnonvirt || isstatic || (newparm->type == ev_function && !arraysize))
{
QC_snprintfz(membername, sizeof(membername), "%s::%s", classname, parmname);
QCC_FreeDef(QCC_PR_GetDef(newparm, membername, NULL, true, 0, gdf_flags));
if (isnonvirt || isstatic)
continue;
}
fieldtype = QCC_PR_NewType(parmname, ev_field, false);
fieldtype->aux_type = newparm;
fieldtype->size = newparm->size;
parms = realloc(parms, sizeof(*parms) * (numparms+1));
parms[numparms].ofs = 0;
parms[numparms].out = false;
parms[numparms].optional = false;
parms[numparms].isvirtual = isvirt;
parms[numparms].paramname = parmname;
parms[numparms].arraysize = arraysize;
parms[numparms].type = newparm;
parms[numparms].defltvalue.cast = NULL;
basicindex = 0;
found = false;
for(pc = newt; pc && !found; pc = pc->parentclass)
{
struct QCC_typeparam_s *pp;
int numpc;
int i;
if (pc == newt)
{
pp = parms;
numpc = numparms;
}
else
{
pp = pc->params;
numpc = pc->num_parms;
}
for (i = 0; i < numpc; i++)
{
if (pp[i].type->type == newparm->type)
{
if (!strcmp(pp[i].paramname, parmname))
{
if (typecmp(pp[i].type, newparm))
{
char bufc[256];
char bufp[256];
TypeName(pp[i].type, bufp, sizeof(bufp));
TypeName(newparm, bufc, sizeof(bufc));
QCC_PR_ParseError(0, "%s defined as %s in %s, but %s in %s\n", parmname, bufc, newt->name, bufp, pc->name);
}
basicindex = pp[i].ofs;
found = true;
break;
}
if ((unsigned int)basicindex < pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1)) //if we found one with the index
basicindex = pp[i].ofs+pp[i].type->size*(pp[i].arraysize?pp[i].arraysize:1); //make sure we don't union it.
}
}
}
parms[numparms].ofs = basicindex; //ulp, its new
numparms++;
if (found)
continue;
if (!*basictypes[newparm->type])
QCC_PR_ParseError(0, "members of type %s are not supported (%s::%s)\n", basictypenames[newparm->type], classname, parmname);
//make sure the union is okay
d = QCC_PR_GetDef(NULL, parmname, NULL, 0, 0, GDF_CONST);
if (d)
basicindex = 0;
else
{ //don't go all weird with unioning generic fields
QC_snprintfz(membername, sizeof(membername), "::*%s", basictypenames[newparm->type]);
d = QCC_PR_GetDef(NULL, membername, NULL, 0, 0, GDF_CONST);
if (!d)
{
d = QCC_PR_GetDef(QCC_PR_FieldType(*basictypes[newparm->type]), membername, NULL, 2, 0, GDF_CONST|GDF_POSTINIT|GDF_USED);
// for (i = 0; (unsigned int)i < newparm->size*(arraysize?arraysize:1); i++)
// d->symboldata[i]._int = pr.size_fields+i;
// pr.size_fields += i;
d->used = true;
d->referenced = true; //always referenced, so you can inherit safely.
}
if (d->arraysize < basicindex+(arraysize?arraysize:1))
{
if (d->symboldata)
QCC_PR_ParseError(ERR_INTERNAL, "array members are kinda limited, sorry. try rearranging them or adding padding for alignment\n"); //FIXME: add relocs to cope with this all of a type can then be contiguous and thus allow arrays.
else
{
int newsize = basicindex+(arraysize?arraysize:1);
if (d->type->type == ev_union || d->type->type == ev_struct)
d->arraysize = newsize;
else while(d->arraysize < newsize)
{
QC_snprintfz(membername, sizeof(membername), "::%s[%i]", basictypenames[newparm->type], d->arraysize/d->type->size);
QCC_PR_DummyDef(d->type, membername, d->scope, 0, d, d->arraysize, true, GDF_CONST);
d->arraysize+=d->type->size;
}
}
}
}
QCC_FreeDef(d);
//and make sure we can do member::__fname
//actually, that seems pointless.
QC_snprintfz(membername, sizeof(membername), "%s::"MEMBERFIELDNAME, classname, parmname);
// externs->Printf("define %s -> %s\n", membername, d->name);
d = QCC_PR_DummyDef(fieldtype, membername, pr_scope, arraysize, d, basicindex, true, (isnull?0:GDF_CONST)|(opt_classfields?GDF_STRIP:0));
d->referenced = true; //always referenced, so you can inherit safely.
}
}
if (redeclaration)
@ -6140,7 +6202,9 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (QCC_PR_CheckKeyword (keyword_union, "union"))
structtype = ev_union;
else if (QCC_PR_CheckKeyword (keyword_struct, "struct"))
structtype = ev_struct;
structtype = ev_struct; //defaults to public
// else if (QCC_PR_CheckKeyword (keyword_class, "class"))
// structtype = ev_struct; //defaults to private. no other difference.
if (structtype != ev_void)
{
struct QCC_typeparam_s *parms = NULL, *oldparm;
@ -6152,6 +6216,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
pbool isnonvirt = false;
pbool isstatic = false;
pbool isvirt = false;
pbool definedsomething = false;
if (QCC_PR_CheckToken("{"))
{
@ -6241,15 +6306,28 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//parse field modifiers
if (QCC_PR_CheckKeyword(1, "public"))
{
/*ispublic = true*/;
QCC_PR_Expect(":");
continue;
}
else if (QCC_PR_CheckKeyword(1, "private"))
{
/*isprivate = true*/;
QCC_PR_Expect(":");
continue;
}
else if (QCC_PR_CheckKeyword(1, "protected"))
{
/*isprotected = true*/;
QCC_PR_Expect(":");
continue;
}
if (QCC_PR_CheckKeyword(1, "nonvirtual"))
isnonvirt = true;
else if (QCC_PR_CheckKeyword(1, "static"))
//if (QCC_PR_CheckKeyword(1, "nonvirtual"))
// isnonvirt = true;
//else
if (QCC_PR_CheckKeyword(1, "static"))
isstatic = true;
else if (QCC_PR_CheckKeyword(1, "virtual"))
isvirt = true;
@ -6260,6 +6338,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
//now parse the actual type.
newparm = QCC_PR_ParseType(false, false);
definedsomething = false;
}
type = newparm;
@ -6269,6 +6348,13 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
arraysize = 0;
if (QCC_PR_CheckToken(";"))
{ //annonymous structs do weird scope stuff.
if (!definedsomething && (type->type != ev_struct && type->type != ev_union))
{
if (flag_qcfuncs && type->type == ev_function && type->aux_type == newt && QCC_PR_PeekToken(";"))
QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "constructors are not supported in structs at this time", newparm->name);
else
QCC_PR_ParseWarning(WARN_POINTLESSSTATEMENT, "declaration does not declare anything (%s)", newparm->name);
}
newparm = NULL;
parmname = "";
}
@ -6277,6 +6363,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
parmname = qccHunkAlloc(strlen(pr_token)+1);
strcpy(parmname, pr_token);
QCC_PR_Lex();
definedsomething = true;
if (QCC_PR_CheckToken("["))
{
arraysize=QCC_PR_IntConstExpr();

View file

@ -241,6 +241,8 @@ struct {
{" F331", WARN_SELFNOTTHIS},
{" F332", WARN_DIVISIONBY0},
{" F333", WARN_ARGUMENTCHECK},
{" F334", WARN_MISSINGMEMBERQUALIFIER},
{" F335", WARN_MEMBERNOTDEFINED}, //defining a new member function inside a class that didn't list it.
{" F207", WARN_NOTREFERENCEDFIELD},
{" F208", WARN_NOTREFERENCEDCONST},
@ -3605,6 +3607,8 @@ static void QCC_PR_BeginCompilation (void *memory, int memsize)
type_uint64 = QCC_PR_NewType("__uint64", ev_uint64, true);
type_variant = QCC_PR_NewType("__variant", ev_variant, true);
type_invalid = QCC_PR_NewType("invalid", ev_void, false);
type_floatfield = QCC_PR_NewType("__fieldfloat", ev_field, false);
type_floatfield->aux_type = type_float;
type_pointer->aux_type = QCC_PR_NewType("__pointeraux", ev_float, false);
@ -4628,7 +4632,7 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
else
*compiler_flag[p].enabled = false;
}
if (!stricmp(myargv[i]+5, "C") || !stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90") || !stricmp(myargv[i]+5, "c99") || !stricmp(myargv[i]+5, "c11") || !stricmp(myargv[i]+5, "c17"))
if (!stricmp(myargv[i]+5, "C") || !stricmp(myargv[i]+5, "c++") ||!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90") || !stricmp(myargv[i]+5, "c99") || !stricmp(myargv[i]+5, "c11") || !stricmp(myargv[i]+5, "c17"))
{ //set up for greatest C compatibility... variations from C are bugs, not features.
keyword_asm = false;
keyword_break = keyword_continue = keyword_for = keyword_goto = keyword_const = keyword_extern = keyword_static = true;
@ -4658,7 +4662,13 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
qccwarningaction[WARN_ASSIGNMENTTOCONSTANT] = WA_ERROR; //const is const. at least its not const by default.
qccwarningaction[WARN_SAMENAMEASGLOBAL] = WA_IGNORE; //shadowing of globals.
if (!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90"))
if (!stricmp(myargv[i]+5, "c++"))
{
keyword_class = /*keyword_new =*/ keyword_inline = true;
cnst = QCC_PR_DefineName("__cplusplus");
val = NULL;
}
else if (!stricmp(myargv[i]+5, "c89") || !stricmp(myargv[i]+5, "c90"))
val = "199409L"; //it was ammended, apparently.
else if (!stricmp(myargv[i]+5, "c99"))
val = "199901L";
@ -4858,11 +4868,12 @@ static void QCC_PR_CommandLinePrecompilerOptions (void)
case WARN_STRICTTYPEMISMATCH:
case WARN_PARAMWITHNONAME:
case WARN_IFSTRING_USED:
case WARN_UNINITIALIZED:
// case WARN_UNINITIALIZED:
case WARN_GMQCC_SPECIFIC:
case WARN_SYSTEMCRC:
case WARN_SYSTEMCRC2:
qccwarningaction[j] = qccwarningaction[WARN_GMQCC_SPECIFIC];
if (qccwarningaction[WARN_GMQCC_SPECIFIC])
qccwarningaction[j] = WA_WARN;
break;
//these warnings require -Wextra to enable, as they're too annoying to have to fix