From ed63b7435ede74960b5d6cdbf22cca8bb0514ed9 Mon Sep 17 00:00:00 2001 From: Spoike Date: Mon, 9 Jan 2023 05:13:12 +0000 Subject: [PATCH] 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 --- engine/qclib/decomp.c | 1 + engine/qclib/qcc.h | 6 +- engine/qclib/qcc_pr_comp.c | 193 ++++++++--- engine/qclib/qcc_pr_lex.c | 687 +++++++++++++++++++++---------------- engine/qclib/qccmain.c | 19 +- 5 files changed, 557 insertions(+), 349 deletions(-) diff --git a/engine/qclib/decomp.c b/engine/qclib/decomp.c index 388aeb188..d69378c30 100644 --- a/engine/qclib/decomp.c +++ b/engine/qclib/decomp.c @@ -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); diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index ad631ff99..d914ec83d 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -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); diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index a431bc94c..42e8ed6d8 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -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); } diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 64369a90c..f51d00ab2 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -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(); diff --git a/engine/qclib/qccmain.c b/engine/qclib/qccmain.c index d5a9f875d..04144cc15 100644 --- a/engine/qclib/qccmain.c +++ b/engine/qclib/qccmain.c @@ -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