mirror of https://git.wuffs.org/MWCC
4846 lines
159 KiB
C
4846 lines
159 KiB
C
#include "compiler/CDecl.h"
|
|
#include "compiler/CABI.h"
|
|
#include "compiler/CBrowse.h"
|
|
#include "compiler/CClass.h"
|
|
#include "compiler/CError.h"
|
|
#include "compiler/CException.h"
|
|
#include "compiler/CExpr.h"
|
|
#include "compiler/CFunc.h"
|
|
#include "compiler/CInit.h"
|
|
#include "compiler/CInline.h"
|
|
#include "compiler/CInt64.h"
|
|
#include "compiler/CMachine.h"
|
|
#include "compiler/CMangler.h"
|
|
#include "compiler/CObjC.h"
|
|
#include "compiler/CParser.h"
|
|
#include "compiler/CPrep.h"
|
|
#include "compiler/CPrepTokenizer.h"
|
|
#include "compiler/CSOM.h"
|
|
#include "compiler/CTemplateClass.h"
|
|
#include "compiler/CTemplateFunc.h"
|
|
#include "compiler/CTemplateNew.h"
|
|
#include "compiler/CTemplateTools.h"
|
|
#include "compiler/CompilerTools.h"
|
|
#include "compiler/objects.h"
|
|
#include "compiler/scopes.h"
|
|
#include "compiler/templates.h"
|
|
#include "compiler/tokens.h"
|
|
|
|
AccessType global_access;
|
|
FileOffsetInfo member_fileoffset;
|
|
|
|
// forward declarations
|
|
static void scandirectdecl1(DeclInfo *declinfo);
|
|
|
|
Type *CDecl_NewStructType(SInt32 size, SInt16 align) {
|
|
TypeStruct *tstruct = galloc(sizeof(TypeStruct));
|
|
memclrw(tstruct, sizeof(TypeStruct));
|
|
|
|
tstruct->type = TYPESTRUCT;
|
|
tstruct->size = size;
|
|
tstruct->align = align;
|
|
tstruct->stype = STRUCT_TYPE_STRUCT;
|
|
|
|
return (Type *) tstruct;
|
|
}
|
|
|
|
Type *CDecl_NewArrayType(Type *type, SInt32 size) {
|
|
TypePointer *tarray = galloc(sizeof(TypePointer));
|
|
memclrw(tarray, sizeof(TypePointer));
|
|
|
|
tarray->type = TYPEARRAY;
|
|
tarray->size = size;
|
|
tarray->target = type;
|
|
tarray->qual = 0;
|
|
|
|
return (Type *) tarray;
|
|
}
|
|
|
|
Type *CDecl_NewPointerType(Type *type) {
|
|
TypePointer *tptr = galloc(sizeof(TypePointer));
|
|
memclrw(tptr, sizeof(TypePointer));
|
|
|
|
tptr->type = TYPEPOINTER;
|
|
tptr->size = 4;
|
|
tptr->target = type;
|
|
|
|
return (Type *) tptr;
|
|
}
|
|
|
|
Type *CDecl_NewRefPointerType(Type *type) {
|
|
TypePointer *tptr = galloc(sizeof(TypePointer));
|
|
memclrw(tptr, sizeof(TypePointer));
|
|
|
|
tptr->type = TYPEPOINTER;
|
|
tptr->size = 4;
|
|
tptr->target = type;
|
|
tptr->qual = Q_REFERENCE;
|
|
|
|
return (Type *) tptr;
|
|
}
|
|
|
|
Type *CDecl_NewTemplDepType(TypeTemplDepType tdt) {
|
|
TypeTemplDep *t = galloc(sizeof(TypeTemplDep));
|
|
memclrw(t, sizeof(TypeTemplDep));
|
|
|
|
t->type = TYPETEMPLATE;
|
|
t->size = 1;
|
|
t->dtype = tdt;
|
|
|
|
return (Type *) t;
|
|
}
|
|
|
|
void CDecl_SetResultReg(TypeFunc *tfunc) {
|
|
}
|
|
|
|
static void CDecl_SetFuncResultReg(TypeFunc *tfunc) {
|
|
}
|
|
|
|
void CDecl_SetFuncFlags(TypeFunc *tfunc, UInt32 flags) {
|
|
CDecl_SetResultReg(tfunc);
|
|
}
|
|
|
|
static void CDecl_ParseCPPFuncDecl(TypeFunc *tfunc) {
|
|
for (;;) {
|
|
if (tk == TK_CONST) {
|
|
if (tfunc->flags & FUNC_FLAGS_CONST)
|
|
CError_Warning(CErrorStr313, "const");
|
|
tfunc->flags |= FUNC_FLAGS_CONST;
|
|
tk = lex();
|
|
} else if (tk == TK_VOLATILE) {
|
|
if (tfunc->flags & FUNC_FLAGS_VOLATILE)
|
|
CError_Warning(CErrorStr313, "volatile");
|
|
tfunc->flags |= FUNC_FLAGS_VOLATILE;
|
|
tk = lex();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tk == TK_THROW)
|
|
CExcept_ScanExceptionSpecification(tfunc);
|
|
}
|
|
|
|
void CDecl_NewConvFuncType(DeclInfo *declinfo) {
|
|
TypeFunc *tfunc;
|
|
|
|
if (tk != '(')
|
|
CError_Error(CErrorStr114);
|
|
else
|
|
tk = lex();
|
|
|
|
if (tk == TK_VOID)
|
|
tk = lex();
|
|
|
|
if (tk != ')')
|
|
CError_Error(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
tfunc = galloc(sizeof(TypeFunc));
|
|
memclrw(tfunc, sizeof(TypeFunc));
|
|
declinfo->name = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual);
|
|
tfunc->type = TYPEFUNC;
|
|
tfunc->functype = declinfo->thetype;
|
|
tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE);
|
|
tfunc->flags = FUNC_FLAGS_40;
|
|
declinfo->x49 = 0;
|
|
CDecl_SetFuncFlags(tfunc, 1);
|
|
CDecl_ParseCPPFuncDecl(tfunc);
|
|
|
|
declinfo->thetype = (Type *) tfunc;
|
|
declinfo->qual &= ~(Q_CONST | Q_VOLATILE);
|
|
declinfo->storageclass = 0;
|
|
}
|
|
|
|
void CDecl_CompleteType(Type *type) {
|
|
switch (type->type) {
|
|
case TYPEPOINTER:
|
|
if ((TYPE_POINTER(type)->qual & Q_REFERENCE) && IS_TYPE_CLASS(TYPE_POINTER(type)->target)) {
|
|
type = TYPE_POINTER(type)->target;
|
|
break;
|
|
}
|
|
return;
|
|
case TYPEARRAY:
|
|
do {
|
|
type = TYPE_POINTER(type)->target;
|
|
} while (IS_TYPE_ARRAY(type));
|
|
if (IS_TYPE_CLASS(type))
|
|
break;
|
|
return;
|
|
case TYPECLASS:
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if ((TYPE_CLASS(type)->flags & (CLASS_FLAGS_2 | CLASS_FLAGS_800)) == CLASS_FLAGS_800)
|
|
CTempl_InstantiateTemplateClass(TYPE_CLASS(type));
|
|
}
|
|
|
|
Boolean IsCompleteType(Type *type) {
|
|
switch (type->type) {
|
|
case TYPEVOID:
|
|
CError_Error(CErrorStr126);
|
|
return 0;
|
|
case TYPEFUNC:
|
|
CError_Error(CErrorStr146);
|
|
return 0;
|
|
case TYPESTRUCT:
|
|
if (!type->size) {
|
|
CError_Error(CErrorStr136, type, 0);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
case TYPECLASS:
|
|
if (
|
|
!(TYPE_CLASS(type)->flags & CLASS_FLAGS_2) &&
|
|
(
|
|
!(TYPE_CLASS(type)->flags & CLASS_FLAGS_800) ||
|
|
!CTempl_InstantiateTemplateClass(TYPE_CLASS(type))
|
|
)
|
|
)
|
|
{
|
|
CError_Error(CErrorStr136, type, 0);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
default:
|
|
if (!type->size) {
|
|
CError_Error(CErrorStr145);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
Boolean CanAllocObject(Type *type) {
|
|
switch (type->type) {
|
|
case TYPEVOID:
|
|
CError_Error(CErrorStr126);
|
|
return 0;
|
|
case TYPEFUNC:
|
|
CError_Error(CErrorStr146);
|
|
return 0;
|
|
case TYPECLASS:
|
|
if (TYPE_CLASS(type)->flags & CLASS_FLAGS_ABSTRACT) {
|
|
CError_AbstractClassError(TYPE_CLASS(type));
|
|
return 0;
|
|
}
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
Boolean CanCreateObject(Type *type) {
|
|
if (!CanAllocObject(type))
|
|
return 0;
|
|
|
|
if (IS_TYPE_CLASS(type)) {
|
|
if (TYPE_CLASS(type)->flags & CLASS_FLAGS_1) {
|
|
CError_Error(CErrorStr191);
|
|
return 0;
|
|
}
|
|
if (TYPE_CLASS(type)->objcinfo) {
|
|
CError_Error(CErrorStr307);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static Boolean CanCreateHandleMemberObject(Type *type) {
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
|
|
if (!CanCreateObject(type))
|
|
return 0;
|
|
|
|
if (IS_TYPE_CLASS(type)) {
|
|
if (CClass_Destructor(TYPE_CLASS(type)) || CClass_Constructor(TYPE_CLASS(type))) {
|
|
CError_Error(CErrorStr191);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void makethetypepointer(DeclInfo *declinfo, UInt32 qual) {
|
|
declinfo->thetype = CDecl_NewPointerType(declinfo->thetype);
|
|
TYPE_POINTER(declinfo->thetype)->qual = qual;
|
|
}
|
|
|
|
void CDecl_AddThisPointerArgument(TypeFunc *tfunc, TypeClass *tclass) {
|
|
Type *ptype;
|
|
FuncArg *arg;
|
|
|
|
ptype = CDecl_NewPointerType(!tclass->sominfo ? (Type *) tclass : &stvoid);
|
|
TYPE_POINTER(ptype)->qual = Q_CONST;
|
|
|
|
arg = CParser_NewFuncArg();
|
|
arg->name = this_name_node;
|
|
arg->type = ptype;
|
|
if (tfunc->flags & FUNC_FLAGS_CONST)
|
|
arg->qual |= Q_CONST;
|
|
if (tfunc->flags & FUNC_FLAGS_VOLATILE)
|
|
arg->qual |= Q_VOLATILE;
|
|
arg->next = tfunc->args;
|
|
tfunc->args = arg;
|
|
}
|
|
|
|
void CDecl_MakePTMFuncType(TypeFunc *tfunc) {
|
|
Type *cvoidp;
|
|
FuncArg *arg1;
|
|
FuncArg *arg2;
|
|
|
|
cvoidp = CDecl_NewPointerType(&stvoid);
|
|
TYPE_POINTER(cvoidp)->qual = Q_CONST;
|
|
|
|
arg1 = CParser_NewFuncArg();
|
|
arg1->name = this_name_node;
|
|
arg1->type = cvoidp;
|
|
if (tfunc->flags & FUNC_FLAGS_CONST)
|
|
arg1->qual |= Q_CONST;
|
|
if (tfunc->flags & FUNC_FLAGS_VOLATILE)
|
|
arg1->qual |= Q_VOLATILE;
|
|
|
|
arg2 = CParser_NewFuncArg();
|
|
arg2->name = this_name_node;
|
|
arg2->type = cvoidp;
|
|
arg2->qual = Q_CONST;
|
|
|
|
arg1->next = tfunc->args;
|
|
arg2->next = arg1;
|
|
tfunc->args = arg2;
|
|
tfunc->flags |= FUNC_FLAGS_80;
|
|
}
|
|
|
|
void CDecl_AddArgument(TypeFunc *tfunc, Type *argtype) {
|
|
FuncArg *arg = CParser_NewFuncArg();
|
|
arg->type = argtype;
|
|
|
|
arg->next = tfunc->args;
|
|
tfunc->args = arg;
|
|
|
|
if (arg->next && arg->next->type == &stvoid)
|
|
arg->next = NULL;
|
|
}
|
|
|
|
Boolean CDecl_CheckArrayIntegr(Type *type) {
|
|
if (!IsCompleteType(type))
|
|
return 0;
|
|
|
|
if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) {
|
|
CError_Error(CErrorStr289);
|
|
return 0;
|
|
}
|
|
|
|
if (IS_TYPE_REFERENCE(type)) {
|
|
CError_Error(CErrorStr196);
|
|
return 0;
|
|
}
|
|
|
|
return CanCreateObject(type);
|
|
}
|
|
|
|
static Boolean checkfuncintegr(Type *type) {
|
|
if (IS_TYPE_VOID(type))
|
|
return 1;
|
|
|
|
if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) {
|
|
CError_Error(CErrorStr283);
|
|
return 0;
|
|
}
|
|
|
|
return CanCreateObject(type);
|
|
}
|
|
|
|
void CDecl_ParseDirectFuncDecl(DeclInfo *declinfo) {
|
|
FuncArg *list;
|
|
TypeFunc *tfunc;
|
|
|
|
if (tk == ')') {
|
|
if (copts.cplusplus)
|
|
list = NULL;
|
|
else
|
|
list = &oldstyle;
|
|
tk = lex();
|
|
} else {
|
|
list = parameter_type_list(declinfo);
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
}
|
|
|
|
tfunc = galloc(sizeof(TypeFunc));
|
|
memclrw(tfunc, sizeof(TypeFunc));
|
|
tfunc->type = TYPEFUNC;
|
|
tfunc->args = list;
|
|
if (declinfo->qual & Q_PASCAL) {
|
|
declinfo->qual &= ~Q_PASCAL;
|
|
tfunc->flags = FUNC_FLAGS_PASCAL;
|
|
}
|
|
|
|
if (copts.cplusplus) {
|
|
CDecl_ParseCPPFuncDecl(tfunc);
|
|
if (declinfo->storageclass == TK_TYPEDEF && tfunc->exspecs)
|
|
CError_Error(CErrorStr264);
|
|
}
|
|
|
|
scandirectdecl1(declinfo);
|
|
if (!checkfuncintegr(declinfo->thetype))
|
|
declinfo->thetype = &stvoid;
|
|
|
|
tfunc->functype = declinfo->thetype;
|
|
tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE);
|
|
declinfo->thetype = (Type *) tfunc;
|
|
declinfo->qual &= ~(Q_CONST | Q_VOLATILE);
|
|
declinfo->x49 = 0;
|
|
}
|
|
|
|
static void scandirectdecl1(DeclInfo *declinfo) {
|
|
Boolean flag;
|
|
CInt64 len;
|
|
ENode *expr;
|
|
TypeTemplDep *ttempl;
|
|
|
|
flag = 0;
|
|
if (tk == '[') {
|
|
if ((tk = lex()) == ']') {
|
|
len = cint64_zero;
|
|
tk = lex();
|
|
flag = 1;
|
|
} else {
|
|
if (!declinfo->x46 || declinfo->x47) {
|
|
expr = CExpr_IntegralConstOrDepExpr();
|
|
if (!ENODE_IS(expr, EINTCONST)) {
|
|
if (tk != ']')
|
|
CError_ErrorSkip(CErrorStr125);
|
|
else
|
|
tk = lex();
|
|
declinfo->x47 = 1;
|
|
scandirectdecl1(declinfo);
|
|
if (!CDecl_CheckArrayIntegr(declinfo->thetype))
|
|
declinfo->thetype = (Type *) &stsignedchar;
|
|
ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY);
|
|
ttempl->u.array.type = declinfo->thetype;
|
|
ttempl->u.array.index = CInline_CopyExpression(expr, CopyMode1);
|
|
declinfo->thetype = (Type *) ttempl;
|
|
return;
|
|
}
|
|
len = expr->data.intval;
|
|
if (CInt64_IsNegative(&len)) {
|
|
CError_Error(CErrorStr124);
|
|
len = cint64_one;
|
|
} else if (CInt64_IsZero(&len)) {
|
|
if (!copts.ANSIstrict && declinfo->x50) {
|
|
flag = 1;
|
|
} else {
|
|
CError_Error(CErrorStr124);
|
|
len = cint64_one;
|
|
}
|
|
}
|
|
} else {
|
|
len = cint64_one;
|
|
expr = expression();
|
|
if (IS_TYPE_INT(expr->rtype)) {
|
|
if (!ENODE_IS(expr, EINTCONST))
|
|
declinfo->x24 = expr;
|
|
else
|
|
len = expr->data.intval;
|
|
} else {
|
|
CError_Error(CErrorStr124);
|
|
}
|
|
}
|
|
|
|
if (tk != ']')
|
|
CError_ErrorSkip(CErrorStr125);
|
|
else
|
|
tk = lex();
|
|
}
|
|
|
|
declinfo->x47 = 1;
|
|
scandirectdecl1(declinfo);
|
|
|
|
if (!flag && !CDecl_CheckArrayIntegr(declinfo->thetype))
|
|
declinfo->thetype = (Type *) &stsignedchar;
|
|
|
|
if (!declinfo->thetype->size && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) {
|
|
ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY);
|
|
ttempl->u.array.type = declinfo->thetype;
|
|
ttempl->u.array.index = CInline_CopyExpression(intconstnode((Type *) &stsignedint, CInt64_GetULong(&len)), CopyMode1);
|
|
declinfo->thetype = (Type *) ttempl;
|
|
} else {
|
|
declinfo->thetype = CDecl_NewArrayType(declinfo->thetype, declinfo->thetype->size * CInt64_GetULong(&len));
|
|
}
|
|
} else if (tk == '(') {
|
|
if (!copts.cplusplus || !declinfo->name || IS_TYPE_VOID(declinfo->thetype) || CParser_TryParamList(!IS_TYPE_CLASS(declinfo->thetype))) {
|
|
tk = lex();
|
|
CDecl_ParseDirectFuncDecl(declinfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void substitute_type(Type *type1, Type *type2) {
|
|
SInt32 oldsize;
|
|
|
|
while (1) {
|
|
switch (type1->type) {
|
|
case TYPEPOINTER:
|
|
if (TYPE_POINTER(type1)->target == &stillegal) {
|
|
TYPE_POINTER(type1)->target = type2;
|
|
type1->size = 4;
|
|
return;
|
|
}
|
|
type1 = TYPE_POINTER(type1)->target;
|
|
break;
|
|
case TYPEMEMBERPOINTER:
|
|
if (TYPE_MEMBER_POINTER(type1)->ty1 == &stillegal) {
|
|
TYPE_MEMBER_POINTER(type1)->ty1 = type2;
|
|
if (IS_TYPE_FUNC(type2)) {
|
|
CDecl_MakePTMFuncType(TYPE_FUNC(type2));
|
|
type1->size = 12;
|
|
} else {
|
|
type1->size = 4;
|
|
}
|
|
return;
|
|
}
|
|
type1 = TYPE_MEMBER_POINTER(type1)->ty1;
|
|
break;
|
|
case TYPEARRAY:
|
|
if (TYPE_POINTER(type1)->target == &stillegal) {
|
|
if (!CDecl_CheckArrayIntegr(type2))
|
|
type2 = (Type *) &stsignedchar;
|
|
type1->size *= type2->size;
|
|
TYPE_POINTER(type1)->target = type2;
|
|
return;
|
|
}
|
|
oldsize = TYPE_POINTER(type1)->target->size;
|
|
substitute_type(TYPE_POINTER(type1)->target, type2);
|
|
if (oldsize != TYPE_POINTER(type1)->target->size && oldsize != 0)
|
|
type1->size = TYPE_POINTER(type1)->target->size * (type1->size / oldsize);
|
|
return;
|
|
case TYPEFUNC:
|
|
if (TYPE_FUNC(type1)->functype == &stillegal) {
|
|
if (!checkfuncintegr(type2))
|
|
type2 = &stvoid;
|
|
TYPE_FUNC(type1)->functype = type2;
|
|
CDecl_SetFuncResultReg((TypeFunc *) type1);
|
|
return;
|
|
}
|
|
type1 = TYPE_FUNC(type1)->functype;
|
|
break;
|
|
case TYPETEMPLATE:
|
|
if (TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_ARRAY) {
|
|
if (TYPE_TEMPLATE(type1)->u.array.type == &stillegal) {
|
|
if (!CDecl_CheckArrayIntegr(type2))
|
|
type2 = (Type *) &stsignedchar;
|
|
TYPE_TEMPLATE(type1)->u.array.type = type2;
|
|
return;
|
|
}
|
|
type1 = TYPE_TEMPLATE(type1)->u.array.type;
|
|
} else {
|
|
CError_Error(CErrorStr146);
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void scandecl(DeclInfo *declinfo) {
|
|
Type *oldtype;
|
|
Type *newtype;
|
|
|
|
oldtype = declinfo->thetype;
|
|
declinfo->thetype = &stillegal;
|
|
scandeclarator(declinfo);
|
|
|
|
if (tk != ')')
|
|
CError_ErrorSkip(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
|
|
newtype = declinfo->thetype;
|
|
if (newtype == &stillegal) {
|
|
declinfo->thetype = oldtype;
|
|
scandirectdecl1(declinfo);
|
|
} else {
|
|
declinfo->thetype = oldtype;
|
|
scandirectdecl1(declinfo);
|
|
substitute_type(newtype, declinfo->thetype);
|
|
declinfo->thetype = newtype;
|
|
}
|
|
}
|
|
|
|
static Boolean CDecl_ParseOperatorDecl(DeclInfo *declinfo) {
|
|
if (declinfo->x3E) {
|
|
CError_Error(CErrorStr121);
|
|
return 0;
|
|
}
|
|
|
|
declinfo->x3E = 0;
|
|
if (!CParser_ParseOperatorName(&declinfo->x3E, declinfo->x4A && cscope_current->theclass, 0))
|
|
return 0;
|
|
|
|
if (!declinfo->x3E) {
|
|
conversion_type_name(declinfo);
|
|
tkidentifier = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual);
|
|
declinfo->x54 = 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static Boolean CDecl_IsEnumClassTypeOrRef(Type *type) {
|
|
if (IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type))
|
|
return 1;
|
|
if (!IS_TYPE_REFERENCE(type))
|
|
return 0;
|
|
type = TYPE_POINTER(type)->target;
|
|
return IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type);
|
|
}
|
|
|
|
typedef enum OpMysteryValue {
|
|
OpMysteryValue0 = 0,
|
|
OpMysteryValue1 = 1,
|
|
OpMysteryValue2 = 2,
|
|
OpMysteryValue3 = 3,
|
|
OpMysteryValue4 = 4
|
|
} OpMysteryValue;
|
|
|
|
static Boolean CDecl_CheckOperatorType(DeclInfo *declinfo, Boolean flag) {
|
|
FuncArg *args;
|
|
FuncArg *secondarg;
|
|
Type *functype;
|
|
short r27;
|
|
Boolean r6;
|
|
|
|
if (!IS_TYPE_FUNC(declinfo->thetype)) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
|
|
functype = TYPE_FUNC(declinfo->thetype)->functype;
|
|
args = TYPE_FUNC(declinfo->thetype)->args;
|
|
if (args) {
|
|
if (args != &elipsis && args != &oldstyle) {
|
|
r27 = OpMysteryValue1;
|
|
if (args->dexpr) {
|
|
switch (declinfo->x3E) {
|
|
case TK_NEW:
|
|
case TK_DELETE:
|
|
case TK_NEW_ARRAY:
|
|
case TK_DELETE_ARRAY:
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr205);
|
|
}
|
|
}
|
|
|
|
secondarg = args->next;
|
|
if (secondarg) {
|
|
//r27 = ((secondarg != &elipsis && !secondarg->next) != 0) ? OpMysteryValue2 : OpMysteryValue3;
|
|
if ((secondarg != &elipsis && !secondarg->next) != 0)
|
|
r27 = OpMysteryValue2;
|
|
else
|
|
r27 = OpMysteryValue3;
|
|
if (secondarg->dexpr) {
|
|
switch (declinfo->x3E) {
|
|
case '(':
|
|
case TK_NEW:
|
|
case TK_DELETE:
|
|
case TK_NEW_ARRAY:
|
|
case TK_DELETE_ARRAY:
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr205);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
r27 = OpMysteryValue3;
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
|
|
r6 = flag && IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype)) && !TYPE_METHOD(declinfo->thetype)->x26;
|
|
switch (declinfo->x3E) {
|
|
case TK_NEW:
|
|
case TK_NEW_ARRAY:
|
|
if (r6 || !is_typesame(functype, (Type *) &void_ptr) || r27 < OpMysteryValue1 || args->type != CABI_GetSizeTType()) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
case TK_DELETE:
|
|
case TK_DELETE_ARRAY:
|
|
if (r6 || !IS_TYPE_VOID(functype) || r27 < OpMysteryValue1 || !is_typesame(args->type, (Type *) &void_ptr)) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
case '=':
|
|
if (!r6) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
break;
|
|
case '(':
|
|
if (!r6) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
case '[':
|
|
if (!r6) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
break;
|
|
case TK_ARROW:
|
|
if (r27 != OpMysteryValue1 || r6 == 0) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
case TK_INCREMENT:
|
|
case TK_DECREMENT:
|
|
if (r27 == OpMysteryValue2 && secondarg->type != (Type *) &stsignedint) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (flag && !r6) {
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
|
|
switch (declinfo->x3E) {
|
|
case '&':
|
|
case '*':
|
|
case '+':
|
|
case '-':
|
|
case TK_INCREMENT:
|
|
case TK_DECREMENT:
|
|
if (r27 != OpMysteryValue1)
|
|
goto whatever;
|
|
case '!':
|
|
case '~':
|
|
if (r27 == OpMysteryValue1) {
|
|
if (flag || CDecl_IsEnumClassTypeOrRef(args->type))
|
|
return 1;
|
|
}
|
|
break;
|
|
case '%':
|
|
case ',':
|
|
case '/':
|
|
case '<':
|
|
case '=':
|
|
case '>':
|
|
case '[':
|
|
case '^':
|
|
case '|':
|
|
case TK_MULT_ASSIGN:
|
|
case TK_DIV_ASSIGN:
|
|
case TK_MOD_ASSIGN:
|
|
case TK_ADD_ASSIGN:
|
|
case TK_SUB_ASSIGN:
|
|
case TK_SHL_ASSIGN:
|
|
case TK_SHR_ASSIGN:
|
|
case TK_AND_ASSIGN:
|
|
case TK_XOR_ASSIGN:
|
|
case TK_OR_ASSIGN:
|
|
case TK_LOGICAL_OR:
|
|
case TK_LOGICAL_AND:
|
|
case TK_LOGICAL_EQ:
|
|
case TK_LOGICAL_NE:
|
|
case TK_LESS_EQUAL:
|
|
case TK_GREATER_EQUAL:
|
|
case TK_SHL:
|
|
case TK_SHR:
|
|
case TK_ARROW:
|
|
case TK_DOT_STAR:
|
|
case TK_ARROW_STAR:
|
|
whatever:
|
|
if (r27 == OpMysteryValue2) {
|
|
if (flag || CDecl_IsEnumClassTypeOrRef(args->type) || CDecl_IsEnumClassTypeOrRef(secondarg->type))
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
CError_Error(CErrorStr193);
|
|
return 0;
|
|
}
|
|
|
|
static void scandirectdeclarator(DeclInfo *declinfo, NameSpace *nspace) {
|
|
HashNameNode *saveident;
|
|
CScopeSave scopesave;
|
|
Boolean flag;
|
|
|
|
if (nspace)
|
|
CScope_SetNameSpaceScope(nspace, &scopesave);
|
|
|
|
if (tk == '(') {
|
|
if ((tk = lex()) == ')') {
|
|
if (declinfo->x55) {
|
|
CDecl_ParseDirectFuncDecl(declinfo);
|
|
if (nspace)
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
if (nspace)
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!(tk >= TK_AUTO && tk <= TK_BYREF)) {
|
|
if (!(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) {
|
|
scandecl(declinfo);
|
|
if (nspace)
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
} else {
|
|
saveident = tkidentifier;
|
|
switch (lookahead()) {
|
|
case ')':
|
|
case ',':
|
|
break;
|
|
default:
|
|
tkidentifier = saveident;
|
|
scandecl(declinfo);
|
|
if (nspace)
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (declinfo->name)
|
|
CError_Error(CErrorStr121);
|
|
|
|
CDecl_ParseDirectFuncDecl(declinfo);
|
|
if (nspace)
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
}
|
|
|
|
if (nspace) {
|
|
if (tk == TK_OPERATOR) {
|
|
if (!CDecl_ParseOperatorDecl(declinfo)) {
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
}
|
|
|
|
if (declinfo->x54) {
|
|
declinfo->nspace = nspace;
|
|
declinfo->name = tkidentifier;
|
|
if (nspace)
|
|
CScope_RestoreScope(&scopesave);
|
|
|
|
if (tk == '(') {
|
|
tk = lex();
|
|
CDecl_ParseDirectFuncDecl(declinfo);
|
|
if (IS_TYPE_FUNC(declinfo->thetype))
|
|
TYPE_FUNC(declinfo->thetype)->flags |= FUNC_FLAGS_40;
|
|
else
|
|
CError_Error(CErrorStr121);
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
return;
|
|
}
|
|
|
|
flag = 1;
|
|
} else if (tk != TK_IDENTIFIER) {
|
|
CError_Error(CErrorStr107);
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
} else {
|
|
flag = 0;
|
|
}
|
|
|
|
if (declinfo->name) {
|
|
CError_Error(CErrorStr121);
|
|
CScope_RestoreScope(&scopesave);
|
|
return;
|
|
}
|
|
|
|
declinfo->nspace = nspace;
|
|
declinfo->name = tkidentifier;
|
|
if (!flag)
|
|
tk = lex();
|
|
} else if (tk == TK_IDENTIFIER) {
|
|
if (declinfo->name)
|
|
CError_Error(CErrorStr121);
|
|
declinfo->name = tkidentifier;
|
|
tk = lex();
|
|
} else if (tk == TK_OPERATOR) {
|
|
if (!CDecl_ParseOperatorDecl(declinfo))
|
|
return;
|
|
declinfo->name = tkidentifier;
|
|
}
|
|
|
|
if (tk == '<' && declinfo->x51) {
|
|
declinfo->expltargs = CTempl_ParseUncheckTemplArgs(NULL, 0);
|
|
declinfo->has_expltargs = 1;
|
|
declinfo->x51 = 0;
|
|
tk = lex();
|
|
}
|
|
|
|
scandirectdecl1(declinfo);
|
|
|
|
if (nspace)
|
|
CScope_RestoreScope(&scopesave);
|
|
}
|
|
|
|
void makememberpointertype(DeclInfo *declinfo, TypeClass *tclass, UInt32 qual) {
|
|
TypeMemberPointer *tmemp;
|
|
TypeFunc *tfunc;
|
|
|
|
if (tclass->flags & CLASS_FLAGS_1) {
|
|
CError_Error(CErrorStr191);
|
|
declinfo->thetype = (Type *) &stsignedint;
|
|
return;
|
|
}
|
|
if (tclass->sominfo) {
|
|
CError_Error(CErrorStr290);
|
|
declinfo->thetype = (Type *) &stsignedint;
|
|
return;
|
|
}
|
|
|
|
tmemp = galloc(sizeof(TypeMemberPointer));
|
|
memclrw(tmemp, sizeof(TypeMemberPointer));
|
|
tmemp->type = TYPEMEMBERPOINTER;
|
|
tmemp->ty2 = (Type *) tclass;
|
|
tmemp->qual = qual;
|
|
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
tfunc = galloc(sizeof(TypeFunc));
|
|
*tfunc = *TYPE_FUNC(declinfo->thetype);
|
|
tmemp->ty1 = (Type *) tfunc;
|
|
tmemp->size = 12;
|
|
CDecl_MakePTMFuncType(tfunc);
|
|
} else {
|
|
tmemp->size = 4;
|
|
tmemp->ty1 = declinfo->thetype;
|
|
}
|
|
declinfo->thetype = (Type *) tmemp;
|
|
}
|
|
|
|
void CDecl_ScanPointer(DeclInfo *declinfo, NameSpace *nspace, Boolean flag) {
|
|
CScopeParseResult pr;
|
|
UInt32 qual;
|
|
|
|
while (1) {
|
|
qual = (tk == '&') ? Q_REFERENCE : 0;
|
|
|
|
for (tk = lex(); ; tk = lex()) {
|
|
switch (tk) {
|
|
case TK_CONST:
|
|
if (qual & Q_CONST)
|
|
CError_Error(CErrorStr121);
|
|
qual |= Q_CONST;
|
|
continue;
|
|
case TK_VOLATILE:
|
|
if (qual & Q_VOLATILE)
|
|
CError_Error(CErrorStr121);
|
|
qual |= Q_VOLATILE;
|
|
continue;
|
|
case TK_RESTRICT:
|
|
if (qual & Q_RESTRICT)
|
|
CError_Error(CErrorStr121);
|
|
qual |= Q_RESTRICT;
|
|
continue;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (IS_TYPE_REFERENCE(declinfo->thetype) || ((qual & Q_REFERENCE) && IS_TYPE_VOID(declinfo->thetype))) {
|
|
CError_Error(CErrorStr196);
|
|
return;
|
|
}
|
|
|
|
if (nspace) {
|
|
makememberpointertype(declinfo, nspace->theclass, qual);
|
|
nspace = NULL;
|
|
} else {
|
|
makethetypepointer(declinfo, qual);
|
|
}
|
|
|
|
switch (tk) {
|
|
case '*':
|
|
continue;
|
|
case '&':
|
|
if (!copts.cplusplus) {
|
|
if (flag)
|
|
scandirectdeclarator(declinfo, NULL);
|
|
return;
|
|
}
|
|
continue;
|
|
case TK_IDENTIFIER:
|
|
if (!copts.cplusplus)
|
|
break;
|
|
if (copts.cpp_extensions && cscope_current->theclass && cscope_current->theclass->classname == tkidentifier && lookahead() == TK_COLON_COLON) {
|
|
tk = lex();
|
|
tk = lex();
|
|
break;
|
|
}
|
|
case TK_COLON_COLON:
|
|
if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) {
|
|
if ((nspace = pr.nspace_0)) {
|
|
if (nspace->theclass && tk == '*')
|
|
continue;
|
|
} else {
|
|
if (pr.x8 && IS_TYPE_TEMPLATE(pr.x8) && declinfo->x30) {
|
|
if (CTempl_IsQualifiedMember(declinfo, pr.x8, &nspace))
|
|
scandirectdeclarator(declinfo, nspace);
|
|
else
|
|
declinfo->x20 = pr.x8;
|
|
return;
|
|
}
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (flag)
|
|
scandirectdeclarator(declinfo, nspace);
|
|
}
|
|
|
|
static void CDecl_TemplatePTM(DeclInfo *declinfo, Type *type) {
|
|
TypeMemberPointer *tmemp = galloc(sizeof(TypeMemberPointer));
|
|
tmemp->type = TYPEMEMBERPOINTER;
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
CDecl_MakePTMFuncType((TypeFunc *) declinfo->thetype);
|
|
tmemp->size = 12;
|
|
} else {
|
|
tmemp->size = 4;
|
|
}
|
|
|
|
tmemp->ty1 = declinfo->thetype;
|
|
tmemp->ty2 = type;
|
|
tmemp->qual = 0;
|
|
declinfo->thetype = (Type *) tmemp;
|
|
}
|
|
|
|
void scandeclarator(DeclInfo *declinfo) {
|
|
CScopeParseResult pr;
|
|
NameSpace *nspace;
|
|
|
|
switch (tk) {
|
|
case '&':
|
|
if (!copts.cplusplus)
|
|
break;
|
|
case '*':
|
|
CDecl_ScanPointer(declinfo, NULL, 1);
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(NULL, declinfo);
|
|
return;
|
|
case TK_IDENTIFIER:
|
|
if (!copts.cplusplus)
|
|
break;
|
|
case TK_COLON_COLON:
|
|
if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) {
|
|
nspace = pr.nspace_0;
|
|
if (nspace) {
|
|
if (nspace->theclass && tk == '*')
|
|
CDecl_ScanPointer(declinfo, nspace, 1);
|
|
else
|
|
scandirectdeclarator(declinfo, nspace);
|
|
return;
|
|
}
|
|
if (pr.x8 && IS_TYPE_TEMPLATE(pr.x8)) {
|
|
if (declinfo->x30 && CTempl_IsQualifiedMember(declinfo, pr.x8, &nspace)) {
|
|
scandirectdeclarator(declinfo, nspace);
|
|
return;
|
|
} else if (declinfo->x30 && tk == TK_OPERATOR) {
|
|
declinfo->x20 = pr.x8;
|
|
return;
|
|
} else if ((tk = lex()) == TK_COLON_COLON && (tk = lex()) == '*') {
|
|
CDecl_TemplatePTM(declinfo, pr.x8);
|
|
tk = lex();
|
|
break;
|
|
} else if (declinfo->x30) {
|
|
declinfo->x20 = pr.x8;
|
|
return;
|
|
}
|
|
}
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
}
|
|
|
|
scandirectdeclarator(declinfo, NULL);
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(NULL, declinfo);
|
|
}
|
|
|
|
void conversion_type_name(DeclInfo *declinfo) {
|
|
CScopeParseResult pr;
|
|
DeclInfo subdeclinfo;
|
|
|
|
memclrw(&subdeclinfo, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&subdeclinfo, 0);
|
|
|
|
switch (tk) {
|
|
case '&':
|
|
case '*':
|
|
CDecl_ScanPointer(&subdeclinfo, NULL, 0);
|
|
break;
|
|
case TK_IDENTIFIER:
|
|
case TK_COLON_COLON:
|
|
if (CScope_ParseQualifiedNameSpace(&pr, 0, 0)) {
|
|
if (pr.nspace_0 && pr.nspace_0->theclass && tk == '*')
|
|
CDecl_ScanPointer(&subdeclinfo, pr.nspace_0, 0);
|
|
else
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
break;
|
|
}
|
|
|
|
declinfo->name = subdeclinfo.name;
|
|
declinfo->thetype = subdeclinfo.thetype;
|
|
declinfo->qual |= subdeclinfo.qual;
|
|
}
|
|
|
|
static void scaninlinefunc(Object *obj) {
|
|
short array[256];
|
|
short r29;
|
|
CInt64 val;
|
|
|
|
if (tk == '{') {
|
|
tk = lex();
|
|
r29 = 0;
|
|
while (1) {
|
|
if (r29 >= 256) {
|
|
CError_Error(CErrorStr127);
|
|
r29 = 255;
|
|
}
|
|
val = CExpr_IntegralConstExpr();
|
|
array[r29++] = CInt64_GetULong(&val);
|
|
if (tk != '}') {
|
|
if (tk != ',')
|
|
CError_Error(CErrorStr116);
|
|
tk = lex();
|
|
} else {
|
|
tk = lex();
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
val = CExpr_IntegralConstExpr();
|
|
array[0] = CInt64_GetULong(&val);
|
|
r29 = 1;
|
|
}
|
|
|
|
obj->datatype = DINLINEFUNC;
|
|
obj->u.ifunc.size = r29 * 2;
|
|
obj->u.ifunc.data = galloc(obj->u.ifunc.size);
|
|
obj->u.ifunc.xrefs = NULL;
|
|
memcpy(obj->u.ifunc.data, array, obj->u.ifunc.size);
|
|
|
|
if (tk != ';')
|
|
CError_Error(CErrorStr123);
|
|
}
|
|
|
|
typedef enum {
|
|
OverloadMode0,
|
|
OverloadMode1,
|
|
OverloadMode2,
|
|
OverloadMode3
|
|
} OverloadMode;
|
|
|
|
static Object *CDecl_OverloadFunctionObject(NameSpaceObjectList *list, DeclInfo *declinfo, Boolean *outflag, OverloadMode mode, Boolean flag2) {
|
|
TypeFunc *scanfunc;
|
|
NameSpaceObjectList *scan;
|
|
TypeFunc *tfunc;
|
|
FuncArg *args;
|
|
FuncArg *scanargs;
|
|
Object *obj;
|
|
Boolean r24;
|
|
short compareresult;
|
|
|
|
if (outflag)
|
|
*outflag = 0;
|
|
|
|
tfunc = (TypeFunc *) declinfo->thetype;
|
|
args = tfunc->args;
|
|
r24 = 0;
|
|
for (scan = list; scan; scan = scan->next) {
|
|
obj = OBJECT(scan->object);
|
|
if (obj->otype != OT_OBJECT)
|
|
continue;
|
|
|
|
scanfunc = TYPE_FUNC(obj->type);
|
|
if (!IS_TYPE_FUNC(scanfunc))
|
|
continue;
|
|
|
|
scanargs = scanfunc->args;
|
|
if (scanfunc->flags & FUNC_FLAGS_100000)
|
|
r24 = 1;
|
|
|
|
if (IS_TYPEFUNC_METHOD(scanfunc)) {
|
|
switch (mode) {
|
|
case OverloadMode0:
|
|
CError_Error(CErrorStr197);
|
|
break;
|
|
case OverloadMode1:
|
|
if (!TYPE_METHOD(scanfunc)->x26)
|
|
continue;
|
|
break;
|
|
case OverloadMode2:
|
|
if (TYPE_METHOD(scanfunc)->x26)
|
|
continue;
|
|
break;
|
|
case OverloadMode3:
|
|
if (!TYPE_METHOD(scanfunc)->x26) {
|
|
if (scanargs->qual & (Q_CONST | Q_VOLATILE))
|
|
continue;
|
|
scanargs = scanargs->next;
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
if (mode)
|
|
CError_Error(CErrorStr197);
|
|
}
|
|
|
|
compareresult = CParser_CompareArgLists(args, scanargs);
|
|
if (compareresult == 1) {
|
|
if (scanfunc->flags & FUNC_FLAGS_40) {
|
|
if (!(tfunc->flags & FUNC_FLAGS_40)) {
|
|
CError_Error(CErrorStr197);
|
|
break;
|
|
}
|
|
if (!is_typesame(tfunc->functype, scanfunc->functype))
|
|
continue;
|
|
if ((tfunc->qual & (Q_CONST | Q_PASCAL)) != (scanfunc->qual & (Q_CONST | Q_PASCAL)))
|
|
continue;
|
|
if ((tfunc->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)) != (scanfunc->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL))) {
|
|
CError_Error(CErrorStr197);
|
|
break;
|
|
}
|
|
if (tfunc->exspecs || scanfunc->exspecs)
|
|
CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs);
|
|
return obj;
|
|
}
|
|
|
|
if (tfunc->flags & FUNC_FLAGS_40) {
|
|
CError_Error(CErrorStr197);
|
|
break;
|
|
}
|
|
|
|
if (!is_typesame(tfunc->functype, scanfunc->functype) || ((tfunc->qual & (Q_CONST | Q_PASCAL)) != (scanfunc->qual & (Q_CONST | Q_PASCAL))) || ((tfunc->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)) != (scanfunc->flags & (FUNC_FLAGS_F0000000 | FUNC_FLAGS_PASCAL)))) {
|
|
CError_Error(CErrorStr197);
|
|
break;
|
|
}
|
|
|
|
if (tfunc->exspecs || scanfunc->exspecs) {
|
|
if (obj->name != newp_fobj->name && obj->name != newa_fobj->name && obj->name != delp_fobj->name && obj->name != dela_fobj->name)
|
|
CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs);
|
|
}
|
|
|
|
return obj;
|
|
} else if (compareresult == 2) {
|
|
CError_Error(CErrorStr197);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (r24 && (flag2 || declinfo->x3C)) {
|
|
if ((obj = CTempl_TemplateFunctionCheck(declinfo, list)))
|
|
return obj;
|
|
}
|
|
|
|
if (!outflag) {
|
|
CError_Error(CErrorStr197);
|
|
return NULL;
|
|
}
|
|
|
|
if (declinfo->nspace)
|
|
CError_Error(CErrorStr336);
|
|
|
|
*outflag = 1;
|
|
obj = CParser_NewFunctionObject(declinfo);
|
|
CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
|
|
|
|
if (tfunc->flags & FUNC_FLAGS_PASCAL) {
|
|
for (scan = list; scan; scan = scan->next) {
|
|
if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) {
|
|
if (TYPE_FUNC(OBJECT(scan->object)->type)->flags & FUNC_FLAGS_PASCAL)
|
|
CError_Error(CErrorStr226);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (copts.cplusplus && declinfo->x4E) {
|
|
for (scan = list; scan; scan = scan->next) {
|
|
if (scan->object->otype == OT_OBJECT && !(OBJECT(scan->object)->qual & Q_80000))
|
|
CError_Error(CErrorStr197);
|
|
}
|
|
}
|
|
|
|
CScope_AddObject(cscope_current, declinfo->name, OBJ_BASE(obj));
|
|
if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_FLAGS_100) &&
|
|
CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
|
|
CTemplClass_RegisterObjectDef(TEMPL_CLASS(cscope_current->theclass), OBJ_BASE(obj));
|
|
|
|
return obj;
|
|
}
|
|
|
|
void MergeDefaultArgs(FuncArg *a, FuncArg *b) {
|
|
FuncArg *scan_a;
|
|
FuncArg *scan_b;
|
|
|
|
if (a == &oldstyle || b == &oldstyle)
|
|
return;
|
|
|
|
scan_a = a;
|
|
scan_b = b;
|
|
while (scan_a && scan_b) {
|
|
if (scan_a->dexpr) {
|
|
while (scan_b) {
|
|
if (scan_b->dexpr) {
|
|
while (a) {
|
|
a->dexpr = NULL;
|
|
a = a->next;
|
|
}
|
|
while (b) {
|
|
b->dexpr = NULL;
|
|
b = b->next;
|
|
}
|
|
CError_Error(CErrorStr205);
|
|
return;
|
|
}
|
|
scan_b = scan_b->next;
|
|
}
|
|
break;
|
|
} else if (scan_b->dexpr) {
|
|
do {
|
|
scan_a = scan_a->next;
|
|
scan_b = scan_b->next;
|
|
if (!scan_a) goto secondpart;
|
|
if (scan_a == &elipsis) goto secondpart;
|
|
if (scan_a->dexpr && scan_b->dexpr) break;
|
|
} while (scan_a->dexpr || scan_b->dexpr);
|
|
|
|
while (a) {
|
|
a->dexpr = NULL;
|
|
a = a->next;
|
|
}
|
|
while (b) {
|
|
b->dexpr = NULL;
|
|
b = b->next;
|
|
}
|
|
CError_Error(CErrorStr205);
|
|
return;
|
|
} else {
|
|
scan_a = scan_a->next;
|
|
scan_b = scan_b->next;
|
|
}
|
|
}
|
|
|
|
secondpart:
|
|
while (a && b) {
|
|
if (b->dexpr)
|
|
a->dexpr = b->dexpr;
|
|
else
|
|
b->dexpr = a->dexpr;
|
|
a = a->next;
|
|
b = b->next;
|
|
}
|
|
}
|
|
|
|
void CheckDefaultArgs(FuncArg *args) {
|
|
FuncArg *scan;
|
|
|
|
scan = args;
|
|
while (scan && !scan->dexpr)
|
|
scan = scan->next;
|
|
|
|
while (scan && scan != &elipsis && scan != &oldstyle) {
|
|
if (!scan->dexpr) {
|
|
while (args) {
|
|
args->dexpr = NULL;
|
|
args = args->next;
|
|
}
|
|
CError_Error(CErrorStr205);
|
|
return;
|
|
}
|
|
scan = scan->next;
|
|
}
|
|
}
|
|
|
|
static void CDecl_FuncRedeclCheck(Object *obj, DeclInfo *declinfo, Boolean flag) {
|
|
if (declinfo->storageclass == TK_STATIC && obj->sclass != TK_STATIC) {
|
|
if (copts.cplusplus)
|
|
CError_Error(CErrorStr260);
|
|
else
|
|
obj->sclass = TK_STATIC;
|
|
}
|
|
|
|
obj->qual |= declinfo->qual;
|
|
if (flag)
|
|
CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
|
|
else
|
|
MergeDefaultArgs(TYPE_FUNC(obj->type)->args, TYPE_FUNC(declinfo->thetype)->args);
|
|
|
|
if (!declinfo->x45)
|
|
TYPE_FUNC(obj->type)->args = TYPE_FUNC(declinfo->thetype)->args;
|
|
}
|
|
|
|
Object *CDecl_GetFunctionObject(DeclInfo *declinfo, NameSpace *nspace, Boolean *pflag, Boolean someotherflag) {
|
|
Boolean r27;
|
|
Object *obj;
|
|
Type *type;
|
|
NameSpace *nspace2;
|
|
NameSpaceObjectList *list;
|
|
TypeMethod tmp;
|
|
Boolean outflag;
|
|
|
|
r27 = 0;
|
|
if (pflag)
|
|
*pflag = 0;
|
|
|
|
nspace2 = declinfo->nspace;
|
|
if (!nspace2)
|
|
nspace2 = cscope_current;
|
|
|
|
CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_OVERLOAD | Q_20000 | Q_INLINE | Q_PASCAL | Q_ASM | Q_VOLATILE | Q_CONST));
|
|
switch (TYPE_FUNC(declinfo->thetype)->functype->type) {
|
|
case TYPEFUNC:
|
|
case TYPEARRAY:
|
|
CError_Error(CErrorStr128);
|
|
TYPE_FUNC(declinfo->thetype)->functype = (Type *) &stsignedint;
|
|
break;
|
|
}
|
|
|
|
if (nspace2->theclass) {
|
|
CError_ASSERT(1969, declinfo->name);
|
|
if (!nspace2->theclass->size)
|
|
CDecl_CompleteType((Type *) nspace2->theclass);
|
|
if (!(list = CScope_GetLocalObject(nspace2, declinfo->name))) {
|
|
CError_Error(CErrorStr140, declinfo->name->name);
|
|
return NULL;
|
|
}
|
|
|
|
obj = OBJECT(list->object);
|
|
type = obj->type;
|
|
if (!IS_TYPE_FUNC(type)) {
|
|
CError_Error(CErrorStr249, CError_GetObjectName(obj), type, obj->qual, declinfo->thetype, declinfo->qual);
|
|
return NULL;
|
|
}
|
|
|
|
if (declinfo->has_expltargs)
|
|
return CTempl_TemplateFunctionCheck(declinfo, list);
|
|
|
|
if (declinfo->x3C || (list->next && list->next->object->otype == OT_OBJECT)) {
|
|
if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_FLAGS_CONST | FUNC_FLAGS_VOLATILE)) {
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass);
|
|
obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode2, someotherflag);
|
|
if (!obj)
|
|
return NULL;
|
|
} else {
|
|
obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode3, someotherflag);
|
|
if (!obj)
|
|
return NULL;
|
|
if (!TYPE_METHOD(obj->type)->x26)
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass);
|
|
}
|
|
} else {
|
|
if (TYPE_METHOD(type)->x26) {
|
|
if (nspace2->theclass->sominfo)
|
|
CSOM_FixNewDeleteFunctype(TYPE_FUNC(declinfo->thetype));
|
|
} else {
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass);
|
|
}
|
|
|
|
if (copts.cpp_extensions) {
|
|
declinfo->qual |= obj->qual & (Q_PASCAL | Q_CONST);
|
|
TYPE_FUNC(declinfo->thetype)->qual |= TYPE_FUNC(obj->type)->qual & (Q_PASCAL | Q_CONST);
|
|
TYPE_FUNC(declinfo->thetype)->flags |= TYPE_FUNC(obj->type)->flags & (FUNC_FLAGS_4000000 | FUNC_FLAGS_10000000);
|
|
}
|
|
|
|
if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_PASCAL | Q_CONST)) != (obj->qual & (Q_PASCAL | Q_CONST))) {
|
|
tmp = *TYPE_METHOD(obj->type);
|
|
*(TYPE_FUNC(&tmp)) = *TYPE_FUNC(declinfo->thetype);
|
|
tmp.flags |= FUNC_FLAGS_METHOD;
|
|
CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, &tmp, declinfo->qual);
|
|
}
|
|
|
|
if (TYPE_FUNC(declinfo->thetype)->exspecs || TYPE_FUNC(obj->type)->exspecs)
|
|
CExcept_CompareSpecifications(TYPE_FUNC(declinfo->thetype)->exspecs, TYPE_FUNC(obj->type)->exspecs);
|
|
}
|
|
|
|
CDecl_FuncRedeclCheck(obj, declinfo, 0);
|
|
if (declinfo->x3C) {
|
|
if (obj->nspace->theclass && !(obj->nspace->theclass->flags & CLASS_FLAGS_800))
|
|
CError_Error(CErrorStr335);
|
|
declinfo->x3C = 0;
|
|
}
|
|
} else {
|
|
if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_FLAGS_VOLATILE | FUNC_FLAGS_CONST))
|
|
CError_Error(CErrorStr384);
|
|
|
|
if (declinfo->x3E && !CDecl_CheckOperatorType(declinfo, 0))
|
|
return NULL;
|
|
|
|
list = CScope_GetLocalObject(nspace2, declinfo->name);
|
|
if (declinfo->has_expltargs)
|
|
return CTempl_TemplateFunctionCheck(declinfo, list);
|
|
|
|
if (list) {
|
|
if (copts.cplusplus) {
|
|
obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, OverloadMode0, someotherflag);
|
|
if (!obj)
|
|
return NULL;
|
|
if (pflag)
|
|
*pflag = outflag;
|
|
if (nspace)
|
|
obj->nspace = nspace;
|
|
} else {
|
|
obj = OBJECT(list->object);
|
|
if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_CONST | Q_PASCAL)) != (obj->qual & (Q_CONST | Q_PASCAL))) {
|
|
CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual);
|
|
r27 = 1;
|
|
if (!IS_TYPE_FUNC(obj->type))
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (!r27 && pflag)
|
|
CDecl_FuncRedeclCheck(obj, declinfo, *pflag);
|
|
} else {
|
|
if (declinfo->nspace)
|
|
CError_Error(CErrorStr336);
|
|
|
|
if (declinfo->has_expltargs) {
|
|
if (declinfo->name)
|
|
CError_Error(CErrorStr140, declinfo->name->name);
|
|
else
|
|
CError_Error(CErrorStr127);
|
|
}
|
|
|
|
obj = CParser_NewFunctionObject(declinfo);
|
|
if (nspace)
|
|
obj->nspace = nspace;
|
|
if (pflag)
|
|
*pflag = 1;
|
|
else
|
|
CError_Error(CErrorStr127);
|
|
|
|
CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
|
|
CScope_AddObject(nspace2, declinfo->name, OBJ_BASE(obj));
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
void CDecl_TypedefDeclarator(DeclInfo *declinfo) {
|
|
NameSpace *nspace;
|
|
NameSpaceObjectList *list;
|
|
ObjType *objt;
|
|
|
|
nspace = declinfo->nspace;
|
|
if (!nspace)
|
|
nspace = cscope_current;
|
|
|
|
CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST));
|
|
if (declinfo->x48 || declinfo->x44)
|
|
CError_Error(CErrorStr121);
|
|
if (declinfo->x3E)
|
|
CError_Error(CErrorStr193);
|
|
|
|
objt = NULL;
|
|
list = CScope_FindName(nspace, declinfo->name);
|
|
if (list) {
|
|
switch (list->object->otype) {
|
|
case OT_TYPE:
|
|
objt = OBJ_TYPE(list->object);
|
|
break;
|
|
case OT_TYPETAG:
|
|
break;
|
|
case OT_NAMESPACE:
|
|
CError_Error(CErrorStr321);
|
|
return;
|
|
case OT_ENUMCONST:
|
|
case OT_OBJECT:
|
|
CError_Error(CErrorStr322);
|
|
return;
|
|
default:
|
|
CError_FATAL(2156);
|
|
}
|
|
}
|
|
|
|
if (objt) {
|
|
const UInt32 mask = Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST;
|
|
if (!is_typesame(objt->type, declinfo->thetype) || (objt->qual & mask) != (declinfo->qual & mask)) {
|
|
CError_Error(CErrorStr249, declinfo->name->name, objt->type, objt->qual, declinfo->thetype, declinfo->qual);
|
|
} else if (!copts.cplusplus && (copts.pedantic || copts.ANSIstrict)) {
|
|
if (copts.pedantic)
|
|
CError_Warning(CErrorStr122, declinfo->name->name);
|
|
else
|
|
CError_Error(CErrorStr122, declinfo->name->name);
|
|
}
|
|
return;
|
|
}
|
|
|
|
objt = galloc(sizeof(ObjType));
|
|
memclrw(objt, sizeof(ObjType));
|
|
objt->otype = OT_TYPE;
|
|
objt->access = ACCESSPUBLIC;
|
|
objt->type = declinfo->thetype;
|
|
objt->qual = declinfo->qual;
|
|
CScope_AddObject(nspace, declinfo->name, OBJ_BASE(objt));
|
|
|
|
if (nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_100) &&
|
|
CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
|
|
CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(objt));
|
|
|
|
if (copts.cplusplus) {
|
|
if (IS_TYPE_CLASS(declinfo->thetype) && IsTempName(TYPE_CLASS(declinfo->thetype)->classname)) {
|
|
TYPE_CLASS(declinfo->thetype)->classname = declinfo->name;
|
|
TYPE_CLASS(declinfo->thetype)->nspace->name = declinfo->name;
|
|
}
|
|
if (IS_TYPE_ENUM(declinfo->thetype) && IsTempName(TYPE_ENUM(declinfo->thetype)->enumname)) {
|
|
TYPE_ENUM(declinfo->thetype)->enumname = declinfo->name;
|
|
}
|
|
}
|
|
|
|
if (cparamblkptr->browseoptions.recordTypedefs && declinfo->file->recordbrowseinfo)
|
|
CBrowse_NewTypedef(nspace, declinfo->name, declinfo->file, declinfo->file2, declinfo->x60, CPrep_BrowserFileOffset());
|
|
}
|
|
|
|
static void CDecl_DataDeclarator(DeclInfo *declinfo, short access, Boolean flag) {
|
|
NameSpaceObjectList *list;
|
|
Object *obj;
|
|
NameSpace *nspace;
|
|
Boolean tmpflag;
|
|
ENode *expr;
|
|
|
|
nspace = declinfo->nspace;
|
|
if (!nspace)
|
|
nspace = cscope_current;
|
|
|
|
CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_OVERLOAD | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST));
|
|
if (declinfo->x48 || declinfo->x44)
|
|
CError_Error(CErrorStr121);
|
|
if (declinfo->x3E)
|
|
CError_Error(CErrorStr193);
|
|
|
|
obj = NULL;
|
|
list = CScope_FindName(nspace, declinfo->name);
|
|
if (list) {
|
|
switch (list->object->otype) {
|
|
case OT_OBJECT:
|
|
obj = OBJECT(list->object);
|
|
if (flag)
|
|
CError_Error(CErrorStr122, declinfo->name->name);
|
|
break;
|
|
case OT_TYPETAG:
|
|
break;
|
|
case OT_NAMESPACE:
|
|
CError_Error(CErrorStr321);
|
|
return;
|
|
case OT_ENUMCONST:
|
|
case OT_TYPE:
|
|
CError_Error(CErrorStr322);
|
|
break;
|
|
case OT_MEMBERVAR:
|
|
CError_Error(CErrorStr221);
|
|
break;
|
|
default:
|
|
CError_FATAL(2281);
|
|
}
|
|
}
|
|
|
|
if (copts.cplusplus) {
|
|
if (!flag)
|
|
CDecl_CompleteType(declinfo->thetype);
|
|
switch (declinfo->storageclass) {
|
|
case TK_EXTERN:
|
|
if (tk == '=' || tk == '(')
|
|
declinfo->storageclass = 0;
|
|
break;
|
|
case 0:
|
|
if (CParser_IsConst(declinfo->thetype, declinfo->qual)) {
|
|
if ((!obj && !nspace->theclass) || (obj && obj->sclass != TK_EXTERN && !obj->nspace->theclass))
|
|
declinfo->storageclass = TK_STATIC;
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
if (declinfo->storageclass == TK_EXTERN && tk == '=')
|
|
declinfo->storageclass = 0;
|
|
}
|
|
|
|
if (IS_TYPE_ARRAY(declinfo->thetype) && !declinfo->thetype->size && !declinfo->storageclass && tk != '=')
|
|
declinfo->storageclass = TK_EXTERN;
|
|
|
|
if (obj) {
|
|
if ((!obj->type->size || !declinfo->thetype->size) && IS_TYPE_ARRAY(declinfo->thetype) && IS_TYPE_ARRAY(obj->type))
|
|
tmpflag = is_typesame(TYPE_POINTER(declinfo->thetype)->target, TYPE_POINTER(obj->type)->target);
|
|
else
|
|
tmpflag = is_typesame(declinfo->thetype, obj->type);
|
|
|
|
if (!tmpflag || (obj->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST)) != (declinfo->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST)))
|
|
CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual);
|
|
|
|
if (obj->qual & Q_10000) {
|
|
if (tk == ',' || tk == ';')
|
|
return;
|
|
CError_Error(CErrorStr333, obj);
|
|
}
|
|
|
|
if (declinfo->storageclass != TK_EXTERN) {
|
|
if (obj->sclass != TK_EXTERN && declinfo->storageclass && obj->sclass != declinfo->storageclass)
|
|
CError_Error(CErrorStr333, obj);
|
|
|
|
if (tmpflag) {
|
|
obj->sclass = declinfo->storageclass;
|
|
obj->qual |= declinfo->qual;
|
|
if (declinfo->thetype->size)
|
|
obj->type = declinfo->thetype;
|
|
}
|
|
|
|
CParser_UpdateObject(obj, declinfo);
|
|
} else {
|
|
flag = 1;
|
|
}
|
|
} else {
|
|
if (declinfo->nspace)
|
|
CError_Error(CErrorStr336);
|
|
if (IS_TYPE_CLASS(declinfo->thetype) && TYPE_CLASS(declinfo->thetype)->sominfo)
|
|
CError_Error(CErrorStr288);
|
|
if (!CanCreateObject(declinfo->thetype))
|
|
declinfo->thetype = (Type *) &stsignedint;
|
|
|
|
obj = CParser_NewGlobalDataObject(declinfo);
|
|
obj->access = access;
|
|
CScope_AddObject(nspace, declinfo->name, OBJ_BASE(obj));
|
|
|
|
if (nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_100) &&
|
|
CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
|
|
CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(obj));
|
|
|
|
if (flag && nspace->theclass && cparamblkptr->browseoptions.recordClasses)
|
|
CBrowse_AddClassMemberData(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
|
|
}
|
|
|
|
if (!flag) {
|
|
if (declinfo->nspace) {
|
|
CScopeSave save;
|
|
CScope_SetNameSpaceScope(declinfo->nspace, &save);
|
|
CInit_InitializeData(obj);
|
|
CScope_RestoreScope(&save);
|
|
|
|
if (declinfo->x3C && obj->nspace->theclass && (TYPE_CLASS(obj->nspace->theclass)->flags & CLASS_FLAGS_800))
|
|
declinfo->x3C = 0;
|
|
} else {
|
|
CInit_InitializeData(obj);
|
|
}
|
|
|
|
if (declinfo->file->recordbrowseinfo && obj->sclass != TK_EXTERN)
|
|
CBrowse_NewData(obj, declinfo->file, declinfo->file2, declinfo->x60, CPrep_BrowserFileOffset());
|
|
} else if (tk == '=') {
|
|
tk = lex();
|
|
expr = CExpr_IntegralConstOrDepExpr();
|
|
if (IS_TYPE_TEMPLATE(obj->type) || !ENODE_IS(expr, EINTCONST)) {
|
|
CError_ASSERT(2426, nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_100));
|
|
CTemplClass_RegisterObjectInit(TEMPL_CLASS(nspace->theclass), obj, expr);
|
|
} else if ((obj->qual & Q_CONST) && IS_TYPE_INT_OR_ENUM(obj->type)) {
|
|
obj->u.data.u.intconst = expr->data.intval;
|
|
obj->qual |= Q_10000 | Q_20000;
|
|
} else {
|
|
CError_Error(CErrorStr354, obj->name->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
Boolean CDecl_FunctionDeclarator(DeclInfo *declinfo, NameSpace *nspace, Boolean flag, Boolean flag2) {
|
|
Object *obj;
|
|
Boolean pflag;
|
|
|
|
obj = CDecl_GetFunctionObject(declinfo, nspace, &pflag, 0);
|
|
if (obj) {
|
|
if (declinfo->x44 || tk == '{' || tk == TK_TRY || (declinfo->x4B && tk == ':') || (!copts.cplusplus && isdeclaration(0, 0, 0, 0))) {
|
|
if (!flag || cscope_currentfunc) {
|
|
CError_Error(CErrorStr127);
|
|
if (cscope_currentfunc)
|
|
return 0;
|
|
}
|
|
|
|
if (obj->nspace == cscope_root && !strcmp(obj->name->name, "main")) {
|
|
if (obj->sclass == TK_STATIC || (copts.ANSIstrict && TYPE_FUNC(obj->type)->functype != (Type *) &stsignedint))
|
|
CError_Error(CErrorStr334);
|
|
} else if (copts.checkprotos && (pflag || declinfo->x64)) {
|
|
if (obj->sclass != TK_STATIC && !(obj->qual & Q_INLINE) && !obj->nspace->is_unnamed)
|
|
CError_Warning(CErrorStr178);
|
|
}
|
|
|
|
CFunc_ParseFuncDef(obj, declinfo, NULL, 0, 0, NULL);
|
|
if (declinfo->file->recordbrowseinfo)
|
|
CBrowse_NewFunction(
|
|
obj,
|
|
declinfo->file,
|
|
declinfo->file2,
|
|
declinfo->x60,
|
|
CPrep_BrowserFileOffset());
|
|
|
|
if (copts.cplusplus && lookahead() == ';')
|
|
tk = lex();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void CDecl_ParseSpecialMember(DeclInfo *declinfo, Boolean flag) {
|
|
Object *r28;
|
|
NameSpace *r25;
|
|
|
|
if (!(r28 = declinfo->x10)) {
|
|
CError_ASSERT(2544, declinfo->x14);
|
|
r28 = OBJECT(declinfo->x14->object);
|
|
CError_ASSERT(2546, r28->otype == OT_OBJECT);
|
|
}
|
|
|
|
if (!r28->nspace->theclass) {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
|
|
if (IS_TYPE_FUNC(r28->type)) {
|
|
if (TYPE_FUNC(r28->type)->flags & (FUNC_FLAGS_1000 | FUNC_FLAGS_2000)) {
|
|
if (r28->nspace->theclass->sominfo)
|
|
declinfo->thetype = TYPE(&stvoid);
|
|
else
|
|
declinfo->thetype = TYPE(&void_ptr);
|
|
declinfo->nspace = r28->nspace;
|
|
declinfo->name = r28->name;
|
|
if (TYPE_FUNC(r28->type)->flags & FUNC_FLAGS_1000)
|
|
declinfo->x4B = 1;
|
|
|
|
if ((tk = lex()) == '(') {
|
|
tk = lex();
|
|
|
|
r25 = cscope_current;
|
|
cscope_current = r28->nspace;
|
|
CDecl_ParseDirectFuncDecl(declinfo);
|
|
cscope_current = r25;
|
|
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
if (TYPE_FUNC(r28->type)->flags & FUNC_FLAGS_1000) {
|
|
if ((r28->nspace->theclass->flags & CLASS_FLAGS_20) && !r28->nspace->theclass->sominfo)
|
|
CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort));
|
|
} else {
|
|
if (!r28->nspace->theclass->sominfo)
|
|
CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort));
|
|
}
|
|
if (flag)
|
|
CDecl_FunctionDeclarator(declinfo, NULL, 1, 1);
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
return;
|
|
} else if (TYPE_FUNC(r28->type)->flags & FUNC_FLAGS_40) {
|
|
CError_FATAL(2603);
|
|
|
|
declinfo->thetype = TYPE_FUNC(r28->type)->functype;
|
|
declinfo->qual |= TYPE_FUNC(r28->type)->qual;
|
|
declinfo->nspace = r28->nspace;
|
|
declinfo->name = r28->name;
|
|
|
|
if ((tk = lex()) == '(') {
|
|
tk = lex();
|
|
CDecl_ParseDirectFuncDecl(declinfo);
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
TYPE_FUNC(declinfo->thetype)->flags |= FUNC_FLAGS_40;
|
|
if (flag)
|
|
CDecl_FunctionDeclarator(declinfo, NULL, 1, 1);
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
return;
|
|
} else {
|
|
declinfo->thetype = TYPE(&stsignedint);
|
|
declinfo->nspace = r28->nspace;
|
|
declinfo->name = r28->name;
|
|
|
|
if ((tk = lex()) == '(') {
|
|
tk = lex();
|
|
|
|
r25 = cscope_current;
|
|
cscope_current = r28->nspace;
|
|
CDecl_ParseDirectFuncDecl(declinfo);
|
|
cscope_current = r25;
|
|
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
if (flag)
|
|
CDecl_FunctionDeclarator(declinfo, NULL, 1, 1);
|
|
return;
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
}
|
|
}
|
|
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
|
|
void CDecl_ScanDeclarator(DeclInfo *declinfo) {
|
|
if (declinfo->x14 || declinfo->x10) {
|
|
CDecl_ParseSpecialMember(declinfo, 0);
|
|
CDecl_GetFunctionObject(declinfo, NULL, NULL, 1);
|
|
return;
|
|
}
|
|
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
TypeFunc *copy = galloc(sizeof(TypeFunc));
|
|
*copy = *TYPE_FUNC(declinfo->thetype);
|
|
declinfo->thetype = TYPE(copy);
|
|
}
|
|
scandeclarator(declinfo);
|
|
if (!declinfo->name) {
|
|
CError_Error(CErrorStr121);
|
|
return;
|
|
}
|
|
|
|
if (declinfo->storageclass && declinfo->storageclass != TK_EXTERN)
|
|
CError_Error(CErrorStr177);
|
|
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
CDecl_GetFunctionObject(declinfo, NULL, NULL, 1);
|
|
return;
|
|
}
|
|
|
|
if (declinfo->x48 || declinfo->x44)
|
|
CError_Error(CErrorStr121);
|
|
|
|
if (declinfo->x3E)
|
|
CError_Error(CErrorStr193);
|
|
|
|
if (
|
|
(declinfo->qual & ~(Q_ALIGNED_MASK | Q_OVERLOAD | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST)) ||
|
|
(declinfo->storageclass == TK_TYPEDEF && (declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST)))
|
|
)
|
|
CError_Error(CErrorStr176);
|
|
}
|
|
|
|
void scandeclaratorlist(DeclInfo *declinfo) {
|
|
CScopeSave savescope;
|
|
Type *r30;
|
|
UInt32 r29;
|
|
Boolean r28;
|
|
|
|
if (declinfo->x14 || declinfo->x10) {
|
|
CDecl_ParseSpecialMember(declinfo, 1);
|
|
return;
|
|
}
|
|
|
|
CScope_GetScope(&savescope);
|
|
CError_ASSERT(2707, declinfo->thetype);
|
|
|
|
r28 = 1;
|
|
while (1) {
|
|
r30 = declinfo->thetype;
|
|
r29 = declinfo->qual;
|
|
declinfo->nspace = NULL;
|
|
declinfo->x3E = 0;
|
|
if (IS_TYPE_FUNC(r30)) {
|
|
declinfo->thetype = galloc(sizeof(TypeFunc));
|
|
*TYPE_FUNC(declinfo->thetype) = *TYPE_FUNC(r30);
|
|
}
|
|
declinfo->name = NULL;
|
|
scandeclarator(declinfo);
|
|
if (!declinfo->name) {
|
|
CError_Error(CErrorStr121);
|
|
break;
|
|
}
|
|
|
|
if (declinfo->storageclass != TK_TYPEDEF) {
|
|
if (IS_TYPE_FUNC(declinfo->thetype)) {
|
|
if (!CDecl_FunctionDeclarator(declinfo, NULL, r28, 1))
|
|
return;
|
|
} else {
|
|
CDecl_DataDeclarator(declinfo, ACCESSPUBLIC, 0);
|
|
}
|
|
} else {
|
|
CDecl_TypedefDeclarator(declinfo);
|
|
}
|
|
|
|
CScope_RestoreScope(&savescope);
|
|
declinfo->thetype = r30;
|
|
declinfo->qual = r29;
|
|
|
|
if (tk != ',')
|
|
break;
|
|
tk = lex();
|
|
r28 = 0;
|
|
}
|
|
|
|
if (tk != ';')
|
|
CError_Error(CErrorStr123);
|
|
}
|
|
|
|
static TypeIntegral *CDecl_FindSignedType(short size) {
|
|
if (stsignedchar.size == size)
|
|
return &stsignedchar;
|
|
if (stsignedshort.size == size)
|
|
return &stsignedshort;
|
|
if (stsignedint.size == size)
|
|
return &stsignedint;
|
|
if (stsignedlong.size == size)
|
|
return &stsignedlong;
|
|
if (copts.longlong && copts.longlong_enums && stsignedlonglong.size == size)
|
|
return &stsignedlonglong;
|
|
return &stsignedlong;
|
|
}
|
|
|
|
static TypeIntegral *CDecl_FindUnsignedType(short size) {
|
|
if (stunsignedchar.size == size)
|
|
return &stunsignedchar;
|
|
if (stunsignedshort.size == size)
|
|
return &stunsignedshort;
|
|
if (stunsignedint.size == size)
|
|
return &stunsignedint;
|
|
if (stunsignedlong.size == size)
|
|
return &stunsignedlong;
|
|
if (copts.longlong && copts.longlong_enums && stunsignedlonglong.size == size)
|
|
return &stunsignedlonglong;
|
|
return &stunsignedlong;
|
|
}
|
|
|
|
static TypeIntegral *CDecl_IterateIntegralEnumType(int *t) {
|
|
switch (*t) {
|
|
case 0:
|
|
*t = 1;
|
|
return &stsignedchar;
|
|
case 1:
|
|
if (stsignedshort.size > stsignedchar.size) {
|
|
*t = 2;
|
|
return &stsignedshort;
|
|
}
|
|
case 2:
|
|
if (stsignedint.size > stsignedshort.size) {
|
|
*t = 3;
|
|
return &stsignedint;
|
|
}
|
|
case 3:
|
|
if (stsignedlong.size > stsignedint.size) {
|
|
*t = 4;
|
|
return &stsignedlong;
|
|
}
|
|
case 4:
|
|
*t = 5;
|
|
if (stsignedlonglong.size > stsignedlong.size && copts.longlong && copts.longlong_enums)
|
|
return &stsignedlonglong;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static TypeIntegral *CDecl_IterateUIntegralEnumType(int *t) {
|
|
switch (*t) {
|
|
case 0:
|
|
*t = 1;
|
|
return &stunsignedchar;
|
|
case 1:
|
|
if (stunsignedshort.size > stunsignedchar.size) {
|
|
*t = 2;
|
|
return &stunsignedshort;
|
|
}
|
|
case 2:
|
|
if (stunsignedint.size > stunsignedshort.size) {
|
|
*t = 3;
|
|
return &stunsignedint;
|
|
}
|
|
case 3:
|
|
if (stunsignedlong.size > stunsignedint.size) {
|
|
*t = 4;
|
|
return &stunsignedlong;
|
|
}
|
|
case 4:
|
|
*t = 5;
|
|
if (stunsignedlonglong.size > stunsignedlong.size && copts.longlong && copts.longlong_enums)
|
|
return &stunsignedlonglong;
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static TypeEnum *CDecl_OldParseEnumList(TypeEnum *tenum, HashNameNode *name) {
|
|
AccessType access;
|
|
Boolean has_template_value;
|
|
Boolean r24;
|
|
Boolean r23;
|
|
ObjEnumConst *oec;
|
|
ObjEnumConst *last;
|
|
Boolean overflowed;
|
|
CInt64 val;
|
|
CInt64 minimum;
|
|
CInt64 maximum;
|
|
CInt64 var_74;
|
|
CInt64 unused;
|
|
Type *basetype;
|
|
Type *basetype2;
|
|
CPrepFileInfo *fileinfo;
|
|
SInt32 offset;
|
|
ENode *expr;
|
|
Type *tmp;
|
|
|
|
if (!tenum) {
|
|
tenum = galloc(sizeof(TypeEnum));
|
|
memclrw(tenum, sizeof(TypeEnum));
|
|
tenum->type = TYPEENUM;
|
|
tenum->nspace = cscope_current;
|
|
|
|
if (name) {
|
|
tenum->enumname = name;
|
|
CScope_DefineTypeTag(cscope_current, name, TYPE(tenum));
|
|
}
|
|
|
|
if (!cscope_current->is_global) {
|
|
do {
|
|
tenum->nspace = tenum->nspace->parent;
|
|
} while (!tenum->nspace->is_global);
|
|
if (tenum->enumname)
|
|
tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name);
|
|
}
|
|
}
|
|
|
|
if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_FLAGS_100)) {
|
|
CTemplClass_RegisterEnumType(TEMPL_CLASS(cscope_current->theclass), tenum);
|
|
}
|
|
|
|
access = cscope_current->theclass ? global_access : ACCESSPUBLIC;
|
|
last = NULL;
|
|
unused = cint64_zero;
|
|
val = cint64_zero;
|
|
minimum = cint64_zero;
|
|
maximum = cint64_zero;
|
|
r23 = 0;
|
|
if (copts.enumsalwaysint) {
|
|
basetype = TYPE(&stsignedint);
|
|
r24 = 1;
|
|
} else {
|
|
basetype = TYPE(&stunsignedchar);
|
|
r24 = 0;
|
|
}
|
|
|
|
tk = lex();
|
|
if (!copts.cplusplus || tk != '}') {
|
|
do {
|
|
if (tk != TK_IDENTIFIER) {
|
|
if (tk == '}') {
|
|
if (copts.cpp_extensions)
|
|
break;
|
|
if (!copts.warn_extracomma)
|
|
break;
|
|
}
|
|
CError_Warning(CErrorStr107);
|
|
break;
|
|
}
|
|
|
|
oec = galloc(sizeof(ObjEnumConst));
|
|
memclrw(oec, sizeof(ObjEnumConst));
|
|
oec->otype = OT_ENUMCONST;
|
|
oec->access = access;
|
|
oec->type = TYPE(tenum);
|
|
oec->name = tkidentifier;
|
|
CPrep_BrowserFilePosition(&fileinfo, &offset);
|
|
overflowed = 0;
|
|
if ((tk = lex()) == '=') {
|
|
tk = lex();
|
|
val = CExpr_IntegralConstExprType(&basetype2);
|
|
if (!CInt64_IsNegative(&val) || is_unsigned(basetype2)) {
|
|
if (CInt64_GreaterU(val, minimum)) {
|
|
minimum = val;
|
|
overflowed = 1;
|
|
}
|
|
} else {
|
|
if (CInt64_Less(val, maximum)) {
|
|
maximum = val;
|
|
overflowed = 1;
|
|
}
|
|
if (!r24) {
|
|
basetype = TYPE(&stsignedchar);
|
|
r24 = 1;
|
|
}
|
|
}
|
|
r23 = 0;
|
|
} else {
|
|
if (r23)
|
|
CError_Error(CErrorStr154);
|
|
|
|
if (!r24 || !CInt64_IsNegative(&val)) {
|
|
if (CInt64_GreaterU(val, minimum)) {
|
|
minimum = val;
|
|
overflowed = 1;
|
|
}
|
|
} else {
|
|
if (CInt64_Less(val, maximum)) {
|
|
maximum = val;
|
|
overflowed = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (copts.enumsalwaysint) {
|
|
if (copts.ANSIstrict) {
|
|
if (!CInt64_IsInRange(val, stsignedint.size))
|
|
CError_Error(CErrorStr154);
|
|
} else {
|
|
if (!CInt64_IsInRange(val, stsignedint.size) && !CInt64_IsInURange(val, stunsignedint.size))
|
|
CError_Error(CErrorStr154);
|
|
}
|
|
} else if (r24) {
|
|
switch (basetype->size) {
|
|
case 1:
|
|
if (CInt64_IsInRange(minimum, 1) && CInt64_IsInRange(maximum, 1))
|
|
break;
|
|
basetype = TYPE(CDecl_FindSignedType(2));
|
|
case 2:
|
|
if (CInt64_IsInRange(minimum, 2) && CInt64_IsInRange(maximum, 2))
|
|
break;
|
|
basetype = TYPE(CDecl_FindSignedType(4));
|
|
case 4:
|
|
if (CInt64_IsInRange(minimum, 4) && CInt64_IsInRange(maximum, 4))
|
|
break;
|
|
basetype = TYPE(CDecl_FindSignedType(8));
|
|
if (basetype->size != 8) {
|
|
if (!copts.ANSIstrict && CInt64_IsInRange(maximum, 4) && CInt64_IsInURange(minimum, 4))
|
|
break;
|
|
if (overflowed)
|
|
CError_Error(CErrorStr154);
|
|
break;
|
|
}
|
|
case 8:
|
|
if (CInt64_Equal(val, minimum) && CInt64_IsNegative(&val))
|
|
CError_Error(CErrorStr154);
|
|
break;
|
|
default:
|
|
CError_FATAL(3071);
|
|
}
|
|
} else {
|
|
switch (basetype->size) {
|
|
case 1:
|
|
if (CInt64_IsInURange(minimum, 1))
|
|
break;
|
|
basetype = TYPE(CDecl_FindUnsignedType(2));
|
|
case 2:
|
|
if (CInt64_IsInURange(minimum, 2))
|
|
break;
|
|
basetype = TYPE(CDecl_FindUnsignedType(4));
|
|
case 4:
|
|
if (CInt64_IsInURange(minimum, 4))
|
|
break;
|
|
basetype = TYPE(CDecl_FindUnsignedType(8));
|
|
if (basetype->size != 8) {
|
|
if (overflowed)
|
|
CError_Error(CErrorStr154);
|
|
break;
|
|
}
|
|
case 8:
|
|
break;
|
|
default:
|
|
CError_FATAL(3099);
|
|
}
|
|
}
|
|
|
|
tenum->size = basetype->size;
|
|
tenum->enumtype = basetype;
|
|
oec->val = val;
|
|
CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec));
|
|
|
|
if (last) {
|
|
last->next = oec;
|
|
last = oec;
|
|
} else {
|
|
last = oec;
|
|
tenum->enumlist = oec;
|
|
}
|
|
|
|
if (cparamblkptr->browseoptions.recordEnums) {
|
|
CPrepFileInfo *f = CPrep_BrowserCurrentFile();
|
|
if (f->recordbrowseinfo) {
|
|
CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset());
|
|
}
|
|
}
|
|
|
|
var_74 = CInt64_Add(val, cint64_one);
|
|
if (r24) {
|
|
if (CInt64_IsNegative(&var_74) && !CInt64_IsNegative(&val))
|
|
r23 = 1;
|
|
} else {
|
|
if (CInt64_IsZero(&var_74))
|
|
r23 = 1;
|
|
}
|
|
val = var_74;
|
|
|
|
if (tk != ',')
|
|
break;
|
|
tk = lex();
|
|
} while (1);
|
|
}
|
|
|
|
tenum->size = basetype->size;
|
|
tenum->enumtype = basetype;
|
|
|
|
for (oec = tenum->enumlist; oec; oec = oec->next)
|
|
oec->type = TYPE(tenum);
|
|
|
|
if (tk != '}')
|
|
CError_ErrorSkip(CErrorStr130);
|
|
else
|
|
tk = lex();
|
|
|
|
return tenum;
|
|
}
|
|
|
|
static Type *CDecl_MaxType(Type *a, Type *b) {
|
|
if (a->size > b->size)
|
|
return a;
|
|
if (b->size > a->size)
|
|
return b;
|
|
if (is_unsigned(b))
|
|
return b;
|
|
else
|
|
return a;
|
|
}
|
|
|
|
void CDecl_ComputeUnderlyingEnumType(TypeEnum *tenum) {
|
|
ObjEnumConst *oec;
|
|
ObjEnumConst *oec2;
|
|
Type *r26;
|
|
int t;
|
|
|
|
if (!copts.enumsalwaysint) {
|
|
for (oec2 = tenum->enumlist; oec2; oec2 = oec2->next) {
|
|
if (CInt64_IsNegative(&oec2->val) && !is_unsigned(oec2->type))
|
|
break;
|
|
}
|
|
|
|
if (oec2) {
|
|
CInt64 unused = cint64_zero;
|
|
CInt64 minimum = cint64_zero;
|
|
CInt64 maximum = cint64_zero;
|
|
for (oec = tenum->enumlist; oec; oec = oec->next) {
|
|
if (CInt64_IsNegative(&oec->val) && !is_unsigned(oec->type)) {
|
|
if (CInt64_Less(oec->val, minimum))
|
|
minimum = oec->val;
|
|
} else {
|
|
if (CInt64_GreaterU(oec->val, maximum))
|
|
maximum = oec->val;
|
|
}
|
|
}
|
|
|
|
if (CInt64_IsNegative(&maximum))
|
|
CError_Error(CErrorStr154);
|
|
|
|
t = 0;
|
|
do {
|
|
r26 = TYPE(CDecl_IterateIntegralEnumType(&t));
|
|
if (!r26) {
|
|
r26 = TYPE(&stsignedlong);
|
|
CError_Error(CErrorStr154);
|
|
break;
|
|
}
|
|
|
|
if (CInt64_IsInRange(maximum, r26->size) && CInt64_IsInRange(minimum, r26->size))
|
|
break;
|
|
if (r26->size == stsignedlong.size && !copts.ANSIstrict && CInt64_IsInRange(minimum, r26->size) && CInt64_IsInURange(maximum, r26->size))
|
|
break;
|
|
} while (1);
|
|
} else {
|
|
CInt64 val = cint64_zero;
|
|
|
|
for (oec = tenum->enumlist; oec; oec = oec->next) {
|
|
if (CInt64_GreaterU(oec->val, val))
|
|
val = oec->val;
|
|
}
|
|
|
|
t = 0;
|
|
do {
|
|
r26 = TYPE(CDecl_IterateUIntegralEnumType(&t));
|
|
if (!r26) {
|
|
r26 = TYPE(&stunsignedlong);
|
|
CError_Error(CErrorStr154);
|
|
break;
|
|
}
|
|
if (CInt64_IsInURange(val, r26->size))
|
|
break;
|
|
} while (1);
|
|
}
|
|
} else {
|
|
r26 = TYPE(&stsignedint);
|
|
}
|
|
|
|
tenum->size = r26->size;
|
|
tenum->enumtype = r26;
|
|
for (oec = tenum->enumlist; oec; oec = oec->next)
|
|
oec->type = TYPE(tenum);
|
|
}
|
|
|
|
static Type *CDecl_FindUnderlyingType(short size, CInt64 *a, CInt64 *b) {
|
|
if (CInt64_IsZero(a)) {
|
|
if (size <= stsignedchar.size && CInt64_IsInURange(*b, stunsignedchar.size))
|
|
return TYPE(&stunsignedchar);
|
|
if (size <= stsignedshort.size && CInt64_IsInURange(*b, stunsignedshort.size))
|
|
return TYPE(&stunsignedshort);
|
|
if (size <= stsignedint.size && CInt64_IsInURange(*b, stunsignedint.size))
|
|
return TYPE(&stunsignedint);
|
|
if (size <= stsignedlong.size && CInt64_IsInURange(*b, stunsignedlong.size))
|
|
return TYPE(&stunsignedlong);
|
|
if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInURange(*b, stunsignedlonglong.size))
|
|
return TYPE(&stunsignedlonglong);
|
|
} else {
|
|
if (size <= stsignedchar.size && CInt64_IsInRange(*a, stsignedchar.size) && CInt64_IsInRange(*b, stsignedchar.size))
|
|
return TYPE(&stsignedchar);
|
|
if (size <= stsignedshort.size && CInt64_IsInRange(*a, stsignedshort.size) && CInt64_IsInRange(*b, stsignedshort.size))
|
|
return TYPE(&stsignedshort);
|
|
if (size <= stsignedint.size && CInt64_IsInRange(*a, stsignedint.size) && CInt64_IsInRange(*b, stsignedint.size))
|
|
return TYPE(&stsignedint);
|
|
if (size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInRange(*b, stsignedlong.size))
|
|
return TYPE(&stsignedlong);
|
|
if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInRange(*a, stsignedlonglong.size) && CInt64_IsInRange(*b, stsignedlonglong.size))
|
|
return TYPE(&stsignedlonglong);
|
|
if (!copts.ANSIstrict && size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInURange(*b, stunsignedlong.size))
|
|
return TYPE(&stsignedlong);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static TypeEnum *CDecl_ParseEnumList(TypeEnum *tenum, HashNameNode *name) {
|
|
AccessType access;
|
|
TemplClass *tmclass;
|
|
ObjEnumConst *oec;
|
|
Boolean has_template_value;
|
|
Boolean overflowed;
|
|
Boolean is_first;
|
|
CInt64 val;
|
|
CInt64 minimum;
|
|
CInt64 maximum;
|
|
CInt64 unused;
|
|
Type *basetype;
|
|
CPrepFileInfo *fileinfo;
|
|
SInt32 offset;
|
|
ENode *expr;
|
|
Type *tmp;
|
|
ObjEnumConst *last;
|
|
|
|
if (!tenum) {
|
|
tenum = galloc(sizeof(TypeEnum));
|
|
memclrw(tenum, sizeof(TypeEnum));
|
|
tenum->type = TYPEENUM;
|
|
tenum->nspace = cscope_current;
|
|
|
|
if (name) {
|
|
tenum->enumname = name;
|
|
CScope_DefineTypeTag(cscope_current, name, TYPE(tenum));
|
|
}
|
|
|
|
if (!cscope_current->is_global) {
|
|
do {
|
|
tenum->nspace = tenum->nspace->parent;
|
|
} while (!tenum->nspace->is_global);
|
|
if (tenum->enumname)
|
|
tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name);
|
|
}
|
|
}
|
|
|
|
if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_FLAGS_100)) {
|
|
tmclass = TEMPL_CLASS(cscope_current->theclass);
|
|
CTemplClass_RegisterEnumType(tmclass, tenum);
|
|
} else {
|
|
tmclass = NULL;
|
|
}
|
|
|
|
access = cscope_current->theclass ? global_access : ACCESSPUBLIC;
|
|
last = NULL;
|
|
is_first = 1;
|
|
has_template_value = 0;
|
|
unused = cint64_zero;
|
|
val = cint64_zero;
|
|
minimum = cint64_zero;
|
|
maximum = cint64_zero;
|
|
basetype = copts.enumsalwaysint ? TYPE(&stsignedint) : TYPE(&stsignedchar);
|
|
tenum->size = basetype->size;
|
|
tenum->enumtype = basetype;
|
|
|
|
do {
|
|
if ((tk = lex()) != TK_IDENTIFIER) {
|
|
if (tk == '}') {
|
|
if (is_first) {
|
|
if (copts.cplusplus)
|
|
break;
|
|
} else {
|
|
if (!copts.warn_extracomma)
|
|
break;
|
|
if (copts.c9x)
|
|
break;
|
|
if (copts.cpp_extensions)
|
|
break;
|
|
}
|
|
CError_Warning(CErrorStr107);
|
|
} else {
|
|
CError_Error(CErrorStr107);
|
|
}
|
|
break;
|
|
}
|
|
|
|
oec = galloc(sizeof(ObjEnumConst));
|
|
memclrw(oec, sizeof(ObjEnumConst));
|
|
oec->otype = OT_ENUMCONST;
|
|
oec->access = access;
|
|
oec->name = tkidentifier;
|
|
CPrep_BrowserFilePosition(&fileinfo, &offset);
|
|
overflowed = 0;
|
|
if ((tk = lex()) == '=') {
|
|
tk = lex();
|
|
if (tmclass) {
|
|
expr = CExpr_IntegralConstOrDepExpr();
|
|
if (ENODE_IS(expr, EINTCONST)) {
|
|
val = expr->data.intval;
|
|
basetype = expr->rtype;
|
|
has_template_value = 0;
|
|
} else {
|
|
val = cint64_zero;
|
|
basetype = TYPE(tenum);
|
|
CTemplClass_RegisterEnumerator(tmclass, oec, expr);
|
|
has_template_value = 1;
|
|
}
|
|
} else {
|
|
val = CExpr_IntegralConstExprType(&basetype);
|
|
has_template_value = 0;
|
|
}
|
|
} else if (has_template_value) {
|
|
CTemplClass_RegisterEnumerator(tmclass, oec, NULL);
|
|
} else if (!is_first) {
|
|
if (is_unsigned(basetype)) {
|
|
val = CInt64_Add(val, cint64_one);
|
|
if (CInt64_IsZero(&val))
|
|
overflowed = 1;
|
|
} else if (!CInt64_IsNegative(&val)) {
|
|
val = CInt64_Add(val, cint64_one);
|
|
if (CInt64_IsNegative(&val))
|
|
overflowed = 1;
|
|
} else {
|
|
val = CInt64_Add(val, cint64_one);
|
|
}
|
|
}
|
|
|
|
if (!has_template_value) {
|
|
if (copts.enumsalwaysint) {
|
|
if (!CInt64_IsInRange(val, stsignedint.size) && (copts.ANSIstrict || !CInt64_IsInURange(val, stunsignedint.size)))
|
|
overflowed = 1;
|
|
basetype = TYPE(&stsignedint);
|
|
} else if (CInt64_IsNegative(&val) && !is_unsigned(basetype)) {
|
|
if (CInt64_Less(val, minimum)) {
|
|
minimum = val;
|
|
if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) {
|
|
tenum->size = tmp->size;
|
|
tenum->enumtype = tmp;
|
|
} else {
|
|
overflowed = 1;
|
|
}
|
|
}
|
|
} else {
|
|
if (CInt64_GreaterU(val, maximum)) {
|
|
maximum = val;
|
|
if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) {
|
|
tenum->size = tmp->size;
|
|
tenum->enumtype = tmp;
|
|
} else {
|
|
overflowed = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (overflowed)
|
|
CError_Error(CErrorStr154);
|
|
|
|
oec->val = val;
|
|
oec->type = basetype;
|
|
CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec));
|
|
|
|
if (last) {
|
|
last->next = oec;
|
|
last = oec;
|
|
} else {
|
|
last = oec;
|
|
tenum->enumlist = oec;
|
|
}
|
|
|
|
if (cparamblkptr->browseoptions.recordEnums) {
|
|
CPrepFileInfo *f = CPrep_BrowserCurrentFile();
|
|
if (f->recordbrowseinfo) {
|
|
CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset());
|
|
}
|
|
}
|
|
|
|
is_first = 0;
|
|
} while (tk == ',');
|
|
|
|
for (oec = tenum->enumlist; oec; oec = oec->next)
|
|
oec->type = TYPE(tenum);
|
|
|
|
if (tk != '}')
|
|
CError_ErrorSkip(CErrorStr130);
|
|
else
|
|
tk = lex();
|
|
|
|
return tenum;
|
|
}
|
|
|
|
void scanenum(DeclInfo *declinfo) {
|
|
HashNameNode *name;
|
|
Type *type;
|
|
CScopeParseResult pr;
|
|
|
|
if (tk == '{') {
|
|
declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL));
|
|
TYPE_ENUM(declinfo->thetype)->enumname = CParser_AppendUniqueNameFile("@enum");
|
|
return;
|
|
}
|
|
|
|
if (tk == TK_IDENTIFIER) {
|
|
name = tkidentifier;
|
|
if (lookahead() == '{') {
|
|
type = CScope_GetLocalTagType(cscope_current, name);
|
|
if (type) {
|
|
lex();
|
|
do_shit:
|
|
if (type->size || !IS_TYPE_ENUM(type)) {
|
|
CError_Error(CErrorStr122, name->name);
|
|
declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL));
|
|
return;
|
|
}
|
|
declinfo->thetype = TYPE(CDecl_ParseEnumList(TYPE_ENUM(type), NULL));
|
|
} else {
|
|
lex();
|
|
declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, name));
|
|
}
|
|
|
|
if (cparamblkptr->browseoptions.recordEnums && declinfo->file->recordbrowseinfo)
|
|
CBrowse_NewEnum(
|
|
cscope_current,
|
|
TYPE_ENUM(declinfo->thetype)->enumname,
|
|
declinfo->file,
|
|
declinfo->file2,
|
|
declinfo->x60,
|
|
CPrep_BrowserFileOffset());
|
|
return;
|
|
} else {
|
|
CError_ASSERT(3851, !copts.cplusplus || tk != ';');
|
|
tkidentifier = name;
|
|
}
|
|
}
|
|
|
|
if (CScope_ParseElaborateName(&pr)) {
|
|
if ((type = pr.x8)) {
|
|
if (!IS_TYPE_ENUM(type))
|
|
CError_Error(CErrorStr121);
|
|
if ((tk = lex()) == '{')
|
|
goto do_shit;
|
|
declinfo->thetype = type;
|
|
return;
|
|
} else {
|
|
CError_ASSERT(3865, pr.name_4);
|
|
if ((tk = lex()) == '{') {
|
|
declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, pr.name_4));
|
|
return;
|
|
} else {
|
|
CError_Error(CErrorStr140, pr.name_4->name);
|
|
}
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
|
|
declinfo->thetype = TYPE(&stsignedint);
|
|
}
|
|
|
|
void CDecl_ScanStructDeclarator(BigDeclInfo *bde) {
|
|
ENode *expr;
|
|
short val;
|
|
short bits;
|
|
Boolean is_bitfield;
|
|
TypeTemplDep *ttempl;
|
|
TypeBitfield *tbitfield;
|
|
Type *type;
|
|
|
|
bde->declinfo2 = bde->declinfo;
|
|
bde->declinfo2.name = NULL;
|
|
bde->declinfo2.x3E = 0;
|
|
bde->xCD = 0;
|
|
is_bitfield = 0;
|
|
|
|
if (tk == ':') {
|
|
bde->declinfo2.name = no_name_node;
|
|
is_bitfield = 1;
|
|
} else {
|
|
bde->declinfo2.x50 = 1;
|
|
scandeclarator(&bde->declinfo2);
|
|
if (!bde->declinfo2.name) {
|
|
CError_Error(CErrorStr131);
|
|
return;
|
|
}
|
|
|
|
if ((!copts.ANSIstrict || copts.c9x) && !bde->declinfo2.thetype->size && IS_TYPE_ARRAY(bde->declinfo2.thetype)) {
|
|
if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) {
|
|
type = TYPE_POINTER(bde->declinfo2.thetype)->target;
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
if (!IsCompleteType(type))
|
|
return;
|
|
if (tk != ';' || lookahead() != '}') {
|
|
CError_Error(CErrorStr145);
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) {
|
|
if (!IS_TYPE_FUNC(bde->declinfo2.thetype) && !IsCompleteType(bde->declinfo2.thetype))
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (IS_TYPE_CLASS(bde->declinfo2.thetype) && TYPE_CLASS(bde->declinfo2.thetype)->sominfo) {
|
|
CError_Error(CErrorStr287);
|
|
return;
|
|
}
|
|
|
|
if (tk != ':')
|
|
goto not_a_bitfield;
|
|
}
|
|
|
|
if (!IS_TYPE_INT_OR_ENUM(bde->declinfo2.thetype)) {
|
|
if (CTemplTool_IsTemplateArgumentDependentType(bde->declinfo2.thetype))
|
|
goto fuckup;
|
|
CError_Error(CErrorStr138);
|
|
bde->declinfo2.thetype = TYPE(&stunsignedint);
|
|
} else if (copts.ANSIstrict && !copts.cplusplus) {
|
|
if (bde->declinfo2.thetype != TYPE(&stsignedint) && bde->declinfo2.thetype != TYPE(&stunsignedint)) {
|
|
CError_Error(CErrorStr138);
|
|
bde->declinfo2.thetype = TYPE(&stunsignedint);
|
|
}
|
|
}
|
|
|
|
switch (bde->declinfo2.thetype->size) {
|
|
case 1:
|
|
bits = 8;
|
|
break;
|
|
case 2:
|
|
bits = 16;
|
|
break;
|
|
case 4:
|
|
bits = 32;
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr138);
|
|
return;
|
|
}
|
|
fuckup:
|
|
tk = lex();
|
|
expr = CExpr_IntegralConstOrDepExpr();
|
|
if (!ENODE_IS(expr, EINTCONST)) {
|
|
ttempl = TYPE_TEMPLATE(CDecl_NewTemplDepType(TEMPLDEP_BITFIELD));
|
|
ttempl->u.bitfield.type = bde->declinfo2.thetype;
|
|
ttempl->u.bitfield.size = CInline_CopyExpression(expr, CopyMode1);
|
|
bde->declinfo2.thetype = TYPE(ttempl);
|
|
bde->xCD = 1;
|
|
return;
|
|
}
|
|
val = CInt64_GetULong(&expr->data.intval);
|
|
if (is_bitfield) {
|
|
if (val < 0 || val > bits) {
|
|
CError_Error(CErrorStr138);
|
|
return;
|
|
}
|
|
} else {
|
|
if (val <= 0 || val > bits) {
|
|
CError_Error(CErrorStr138);
|
|
return;
|
|
}
|
|
}
|
|
|
|
tbitfield = galloc(sizeof(TypeBitfield));
|
|
memclrw(tbitfield, sizeof(TypeBitfield));
|
|
tbitfield->type = TYPEBITFIELD;
|
|
tbitfield->size = bde->declinfo2.thetype->size;
|
|
tbitfield->bitfieldtype = bde->declinfo2.thetype;
|
|
tbitfield->unkB = val;
|
|
bde->declinfo2.thetype = TYPE(tbitfield);
|
|
|
|
if (tk == TK_UU_ATTRIBUTE_UU)
|
|
CParser_ParseAttribute(NULL, &bde->declinfo2);
|
|
|
|
not_a_bitfield:
|
|
bde->xCD = 1;
|
|
}
|
|
|
|
static void CDecl_LayoutStruct(TypeStruct *tstruct) {
|
|
StructMember *member;
|
|
SInt32 r28;
|
|
StructMember *innermember;
|
|
SInt32 innerbase;
|
|
StructMember *newmember;
|
|
StructMember **memberp;
|
|
TypeBitfield *bf;
|
|
SInt32 r24;
|
|
Boolean r23;
|
|
SInt32 tmp;
|
|
|
|
r28 = 0;
|
|
r23 = 0;
|
|
CMach_StructLayoutInitOffset(0);
|
|
for (member = tstruct->members; member; member = member->next) {
|
|
if (tstruct->stype == STRUCT_TYPE_UNION)
|
|
CMach_StructLayoutInitOffset(0);
|
|
|
|
if (IS_TYPE_BITFIELD(member->type))
|
|
member->offset = CMach_StructLayoutBitfield(TYPE_BITFIELD(member->type), member->qual);
|
|
else
|
|
member->offset = CMach_StructLayoutGetOffset(member->type, member->qual);
|
|
|
|
if (tstruct->stype == STRUCT_TYPE_UNION) {
|
|
tmp = CMach_StructLayoutGetCurSize();
|
|
if (tmp > r28)
|
|
r28 = tmp;
|
|
}
|
|
|
|
if (member->name == no_name_node)
|
|
r23 = 1;
|
|
|
|
if (!member->name) {
|
|
CError_ASSERT(4064, IS_TYPE_STRUCT(member->type));
|
|
innerbase = member->offset;
|
|
innermember = TYPE_STRUCT(member->type)->members;
|
|
r23 = 1;
|
|
while (innermember) {
|
|
if (ismember(tstruct, innermember->name))
|
|
CError_Error(CErrorStr133, innermember->name->name);
|
|
if (r23) {
|
|
member->type = innermember->type;
|
|
member->name = innermember->name;
|
|
member->qual = innermember->qual;
|
|
member->offset = innerbase + innermember->offset;
|
|
} else {
|
|
newmember = galloc(sizeof(StructMember));
|
|
memclrw(newmember, sizeof(StructMember));
|
|
newmember->next = member->next;
|
|
newmember->type = innermember->type;
|
|
newmember->name = innermember->name;
|
|
newmember->qual = innermember->qual | Q_OVERLOAD;
|
|
newmember->offset = innerbase + innermember->offset;
|
|
member->next = newmember;
|
|
member = newmember;
|
|
}
|
|
if (copts.reverse_bitfields && IS_TYPE_BITFIELD(member->type)) {
|
|
bf = galloc(sizeof(TypeBitfield));
|
|
*bf = *TYPE_BITFIELD(member->type);
|
|
CABI_ReverseBitField(bf);
|
|
member->type = TYPE(bf);
|
|
}
|
|
r23 = 0;
|
|
innermember = innermember->next;
|
|
}
|
|
r23 = 1;
|
|
}
|
|
}
|
|
|
|
if (r23) {
|
|
memberp = &tstruct->members;
|
|
while (*memberp) {
|
|
if ((*memberp)->name == no_name_node || !(*memberp)->name)
|
|
*memberp = (*memberp)->next;
|
|
else
|
|
memberp = &(*memberp)->next;
|
|
}
|
|
}
|
|
|
|
if (tstruct->stype == STRUCT_TYPE_UNION)
|
|
r24 = r28;
|
|
else
|
|
r24 = CMach_StructLayoutGetCurSize();
|
|
tstruct->size = r24;
|
|
tstruct->align = CMach_GetStructAlign(tstruct);
|
|
tstruct->size = r24 + CABI_StructSizeAlignValue(TYPE(tstruct), r24);
|
|
|
|
if (copts.reverse_bitfields) {
|
|
for (member = tstruct->members; member; member = member->next) {
|
|
if (IS_TYPE_BITFIELD(member->type))
|
|
CABI_ReverseBitField(TYPE_BITFIELD(member->type));
|
|
}
|
|
}
|
|
|
|
if (copts.warn_padding && tstruct->stype != STRUCT_TYPE_UNION) {
|
|
StructMember *prev;
|
|
|
|
member = tstruct->members;
|
|
prev = NULL;
|
|
while (member) {
|
|
if (prev && (prev->offset + prev->type->size) < member->offset) {
|
|
CError_Warning(CErrorStr350, member->offset - (prev->offset + prev->type->size), prev->name->name);
|
|
}
|
|
prev = member;
|
|
member = member->next;
|
|
}
|
|
|
|
if (prev && (prev->offset + prev->type->size) < tstruct->size) {
|
|
CError_Warning(CErrorStr350, tstruct->size - (prev->offset + prev->type->size), prev->name->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
static SInt32 scanstructdeclarationlist(TypeStruct *tstruct, Boolean flag) {
|
|
SInt32 offset;
|
|
StructMember *member;
|
|
BigDeclInfo bde;
|
|
|
|
offset = -1;
|
|
memclrw(&bde, sizeof(BigDeclInfo));
|
|
|
|
if (tk == TK_AT_DEFS) {
|
|
CPrep_NewFileOffsetInfo(&member_fileoffset, NULL);
|
|
CObjC_ParseDefs(tstruct);
|
|
if ((tk = lex()) != '}')
|
|
CError_Error(CErrorStr130);
|
|
} else {
|
|
do {
|
|
CPrep_NewFileOffsetInfo(&member_fileoffset, NULL);
|
|
memclrw(&bde.declinfo, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&bde.declinfo, 0);
|
|
if (bde.declinfo.storageclass || bde.declinfo.x44) {
|
|
CError_Error(CErrorStr131);
|
|
tstruct->members = NULL;
|
|
return -1;
|
|
}
|
|
|
|
if (tk != ';') {
|
|
while (1) {
|
|
CDecl_ScanStructDeclarator(&bde);
|
|
if (!CanCreateObject(bde.declinfo2.thetype)) {
|
|
CError_Error(CErrorStr131);
|
|
bde.xCD = 0;
|
|
}
|
|
|
|
if (bde.declinfo2.x3E) {
|
|
CError_Error(CErrorStr131);
|
|
bde.xCD = 0;
|
|
}
|
|
|
|
if (bde.xCD) {
|
|
if (bde.declinfo2.name == no_name_node || !ismember(tstruct, bde.declinfo2.name)) {
|
|
member = galloc(sizeof(StructMember));
|
|
memclrw(member, sizeof(StructMember));
|
|
member->type = bde.declinfo2.thetype;
|
|
member->name = bde.declinfo2.name;
|
|
member->qual = bde.declinfo2.qual;
|
|
appendmember(tstruct, member);
|
|
|
|
if (flag) {
|
|
CBrowse_AddStructMember(member, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr133, bde.declinfo2.name->name);
|
|
}
|
|
}
|
|
|
|
if (tk != ',')
|
|
break;
|
|
tk = lex();
|
|
}
|
|
} else if (!copts.ANSIstrict && IS_TYPE_STRUCT(bde.declinfo.thetype)) {
|
|
member = galloc(sizeof(StructMember));
|
|
memclrw(member, sizeof(StructMember));
|
|
member->type = bde.declinfo.thetype;
|
|
appendmember(tstruct, member);
|
|
} else {
|
|
CError_Error(CErrorStr131);
|
|
}
|
|
|
|
if (tk != ';') {
|
|
tstruct->members = NULL;
|
|
CError_Error(CErrorStr123);
|
|
return -1;
|
|
}
|
|
|
|
CPrep_TokenStreamFlush();
|
|
} while ((tk = lex()) != '}');
|
|
CDecl_LayoutStruct(tstruct);
|
|
}
|
|
|
|
if (flag) {
|
|
offset = CPrep_BrowserFileOffset();
|
|
if (tk == ';')
|
|
offset++;
|
|
}
|
|
|
|
tk = lex();
|
|
return offset;
|
|
}
|
|
|
|
static TypeStruct *CDecl_DefineStruct(HashNameNode *name, short stype) {
|
|
TypeStruct *tstruct;
|
|
|
|
tstruct = galloc(sizeof(TypeStruct));
|
|
memclrw(tstruct, sizeof(TypeStruct));
|
|
|
|
tstruct->type = TYPESTRUCT;
|
|
tstruct->align = 1;
|
|
tstruct->stype = stype;
|
|
if (name) {
|
|
tstruct->name = name;
|
|
CScope_DefineTypeTag((in_func_arglist && !copts.cplusplus) ? cscope_root : cscope_current, name, (Type *) tstruct);
|
|
}
|
|
|
|
return tstruct;
|
|
}
|
|
|
|
void scanstruct(DeclInfo *declinfo, short structtype) {
|
|
Type *type;
|
|
HashNameNode *name;
|
|
TypeStruct typecopy;
|
|
Boolean add_to_browse;
|
|
GList gl;
|
|
SInt32 offset;
|
|
|
|
if (copts.cplusplus) {
|
|
CDecl_ParseClass(declinfo, structtype, 1, 0);
|
|
return;
|
|
}
|
|
|
|
if (tk == TK_IDENTIFIER) {
|
|
name = tkidentifier;
|
|
type = CScope_GetTagType(cscope_current, name);
|
|
if (type) {
|
|
if (IS_TYPE_CLASS(type)) {
|
|
CDecl_ParseClass(declinfo, structtype, 1, 0);
|
|
return;
|
|
}
|
|
|
|
tk = lex();
|
|
if (!CScope_GetLocalTagType(cscope_current, name) && (tk == ';' || tk == '{'))
|
|
type = (Type *) CDecl_DefineStruct(name, structtype);
|
|
|
|
if (!IS_TYPE_STRUCT(type) || TYPE_STRUCT(type)->stype != structtype) {
|
|
CError_Error(CErrorStr132, name->name);
|
|
declinfo->thetype = type;
|
|
return;
|
|
}
|
|
|
|
if (tk != '{') {
|
|
declinfo->thetype = type;
|
|
return;
|
|
}
|
|
|
|
if (type->size) {
|
|
CError_Error(CErrorStr132, name->name);
|
|
type = (Type *) CDecl_DefineStruct(NULL, structtype);
|
|
}
|
|
} else {
|
|
type = (Type *) CDecl_DefineStruct(name, structtype);
|
|
if ((tk = lex()) != '{') {
|
|
declinfo->thetype = type;
|
|
return;
|
|
}
|
|
}
|
|
} else if (tk != '{') {
|
|
CError_Error(CErrorStr131);
|
|
declinfo->thetype = (Type *) &stsignedint;
|
|
return;
|
|
} else {
|
|
type = (Type *) CDecl_DefineStruct(NULL, structtype);
|
|
}
|
|
|
|
if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo))
|
|
CBrowse_BeginStruct(declinfo, TYPE_STRUCT(type), &gl);
|
|
|
|
typecopy = *TYPE_STRUCT(type);
|
|
tk = lex();
|
|
offset = scanstructdeclarationlist(&typecopy, add_to_browse);
|
|
*TYPE_STRUCT(type) = typecopy;
|
|
declinfo->thetype = type;
|
|
|
|
if (add_to_browse)
|
|
CBrowse_EndStruct(offset, &gl);
|
|
}
|
|
|
|
static void InlineFunctionObject(Object *obj, TypeClass *tclass) {
|
|
TokenStream stream;
|
|
CPrepFileInfo *file;
|
|
|
|
obj->qual |= Q_INLINE;
|
|
TYPE_FUNC(obj->type)->flags |= FUNC_FLAGS_2;
|
|
|
|
CPrep_StreamGetBlock(&stream, NULL, 1);
|
|
if (stream.tokens) {
|
|
if (IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type)) && (TYPE_METHOD(obj->type)->theclass->flags & CLASS_FLAGS_100)) {
|
|
TYPE_FUNC(obj->type)->flags |= FUNC_FLAGS_800000;
|
|
CTemplClass_DefineMember(TEMPL_CLASS(TYPE_METHOD(obj->type)->theclass), obj, &member_fileoffset, &stream);
|
|
} else {
|
|
CInline_AddInlineFunctionAction(obj, tclass, &member_fileoffset, &stream, 0);
|
|
}
|
|
}
|
|
|
|
file = CPrep_BrowserCurrentFile();
|
|
if (file->recordbrowseinfo) {
|
|
CBrowse_NewFunction(
|
|
obj, file,
|
|
member_fileoffset.file,
|
|
CPrep_BrowserTokenOffset(&member_fileoffset) + 1,
|
|
CPrep_BrowserFileOffset());
|
|
}
|
|
|
|
if (lookahead() == ';')
|
|
tk = lex();
|
|
else
|
|
tk = ';';
|
|
}
|
|
|
|
void CDecl_ExtractClassExportFlags(DeclInfo *declinfo, UInt8 flags) {
|
|
if (flags & CLASS_EFLAGS_INTERNAL)
|
|
declinfo->exportflags |= EXPORT_FLAGS_INTERNAL;
|
|
if (flags & CLASS_EFLAGS_IMPORT)
|
|
declinfo->exportflags |= EXPORT_FLAGS_IMPORT;
|
|
if (flags & CLASS_EFLAGS_EXPORT)
|
|
declinfo->exportflags |= EXPORT_FLAGS_EXPORT;
|
|
}
|
|
|
|
TypeMethod *CDecl_MakeTypeMemberFunc(TypeFunc *tfunc, TypeClass *tclass, Boolean flag) {
|
|
TypeMethod *method;
|
|
|
|
method = galloc(sizeof(TypeMethod));
|
|
memclrw(method, sizeof(TypeMethod));
|
|
*TYPE_FUNC(method) = *tfunc;
|
|
method->theclass = tclass;
|
|
method->x26 = flag;
|
|
method->flags |= FUNC_FLAGS_METHOD;
|
|
if (!flag)
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(method), tclass);
|
|
|
|
if ((flag || (tfunc->flags & (FUNC_FLAGS_1000 | FUNC_FLAGS_2000))) && (tfunc->flags & (FUNC_FLAGS_CONST | FUNC_FLAGS_VOLATILE)))
|
|
CError_Error(CErrorStr384);
|
|
|
|
return method;
|
|
}
|
|
|
|
static void CDecl_MakeFunctionVirtual(TypeClass *tclass, Object *func) {
|
|
if (is_pascal_object(func))
|
|
CError_Error(CErrorStr219);
|
|
if (tclass->mode == CLASS_MODE_1)
|
|
CError_Error(CErrorStr352, func);
|
|
func->datatype = DVFUNC;
|
|
}
|
|
|
|
static void CDecl_AddFunctionMember(DeclE *decle, TypeClass *tclass, DeclInfo *declinfo, short access, Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4) {
|
|
NameSpaceObjectList *list; // r20
|
|
Object *obj; // also r20
|
|
TypeMethod *tfunc; // r19
|
|
Boolean r31;
|
|
Boolean outflag;
|
|
|
|
if (IS_TYPE_ARRAY(TYPE_FUNC(declinfo->thetype)->functype) || IS_TYPE_FUNC(TYPE_FUNC(declinfo->thetype)->functype)) {
|
|
CError_Error(CErrorStr128);
|
|
TYPE_FUNC(declinfo->thetype)->functype = (Type *) &stsignedint;
|
|
}
|
|
|
|
if (tclass->sominfo)
|
|
CSOM_CheckFuncType(TYPE_FUNC(declinfo->thetype));
|
|
|
|
r31 = 0;
|
|
if (declinfo->qual & Q_VIRTUAL) {
|
|
declinfo->qual &= ~Q_VIRTUAL;
|
|
r31 = 1;
|
|
flag1 = 1;
|
|
}
|
|
|
|
if ((list = CScope_FindName(tclass->nspace, declinfo->name))) {
|
|
if (list->object->otype != OT_TYPETAG) {
|
|
if (list->object->otype != OT_OBJECT || !IS_TYPE_FUNC(OBJECT(list->object)->type))
|
|
CError_Error(CErrorStr133, declinfo->name->name);
|
|
} else {
|
|
list = NULL;
|
|
}
|
|
}
|
|
|
|
if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype))) {
|
|
tfunc = CDecl_MakeTypeMemberFunc(TYPE_FUNC(declinfo->thetype), tclass, flag4);
|
|
declinfo->thetype = (Type *) tfunc;
|
|
} else {
|
|
tfunc = TYPE_METHOD(declinfo->thetype);
|
|
CError_ASSERT(4579, !tclass->sominfo);
|
|
}
|
|
|
|
CDecl_ExtractClassExportFlags(declinfo, tclass->eflags);
|
|
|
|
CError_ASSERT(4597, cscope_current == tclass->nspace);
|
|
|
|
if (list) {
|
|
obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, flag4 ? OverloadMode1 : OverloadMode2, 0);
|
|
if (!obj)
|
|
return;
|
|
if (outflag)
|
|
tfunc->x1E = ++decle->x8;
|
|
else
|
|
CError_Error(CErrorStr133, CError_GetObjectName(obj));
|
|
} else {
|
|
tfunc->x1E = ++decle->x8;
|
|
obj = CParser_NewFunctionObject(declinfo);
|
|
if ((tclass->flags & CLASS_FLAGS_100) && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype))
|
|
CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(obj));
|
|
CScope_AddObject(tclass->nspace, declinfo->name, OBJ_BASE(obj));
|
|
}
|
|
|
|
obj->access = access;
|
|
CheckDefaultArgs(TYPE_FUNC(obj->type)->args);
|
|
|
|
if (flag2) {
|
|
tfunc->flags |= FUNC_FLAGS_40;
|
|
tclass->flags |= CLASS_FLAGS_40;
|
|
}
|
|
|
|
if (r31) {
|
|
CDecl_MakeFunctionVirtual(tclass, obj);
|
|
decle->xC = 1;
|
|
}
|
|
|
|
if ((flag1 || r31) && flag3 && (tk == '=')) {
|
|
if ((tk = lex()) == TK_INTCONST) {
|
|
if (!CInt64_IsZero(&tkintconst))
|
|
CError_Error(CErrorStr121);
|
|
tfunc->flags |= FUNC_FLAGS_8;
|
|
tclass->flags |= CLASS_FLAGS_ABSTRACT;
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
}
|
|
|
|
if (flag3 && ((tk == '{') || (tk == TK_TRY) || ((tk == ':') && CClass_IsConstructor(obj)))) {
|
|
if (declinfo->x49)
|
|
CError_Error(CErrorStr127);
|
|
InlineFunctionObject(obj, NULL);
|
|
}
|
|
|
|
if (cparamblkptr->browseoptions.recordClasses)
|
|
CBrowse_AddClassMemberFunction(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
|
|
}
|
|
|
|
static Boolean CDecl_IsAccessDeclaration(TypeClass *tclass, short access) {
|
|
SInt32 state;
|
|
Boolean flag;
|
|
|
|
CPrep_TokenStreamGetState(&state);
|
|
flag = 0;
|
|
|
|
restart:
|
|
switch (tk) {
|
|
case TK_IDENTIFIER:
|
|
if ((tk = lex()) != ';')
|
|
break;
|
|
case TK_OPERATOR:
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
if (flag) {
|
|
CScope_ParseUsingDeclaration(tclass->nspace, access, 1);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
default:
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 0;
|
|
}
|
|
|
|
switch (tk) {
|
|
case TK_COLON_COLON:
|
|
flag = 1;
|
|
tk = lex();
|
|
goto restart;
|
|
case '<':
|
|
tk = lex();
|
|
while (1) {
|
|
switch (tk) {
|
|
case 0:
|
|
case ';':
|
|
case '{':
|
|
case '}':
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 0;
|
|
case '>':
|
|
if ((tk = lex()) == TK_COLON_COLON) {
|
|
flag = 1;
|
|
tk = lex();
|
|
goto restart;
|
|
}
|
|
default:
|
|
tk = lex();
|
|
}
|
|
}
|
|
}
|
|
|
|
CPrep_TokenStreamSetCurState(&state);
|
|
return 0;
|
|
}
|
|
|
|
void CDecl_PackDeclInfo(PackedDeclInfo *packed, DeclInfo *declinfo) {
|
|
packed->thetype = declinfo->thetype;
|
|
packed->qual = declinfo->qual;
|
|
packed->nspace = declinfo->nspace;
|
|
packed->name = declinfo->name;
|
|
packed->expltargs = CTemplTool_MakeGlobalTemplArgCopy(declinfo->expltargs);
|
|
packed->storageclass = declinfo->storageclass;
|
|
packed->section = declinfo->section;
|
|
packed->exportflags = declinfo->exportflags;
|
|
packed->has_expltargs = declinfo->has_expltargs;
|
|
}
|
|
|
|
void CDecl_UnpackDeclInfo(DeclInfo *declinfo, PackedDeclInfo *packed) {
|
|
memclrw(declinfo, sizeof(DeclInfo));
|
|
declinfo->thetype = packed->thetype;
|
|
declinfo->qual = packed->qual;
|
|
declinfo->nspace = packed->nspace;
|
|
declinfo->name = packed->name;
|
|
declinfo->expltargs = packed->expltargs;
|
|
declinfo->storageclass = packed->storageclass;
|
|
declinfo->section = packed->section;
|
|
declinfo->exportflags = packed->exportflags;
|
|
declinfo->has_expltargs = packed->has_expltargs;
|
|
}
|
|
|
|
void CDecl_AddFriend(TypeClass *tclass, Object *friendfunc, TypeClass *friendclass) {
|
|
ClassFriend *scan;
|
|
ClassFriend *newfriend;
|
|
|
|
if (friendfunc) {
|
|
for (scan = tclass->friends; scan; scan = scan->next) {
|
|
if (!scan->isclass && scan->u.obj == friendfunc)
|
|
break;
|
|
}
|
|
if (!scan) {
|
|
newfriend = galloc(sizeof(ClassFriend));
|
|
memclrw(newfriend, sizeof(ClassFriend));
|
|
newfriend->next = tclass->friends;
|
|
tclass->friends = newfriend;
|
|
newfriend->u.obj = friendfunc;
|
|
newfriend->isclass = 0;
|
|
}
|
|
}
|
|
|
|
if (friendclass) {
|
|
for (scan = tclass->friends; scan; scan = scan->next) {
|
|
if (scan->isclass && scan->u.theclass == friendclass)
|
|
break;
|
|
}
|
|
if (!scan) {
|
|
newfriend = galloc(sizeof(ClassFriend));
|
|
memclrw(newfriend, sizeof(ClassFriend));
|
|
newfriend->next = tclass->friends;
|
|
tclass->friends = newfriend;
|
|
newfriend->u.theclass = friendclass;
|
|
newfriend->isclass = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CDecl_ParseFriendDecl(TypeClass *tclass) {
|
|
DeclInfo declinfo;
|
|
DeclInfo declinfo_copy;
|
|
Boolean is_templ;
|
|
Boolean r27;
|
|
Boolean pflag;
|
|
CScopeSave save;
|
|
Object *obj;
|
|
NameSpace *nspace;
|
|
|
|
is_templ = (tclass->flags & CLASS_FLAGS_100) ? 1 : 0;
|
|
r27 = (tk == TK_CLASS || tk == TK_STRUCT || tk == TK_UNION);
|
|
memclrw(&declinfo, sizeof(DeclInfo));
|
|
|
|
declinfo.x4C = 1;
|
|
CParser_GetDeclSpecs(&declinfo, 1);
|
|
if (declinfo.storageclass) {
|
|
CError_Error(CErrorStr177);
|
|
declinfo.storageclass = 0;
|
|
}
|
|
declinfo.x4C = 0;
|
|
|
|
if (tk == ';') {
|
|
if (!r27)
|
|
CError_Error(CErrorStr201);
|
|
|
|
if (IS_TYPE_CLASS(declinfo.thetype)) {
|
|
if (!(TYPE_CLASS(declinfo.thetype)->flags & CLASS_FLAGS_100) || CParser_CheckTemplateClassUsage(TEMPL_CLASS(declinfo.thetype), 1)) {
|
|
if (!is_templ)
|
|
CDecl_AddFriend(tclass, NULL, TYPE_CLASS(declinfo.thetype));
|
|
else
|
|
CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo);
|
|
}
|
|
} else {
|
|
if (IS_TYPE_TEMPLATE(declinfo.thetype) && is_templ)
|
|
CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo);
|
|
else
|
|
CError_Error(CErrorStr201);
|
|
}
|
|
} else {
|
|
if (declinfo.x14 || declinfo.x10) {
|
|
CDecl_ParseSpecialMember(&declinfo, 0);
|
|
if (declinfo.name) {
|
|
obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0);
|
|
if (obj)
|
|
CDecl_AddFriend(tclass, obj, NULL);
|
|
if (tk != ';')
|
|
CError_Error(CErrorStr123);
|
|
else
|
|
tk = lex();
|
|
}
|
|
return;
|
|
} else {
|
|
nspace = CScope_FindGlobalNS(cscope_current);
|
|
declinfo_copy = declinfo;
|
|
while (1) {
|
|
declinfo = declinfo_copy;
|
|
declinfo.x4D = 1;
|
|
declinfo.x51 = 1;
|
|
scandeclarator(&declinfo);
|
|
|
|
if (IS_TYPE_FUNC(declinfo.thetype)) {
|
|
if (!is_templ) {
|
|
CScope_SetNameSpaceScope(nspace, &save);
|
|
obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0);
|
|
CScope_RestoreScope(&save);
|
|
|
|
if (obj) {
|
|
CDecl_AddFriend(tclass, obj, NULL);
|
|
if (!declinfo.nspace && tk == '{') {
|
|
InlineFunctionObject(obj, tclass);
|
|
} else {
|
|
if (!obj->sclass)
|
|
obj->sclass = TK_EXTERN;
|
|
}
|
|
}
|
|
} else {
|
|
CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo);
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr201);
|
|
}
|
|
|
|
if (tk != ',')
|
|
break;
|
|
tk = lex();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tk == ';')
|
|
tk = lex();
|
|
else
|
|
CError_Error(CErrorStr123);
|
|
}
|
|
|
|
static ObjMemberVar *CDecl_InstanceDataDeclarator(DeclE *decle, TypeClass *tclass, Type *type, UInt32 qual, HashNameNode *name, short access) {
|
|
NameSpaceObjectList *list;
|
|
ObjMemberVar *ivar;
|
|
ObjMemberVar *scan;
|
|
|
|
if (name && (list = CScope_FindName(tclass->nspace, name))) {
|
|
switch (list->object->otype) {
|
|
case OT_NAMESPACE:
|
|
CError_Error(CErrorStr321);
|
|
return NULL;
|
|
case OT_ENUMCONST:
|
|
case OT_TYPE:
|
|
case OT_OBJECT:
|
|
CError_Error(CErrorStr322);
|
|
return NULL;
|
|
case OT_MEMBERVAR:
|
|
CError_Error(CErrorStr122, name->name);
|
|
return NULL;
|
|
case OT_TYPETAG:
|
|
break;
|
|
default:
|
|
CError_FATAL(4989);
|
|
}
|
|
}
|
|
|
|
ivar = galloc(sizeof(ObjMemberVar));
|
|
memclrw(ivar, sizeof(ObjMemberVar));
|
|
ivar->otype = OT_MEMBERVAR;
|
|
ivar->access = access;
|
|
ivar->name = name;
|
|
ivar->type = type;
|
|
ivar->qual = qual;
|
|
if (!tclass->sominfo)
|
|
decle->x8++;
|
|
|
|
if ((scan = tclass->ivars)) {
|
|
while (scan->next)
|
|
scan = scan->next;
|
|
scan->next = ivar;
|
|
} else {
|
|
tclass->ivars = ivar;
|
|
}
|
|
|
|
if (name && name != no_name_node) {
|
|
CScope_AddObject(tclass->nspace, name, OBJ_BASE(ivar));
|
|
if ((tclass->flags & CLASS_FLAGS_100) && CTemplTool_IsTemplateArgumentDependentType(type))
|
|
CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(ivar));
|
|
if (cparamblkptr->browseoptions.recordClasses)
|
|
CBrowse_AddClassMemberVar(ivar, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset());
|
|
}
|
|
|
|
return ivar;
|
|
}
|
|
|
|
void CDecl_CheckCtorIntegrity(FuncArg *args, TypeClass *tclass) {
|
|
if (args && args->type == TYPE(tclass)) {
|
|
if (!args->next || args->next->dexpr) {
|
|
CError_Error(CErrorStr239);
|
|
args->type = &stvoid;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void CDecl_ParseClassMembers(DeclE *decle, TypeClass *tclass, short mode) {
|
|
short access;
|
|
UInt32 r22;
|
|
UInt32 r21;
|
|
UInt8 r20;
|
|
Boolean r19;
|
|
UInt8 r18;
|
|
Boolean r17;
|
|
BigDeclInfo bde;
|
|
DeclInfo declinfo;
|
|
//Type *newtype
|
|
ObjMemberVar *ivar;
|
|
ObjMemberVar *scanivar;
|
|
Type *tmptype;
|
|
short t;
|
|
|
|
r17 = (tclass->flags & CLASS_FLAGS_100) && TEMPL_CLASS(tclass)->pspec_owner;
|
|
memclrw(&bde, sizeof(BigDeclInfo));
|
|
|
|
if (mode == CLASS_MODE_2)
|
|
access = ACCESSPRIVATE;
|
|
else
|
|
access = ACCESSPUBLIC;
|
|
global_access = access;
|
|
//global_access = (mode == CLASS_MODE_2) ? ACCESSPRIVATE : ACCESSPUBLIC;
|
|
//access = (mode == CLASS_MODE_2) ? ACCESSPRIVATE : ACCESSPUBLIC;
|
|
|
|
restart:
|
|
while (tk != '}') {
|
|
CPrep_NewFileOffsetInfo(&member_fileoffset, NULL);
|
|
r21 = 0;
|
|
r22 = 0;
|
|
r20 = 0;
|
|
r18 = 0;
|
|
|
|
if (tk == TK_TEMPLATE) {
|
|
NameSpace *nspace = cscope_current;
|
|
TemplClass *tmclass;
|
|
|
|
if (nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_100)) {
|
|
tmclass = TEMPL_CLASS(nspace->theclass);
|
|
} else {
|
|
for (; nspace; nspace = nspace->parent) {
|
|
if (!nspace->name && !nspace->theclass && nspace->parent && !nspace->is_templ) {
|
|
CError_Error(CErrorStr347);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CTempl_Parse(TEMPL_CLASS(tclass), access);
|
|
tk = lex();
|
|
continue;
|
|
}
|
|
|
|
restart2:
|
|
r19 = 0;
|
|
switch (tk) {
|
|
case TK_UU_DECLSPEC:
|
|
if ((tk = lex()) != '(')
|
|
CError_Error(CErrorStr114);
|
|
memclrw(&declinfo, sizeof(DeclInfo));
|
|
CParser_ParseDeclSpec(&declinfo, 1);
|
|
r21 |= declinfo.qual;
|
|
r20 |= declinfo.exportflags;
|
|
r18 = declinfo.section;
|
|
if ((tk = lex()) != ')')
|
|
CError_Error(CErrorStr115);
|
|
tk = lex();
|
|
goto restart2;
|
|
case TK_PRIVATE:
|
|
global_access = access = ACCESSPRIVATE;
|
|
goto check_access;
|
|
case TK_PROTECTED:
|
|
global_access = access = ACCESSPROTECTED;
|
|
goto check_access;
|
|
case TK_PUBLIC:
|
|
global_access = access = ACCESSPUBLIC;
|
|
check_access:
|
|
if (r22 || r20)
|
|
CError_Error(CErrorStr121);
|
|
if ((tk = lex()) != ':')
|
|
CError_Error(CErrorStr170);
|
|
else
|
|
tk = lex();
|
|
goto restart;
|
|
case TK_EXPLICIT:
|
|
CError_QualifierCheck(r22 & Q_EXPLICIT);
|
|
r22 |= Q_EXPLICIT;
|
|
tk = lex();
|
|
goto restart2;
|
|
case TK_INLINE:
|
|
CError_QualifierCheck(r22 & Q_INLINE);
|
|
r22 |= Q_INLINE;
|
|
tk = lex();
|
|
goto restart2;
|
|
case TK_ASM:
|
|
CError_QualifierCheck(r22 & Q_ASM);
|
|
r22 |= Q_ASM;
|
|
tk = lex();
|
|
goto restart2;
|
|
case TK_VIRTUAL:
|
|
CError_QualifierCheck(r22 & Q_VIRTUAL);
|
|
r22 |= Q_VIRTUAL;
|
|
tk = lex();
|
|
goto restart2;
|
|
case TK_IDENTIFIER:
|
|
while (1) {
|
|
if (tkidentifier == tclass->classname) {
|
|
t = lookahead();
|
|
tkidentifier = tclass->classname;
|
|
r19 = 1;
|
|
if (copts.cpp_extensions && t == TK_COLON_COLON) {
|
|
lex();
|
|
tk = lex();
|
|
if (tk == TK_IDENTIFIER)
|
|
continue;
|
|
if (tk == '~')
|
|
goto restart2;
|
|
CError_Error(CErrorStr107);
|
|
}
|
|
|
|
if (t == '(') {
|
|
redo_thing:
|
|
CError_QualifierCheck(r22 & ~(Q_EXPLICIT | Q_INLINE | Q_ASM));
|
|
memclrw(&bde.declinfo2, sizeof(DeclInfo));
|
|
if (tclass->sominfo)
|
|
bde.declinfo2.thetype = &stvoid;
|
|
else
|
|
bde.declinfo2.thetype = TYPE(&void_ptr);
|
|
|
|
bde.declinfo2.qual = r22;
|
|
bde.declinfo2.exportflags = r20;
|
|
bde.declinfo2.section = r18;
|
|
bde.declinfo2.x4B = 1;
|
|
scandeclarator(&bde.declinfo2);
|
|
if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
|
|
if (r17)
|
|
bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual);
|
|
if (tclass->sominfo) {
|
|
if (TYPE_FUNC(bde.declinfo2.thetype)->args)
|
|
CError_Error(CErrorStr272);
|
|
bde.declinfo2.qual |= Q_VIRTUAL;
|
|
} else {
|
|
CDecl_CheckCtorIntegrity(TYPE_FUNC(bde.declinfo2.thetype)->args, tclass);
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort));
|
|
bde.declinfo2.qual &= ~Q_VIRTUAL;
|
|
}
|
|
TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_FLAGS_1000;
|
|
bde.declinfo2.name = constructor_name_node;
|
|
bde.declinfo2.qual |= r21;
|
|
CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 0);
|
|
} else {
|
|
CError_Error(CErrorStr241);
|
|
}
|
|
if (tk == ';')
|
|
tk = lex();
|
|
else
|
|
CError_Error(CErrorStr123);
|
|
goto restart;
|
|
}
|
|
}
|
|
// 6F8D8
|
|
if (!r22 && CDecl_IsAccessDeclaration(tclass, access)) {
|
|
tk = lex();
|
|
goto restart;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case TK_USING:
|
|
CError_QualifierCheck(r22);
|
|
tk = lex();
|
|
CScope_ParseUsingDeclaration(tclass->nspace, access, 0);
|
|
tk = lex();
|
|
goto restart;
|
|
case '~':
|
|
if ((tk = lex()) != TK_IDENTIFIER || tkidentifier != tclass->classname) {
|
|
CError_Error(CErrorStr241);
|
|
goto restart;
|
|
}
|
|
CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM));
|
|
if (tclass->flags & CLASS_FLAGS_900) {
|
|
t = lookahead();
|
|
tkidentifier = tclass->classname;
|
|
if (t == '<') {
|
|
memclrw(&bde.declinfo, sizeof(DeclInfo));
|
|
CParser_GetDeclSpecs(&bde.declinfo, 0);
|
|
if (tk != '(' || bde.declinfo.thetype != TYPE(tclass) || bde.declinfo.nspace) {
|
|
CError_Error(CErrorStr241);
|
|
goto restart;
|
|
}
|
|
CPrep_UnLex();
|
|
tk = TK_IDENTIFIER;
|
|
tkidentifier = tclass->classname;
|
|
}
|
|
}
|
|
memclrw(&bde.declinfo2, sizeof(DeclInfo));
|
|
bde.declinfo2.qual = r22;
|
|
bde.declinfo2.exportflags = r20;
|
|
bde.declinfo2.section = r18;
|
|
if (tclass->sominfo)
|
|
bde.declinfo2.thetype = &stvoid;
|
|
else
|
|
bde.declinfo2.thetype = TYPE(&void_ptr);
|
|
scandeclarator(&bde.declinfo2);
|
|
if (IS_TYPE_FUNC(bde.declinfo2.thetype) && !TYPE_FUNC(bde.declinfo2.thetype)->args) {
|
|
if (!CScope_FindName(tclass->nspace, destructor_name_node)) {
|
|
if (tclass->sominfo)
|
|
bde.declinfo2.qual |= Q_VIRTUAL;
|
|
else
|
|
CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort));
|
|
bde.declinfo2.name = destructor_name_node;
|
|
TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_FLAGS_2000;
|
|
bde.declinfo2.qual |= r21;
|
|
CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0);
|
|
} else {
|
|
CError_Error(CErrorStr133, CError_GetFunctionName(tclass->nspace, destructor_name_node, NULL));
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr146);
|
|
}
|
|
if (tk == ';')
|
|
tk = lex();
|
|
else
|
|
CError_Error(CErrorStr123);
|
|
goto restart;
|
|
case TK_OPERATOR:
|
|
if (CMangler_OperatorName(lookahead())) {
|
|
memclrw(&bde.declinfo, sizeof(DeclInfo));
|
|
bde.declinfo.thetype = TYPE(&stsignedint);
|
|
goto after_various_things;
|
|
} else {
|
|
tk = lex();
|
|
CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM));
|
|
memclrw(&bde.declinfo2, sizeof(DeclInfo));
|
|
bde.declinfo2.qual = r22;
|
|
bde.declinfo2.exportflags = r20;
|
|
bde.declinfo2.section = r18;
|
|
conversion_type_name(&bde.declinfo2);
|
|
bde.declinfo2.qual |= r21;
|
|
tmptype = bde.declinfo2.thetype;
|
|
CDecl_NewConvFuncType(&bde.declinfo2);
|
|
if ((tclass->flags & CLASS_FLAGS_100) && CTemplTool_IsTemplateArgumentDependentType(tmptype))
|
|
bde.declinfo2.name = CParser_GetUniqueName();
|
|
CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 1, 1, 0);
|
|
if (tk == ';')
|
|
tk = lex();
|
|
else
|
|
CError_Error(CErrorStr123);
|
|
goto restart;
|
|
}
|
|
case TK_FRIEND:
|
|
tk = lex();
|
|
CDecl_ParseFriendDecl(tclass);
|
|
goto restart;
|
|
}
|
|
|
|
CError_QualifierCheck(r22 & Q_EXPLICIT);
|
|
global_access = access;
|
|
memclrw(&bde.declinfo, sizeof(DeclInfo));
|
|
bde.declinfo.qual = r22;
|
|
bde.declinfo.exportflags = r20;
|
|
bde.declinfo.section = r18;
|
|
CParser_GetDeclSpecs(&bde.declinfo, 0);
|
|
|
|
if (r19 && tk == '(' && (tclass->flags & CLASS_FLAGS_900) && bde.declinfo.thetype == TYPE(tclass) && !bde.declinfo.nspace) {
|
|
CPrep_UnLex();
|
|
tk = TK_IDENTIFIER;
|
|
tkidentifier = tclass->classname;
|
|
r22 = bde.declinfo.qual;
|
|
goto redo_thing;
|
|
}
|
|
|
|
after_various_things:
|
|
switch (bde.declinfo.storageclass) {
|
|
case 0:
|
|
case TK_STATIC:
|
|
case TK_TYPEDEF:
|
|
case TK_MUTABLE:
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr177);
|
|
bde.declinfo.storageclass = 0;
|
|
}
|
|
|
|
if (tk != ';') {
|
|
while (1) {
|
|
CDecl_ScanStructDeclarator(&bde);
|
|
if (r17)
|
|
bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual);
|
|
if (bde.declinfo2.nspace)
|
|
CError_Error(CErrorStr200);
|
|
if (bde.declinfo2.x3E) {
|
|
if (bde.declinfo.storageclass == TK_MUTABLE)
|
|
CError_QualifierCheck(Q_MUTABLE);
|
|
r19 = 0;
|
|
switch (bde.declinfo2.x3E) {
|
|
case TK_NEW:
|
|
case TK_NEW_ARRAY:
|
|
CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
|
|
r19 = 1;
|
|
break;
|
|
case TK_DELETE:
|
|
case TK_DELETE_ARRAY:
|
|
CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
|
|
r19 = 1;
|
|
break;
|
|
default:
|
|
if (bde.declinfo2.storageclass == TK_STATIC)
|
|
CError_Error(CErrorStr193);
|
|
if (tclass->sominfo)
|
|
CError_Error(CErrorStr193);
|
|
}
|
|
|
|
bde.declinfo2.storageclass = 0;
|
|
if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
|
|
bde.declinfo2.qual |= r21;
|
|
CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, r19 == 0, 0, 1, r19);
|
|
CDecl_CheckOperatorType(&bde.declinfo2, 1);
|
|
if (tclass->sominfo)
|
|
CSOM_FixNewDeleteFunctype(TYPE_FUNC(bde.declinfo2.thetype));
|
|
} else {
|
|
CError_Error(CErrorStr121);
|
|
}
|
|
} else if (bde.xCD) {
|
|
if (bde.declinfo2.name == constructor_name_node || bde.declinfo2.name == destructor_name_node)
|
|
CError_Error(CErrorStr241);
|
|
switch (bde.declinfo2.storageclass) {
|
|
case TK_TYPEDEF:
|
|
CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
|
|
CDecl_TypedefDeclarator(&bde.declinfo2);
|
|
break;
|
|
case TK_STATIC:
|
|
CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL);
|
|
if (tclass->sominfo)
|
|
CError_Error(CErrorStr271);
|
|
if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
|
|
bde.declinfo2.qual |= r21;
|
|
bde.declinfo2.storageclass = 0;
|
|
if (bde.declinfo2.name == tclass->classname)
|
|
CError_Error(CErrorStr241);
|
|
CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 1);
|
|
} else {
|
|
CDecl_ExtractClassExportFlags(&bde.declinfo2, tclass->eflags);
|
|
bde.declinfo2.storageclass = 0;
|
|
CDecl_DataDeclarator(&bde.declinfo2, access, 1);
|
|
}
|
|
break;
|
|
case 0:
|
|
case TK_MUTABLE:
|
|
if (IS_TYPE_FUNC(bde.declinfo2.thetype)) {
|
|
if (bde.declinfo2.name == tclass->classname)
|
|
CError_Error(CErrorStr241);
|
|
if (bde.declinfo.storageclass == TK_MUTABLE)
|
|
CError_QualifierCheck(Q_MUTABLE);
|
|
bde.declinfo2.qual |= r21;
|
|
CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0);
|
|
} else {
|
|
CDecl_CompleteType(bde.declinfo2.thetype);
|
|
CanCreateObject(bde.declinfo2.thetype);
|
|
CError_QualifierCheck(bde.declinfo2.qual & (Q_VIRTUAL | Q_INLINE));
|
|
if (bde.declinfo2.storageclass == TK_MUTABLE)
|
|
bde.declinfo2.qual |= Q_MUTABLE;
|
|
CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo2.thetype, bde.declinfo2.qual, bde.declinfo2.name, access);
|
|
}
|
|
break;
|
|
default:
|
|
CError_Error(CErrorStr177);
|
|
}
|
|
}
|
|
|
|
// this should be 70058
|
|
if (tk != ',')
|
|
break; // goes to 70148
|
|
tk = lex();
|
|
}
|
|
} else if (CParser_IsAnonymousUnion(&bde.declinfo, 1)) {
|
|
if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo.thetype, 0, NULL, access)))
|
|
ivar->anonunion = 1;
|
|
for (scanivar = TYPE_CLASS(bde.declinfo.thetype)->ivars; scanivar; scanivar = scanivar->next) {
|
|
tmptype = scanivar->type;
|
|
if (IS_TYPE_BITFIELD(tmptype) && copts.reverse_bitfields) {
|
|
TypeBitfield *newtype = galloc(sizeof(TypeBitfield));
|
|
*newtype = *TYPE_BITFIELD(tmptype);
|
|
CABI_ReverseBitField(newtype);
|
|
tmptype = TYPE(newtype);
|
|
}
|
|
if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, tmptype, scanivar->qual, scanivar->name, access)))
|
|
ivar->offset = scanivar->offset | 0x80000000;
|
|
}
|
|
}
|
|
|
|
// this should be 70148 i think
|
|
if (tk != ';') {
|
|
CError_Error(CErrorStr123);
|
|
return;
|
|
}
|
|
CPrep_TokenStreamFlush();
|
|
tk = lex();
|
|
}
|
|
}
|
|
|
|
static VClassList *AddVBaseToList(TypeClass *tclass, TypeClass *baseclass) {
|
|
VClassList *scan;
|
|
VClassList *vbase;
|
|
|
|
for (scan = tclass->vbases; scan; scan = scan->next) {
|
|
if (scan->base == baseclass)
|
|
return NULL;
|
|
}
|
|
|
|
vbase = galloc(sizeof(VClassList));
|
|
memclrw(vbase, sizeof(VClassList));
|
|
vbase->base = baseclass;
|
|
|
|
if ((scan = tclass->vbases)) {
|
|
while (scan->next)
|
|
scan = scan->next;
|
|
scan->next = vbase;
|
|
} else {
|
|
tclass->vbases = vbase;
|
|
}
|
|
|
|
return vbase;
|
|
}
|
|
|
|
void CDecl_MakeVBaseList(TypeClass *tclass) {
|
|
ClassList *base;
|
|
VClassList *vbase;
|
|
VClassList *new_vbase;
|
|
SInt32 offset;
|
|
|
|
if (copts.vbase_ctor_offset)
|
|
tclass->flags |= CLASS_FLAGS_8000;
|
|
|
|
for (base = tclass->bases, offset = tclass->size; base; base = base->next) {
|
|
for (vbase = base->base->vbases; vbase; vbase = vbase->next) {
|
|
if ((new_vbase = AddVBaseToList(tclass, vbase->base))) {
|
|
new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(vbase->base), offset);
|
|
offset = new_vbase->offset + vbase->base->size;
|
|
}
|
|
}
|
|
|
|
if (base->is_virtual && (new_vbase = AddVBaseToList(tclass, base->base))) {
|
|
new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(base->base), offset);
|
|
offset = new_vbase->offset + base->base->size;
|
|
}
|
|
}
|
|
}
|
|
|
|
Boolean CDecl_CheckNewBase(TypeClass *tclass, TypeClass *baseclass, Boolean is_virtual) {
|
|
ClassList *scan;
|
|
|
|
if (tclass == baseclass) {
|
|
CError_Error(CErrorStr131);
|
|
return 0;
|
|
}
|
|
|
|
if (!(baseclass->flags & CLASS_FLAGS_2)) {
|
|
CError_Error(CErrorStr136, baseclass, 0);
|
|
return 0;
|
|
}
|
|
|
|
if (baseclass->flags & CLASS_FLAGS_10) {
|
|
if (is_virtual || tclass->bases) {
|
|
CError_Error(CErrorStr191);
|
|
return 0;
|
|
}
|
|
tclass->flags |= CLASS_FLAGS_10;
|
|
}
|
|
|
|
if (baseclass->flags & CLASS_FLAGS_1) {
|
|
if (is_virtual || tclass->bases) {
|
|
CError_Error(CErrorStr191);
|
|
return 0;
|
|
}
|
|
tclass->flags |= CLASS_FLAGS_1;
|
|
}
|
|
|
|
if (baseclass->sominfo) {
|
|
if (!is_virtual)
|
|
CError_Error(CErrorStr268);
|
|
CSOM_MakeSOMClass(tclass);
|
|
} else if (tclass->sominfo) {
|
|
CError_Error(CErrorStr267);
|
|
}
|
|
|
|
if (tclass->bases && (tclass->flags & CLASS_FLAGS_10) && (tclass->flags & CLASS_FLAGS_10)) {
|
|
CError_Error(CErrorStr131);
|
|
return 0;
|
|
}
|
|
|
|
if (copts.ecplusplus && (is_virtual || tclass->bases)) {
|
|
CError_Error(CErrorStr339);
|
|
return 0;
|
|
}
|
|
|
|
for (scan = tclass->bases; scan; scan = scan->next) {
|
|
if (scan->base == baseclass) {
|
|
CError_Error(CErrorStr131);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (baseclass->flags & CLASS_FLAGS_2000)
|
|
tclass->flags |= CLASS_FLAGS_2000;
|
|
if (baseclass->flags & CLASS_FLAGS_40)
|
|
tclass->flags |= CLASS_FLAGS_40;
|
|
if (baseclass->flags & CLASS_FLAGS_20)
|
|
tclass->flags |= CLASS_FLAGS_20;
|
|
|
|
if (is_virtual)
|
|
tclass->flags |= CLASS_FLAGS_20;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void CDecl_ParseBaseClassList(TypeClass *tclass, short mode, Boolean is_templ) {
|
|
Boolean is_virtual;
|
|
short access;
|
|
CScopeParseResult pr;
|
|
ObjType *inherited_type;
|
|
ClassList *base;
|
|
ClassList *scan;
|
|
TypeClass *baseclass;
|
|
|
|
do {
|
|
if (mode == CLASS_MODE_2)
|
|
access = ACCESSPRIVATE;
|
|
else
|
|
access = ACCESSPUBLIC;
|
|
|
|
is_virtual = 0;
|
|
if ((tk = lex()) == TK_VIRTUAL) {
|
|
tk = lex();
|
|
is_virtual = 1;
|
|
}
|
|
|
|
switch (tk) {
|
|
case TK_PRIVATE:
|
|
access = ACCESSPRIVATE;
|
|
tk = lex();
|
|
break;
|
|
case TK_PUBLIC:
|
|
access = ACCESSPUBLIC;
|
|
tk = lex();
|
|
break;
|
|
case TK_PROTECTED:
|
|
if (!copts.ARMconform) {
|
|
access = ACCESSPROTECTED;
|
|
tk = lex();
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (tk == TK_VIRTUAL) {
|
|
if (is_virtual)
|
|
CError_Error(CErrorStr121);
|
|
is_virtual = 1;
|
|
tk = lex();
|
|
}
|
|
|
|
if (CScope_ParseDeclName(&pr)) {
|
|
if (!pr.x8) {
|
|
if (!pr.name_4) {
|
|
CError_Error(CErrorStr121);
|
|
} else if (tk == TK_IDENTIFIER && pr.name_4 == tkidentifier) {
|
|
goto special_parsing;
|
|
}
|
|
CError_Error(CErrorStr140, tkidentifier->name);
|
|
continue;
|
|
}
|
|
|
|
CDecl_CompleteType(pr.x8);
|
|
if (is_templ && CTemplTool_IsTemplateArgumentDependentType(pr.x8)) {
|
|
if (!IS_TYPE_CLASS(pr.x8) || !(TYPE_CLASS(pr.x8)->flags & CLASS_FLAGS_100) ||
|
|
CParser_CheckTemplateClassUsage(TEMPL_CLASS(pr.x8), 1)) {
|
|
CTemplClass_RegisterBaseClass(TEMPL_CLASS(tclass), pr.x8, access, is_virtual);
|
|
if (is_virtual)
|
|
tclass->flags |= CLASS_FLAGS_20;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!IS_TYPE_CLASS(pr.x8) || (TYPE_CLASS(pr.x8)->flags & CLASS_FLAGS_100)) {
|
|
CError_Error(CErrorStr131);
|
|
continue;
|
|
}
|
|
baseclass = TYPE_CLASS(pr.x8);
|
|
} else {
|
|
special_parsing:
|
|
if (!strcmp(tkidentifier->name, "HandleObject")) {
|
|
if (tclass->bases)
|
|
CError_Error(CErrorStr191);
|
|
tclass->flags |= CLASS_FLAGS_10 | CLASS_FLAGS_1;
|
|
tk = lex();
|
|
break;
|
|
}
|
|
if (!strcmp(tkidentifier->name, "SingleObject") || !strcmp(tkidentifier->name, "SingleInheritance")) {
|
|
if (tclass->bases)
|
|
CError_Error(CErrorStr191);
|
|
tclass->flags |= CLASS_FLAGS_10;
|
|
tk = lex();
|
|
break;
|
|
}
|
|
if (!strcmp(tkidentifier->name, "__comobject")) {
|
|
tclass->flags |= CLASS_FLAGS_2000;
|
|
tk = lex();
|
|
break;
|
|
}
|
|
if (!strcmp(tkidentifier->name, "__somobject")) {
|
|
if (!is_virtual)
|
|
CError_Error(CErrorStr268);
|
|
CSOM_MakeSOMClass(tclass);
|
|
tk = lex();
|
|
break;
|
|
}
|
|
if (!strcmp(tkidentifier->name, "__javaobject")) {
|
|
tk = lex();
|
|
tclass->action = CLASS_ACTION_3;
|
|
break;
|
|
}
|
|
|
|
CError_Error(CErrorStr140, tkidentifier->name);
|
|
continue;
|
|
}
|
|
|
|
if (CDecl_CheckNewBase(tclass, baseclass, is_virtual)) {
|
|
base = galloc(sizeof(ClassList));
|
|
memclrw(base, sizeof(ClassList));
|
|
base->base = baseclass;
|
|
base->access = access;
|
|
base->is_virtual = is_virtual;
|
|
if ((scan = tclass->bases)) {
|
|
while (scan->next)
|
|
scan = scan->next;
|
|
scan->next = base;
|
|
} else {
|
|
tclass->bases = base;
|
|
}
|
|
}
|
|
} while ((tk = lex()) == ',');
|
|
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
CDecl_MakeVBaseList(tclass);
|
|
|
|
if (copts.def_inherited && tclass->bases && !tclass->bases->next) {
|
|
inherited_type = galloc(sizeof(ObjType));
|
|
memclrw(inherited_type, sizeof(ObjType));
|
|
inherited_type->otype = OT_TYPE;
|
|
inherited_type->access = ACCESSPUBLIC;
|
|
inherited_type->type = TYPE(tclass->bases->base);
|
|
CScope_AddObject(tclass->nspace, GetHashNameNodeExport("inherited"), OBJ_BASE(inherited_type));
|
|
}
|
|
}
|
|
|
|
static short getaccesstype(AccessType a, AccessType b, AccessType c) {
|
|
if (a == ACCESSNONE || b == ACCESSNONE || b == ACCESSPRIVATE)
|
|
return ACCESSNONE;
|
|
|
|
if (c == ACCESSPUBLIC && b != ACCESSPUBLIC)
|
|
return ACCESSNONE;
|
|
|
|
return ACCESSPUBLIC;
|
|
}
|
|
|
|
static TypeMethod *CDecl_MakeDefaultCtorType(TypeClass *tclass) {
|
|
TypeMethod *tmeth = galloc(sizeof(TypeMethod));
|
|
memclrw(tmeth, sizeof(TypeMethod));
|
|
tmeth->type = TYPEFUNC;
|
|
tmeth->functype = TYPE(&void_ptr);
|
|
tmeth->flags = FUNC_FLAGS_1000 | FUNC_FLAGS_100 | FUNC_FLAGS_METHOD;
|
|
tmeth->theclass = tclass;
|
|
CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
|
|
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort));
|
|
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
|
|
return tmeth;
|
|
}
|
|
|
|
static void CDecl_AddDefArgConstructor(TypeClass *tclass) {
|
|
// empty
|
|
}
|
|
|
|
static void CDecl_AddMemberFunctionObject(TypeClass *tclass, HashNameNode *name, TypeMethod *tmeth, short access) {
|
|
Object *obj = CParser_NewCompilerDefFunctionObject();
|
|
obj->name = name;
|
|
obj->type = TYPE(tmeth);
|
|
obj->qual = Q_80000;
|
|
obj->access = access;
|
|
obj->nspace = tclass->nspace;
|
|
obj->qual |= Q_INLINE;
|
|
CScope_AddObject(tclass->nspace, obj->name, OBJ_BASE(obj));
|
|
}
|
|
|
|
static void CDecl_AddDefaultConstructor(DeclE *decle, TypeClass *tclass) {
|
|
ClassList *base;
|
|
ObjMemberVar *ivar;
|
|
Object *obj;
|
|
Boolean has_ctor;
|
|
|
|
if (CClass_Constructor(tclass)) {
|
|
CDecl_AddDefArgConstructor(tclass);
|
|
return;
|
|
}
|
|
|
|
has_ctor = 0;
|
|
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
has_ctor = 1;
|
|
if (decle->xC)
|
|
has_ctor = 1;
|
|
|
|
for (base = tclass->bases; base; base = base->next) {
|
|
if (CClass_Constructor(base->base))
|
|
has_ctor = 1;
|
|
}
|
|
|
|
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
|
|
Type *type = ivar->type;
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type)))
|
|
has_ctor = 1;
|
|
}
|
|
|
|
if (has_ctor) {
|
|
CDecl_AddMemberFunctionObject(
|
|
tclass,
|
|
constructor_name_node,
|
|
CDecl_MakeDefaultCtorType(tclass),
|
|
ACCESSPUBLIC
|
|
);
|
|
}
|
|
}
|
|
|
|
static TypeMethod *CDecl_MakeCopyCtorType(TypeClass *tclass, Boolean is_const) {
|
|
FuncArg *arg;
|
|
TypeMethod *tmeth = galloc(sizeof(TypeMethod));
|
|
memclrw(tmeth, sizeof(TypeMethod));
|
|
tmeth->type = TYPEFUNC;
|
|
tmeth->functype = TYPE(&void_ptr);
|
|
tmeth->flags = FUNC_FLAGS_1000 | FUNC_FLAGS_100 | FUNC_FLAGS_METHOD;
|
|
tmeth->theclass = tclass;
|
|
CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
|
|
|
|
arg = CParser_NewFuncArg();
|
|
if (is_const)
|
|
arg->qual = Q_CONST;
|
|
arg->type = CDecl_NewRefPointerType(TYPE(tclass));
|
|
tmeth->args = arg;
|
|
|
|
if (tclass->flags & CLASS_FLAGS_20)
|
|
CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort));
|
|
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
|
|
return tmeth;
|
|
}
|
|
|
|
static void CDecl_AddDefaultCopyConstructor(DeclE *decle, TypeClass *tclass) {
|
|
ClassList *base;
|
|
ObjMemberVar *ivar;
|
|
Object *obj;
|
|
short access;
|
|
Boolean has_copyctor;
|
|
Boolean is_const;
|
|
FuncArg *arg;
|
|
|
|
if (CClass_CopyConstructor(tclass))
|
|
return;
|
|
|
|
access = ACCESSPUBLIC;
|
|
is_const = 1;
|
|
has_copyctor = 0;
|
|
|
|
if (CClass_Constructor(tclass))
|
|
has_copyctor = 1;
|
|
if ((tclass->flags & CLASS_FLAGS_20) || decle->xC)
|
|
has_copyctor = 1;
|
|
|
|
for (base = tclass->bases; base; base = base->next) {
|
|
if ((obj = CClass_CopyConstructor(base->base))) {
|
|
has_copyctor = 1;
|
|
access = getaccesstype(access, obj->access, ACCESSPRIVATE);
|
|
arg = TYPE_FUNC(obj->type)->args->next;
|
|
if (base->base->flags & CLASS_FLAGS_20)
|
|
arg = arg->next;
|
|
if (!(arg->qual & Q_CONST))
|
|
is_const = 0;
|
|
}
|
|
}
|
|
|
|
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
|
|
Type *type = ivar->type;
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
if (IS_TYPE_CLASS(type) && (obj = CClass_CopyConstructor(TYPE_CLASS(type)))) {
|
|
has_copyctor = 1;
|
|
access = getaccesstype(access, obj->access, ACCESSPUBLIC);
|
|
arg = TYPE_FUNC(obj->type)->args->next;
|
|
if (TYPE_CLASS(type)->flags & CLASS_FLAGS_20)
|
|
arg = arg->next;
|
|
if (!(arg->qual & Q_CONST))
|
|
is_const = 0;
|
|
}
|
|
}
|
|
|
|
if (has_copyctor) {
|
|
CDecl_AddMemberFunctionObject(
|
|
tclass,
|
|
constructor_name_node,
|
|
CDecl_MakeCopyCtorType(tclass, is_const),
|
|
access
|
|
);
|
|
}
|
|
}
|
|
|
|
static TypeMethod *CDecl_MakeAssignmentOperatorType(TypeClass *tclass, Boolean is_const) {
|
|
FuncArg *arg;
|
|
TypeMethod *tmeth = galloc(sizeof(TypeMethod));
|
|
memclrw(tmeth, sizeof(TypeMethod));
|
|
tmeth->type = TYPEFUNC;
|
|
tmeth->functype = CDecl_NewRefPointerType(TYPE(tclass));
|
|
tmeth->flags = FUNC_FLAGS_100 | FUNC_FLAGS_METHOD;
|
|
tmeth->theclass = tclass;
|
|
CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
|
|
|
|
arg = CParser_NewFuncArg();
|
|
if (is_const)
|
|
arg->qual = Q_CONST;
|
|
arg->type = CDecl_NewRefPointerType(TYPE(tclass));
|
|
tmeth->args = arg;
|
|
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
|
|
return tmeth;
|
|
}
|
|
|
|
static void CDecl_AddDefaultAssignmentOperator(DeclE *decle, TypeClass *tclass) {
|
|
ClassList *base;
|
|
ObjMemberVar *ivar;
|
|
Object *obj;
|
|
short access;
|
|
Boolean is_const;
|
|
Boolean has_ass;
|
|
DeclInfo declinfo;
|
|
|
|
is_const = 1;
|
|
has_ass = 0;
|
|
access = ACCESSPUBLIC;
|
|
|
|
if (!CClass_AssignmentOperator(tclass)) {
|
|
if (!copts.old_argmatch)
|
|
has_ass = 1;
|
|
|
|
if ((tclass->flags & CLASS_FLAGS_20) || decle->xC || CClass_MemberObject(tclass, asop_name_node))
|
|
has_ass = 1;
|
|
|
|
for (base = tclass->bases; base; base = base->next) {
|
|
if ((obj = CClass_AssignmentOperator(base->base))) {
|
|
has_ass = 1;
|
|
access = getaccesstype(access, obj->access, ACCESSPRIVATE);
|
|
if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST))
|
|
is_const = 0;
|
|
}
|
|
}
|
|
|
|
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
|
|
Type *type = ivar->type;
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
if (IS_TYPE_CLASS(type) && (obj = CClass_AssignmentOperator(TYPE_CLASS(type)))) {
|
|
has_ass = 1;
|
|
access = getaccesstype(access, obj->access, ACCESSPUBLIC);
|
|
if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST))
|
|
is_const = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (has_ass) {
|
|
memclrw(&declinfo, sizeof(DeclInfo));
|
|
declinfo.qual |= Q_INLINE;
|
|
declinfo.thetype = (Type *) CDecl_MakeAssignmentOperatorType(tclass, is_const);
|
|
declinfo.name = asop_name_node;
|
|
CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
TypeMethod *CDecl_MakeDefaultDtorType(TypeClass *tclass, Boolean is_virtual) {
|
|
TypeMethod *tmeth = galloc(sizeof(TypeMethod));
|
|
memclrw(tmeth, sizeof(TypeMethod));
|
|
tmeth->type = TYPEFUNC;
|
|
tmeth->functype = (Type *) &void_ptr;
|
|
tmeth->flags = FUNC_FLAGS_2000 | FUNC_FLAGS_100 | FUNC_FLAGS_METHOD;
|
|
tmeth->theclass = tclass;
|
|
CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1);
|
|
if (is_virtual)
|
|
CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort));
|
|
CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass);
|
|
return tmeth;
|
|
}
|
|
|
|
static void CDecl_AddDefaultDestructor(DeclE *decle, TypeClass *tclass) {
|
|
ClassList *base;
|
|
ObjMemberVar *ivar;
|
|
Object *obj;
|
|
short access;
|
|
Boolean has_dtor;
|
|
Boolean is_virtual;
|
|
DeclInfo declinfo;
|
|
|
|
if (CClass_Destructor(tclass))
|
|
return;
|
|
|
|
has_dtor = 0;
|
|
is_virtual = 0;
|
|
access = ACCESSPUBLIC;
|
|
|
|
for (base = tclass->bases; base; base = base->next) {
|
|
if ((obj = CClass_Destructor(base->base))) {
|
|
has_dtor = 1;
|
|
if (obj->datatype == DVFUNC)
|
|
is_virtual = 1;
|
|
access = getaccesstype(access, obj->access, ACCESSPRIVATE);
|
|
}
|
|
}
|
|
|
|
for (ivar = tclass->ivars; ivar; ivar = ivar->next) {
|
|
Type *type = ivar->type;
|
|
while (IS_TYPE_ARRAY(type))
|
|
type = TYPE_POINTER(type)->target;
|
|
if (IS_TYPE_CLASS(type) && (obj = CClass_Destructor(TYPE_CLASS(type)))) {
|
|
has_dtor = 1;
|
|
access = getaccesstype(access, obj->access, ACCESSPUBLIC);
|
|
}
|
|
}
|
|
|
|
if (has_dtor) {
|
|
memclrw(&declinfo, sizeof(DeclInfo));
|
|
declinfo.qual |= Q_INLINE;
|
|
if (is_virtual)
|
|
declinfo.qual |= Q_VIRTUAL;
|
|
|
|
declinfo.thetype = (Type *) CDecl_MakeDefaultDtorType(tclass, 1);
|
|
declinfo.name = destructor_name_node;
|
|
CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0);
|
|
}
|
|
}
|
|
|
|
static void CDecl_SetupClassLayout(DeclE *decle, TypeClass *tclass, ObjBase **objbuf) {
|
|
SInt32 index;
|
|
SInt32 i;
|
|
Object *obj;
|
|
CScopeObjectIterator iter;
|
|
ObjMemberVar *ivar;
|
|
SInt32 bufsize;
|
|
|
|
if (decle->x8 > 32) {
|
|
bufsize = decle->x8 * sizeof(ObjBase *);
|
|
objbuf = lalloc(bufsize);
|
|
} else {
|
|
bufsize = 32 * sizeof(ObjBase *);
|
|
}
|
|
memclrw(objbuf, bufsize);
|
|
decle->objlist = objbuf;
|
|
|
|
CScope_InitObjectIterator(&iter, tclass->nspace);
|
|
index = 0;
|
|
while (1) {
|
|
obj = OBJECT(CScope_NextObjectIteratorObject(&iter));
|
|
if (!obj) break;
|
|
|
|
if (!IS_TYPE_FUNC(obj->type))
|
|
continue;
|
|
if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type)))
|
|
continue;
|
|
if (obj->datatype == DALIAS)
|
|
continue;
|
|
|
|
i = TYPE_METHOD(obj->type)->x1E;
|
|
if (i > 0) {
|
|
CError_ASSERT(6363, (i - 1) < decle->x8 && !objbuf[(int) (i - 1)]);
|
|
objbuf[(int) (i - 1)] = OBJ_BASE(obj);
|
|
index++;
|
|
if (obj->datatype != DVFUNC && !TYPE_METHOD(obj->type)->x26 && CClass_OverridesBaseMember(tclass, obj->name, obj))
|
|
CDecl_MakeFunctionVirtual(tclass, obj);
|
|
|
|
if (obj->datatype == DVFUNC) {
|
|
decle->xC = 1;
|
|
if (!tclass->vtable) {
|
|
CABI_AddVTable(tclass);
|
|
decle->xA = i - 1;
|
|
} else {
|
|
if ((i - 1) < decle->xA)
|
|
decle->xA = i - 1;
|
|
}
|
|
} else if (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_8) {
|
|
CError_Error(CErrorStr351, obj);
|
|
TYPE_FUNC(obj->type)->flags &= ~FUNC_FLAGS_8;
|
|
}
|
|
} else {
|
|
CError_ASSERT(6412, i == 0);
|
|
}
|
|
|
|
if (!tclass->sominfo)
|
|
TYPE_METHOD(obj->type)->x1E = 0;
|
|
}
|
|
|
|
if (!tclass->action) {
|
|
for (i = 0; i < decle->x8; i++) {
|
|
Object *obj2 = OBJECT(objbuf[i]);
|
|
if (obj2 && obj2->datatype == DVFUNC && !(obj2->qual & Q_INLINE) && !(TYPE_FUNC(obj2->type)->flags & FUNC_FLAGS_8)) {
|
|
tclass->action = CLASS_ACTION_1;
|
|
TYPE_FUNC(obj2->type)->flags |= FUNC_FLAGS_4;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!tclass->sominfo) {
|
|
for (i = 0, ivar = tclass->ivars; i < decle->x8; i++) {
|
|
if (!objbuf[i]) {
|
|
CError_ASSERT(6449, ivar);
|
|
objbuf[i] = OBJ_BASE(ivar);
|
|
ivar = ivar->next;
|
|
index++;
|
|
}
|
|
}
|
|
CError_ASSERT(6455, ivar == NULL);
|
|
}
|
|
|
|
CError_ASSERT(6458, index == decle->x8);
|
|
}
|
|
|
|
void CDecl_CompleteClass(DeclE *decle, TypeClass *tclass) {
|
|
ClassList *base;
|
|
ObjBase *buf[32];
|
|
|
|
for (base = tclass->bases; base; base = base->next) {
|
|
if (base->base->vtable)
|
|
decle->xC = 1;
|
|
}
|
|
|
|
if (!tclass->sominfo) {
|
|
CDecl_AddDefaultDestructor(decle, tclass);
|
|
CDecl_AddDefaultAssignmentOperator(decle, tclass);
|
|
CDecl_AddDefaultConstructor(decle, tclass);
|
|
CDecl_AddDefaultCopyConstructor(decle, tclass);
|
|
}
|
|
|
|
CDecl_SetupClassLayout(decle, tclass, buf);
|
|
if (decle->xC)
|
|
CClass_CheckOverrides(tclass);
|
|
CABI_LayoutClass(decle, tclass);
|
|
if (tclass->sominfo)
|
|
CSOM_ClassComplete(tclass);
|
|
|
|
if ((tclass->flags & CLASS_FLAGS_800) && !TEMPL_CLASS_INST(tclass)->is_specialized)
|
|
tclass->action = CLASS_ACTION_0;
|
|
|
|
if (!tclass->action)
|
|
CClass_MakeStaticActionClass(tclass);
|
|
CClass_ClassDefaultFuncAction(tclass);
|
|
}
|
|
|
|
TypeClass *CDecl_DefineClass(NameSpace *nspace, HashNameNode *name, TypeClass *tclass, short mode, Boolean flag2, Boolean flag3) {
|
|
NameSpace *mynspace;
|
|
ObjType *objtype;
|
|
|
|
if (!tclass && nspace->theclass && (nspace->theclass->flags & CLASS_FLAGS_100)) {
|
|
CError_ASSERT(6556, !flag2);
|
|
return TYPE_CLASS(CTemplClass_DefineNestedClass(TEMPL_CLASS(nspace->theclass), name, mode));
|
|
}
|
|
|
|
mynspace = CScope_NewListNameSpace(name, 1);
|
|
if (!tclass) {
|
|
tclass = galloc(sizeof(TypeClass));
|
|
memclrw(tclass, sizeof(TypeClass));
|
|
}
|
|
|
|
tclass->type = TYPECLASS;
|
|
tclass->align = 1;
|
|
tclass->mode = mode;
|
|
tclass->action = CLASS_ACTION_0;
|
|
if (name) {
|
|
tclass->classname = name;
|
|
if (flag3) {
|
|
if (flag2) {
|
|
objtype = galloc(sizeof(ObjType));
|
|
memclrw(objtype, sizeof(ObjType));
|
|
objtype->otype = OT_TYPE;
|
|
objtype->access = ACCESSPUBLIC;
|
|
objtype->type = (Type *) tclass;
|
|
CScope_AddObject(nspace, name, OBJ_BASE(objtype));
|
|
} else {
|
|
CScope_DefineTypeTag(nspace, name, (Type *) tclass);
|
|
}
|
|
}
|
|
CScope_DefineTypeTag(mynspace, name, (Type *) tclass);
|
|
|
|
if (cscope_currentfunc)
|
|
mynspace->name = CParser_AppendUniqueNameFile(name->name);
|
|
|
|
if (copts.direct_to_som && nspace == cscope_root && !strcmp(name->name, "SOMObject"))
|
|
CSOM_MakeSOMClass(tclass);
|
|
} else {
|
|
tclass->classname = CParser_AppendUniqueNameFile("@class");
|
|
mynspace->name = tclass->classname;
|
|
}
|
|
|
|
tclass->nspace = mynspace;
|
|
mynspace->theclass = tclass;
|
|
mynspace->parent = nspace;
|
|
if (!nspace->is_global)
|
|
CParser_RegisterNonGlobalClass(tclass);
|
|
|
|
return tclass;
|
|
}
|
|
|
|
void CDecl_ParseClassDeclSpec(UInt8 *declspec) {
|
|
DeclInfo declinfo;
|
|
|
|
if ((tk = lex()) == '(') {
|
|
memclrw(&declinfo, sizeof(DeclInfo));
|
|
CParser_ParseDeclSpec(&declinfo, 1);
|
|
if (declinfo.exportflags & EXPORT_FLAGS_INTERNAL)
|
|
*declspec |= CLASS_EFLAGS_INTERNAL;
|
|
if (declinfo.exportflags & EXPORT_FLAGS_IMPORT)
|
|
*declspec |= CLASS_EFLAGS_IMPORT;
|
|
if (declinfo.exportflags & EXPORT_FLAGS_EXPORT)
|
|
*declspec |= CLASS_EFLAGS_EXPORT;
|
|
if ((tk = lex()) != ')')
|
|
CError_Error(CErrorStr115);
|
|
else
|
|
tk = lex();
|
|
} else {
|
|
CError_Error(CErrorStr114);
|
|
}
|
|
}
|
|
|
|
static TemplClass *CDecl_SpecializeTemplateClass(TemplClass *tmclass) {
|
|
tmclass->theclass.nspace->names = 0;
|
|
tmclass->theclass.nspace->data.list = NULL;
|
|
tmclass->theclass.ivars = NULL;
|
|
tmclass->theclass.bases = NULL;
|
|
tmclass->theclass.vbases = NULL;
|
|
tmclass->theclass.friends = NULL;
|
|
tmclass->theclass.vtable = NULL;
|
|
tmclass->members = NULL;
|
|
tmclass->instances = NULL;
|
|
tmclass->pspec_owner = NULL;
|
|
tmclass->pspecs = NULL;
|
|
tmclass->actions = NULL;
|
|
tmclass->lex_order_count = 0;
|
|
tmclass->align = 0;
|
|
tmclass->flags = TEMPLCLASS_FLAGS_2;
|
|
return tmclass;
|
|
}
|
|
|
|
void CDecl_ParseClass(DeclInfo *declinfo, short mode, Boolean flag1, UInt8 class_declspec) {
|
|
DeclE decle;
|
|
TypeClass *tclass;
|
|
HashNameNode *classname;
|
|
Type *search;
|
|
short t;
|
|
NameSpace *nspace;
|
|
CScopeParseResult pr;
|
|
CScopeSave scopesave;
|
|
GList gl;
|
|
FileOffsetInfo offsetsave;
|
|
SInt32 offset;
|
|
Boolean is_templ;
|
|
Boolean add_to_browse;
|
|
|
|
memclrw(&decle, sizeof(DeclE));
|
|
if (declinfo->x28) {
|
|
tclass = TYPE_CLASS(declinfo->x28);
|
|
} else {
|
|
if (tk == TK_UU_DECLSPEC)
|
|
CDecl_ParseClassDeclSpec(&class_declspec);
|
|
|
|
switch (tk) {
|
|
case ':':
|
|
case '{':
|
|
tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
|
|
tclass->eflags |= class_declspec;
|
|
break;
|
|
case TK_IDENTIFIER:
|
|
classname = tkidentifier;
|
|
if (!declinfo->x4C && !declinfo->x4F && ((t = lookahead()) == ':' || t == ';' || t == '{')) {
|
|
tk = lex();
|
|
search = CScope_GetLocalTagType(cscope_current, classname);
|
|
if (search) {
|
|
tagtype_search:
|
|
if (!IS_TYPE_CLASS(search)) {
|
|
if ((IS_TYPE_TEMPLATE(search) || IS_TYPE_STRUCT(search)) && tk != '{' && tk != ':') {
|
|
declinfo->thetype = search;
|
|
return;
|
|
}
|
|
if (!IS_TYPE_TEMPLATE(search) || !(tclass = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(search)))) {
|
|
CError_Error(CErrorStr132, classname->name);
|
|
tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
|
|
break;
|
|
}
|
|
} else {
|
|
tclass = TYPE_CLASS(search);
|
|
}
|
|
if (tclass->mode != mode) {
|
|
if ((mode == CLASS_FLAGS_2 && tclass->mode == CLASS_MODE_0) || (mode == CLASS_MODE_0 && tclass->mode == CLASS_MODE_2)) {
|
|
if (copts.warn_structclass)
|
|
CError_Warning(CErrorStr343);
|
|
} else {
|
|
CError_Error(CErrorStr132, classname);
|
|
}
|
|
}
|
|
tclass->eflags |= class_declspec;
|
|
break;
|
|
} else {
|
|
tclass = CDecl_DefineClass(cscope_current, classname, NULL, mode, 0, 1);
|
|
tclass->eflags |= class_declspec;
|
|
break;
|
|
}
|
|
} else {
|
|
tkidentifier = classname;
|
|
}
|
|
default:
|
|
if (!CScope_ParseElaborateName(&pr)) {
|
|
CError_Error(CErrorStr121);
|
|
declinfo->thetype = (Type *) &stsignedint;
|
|
return;
|
|
}
|
|
|
|
tk = lex();
|
|
if ((search = pr.x8)) {
|
|
goto tagtype_search;
|
|
}
|
|
|
|
CError_ASSERT(6786, pr.name_4);
|
|
|
|
tclass = CDecl_DefineClass(CScope_FindNonClassNonFunctionNS(cscope_current), pr.name_4, NULL, mode, 0, 1);
|
|
tclass->eflags |= class_declspec;
|
|
}
|
|
}
|
|
|
|
declinfo->thetype = (Type *) tclass;
|
|
if (tk == ':' || tk == '{') {
|
|
if (declinfo->x4C)
|
|
CError_Error(CErrorStr201);
|
|
|
|
if (tclass->flags & CLASS_FLAGS_2) {
|
|
if ((tclass->flags & CLASS_FLAGS_100) && !TEMPL_CLASS(tclass)->instances && !(TEMPL_CLASS(tclass)->flags & TEMPLCLASS_FLAGS_2)) {
|
|
tclass = TYPE_CLASS(CDecl_SpecializeTemplateClass(TEMPL_CLASS(tclass)));
|
|
} else {
|
|
CError_Error(CErrorStr132, tclass->classname->name);
|
|
tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
|
|
}
|
|
}
|
|
|
|
for (nspace = cscope_current; nspace; nspace = nspace->parent) {
|
|
if (nspace == tclass->nspace) {
|
|
CError_Error(CErrorStr132, tclass->classname->name);
|
|
tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
is_templ = (tclass->flags & CLASS_FLAGS_100) ? 1 : 0;
|
|
if (tclass->flags & CLASS_FLAGS_800) {
|
|
TEMPL_CLASS_INST(tclass)->is_instantiated = 1;
|
|
if (!declinfo->x28)
|
|
TEMPL_CLASS_INST(tclass)->is_specialized = 1;
|
|
}
|
|
|
|
CError_ASSERT(6853, copts.structalignment >= 0 && copts.structalignment <= 14);
|
|
|
|
tclass->eflags |= (UInt8) ((copts.structalignment + 1) << 4);
|
|
if (tk == ':')
|
|
CDecl_ParseBaseClassList(tclass, mode, is_templ);
|
|
|
|
CScope_SetClassDefScope(tclass, &scopesave);
|
|
if (tk == '{') {
|
|
tk = lex();
|
|
if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo)) {
|
|
offsetsave = member_fileoffset;
|
|
CBrowse_BeginClass(declinfo, &gl);
|
|
}
|
|
CDecl_ParseClassMembers(&decle, tclass, mode);
|
|
offset = CPrep_BrowserFileOffset();
|
|
if (flag1)
|
|
tk = lex();
|
|
if (add_to_browse) {
|
|
member_fileoffset = offsetsave;
|
|
if (flag1 && tk == ';')
|
|
CPrep_BrowserFileOffset();
|
|
CBrowse_EndClass(offset, &gl);
|
|
}
|
|
} else {
|
|
CError_Error(CErrorStr135);
|
|
}
|
|
|
|
if (is_templ)
|
|
CTemplClass_CompleteClass(TEMPL_CLASS(tclass), &decle);
|
|
else
|
|
CDecl_CompleteClass(&decle, tclass);
|
|
CScope_RestoreScope(&scopesave);
|
|
}
|
|
}
|