#include "compiler/CClass.h" #include "compiler/CABI.h" #include "compiler/CDecl.h" #include "compiler/CError.h" #include "compiler/CExpr.h" #include "compiler/CInit.h" #include "compiler/CInline.h" #include "compiler/CMachine.h" #include "compiler/CMangler.h" #include "compiler/CObjC.h" #include "compiler/CParser.h" #include "compiler/CRTTI.h" #include "compiler/CSOM.h" #include "compiler/CompilerTools.h" #include "compiler/CodeGen.h" #include "compiler/objects.h" #include "compiler/scopes.h" #ifdef __MWERKS__ #pragma options align=mac68k #endif typedef struct OVClassBase { struct OVClassBase *next; struct OVClass *ovclass; Boolean is_virtual; } OVClassBase; typedef struct OVFunc { struct OVFunc *next; Object *obj; struct OVClass *ovc8; struct OVFunc *ovfC; struct OVFunc *ovf10; } OVFunc; typedef struct OVClass { TypeClass *tclass; OVFunc *vfuncs; OVClassBase *bases; SInt32 offset; SInt32 voffset; Boolean alloced_vtable; } OVClass; typedef struct ThunkList { struct ThunkList *next; Object *thunkobj; Object *obj; SInt32 a; SInt32 b; SInt32 c; } ThunkList; #ifdef __MWERKS__ #pragma options align=reset #endif static TypeClass *main_class; static ThunkList *cclass_thunklist; static TypeClass *cclass_isbase_mostderived; static SInt32 cclass_isbase_foundoffset; static Boolean cclass_isambigbase; static short cclass_founddepth; static char *vtable_object_data; static SInt32 vtable_data_size; static OLinkList *vtable_object_links; static TypeClass *cclass_vbase; static OVClass *cclass_ovbase; static OVClass *cclass_root; static Object *found_pure; static Boolean check_pures; static Object *cclass_dominator_vobject; static SInt32 cclass_dominator_voffset; static Object *cclass_dominator_oobject; static TypeClass *cclass_dominator_oclass; static SInt32 cclass_dominator_ooffset; static Object *cclass_dominator_eobject; void CClass_Init(void) { cclass_thunklist = NULL; } void CClass_GenThunks(void) { ThunkList *list; for (list = cclass_thunklist; list; list = list->next) { list->thunkobj->flags |= OBJECT_FLAGS_4; CodeGen_GenVDispatchThunk(list->thunkobj, list->obj, list->a, list->b, list->c); } } static Object *CClass_ThunkObject(Object *obj, SInt32 a, SInt32 b, SInt32 c) { Object *thunkobj; ThunkList *list; CInline_ObjectAddrRef(obj); for (list = cclass_thunklist; list; list = list->next) { if (obj == list->obj && a == list->a && b == list->b && c == list->c) return list->thunkobj; } thunkobj = CParser_NewCompilerDefFunctionObject(); thunkobj->name = CMangler_ThunkName(obj, a, b, c); thunkobj->type = TYPE(&rt_func); thunkobj->sclass = TK_EXTERN; thunkobj->qual = Q_20000; thunkobj->u.func.linkname = thunkobj->name; list = galloc(sizeof(ThunkList)); list->thunkobj = thunkobj; list->obj = obj; list->a = a; list->b = b; list->c = c; list->next = cclass_thunklist; cclass_thunklist = list; return thunkobj; } static Boolean CClass_IsZeroOffsetClass(TypeClass *a, TypeClass *b) { while (1) { if (a == b) return 1; if (!a->bases || a->bases->is_virtual) return 0; a = a->bases->base; } } static UInt8 CClass_IsCovariantResult(Type *a, UInt32 qualA, Type *b, UInt32 qualB, Boolean errorflag) { TypeClass *tclassA; TypeClass *tclassB; if ( IS_TYPE_POINTER_ONLY(a) && IS_TYPE_POINTER_ONLY(b) && TPTR_QUAL(a) == TPTR_QUAL(b) && !CParser_IsMoreCVQualified(qualB, qualA) && IS_TYPE_CLASS(TPTR_TARGET(a)) && IS_TYPE_CLASS(TPTR_TARGET(b)) ) { tclassA = TYPE_CLASS(TPTR_TARGET(a)); tclassB = TYPE_CLASS(TPTR_TARGET(b)); if (tclassA == tclassB || CClass_IsBaseClass(tclassB, tclassA, NULL, errorflag, errorflag)) { if (!CClass_IsZeroOffsetClass(tclassB, tclassA)) return 2; else return 1; } } return 0; } UInt8 CClass_GetOverrideKind(TypeFunc *a, TypeFunc *b, Boolean errorflag) { if (!a->args || !b->args) return 0; if ( (a->flags & (FUNC_FLAGS_PASCAL | FUNC_FLAGS_F0000000)) != (b->flags & (FUNC_FLAGS_PASCAL | FUNC_FLAGS_F0000000)) || !is_arglistsame(a->args->next, b->args->next) || a->args->qual != b->args->qual ) return 0; if (!is_typesame(a->functype, b->functype)) { switch (CClass_IsCovariantResult(a->functype, a->qual, b->functype, b->qual, errorflag)) { case 0: if (errorflag) CError_Error(CErrorStr227); return 0; case 1: return 1; case 2: return 2; default: CError_FATAL(225); } } return 1; } Boolean CClass_IsEmpty(TypeClass *tclass) { ClassList *base; if (tclass->ivars) return 0; for (base = tclass->bases; base; base = base->next) { if (!CClass_IsEmpty(base->base)) return 0; } return 1; } Boolean CClass_IsNonStaticMemberFunc(TypeFunc *tfunc) { return IS_TYPEFUNC_NONSTATIC_METHOD(tfunc) || (tfunc->flags & FUNC_FLAGS_80); } Object *CClass_DefaultConstructor(TypeClass *tclass) { NameSpaceObjectList *nsol; Object *object; for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) { object = OBJECT(nsol->object); if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { if ((tclass->flags & CLASS_FLAGS_20) && !tclass->sominfo) { if (TYPE_FUNC(object->type)->args->next && !TYPE_FUNC(object->type)->args->next->next) return object; } else { if (!TYPE_FUNC(object->type)->args->next) return object; } } } return NULL; } Object *CClass_DummyDefaultConstructor(TypeClass *tclass) { Object *ctor; FuncArg *args; NameSpaceObjectList *nsol; HashNameNode *name; TypeMethod *tmethod; Object *object; ObjectList list; ctor = NULL; for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) { object = OBJECT(nsol->object); if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { CError_ASSERT(305, args = TYPE_FUNC(object->type)->args); args = args->next; if ((tclass->flags & CLASS_FLAGS_20) && !tclass->sominfo) { CError_ASSERT(309, args); args = args->next; } CError_ASSERT(312, args); if (args->dexpr) { if (ctor) { list.next = NULL; list.object = object; CError_OverloadedFunctionError(ctor, &list); break; } ctor = object; } } } if (!ctor) { CError_Error(CErrorStr203); return NULL; } name = GetHashNameNodeExport("__defctor"); if ((nsol = CScope_FindName(tclass->nspace, name))) { CError_ASSERT(339, nsol->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(nsol->object)->type)); return OBJECT(nsol->object); } tmethod = galloc(sizeof(TypeMethod)); memclrw(tmethod, sizeof(TypeMethod)); tmethod->type = TYPEFUNC; tmethod->functype = TYPE(&void_ptr); tmethod->flags = FUNC_FLAGS_METHOD; tmethod->theclass = tclass; CDecl_SetFuncFlags(TYPE_FUNC(tmethod), 0); if ((tclass->flags & CLASS_FLAGS_20) && !tclass->sominfo) CDecl_AddArgument(TYPE_FUNC(tmethod), TYPE(&stsignedshort)); CDecl_AddThisPointerArgument(TYPE_FUNC(tmethod), tclass); object = CParser_NewCompilerDefFunctionObject(); object->type = TYPE(tmethod); object->qual = Q_INLINE | Q_80000; object->nspace = tclass->nspace; object->name = name; CScope_AddObject(tclass->nspace, name, OBJ_BASE(object)); CParser_RegisterDummyCtorFunction(object, ctor); return object; } ENode *CClass_DefaultConstructorCall(TypeClass *tclass, TypeClass *b, ENode *objexpr, SInt32 varg, Boolean flag1, Boolean flag2, Boolean *errorflag) { NameSpaceObjectList *nsol; Object *ctor; Object *object; FuncArg *args; ENodeList *argexprs; ENode *expr; BClassList *path; BClassList list1; ObjectList objlist; BClassList list2; short founddepth; Boolean isambigbase; *errorflag = 0; if (!(nsol = CScope_FindName(tclass->nspace, constructor_name_node))) return NULL; ctor = NULL; do { object = OBJECT(nsol->object); if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { CError_ASSERT(397, args = TYPE_FUNC(object->type)->args); args = args->next; if ((tclass->flags & CLASS_FLAGS_20) && !tclass->sominfo) { CError_ASSERT(401, args); args = args->next; } if (!args || args->dexpr) { if (ctor) { objlist.next = NULL; objlist.object = object; CError_OverloadedFunctionError(ctor, &objlist); break; } ctor = object; } } } while ((nsol = nsol->next)); if (!ctor) { *errorflag = 1; return NULL; } if (flag1) { if (b) { if (flag2) { if ((path = CClass_GetBasePath(b, tclass, &founddepth, &isambigbase))) list1 = *path; else goto skipCheck; } else { list1.next = &list2; list1.type = TYPE(b); list2.next = NULL; list2.type = TYPE(tclass); } } else { list1.next = NULL; list1.type = TYPE(tclass); } CClass_CheckPathAccess(&list1, ctor, ctor->access); } skipCheck: if ((tclass->flags & CLASS_FLAGS_20) && !tclass->sominfo) { argexprs = lalloc(sizeof(ENodeList)); argexprs->next = NULL; argexprs->node = intconstnode(TYPE(&stsignedshort), varg); } else { argexprs = NULL; } CError_ASSERT(471, IS_TYPE_POINTER_ONLY(objexpr->rtype)); objexpr = makemonadicnode(objexpr, EINDIRECT); objexpr->rtype = TYPE(tclass); list1.next = NULL; list1.type = TYPE(tclass); expr = CExpr_GenericFuncCall( &list1, objexpr, 0, ctor, NULL, NULL, argexprs, 0, 0, 0 ); if (ENODE_IS2(expr, EFUNCCALL, EFUNCCALLP)) expr->rtype = CDecl_NewPointerType(TYPE(tclass)); return expr; } Object *CClass_AssignmentOperator(TypeClass *tclass) { NameSpaceObjectList *nsol; Object *object; for (nsol = CScope_FindName(tclass->nspace, asop_name_node); nsol; nsol = nsol->next) { object = OBJECT(nsol->object); if ( object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type) && TYPE_FUNC(object->type)->args && TYPE_FUNC(object->type)->args->next && !TYPE_FUNC(object->type)->args->next->next ) { if ( IS_TYPE_CLASS(TYPE_FUNC(object->type)->args->next->type) && TYPE_CLASS(TYPE_FUNC(object->type)->args->next->type) == tclass ) return object; if ( IS_TYPE_REFERENCE(TYPE_FUNC(object->type)->args->next->type) && TPTR_TARGET(TYPE_FUNC(object->type)->args->next->type) == TYPE(tclass) ) return object; } } return NULL; } Object *CClass_CopyConstructor(TypeClass *tclass) { NameSpaceObjectList *nsol; Object *object; FuncArg *args; if (tclass->sominfo) return NULL; for (nsol = CScope_FindName(tclass->nspace, constructor_name_node); nsol; nsol = nsol->next) { object = OBJECT(nsol->object); if (object->otype == OT_OBJECT && IS_TYPE_FUNC(object->type)) { CError_ASSERT(532, args = TYPE_FUNC(object->type)->args); args = args->next; if (tclass->flags & CLASS_FLAGS_20) { CError_ASSERT(536, args); args = args->next; } if ( args && args != &elipsis && (!args->next || args->next->dexpr) && IS_TYPE_REFERENCE(args->type) && TPTR_TARGET(args->type) == TYPE(tclass) ) return object; } } return NULL; } NameSpaceObjectList *CClass_MemberObject(TypeClass *tclass, HashNameNode *name) { NameSpaceObjectList *nsol; if ((nsol = CScope_FindName(tclass->nspace, name)) && nsol->object->otype == OT_OBJECT) return nsol; return NULL; } NameSpaceObjectList *CClass_Constructor(TypeClass *tclass) { NameSpaceObjectList *nsol; if ( (nsol = CScope_FindName(tclass->nspace, constructor_name_node)) && nsol->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(nsol->object)->type) ) return nsol; return NULL; } Object *CClass_Destructor(TypeClass *tclass) { NameSpaceObjectList *nsol; for (nsol = CScope_FindName(tclass->nspace, destructor_name_node); nsol; nsol = nsol->next) { if ( nsol->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(nsol->object)->type) ) return OBJECT(nsol->object); } return NULL; } Boolean CClass_IsConstructor(Object *obj) { return obj && IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_1000); } Boolean CClass_IsDestructor(Object *obj) { return obj && IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_2000); } Boolean CClass_IsPODClass(TypeClass *tclass) { NameSpaceObjectList *nsol; Object *object; ObjMemberVar *ivar; Type *type; if (tclass->vtable || tclass->bases || CClass_Destructor(tclass)) return 0; for (nsol = CClass_Constructor(tclass); nsol; nsol = nsol->next) { if ( nsol->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(nsol->object)->type) && !(TYPE_FUNC(OBJECT(nsol->object)->type)->flags & FUNC_FLAGS_100) ) return 0; } object = CClass_AssignmentOperator(tclass); if (object && !(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100)) return 0; for (ivar = tclass->ivars; ivar; ivar = ivar->next) { if (ivar->access != ACCESSPUBLIC) return 0; type = ivar->type; while (IS_TYPE_ARRAY(type)) type = TPTR_TARGET(type); switch (type->type) { case TYPECLASS: if (!CClass_IsPODClass(TYPE_CLASS(type))) return 0; break; case TYPEMEMBERPOINTER: return 0; case TYPEPOINTER: if (TPTR_QUAL(type) & Q_REFERENCE) return 0; break; } } return 1; } Boolean CClass_IsTrivialCopyClass(TypeClass *tclass) { Object *object; ClassList *base; ObjMemberVar *ivar; Type *type; if (tclass->vtable || tclass->vbases || CClass_Destructor(tclass)) return 0; object = CClass_CopyConstructor(tclass); if (object && IS_TYPE_FUNC(object->type) && !(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100)) return 0; for (base = tclass->bases; base; base = base->next) { if (!CClass_IsTrivialCopyClass(base->base)) return 0; } for (ivar = tclass->ivars; ivar; ivar = ivar->next) { type = ivar->type; while (IS_TYPE_ARRAY(type)) type = TPTR_TARGET(type); if (IS_TYPE_CLASS(type) && !CClass_IsTrivialCopyClass(TYPE_CLASS(type))) return 0; } return 1; } Boolean CClass_IsTrivialCopyAssignClass(TypeClass *tclass) { Object *object; ObjMemberVar *ivar; Type *type; if (tclass->vtable || tclass->bases || CClass_Destructor(tclass)) return 0; object = CClass_AssignmentOperator(tclass); if (object && !(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_100)) return 0; for (ivar = tclass->ivars; ivar; ivar = ivar->next) { type = ivar->type; while (IS_TYPE_ARRAY(type)) type = TPTR_TARGET(type); if (IS_TYPE_REFERENCE(type)) return 0; if (CParser_IsConst(type, ivar->qual)) return 0; if (IS_TYPE_CLASS(type) && !CClass_IsTrivialCopyAssignClass(TYPE_CLASS(type))) return 0; } return 1; } Boolean CClass_ReferenceArgument(TypeClass *tclass) { if ((tclass->flags & (CLASS_FLAGS_2 | CLASS_FLAGS_800)) == CLASS_FLAGS_800) CDecl_CompleteType(TYPE(tclass)); if (copts.simple_class_byval) return !CClass_IsTrivialCopyClass(tclass); return CClass_Destructor(tclass) || CClass_CopyConstructor(tclass); } BClassList *CClass_GetPathCopy(BClassList *path, Boolean is_global) { BClassList *last; BClassList *copy; if (!path) return NULL; copy = last = is_global ? galloc(sizeof(BClassList)) : lalloc(sizeof(BClassList)); last->next = path->next; last->type = path->type; while ((path = path->next)) { last->next = is_global ? galloc(sizeof(BClassList)) : lalloc(sizeof(BClassList)); last = last->next; last->next = path->next; last->type = path->type; } return copy; } BClassList *CClass_AppendPath(BClassList *dest, BClassList *src) { BClassList *last; if (!(last = dest)) return src; while (last->next) last = last->next; while (src && src->type == last->type) src = src->next; last->next = src; return dest; } static AccessType CClass_GetPathAccess(BClassList *path) { AccessType result; ClassList *base; TypeClass *tclass; CError_ASSERT(930, path); result = ACCESSPUBLIC; while (1) { tclass = TYPE_CLASS(path->type); if (!(path = path->next)) break; for (base = tclass->bases; base; base = base->next) { if (base->base == TYPE_CLASS(path->type)) break; } CError_ASSERT(939, base); switch (base->access) { case ACCESSPUBLIC: break; case ACCESSPROTECTED: if (result == ACCESSPUBLIC) result = ACCESSPROTECTED; break; case ACCESSPRIVATE: if (result == ACCESSPUBLIC || result == ACCESSPROTECTED) result = ACCESSPRIVATE; else return ACCESSNONE; break; case ACCESSNONE: return ACCESSNONE; default: CError_FATAL(960); } } return result; } Boolean CClass_IsMoreAccessiblePath(BClassList *path1, BClassList *path2) { switch (CClass_GetPathAccess(path2)) { case ACCESSPUBLIC: return 0; case ACCESSNONE: return 1; default: CError_FATAL(978); case ACCESSPROTECTED: switch (CClass_GetPathAccess(path1)) { case ACCESSPUBLIC: return 1; case ACCESSPRIVATE: case ACCESSPROTECTED: case ACCESSNONE: return 0; default: CError_FATAL(987); } case ACCESSPRIVATE: switch (CClass_GetPathAccess(path1)) { case ACCESSPUBLIC: case ACCESSPROTECTED: return 1; case ACCESSPRIVATE: case ACCESSNONE: return 0; default: CError_FATAL(997); } } return 0; } static BClassList *CClass_GetBasePathRec(TypeClass *a, TypeClass *b, SInt32 offset, short depth) { ClassList *base; BClassList *checkpath; BClassList *bestpath; BClassList *newpath; SInt32 newOffset; for (base = a->bases, bestpath = NULL; base; base = base->next) { if (base->is_virtual) newOffset = CClass_VirtualBaseOffset(cclass_isbase_mostderived, base->base); else newOffset = offset + base->offset; if (base->base == b) { if (cclass_founddepth && newOffset != cclass_isbase_foundoffset) { cclass_isambigbase = 1; return NULL; } cclass_isbase_foundoffset = newOffset; cclass_founddepth = depth; bestpath = lalloc(sizeof(BClassList)); bestpath->next = NULL; bestpath->type = TYPE(b); } else if ((checkpath = CClass_GetBasePathRec(base->base, b, newOffset, depth + 1))) { newpath = lalloc(sizeof(BClassList)); newpath->next = checkpath; newpath->type = TYPE(base->base); if (!bestpath || CClass_IsMoreAccessiblePath(newpath, bestpath)) bestpath = newpath; } } return bestpath; } BClassList *CClass_GetBasePath(TypeClass *a, TypeClass *b, short *founddepth, Boolean *isambigbase) { BClassList *path; BClassList *result; if ((a->flags & (CLASS_FLAGS_2 | CLASS_FLAGS_800)) == CLASS_FLAGS_800) CDecl_CompleteType(TYPE(a)); if ((b->flags & (CLASS_FLAGS_2 | CLASS_FLAGS_800)) == CLASS_FLAGS_800) CDecl_CompleteType(TYPE(b)); cclass_founddepth = 0; cclass_isbase_mostderived = a; cclass_isbase_foundoffset = -1; cclass_isambigbase = 0; if ((path = CClass_GetBasePathRec(a, b, 0, 1))) { *founddepth = cclass_founddepth; *isambigbase = cclass_isambigbase; result = lalloc(sizeof(BClassList)); result->next = path; result->type = TYPE(a); return result; } else { *isambigbase = 0; return NULL; } } Boolean CClass_IsBaseClass(TypeClass *a, TypeClass *b, short *founddepth, Boolean pathcheckflag, Boolean ambigerrorflag) { BClassList *path; short depth; Boolean isambigbase; if ((path = CClass_GetBasePath(a, b, &depth, &isambigbase))) { if (isambigbase && ambigerrorflag) CError_Error(CErrorStr188); if (pathcheckflag) CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); if (founddepth) *founddepth = depth; return 1; } return 0; } TypeClass *CClass_GetQualifiedClass(void) { DeclInfo di; memclrw(&di, sizeof(di)); CParser_GetDeclSpecs(&di, 0); if (IS_TYPE_CLASS(di.thetype)) return TYPE_CLASS(di.thetype); return NULL; } ENode *CClass_AccessPathCast(BClassList *path, ENode *expr, Boolean reverse) { ClassList *base; SInt32 offset; while (path && path->next) { base = TYPE_CLASS(path->type)->bases; while (1) { if (base->base == TYPE_CLASS(path->next->type)) break; CError_ASSERT(1157, base = base->next); } if (base->is_virtual) { if (reverse) { CError_Error(CErrorStr164); break; } if (!base->base->sominfo) { offset = base->offset; if (offset && !canadd(expr, offset)) { expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); optimizecomm(expr); } expr->rtype = CDecl_NewPointerType(CDecl_NewPointerType(TYPE(base->base))); expr = makemonadicnode(expr, EINDIRECT); expr->rtype = expr->data.monadic->rtype; } } else { offset = base->offset; if (offset) { if (reverse) offset = -offset; if (!canadd(expr, offset)) { expr = makediadicnode(expr, intconstnode(TYPE(&stunsignedlong), offset), EADD); optimizecomm(expr); } } } path = path->next; } return expr; } ENode *CClass_ClassPointerCast(ENode *expr, TypeClass *a, TypeClass *b, Boolean typconflag, Boolean ambigerrorflag, Boolean pathcheckflag) { BClassList *path; Boolean reverse; short depth; Boolean isambigbase; reverse = 0; if (a != b) { if (!(path = CClass_GetBasePath(a, b, &depth, &isambigbase))) { CError_ASSERT(1216, typconflag); if ((path = CClass_GetBasePath(b, a, &depth, &isambigbase))) { reverse = 1; goto doCast; } } else { doCast: if (isambigbase && ambigerrorflag) CError_Error(CErrorStr188); if (pathcheckflag) CClass_CheckPathAccess(path, NULL, ACCESSPUBLIC); if (!(a->flags & CLASS_FLAGS_10) && !b->sominfo) expr = CClass_AccessPathCast(path, expr, reverse); } } if (typconflag && ENODE_IS(expr, EINDIRECT) && IS_TYPE_POINTER_ONLY(expr->rtype)) expr = makemonadicnode(expr, ETYPCON); return expr; } ENode *CClass_DirectBasePointerCast(ENode *expr, TypeClass *a, TypeClass *b) { ClassList *base; VClassList *vbase; BClassList *path; BClassList list1; BClassList list2; short depth; Boolean isambigbase; for (base = a->bases; base; base = base->next) { if (base->base == b) { list1.next = &list2; list1.type = TYPE(a); list2.next = NULL; list2.type = TYPE(b); return CClass_AccessPathCast(&list1, expr, 0); } } for (vbase = a->vbases; vbase; vbase = vbase->next) { if (vbase->base == b) { CError_ASSERT(1273, path = CClass_GetBasePath(a, b, &depth, &isambigbase)); return CClass_AccessPathCast(path, expr, 0); } } CError_FATAL(1277); return expr; } SInt32 CClass_GetPathOffset(BClassList *path) { SInt32 offset; ClassList *base; offset = 0; while (path->next) { if (path->type != path->next->type) { for (base = TYPE_CLASS(path->type)->bases; base; base = base->next) { if (base->base == TYPE_CLASS(path->next->type)) break; } if (!base) { CError_Error(CErrorStr221); return offset; } } if (base->is_virtual) return -1; offset += base->offset; path = path->next; } return offset; } Boolean CClass_ClassDominates(TypeClass *tclass, TypeClass *baseclass) { ClassList *base; for (base = tclass->bases; base; base = base->next) { if (base->base == baseclass || CClass_ClassDominates(base->base, baseclass)) return 1; } return 0; } SInt32 CClass_VirtualBaseOffset(TypeClass *tclass, TypeClass *baseclass) { VClassList *vbase; for (vbase = tclass->vbases; vbase; vbase = vbase->next) { if (vbase->base == baseclass) return vbase->offset; } CError_FATAL(1342); return 0; } SInt32 CClass_VirtualBaseVTableOffset(TypeClass *tclass, TypeClass *baseclass) { VClassList *vbase; for (vbase = tclass->vbases; vbase; vbase = vbase->next) { if (vbase->base == baseclass) return vbase->voffset; } CError_FATAL(1359); return 0; } SInt32 CClass_GetMemberOffset(TypeClass *tclass, HashNameNode *name, ObjMemberVar **resultIvar) { ObjMemberVar *ivar; ClassList *base; SInt32 offset; SInt32 tmp; Boolean foundflag; for (ivar = tclass->ivars; ivar; ivar = ivar->next) { if (ivar->name == name) { if (resultIvar) *resultIvar = ivar; return ivar->offset; } } for (base = tclass->bases, foundflag = 0; base; base = base->next) { switch ((tmp = CClass_GetMemberOffset(base->base, name, resultIvar))) { case -3: case -2: return tmp; case -1: break; default: if (base->is_virtual) return -3; if (foundflag) return -2; foundflag = 1; offset = base->offset + tmp; } } return foundflag ? offset : -1; } Boolean CClass_OverridesBaseMember(TypeClass *tclass, HashNameNode *name, Object *obj) { NameSpaceObjectList *nsol; ClassList *base; Boolean result; result = 0; for (base = tclass->bases; base; base = base->next) { if (base->base->vtable) { for (nsol = CScope_FindName(base->base->nspace, name); nsol; nsol = nsol->next) { if ( nsol->object->otype == OT_OBJECT && OBJECT(nsol->object)->datatype == DVFUNC && CClass_GetOverrideKind(TYPE_FUNC(OBJECT(nsol->object)->type), TYPE_FUNC(obj->type), 1) ) result = 1; } if (CClass_OverridesBaseMember(base->base, name, obj)) result = 1; } } return result; } static OVClass *CClass_FindOVClass(OVClass *ovclass, TypeClass *tclass, SInt32 offset) { OVClassBase *ovbase; if (ovclass->tclass == tclass && ovclass->offset == offset) return ovclass; for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) { if ((ovclass = CClass_FindOVClass(ovbase->ovclass, tclass, offset))) return ovclass; } return NULL; } static OVClass *CClass_BuildOVClassTree(OVClass *root, TypeClass *tclass, SInt32 offset, SInt32 voffset) { ClassList *base; Object *object; OVClass *tree; OVFunc *ovfunc; OVClassBase *ovbase; SInt32 vboffset; SInt32 vbvoffset; CScopeObjectIterator iter; tree = lalloc(sizeof(OVClass)); memclrw(tree, sizeof(OVClass)); tree->tclass = tclass; tree->offset = offset; tree->voffset = voffset; if (!root) root = tree; CScope_InitObjectIterator(&iter, tclass->nspace); while (1) { if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) break; if (object->datatype == DVFUNC) { ovfunc = lalloc(sizeof(OVFunc)); memclrw(ovfunc, sizeof(OVFunc)); ovfunc->next = tree->vfuncs; ovfunc->obj = object; tree->vfuncs = ovfunc; } } for (base = tclass->bases; base; base = base->next) { if (base->base->vtable || base->base->sominfo) { ovbase = lalloc(sizeof(OVClassBase)); memclrw(ovbase, sizeof(OVClassBase)); if (base->is_virtual) { vboffset = CClass_VirtualBaseOffset(main_class, base->base); if (!(ovbase->ovclass = CClass_FindOVClass(root, base->base, vboffset))) { vbvoffset = CClass_VirtualBaseVTableOffset(main_class, base->base); ovbase->ovclass = CClass_BuildOVClassTree(root, base->base, vboffset, vbvoffset); } ovbase->is_virtual = 1; } else { ovbase->ovclass = CClass_BuildOVClassTree( root, base->base, offset + base->offset, voffset + base->voffset); ovbase->is_virtual = 0; } ovbase->next = tree->bases; tree->bases = ovbase; } } return tree; } static Boolean CClass_IsBaseOf(OVClass *a, OVClass *b) { OVClassBase *ovbase; for (ovbase = b->bases; ovbase; ovbase = ovbase->next) { if ( (ovbase->ovclass->tclass == a->tclass && ovbase->ovclass->offset == a->offset) || CClass_IsBaseOf(a, ovbase->ovclass) ) { if (!cclass_ovbase && ovbase->is_virtual) cclass_ovbase = ovbase->ovclass; return 1; } } return 0; } static void CClass_FindOVFunc(OVClass *a, OVClass *b, OVFunc *func) { OVFunc *scan; OVClassBase *ovbase; UInt8 overrideKind; if (CClass_IsBaseOf(b, a)) { for (scan = a->vfuncs; scan; scan = scan->next) { if ( (func->obj->name == scan->obj->name) && (overrideKind = CClass_GetOverrideKind(TYPE_FUNC(func->obj->type), TYPE_FUNC(scan->obj->type), 0)) ) { if (func->ovc8) { if (func->ovc8->tclass == a->tclass || CClass_ClassDominates(func->ovc8->tclass, a->tclass)) return; if (!CClass_ClassDominates(a->tclass, func->ovc8->tclass)) { func->ovf10 = scan; return; } } if (a == cclass_root) { TYPE_FUNC(scan->obj->type)->flags |= FUNC_FLAGS_20; if (overrideKind == 2) TYPE_FUNC(scan->obj->type)->flags |= FUNC_FLAGS_400000; } func->ovc8 = a; func->ovfC = scan; func->ovf10 = NULL; return; } } for (ovbase = a->bases; ovbase; ovbase = ovbase->next) CClass_FindOVFunc(ovbase->ovclass, b, func); } } static TypeList *CClass_GetCoVariantClassList(TypeList *list, TypeClass *tclass, Object *func, Boolean flag) { Object *object; TypeList *scan; Type *type; ClassList *base; CScopeObjectIterator iter; if (!flag) { CScope_InitObjectIterator(&iter, tclass->nspace); while (1) { if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) break; if ( object->name == func->name && object->datatype == DVFUNC && CClass_GetOverrideKind(TYPE_FUNC(object->type), TYPE_FUNC(func->type), 0) == 2 ) { CError_ASSERT(1686, IS_TYPE_POINTER_ONLY(TYPE_FUNC(object->type)->functype) && IS_TYPE_CLASS(TPTR_TARGET(TYPE_FUNC(object->type)->functype))); type = TPTR_TARGET(TYPE_FUNC(object->type)->functype); for (scan = list; scan; scan = scan->next) { if (scan->type == type) break; } if (!scan) { scan = lalloc(sizeof(TypeList)); scan->type = type; scan->next = list; list = scan; } } } } for (base = tclass->bases; base; base = base->next) { if (base->base->vtable) list = CClass_GetCoVariantClassList(list, base->base, func, 0); } return list; } static TypeMethod *CClass_GetCovariantType(TypeMethod *tmethod, Type *type) { TypePointer *tptr; TypeMethod *result; CError_ASSERT(1724, IS_TYPE_METHOD(tmethod) && IS_TYPE_POINTER_ONLY(tmethod->functype)); tptr = galloc(sizeof(TypePointer)); *tptr = *TYPE_POINTER(tmethod->functype); tptr->target = type; result = galloc(sizeof(TypeMethod)); *result = *tmethod; result->flags &= ~(FUNC_FLAGS_20 | FUNC_FLAGS_400000); result->functype = TYPE(tptr); return result; } static Object *CClass_FindCovariantFunction(Object *func, Type *type) { NameSpaceObjectList *nsol; nsol = CScope_FindName( TYPE_METHOD(func->type)->theclass->nspace, CMangler_GetCovariantFunctionName(func, TYPE_CLASS(type))); CError_ASSERT(1754, nsol && !nsol->next && nsol->object->otype == OT_OBJECT); return OBJECT(nsol->object); } static ObjectList *CClass_DeclareCovariantFuncs(ObjectList *list, Object *func, TypeClass *tclass) { Object *newfunc; HashNameNode *name; TypeList *types; ObjectList *newlist; for (types = CClass_GetCoVariantClassList(NULL, tclass, func, 1); types; types = types->next) { name = CMangler_GetCovariantFunctionName(func, TYPE_CLASS(types->type)); newfunc = galloc(sizeof(Object)); memclrw(newfunc, sizeof(Object)); newfunc->otype = OT_OBJECT; newfunc->datatype = DFUNC; newfunc->section = func->section; newfunc->nspace = func->nspace; newfunc->name = name; newfunc->type = TYPE(CClass_GetCovariantType(TYPE_METHOD(func->type), types->type)); newfunc->qual = func->qual & ~Q_INLINE; newfunc->sclass = func->sclass; newfunc->u.func.linkname = name; newlist = lalloc(sizeof(ObjectList)); newlist->object = newfunc; newlist->next = list; list = newlist; } return list; } void CClass_DefineCovariantFuncs(Object *method, CI_FuncData *ifuncdata) { NameSpace *nspace; TypeList *types; Object *covariantFunc; Statement *stmt; Type *tptr; Statement firstStmt; for (types = CClass_GetCoVariantClassList(NULL, TYPE_METHOD(method->type)->theclass, method, 1); types; types = types->next) { covariantFunc = CClass_FindCovariantFunction(method, types->type); tptr = CDecl_NewPointerType(types->type); nspace = CFunc_FuncGenSetup(&firstStmt, covariantFunc); CInline_UnpackIFunctionData(covariantFunc, ifuncdata, &firstStmt); for (stmt = &firstStmt; stmt; stmt = stmt->next) { if (stmt->type == ST_RETURN && stmt->expr) stmt->expr = CExpr_AssignmentPromotion(stmt->expr, tptr, ENODE_QUALS(stmt->expr), 0); } CFunc_Gen(&firstStmt, covariantFunc, 0); cscope_current = nspace->parent; } } static void CClass_OverrideOVClassTree(OVClass *ovclass) { OVClassBase *ovbase; OVFunc *ovfunc; if (cclass_root != ovclass) { for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) CClass_FindOVFunc(cclass_root, ovclass, ovfunc); } for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) CClass_OverrideOVClassTree(ovbase->ovclass); } static void CClass_AllocVTableRec(OVClass *ovclass) { OVFunc *ovfunc; Object *object; SInt32 offset27; SInt32 offset26; SInt32 offset23; OVClassBase *ovbase; OLinkList *link; if (ovclass->alloced_vtable) return; for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) { offset27 = ovclass->voffset + TYPE_METHOD(ovfunc->obj->type)->x1E + CABI_GetVTableOffset(ovclass->tclass); CError_ASSERT(1867, offset27 < vtable_data_size); if (!(vtable_object_data[offset27])) { if (ovfunc->ovfC) { object = ovfunc->ovfC->obj; if ( (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_400000) && CClass_GetOverrideKind(TYPE_FUNC(ovfunc->obj->type), TYPE_FUNC(object->type), 0) == 2 ) { CError_ASSERT(1887, IS_TYPE_POINTER_ONLY(TYPE_FUNC(ovfunc->obj->type)->functype) && IS_TYPE_CLASS(TPTR_TARGET(TYPE_FUNC(ovfunc->obj->type)->functype))); object = CClass_FindCovariantFunction( object, TPTR_TARGET(TYPE_FUNC(ovfunc->obj->type)->functype)); } if ((offset26 = ovfunc->ovc8->offset - ovclass->offset)) { if (!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_8)) { cclass_ovbase = NULL; CError_ASSERT(1899, CClass_IsBaseOf(ovclass, ovfunc->ovc8)); if (cclass_ovbase && (main_class->flags & CLASS_FLAGS_8000)) { offset23 = ovclass->offset - cclass_ovbase->offset; offset23 = CABI_GetCtorOffsetOffset(cclass_ovbase->tclass, NULL) - offset23; CError_ASSERT(1906, offset23 > 0); object = CClass_ThunkObject(object, offset26, 0, offset23); } else { object = CClass_ThunkObject(object, offset26, 0, -1); } } } } else { object = ovfunc->obj; } if (!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_8)) { link = lalloc(sizeof(OLinkList)); link->next = vtable_object_links; link->obj = object; link->offset = offset27; link->somevalue = 0; vtable_object_links = link; vtable_object_data[offset27] = 1; } } } ovclass->alloced_vtable = 1; for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) CClass_AllocVTableRec(ovbase->ovclass); } static Object *CClass_CheckClass(OVClass *ovclass, Boolean errorflag) { Object *object; Object *check; OVFunc *ovfunc; OVClassBase *ovbase; object = NULL; for (ovfunc = ovclass->vfuncs; ovfunc; ovfunc = ovfunc->next) { if (ovfunc->ovf10 && errorflag) CError_Error(CErrorStr251, main_class, 0, ovfunc->obj, ovfunc->ovfC->obj, ovfunc->ovf10->obj); if (!object) { check = ovfunc->ovfC ? ovfunc->ovfC->obj : ovfunc->obj; if (TYPE_FUNC(check->type)->flags & FUNC_FLAGS_8) object = check; } } for (ovbase = ovclass->bases; ovbase; ovbase = ovbase->next) { if (object) CClass_CheckClass(ovbase->ovclass, errorflag); else object = CClass_CheckClass(ovbase->ovclass, errorflag); } return object; } static void CClass_AllocVTable(TypeClass *tclass) { OVClass *ovclass; main_class = tclass; ovclass = CClass_BuildOVClassTree(NULL, tclass, 0, 0); cclass_root = ovclass; CClass_OverrideOVClassTree(ovclass); CClass_CheckClass(ovclass, 1); CClass_AllocVTableRec(ovclass); } static Object *CClass_CheckVirtuals(TypeClass *tclass) { OVClass *ovclass; main_class = tclass; ovclass = CClass_BuildOVClassTree(NULL, tclass, 0, 0); cclass_root = ovclass; CClass_OverrideOVClassTree(ovclass); return CClass_CheckClass(ovclass, 0); } static void CClass_CheckVirtualBaseOverrides(OVClass *a, OVClass *b, Boolean flag) { VClassList *vbase; OVFunc *ovfunc; OVClassBase *ovbase; if (flag) { for (ovfunc = b->vfuncs; ovfunc; ovfunc = ovfunc->next) { if (ovfunc->ovfC) { cclass_ovbase = NULL; CError_ASSERT(2040, CClass_IsBaseOf(b, ovfunc->ovc8)); if (cclass_ovbase) { for (vbase = a->tclass->vbases; vbase; vbase = vbase->next) { if (vbase->base == cclass_ovbase->tclass) break; } CError_ASSERT(2047, vbase); vbase->has_override = 1; } } } } for (ovbase = b->bases; ovbase; ovbase = ovbase->next) { CClass_CheckVirtualBaseOverrides(a, ovbase->ovclass, flag || ovbase->is_virtual); } } static void CClass_CheckHideVirtual(OVClass *a, OVClass *b) { OVClassBase *ovbase; OVFunc *ovfunc; Object *foundObject; Boolean isAlias; Object *object; CScopeObjectIterator iter; if (a != b) { for (ovfunc = b->vfuncs; ovfunc; ovfunc = ovfunc->next) { if (ovfunc->ovc8 != a) { foundObject = NULL; isAlias = 0; CScope_InitObjectIterator(&iter, a->tclass->nspace); while (1) { if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) break; if (object->name == ovfunc->obj->name && IS_TYPE_FUNC(object->type)) { if (object->datatype != DALIAS) { if (!(TYPE_FUNC(object->type)->flags & FUNC_FLAGS_20)) foundObject = object; } else { if (object->u.alias.object == ovfunc->obj) { // don't show a warning if this is just an alias to the base function isAlias = 1; break; } } } } if (foundObject && !isAlias) CError_Warning(CErrorStr225, foundObject, ovfunc->obj); } } } for (ovbase = b->bases; ovbase; ovbase = ovbase->next) CClass_CheckHideVirtual(a, ovbase->ovclass); } void CClass_CheckOverrides(TypeClass *tclass) { OVClass *tree; Object *object; ObjectList *objlist; ClassList *base; VClassList *vbase; int i; CScopeObjectIterator iter; i = 0; for (base = tclass->bases; base; base = base->next) { base->offset = i; base->voffset = i; i++; } for (vbase = tclass->vbases; vbase; vbase = vbase->next) { vbase->offset = i; vbase->voffset = i; i++; } main_class = tclass; tree = CClass_BuildOVClassTree(NULL, tclass, 0, 0); cclass_root = tree; CClass_OverrideOVClassTree(tree); if (CClass_CheckClass(tree, 0)) tclass->flags |= CLASS_FLAGS_ABSTRACT; if (copts.warn_hidevirtual) CClass_CheckHideVirtual(tree, tree); if (tclass->flags & CLASS_FLAGS_8000) CClass_CheckVirtualBaseOverrides(tree, tree, 0); objlist = NULL; CScope_InitObjectIterator(&iter, tclass->nspace); while (1) { if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) break; if (object->datatype == DVFUNC) { CError_ASSERT(2175, IS_TYPE_FUNC(object->type)); if (TYPE_FUNC(object->type)->flags & FUNC_FLAGS_400000) objlist = CClass_DeclareCovariantFuncs(objlist, object, tclass); } } while (objlist) { CScope_AddObject(tclass->nspace, objlist->object->name, OBJ_BASE(objlist->object)); objlist = objlist->next; } for (base = tclass->bases; base; base = base->next) { base->offset = 0; base->voffset = 0; } for (vbase = tclass->vbases; vbase; vbase = vbase->next) { vbase->offset = 0; vbase->voffset = 0; } } static void CClass_FindDominator(TypeClass *tclass1, SInt32 offset1, Object *object1, TypeClass *tclass2, SInt32 offset2, TypeClass *tclass3) { Object *object; ClassList *base; CScopeObjectIterator iter; CScope_InitObjectIterator(&iter, tclass1->nspace); while (1) { if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) break; if ( object->name == cclass_dominator_vobject->name && object->datatype == DVFUNC && CClass_GetOverrideKind(TYPE_FUNC(cclass_dominator_vobject->type), TYPE_FUNC(object->type), 0) ) { if (object == cclass_dominator_vobject && offset1 == cclass_dominator_voffset) { if (object1) { if (cclass_dominator_oobject && cclass_dominator_ooffset != offset2) { if (CClass_ClassDominates(cclass_dominator_oclass, tclass2)) return; if (!CClass_ClassDominates(tclass2, cclass_dominator_oclass)) { cclass_dominator_eobject = object1; cclass_vbase = tclass3; return; } } cclass_dominator_oobject = object1; cclass_dominator_ooffset = offset2; cclass_dominator_oclass = tclass2; cclass_dominator_eobject = NULL; cclass_vbase = tclass3; } return; } else { if (!object1) { object1 = object; tclass2 = tclass1; offset2 = offset1; } break; } } } for (base = tclass1->bases; base; base = base->next) { if (base->base->vtable) { if (!base->is_virtual) { CClass_FindDominator(base->base, offset1 + base->offset, object1, tclass2, offset2, tclass3); } else { SInt32 vboffset = CClass_VirtualBaseOffset(main_class, base->base); CClass_FindDominator(base->base, vboffset, object1, tclass2, offset2, base->base); } } } } static void CClass_ConstructVTable(TypeClass *tclass, SInt32 voffset, SInt32 offset, TypeClass *baseclass) { Object *object; Object *thunkobject; SInt32 newoffset; SInt32 newvoffset; ClassList *base; SInt32 thunkoffset; OLinkList *olink; CScopeObjectIterator iter; CScope_InitObjectIterator(&iter, tclass->nspace); while (1) { if (!(object = OBJECT(CScope_NextObjectIteratorObject(&iter)))) break; if (object->datatype == DVFUNC) { newoffset = voffset + TYPE_METHOD(object->type)->x1E + CABI_GetVTableOffset(tclass); CError_ASSERT(2288, newoffset < vtable_data_size); if (!vtable_object_data[newoffset]) { cclass_dominator_vobject = object; cclass_dominator_voffset = offset; cclass_dominator_oobject = NULL; cclass_dominator_ooffset = offset; CClass_FindDominator(main_class, 0, NULL, NULL, 0, NULL); if (cclass_dominator_oobject) { if (cclass_dominator_eobject) CError_Error(CErrorStr251, main_class, 0, cclass_dominator_vobject, cclass_dominator_oobject, cclass_dominator_eobject); } else { cclass_dominator_oobject = object; cclass_vbase = NULL; } vtable_object_data[newoffset] = 1; if (!(TYPE_FUNC(cclass_dominator_oobject->type)->flags & FUNC_FLAGS_8)) { if (!check_pures) { thunkobject = cclass_dominator_oobject; if ((thunkoffset = cclass_dominator_ooffset - offset)) { if (cclass_vbase && (main_class->flags & CLASS_FLAGS_8000)) { thunkobject = CClass_ThunkObject(cclass_dominator_oobject, thunkoffset, 0, CABI_GetCtorOffsetOffset(cclass_vbase, tclass)); } else { thunkobject = CClass_ThunkObject(cclass_dominator_oobject, thunkoffset, 0, -1); } } olink = lalloc(sizeof(OLinkList)); olink->next = vtable_object_links; olink->obj = thunkobject; olink->offset = newoffset; olink->somevalue = 0; vtable_object_links = olink; } } else { found_pure = cclass_dominator_oobject; } } } } for (base = tclass->bases; base; base = base->next) { if (base->base->vtable) { if (base->is_virtual) { newoffset = CClass_VirtualBaseOffset(main_class, base->base); newvoffset = CClass_VirtualBaseVTableOffset(main_class, base->base); CClass_ConstructVTable( base->base, newvoffset, newoffset, base->base ); } else { CClass_ConstructVTable( base->base, voffset + base->voffset, offset + base->offset, baseclass ); } } } } void CClass_ClassDefaultFuncAction(TypeClass *tclass) { } void CClass_ClassAction(TypeClass *tclass) { if (tclass->sominfo) { CSOM_GenerateClassStructures(tclass); } else if (tclass->vtable) { vtable_data_size = tclass->vtable->size; vtable_object_data = lalloc(vtable_data_size); memclrw(vtable_object_data, vtable_data_size); main_class = tclass; vtable_object_links = NULL; found_pure = NULL; check_pures = 0; CClass_AllocVTable(tclass); memclrw(vtable_object_data, vtable_data_size); if (copts.useRTTI && !(tclass->flags & (CLASS_FLAGS_10 | CLASS_FLAGS_2000))) vtable_object_links = CRTTI_ConstructVTableHeaders(tclass, vtable_object_data, vtable_object_links); CError_ASSERT(2492, tclass->vtable->object->type->size == tclass->vtable->size); CInit_DeclareData(tclass->vtable->object, vtable_object_data, vtable_object_links, tclass->vtable->size); } } void CClass_MakeStaticActionClass(TypeClass *tclass) { if (tclass->vtable) { tclass->vtable->object->sclass = TK_STATIC; tclass->vtable->object->qual |= Q_20000; if (!(tclass->vtable->object->flags & OBJECT_FLAGS_2)) { CParser_NewCallBackAction(tclass->vtable->object, tclass); } else if (cparamblkptr->isPrecompiling != 1) { CParser_NewClassAction(tclass); } } } Object *CClass_CheckPures(TypeClass *tclass) { return CClass_CheckVirtuals(tclass); } void CClass_MemberDef(Object *obj, TypeClass *tclass) { switch (tclass->action) { case CLASS_ACTION_0: break; case CLASS_ACTION_1: if (IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_FLAGS_4)) { if (obj->qual & Q_INLINE) { if (tclass->sominfo) CError_Error(CErrorStr280); tclass->action = CLASS_ACTION_0; CClass_MakeStaticActionClass(tclass); } else if (cparamblkptr->isPrecompiling != 1) { CParser_NewClassAction(tclass); } } break; case CLASS_ACTION_2: CError_FATAL(2682); break; case CLASS_ACTION_3: break; default: CError_FATAL(2701); } } Object *CClass_ThisSelfObject(void) { ObjectList *list; if (cscope_currentfunc && cscope_currentclass) { if (cscope_currentclass->objcinfo) { for (list = arguments; list; list = list->next) { if (list->object->name == self_name_node) return list->object; } CError_Error(CErrorStr301); } else { if (cscope_is_member_func) { for (list = arguments; list; list = list->next) { if (list->object->name == this_name_node) return list->object; } } CError_Error(CErrorStr189); } } CError_Error(copts.cplusplus ? CErrorStr189 : CErrorStr301); return NULL; } ENode *CClass_CreateThisSelfExpr(void) { Object *object; ENode *expr; if (!(object = CClass_ThisSelfObject())) return NULL; expr = create_objectrefnode(object); expr->rtype = CDecl_NewPointerType(TYPE(cscope_currentclass)); expr = makemonadicnode(expr, EINDIRECT); expr->data.monadic->rtype = CDecl_NewPointerType(expr->rtype); return expr; } static AccessType CClass_BaseMemberAccess(BClassList *path, AccessType access) { ClassList *base; if (path->next) { access = CClass_BaseMemberAccess(path->next, access); switch (access) { case ACCESSPRIVATE: case ACCESSNONE: return ACCESSNONE; } for (base = TYPE_CLASS(path->type)->bases; ; base = base->next) { if (!base) return ACCESSNONE; if (base->base == TYPE_CLASS(path->next->type)) { switch (base->access) { case ACCESSNONE: access = ACCESSNONE; break; case ACCESSPROTECTED: if (access == ACCESSPUBLIC) access = ACCESSPROTECTED; break; case ACCESSPRIVATE: if (access == ACCESSPRIVATE) access = ACCESSNONE; else access = ACCESSPRIVATE; break; case ACCESSPUBLIC: break; } break; } } } return access; } static Boolean CClass_CanAccess(BClassList *path, AccessType access) { AccessType access2; BClassList *scan; BClassList *next; TypeClass *prevclass; TypeClass *tclass; ClassList *base; ClassFriend *cfriend; tclass = TYPE_CLASS(path->type); access2 = access; if ((scan = path->next)) { if (access2 != ACCESSPRIVATE) { prevclass = tclass; while (scan) { for (base = prevclass->bases; base; base = base->next) { if (base->base == TYPE_CLASS(scan->type)) break; } if (!base) return 0; switch (base->access) { case ACCESSNONE: access2 = ACCESSNONE; break; case ACCESSPROTECTED: if (access2 == ACCESSPUBLIC) access2 = ACCESSPROTECTED; break; case ACCESSPRIVATE: if (access2 == ACCESSPRIVATE) access2 = ACCESSNONE; else access2 = ACCESSPRIVATE; break; case ACCESSPUBLIC: break; } prevclass = TYPE_CLASS(scan->type); scan = scan->next; } } else { access2 = ACCESSNONE; } } if (access2 == ACCESSPUBLIC) return 1; if (access2 != ACCESSNONE) { if (cscope_currentclass == tclass) return 1; if (cobjc_currentclass == tclass) return 1; for (cfriend = tclass->friends; cfriend; cfriend = cfriend->next) { if (cfriend->isclass) { if (cfriend->u.theclass == cscope_currentclass) return 1; } else { if (cfriend->u.obj == cscope_currentfunc) return 1; } } } for (scan = path; scan->next; scan = scan->next) { if (CClass_CanAccess(scan->next, access)) { if ((next = scan->next->next) || access != ACCESSPUBLIC) { scan->next->next = NULL; if (CClass_CanAccess(path, ACCESSPUBLIC)) { scan->next->next = next; return 1; } scan->next->next = next; } } } return 0; } void CClass_CheckPathAccess(BClassList *path, Object *obj, AccessType access) { if (!CClass_CanAccess(path, access)) { if (path && obj) CError_Error(CErrorStr381, path->type, 0, obj); else CError_Error(CErrorStr187); } } static BClassList *CClass_PathCleanup(BClassList *path, TypeClass *tclass) { BClassList *first; ClassList *base; first = path; while (1) { if (!path->next) { if (!tclass) return first; if (path->type == TYPE(tclass)) return first; return NULL; } if (path->type != path->next->type) { for (base = TYPE_CLASS(path->type)->bases; base; base = base->next) { if (base->base == TYPE_CLASS(path->next->type)) break; } if (base) { path = path->next; } else { first = path = path->next; } } else { path->next = path->next->next; } } } void CClass_CheckStaticAccess(BClassList *path, TypeClass *tclass, AccessType access) { ClassFriend *cfriend; if (path) { path = CClass_PathCleanup(path, tclass); if (path && path->next) { if (!CClass_CanAccess(path, access)) CError_Error(CErrorStr187); return; } } switch (access) { case ACCESSPUBLIC: return; case ACCESSPRIVATE: case ACCESSPROTECTED: if (tclass == cscope_currentclass) return; for (cfriend = tclass->friends; cfriend; cfriend = cfriend->next) { if (cfriend->isclass) { if (cfriend->u.theclass == cscope_currentclass) return; } else { if (cfriend->u.obj == cscope_currentfunc) return; } } case ACCESSNONE: CError_Warning(CErrorStr187); return; default: CError_FATAL(3013); } } void CClass_CheckObjectAccess(BClassList *path, Object *obj) { short depth; Boolean isambigbase; if (obj->nspace && obj->nspace->theclass) { if (!path && cscope_currentclass) path = CClass_GetBasePath(cscope_currentclass, obj->nspace->theclass, &depth, &isambigbase); CClass_CheckStaticAccess(path, obj->nspace->theclass, obj->access); } } void CClass_CheckEnumAccess(BClassList *path, ObjEnumConst *objec) { if (path) { if ((path = CClass_PathCleanup(path, NULL))) { if (!CClass_CanAccess(path, objec->access)) CError_Error(CErrorStr187); return; } } if ( objec->access != ACCESSPUBLIC && IS_TYPE_ENUM(objec->type) && TYPE_ENUM(objec->type)->nspace && TYPE_ENUM(objec->type)->nspace->theclass ) CClass_CheckStaticAccess(NULL, TYPE_ENUM(objec->type)->nspace->theclass, objec->access); } static Type *CClass_PointerTypeCopy(Type *type) { Type *copy; switch (type->type) { case TYPEPOINTER: case TYPEARRAY: copy = galloc(sizeof(TypePointer)); *TYPE_POINTER(copy) = *TYPE_POINTER(type); TPTR_TARGET(copy) = CClass_PointerTypeCopy(TPTR_TARGET(copy)); return copy; case TYPEMEMBERPOINTER: copy = galloc(sizeof(TypeMemberPointer)); *TYPE_MEMBER_POINTER(copy) = *TYPE_MEMBER_POINTER(type); return copy; default: return type; } } Type *CClass_CombineClassAccessQualifiers(Type *type, UInt32 qual1, UInt32 qual2, UInt32 *outflags) { Type *inner; qual2 = qual2 & (Q_CONST | Q_VOLATILE); if (qual1 & Q_MUTABLE) qual2 &= ~Q_CONST; qual1 = qual1 & (Q_CONST | Q_VOLATILE); inner = type; while (IS_TYPE_ARRAY(inner)) inner = TPTR_TARGET(inner); switch (inner->type) { case TYPEMEMBERPOINTER: case TYPEPOINTER: if (qual2) { type = CClass_PointerTypeCopy(type); inner = type; while (IS_TYPE_ARRAY(inner)) inner = TPTR_TARGET(inner); switch (inner->type) { case TYPEPOINTER: TPTR_QUAL(inner) |= qual2; break; case TYPEMEMBERPOINTER: TYPE_MEMBER_POINTER(inner)->qual |= qual2; break; default: CError_FATAL(3125); } } break; default: qual1 |= qual2; } *outflags = qual1; return type; } static void CClass_OptimizeBitFieldAccess(Type **ptype, SInt32 *poffset) { Type *innertype; TypeBitfield *newtype; short i; innertype = TYPE_BITFIELD(*ptype)->bitfieldtype; if (TYPE_BITFIELD(*ptype)->unkB == 8) { switch (TYPE_BITFIELD(*ptype)->unkA) { case 0: i = 0; break; case 8: i = 1; break; case 16: i = 2; break; case 24: i = 3; break; default: i = -1; break; } if (i >= 0) { if (innertype->size != 1) { if (is_unsigned(TYPE_BITFIELD(*ptype)->bitfieldtype)) *ptype = TYPE(&stunsignedchar); else *ptype = TYPE(&stsignedchar); } else { *ptype = innertype; } *poffset += i; return; } } if (TYPE_BITFIELD(*ptype)->unkB == 16) { switch (TYPE_BITFIELD(*ptype)->unkA) { case 0: i = 0; break; case 16: i = 2; break; default: i = -1; break; } if (i >= 0) { if (innertype->size != stsignedshort.size) { if (is_unsigned(innertype)) *ptype = TYPE(&stunsignedshort); else *ptype = TYPE(&stsignedshort); } else { *ptype = innertype; } *poffset += i; return; } } if (TYPE_BITFIELD(*ptype)->unkB == 32 && TYPE_BITFIELD(*ptype)->unkA == 0) { if (innertype->size != stsignedlong.size) { if (is_unsigned(innertype)) *ptype = TYPE(&stunsignedlong); else *ptype = TYPE(&stsignedlong); } else { *ptype = innertype; } return; } if ((*ptype)->size != stsignedchar.size) { i = TYPE_BITFIELD(*ptype)->unkA + TYPE_BITFIELD(*ptype)->unkB - 1; if (TYPE_BITFIELD(*ptype)->unkB < 8 && (TYPE_BITFIELD(*ptype)->unkA & 0xFFF8) == (i & 0xFFF8)) { newtype = galloc(sizeof(TypeBitfield)); *newtype = *TYPE_BITFIELD(*ptype); *ptype = TYPE(newtype); i = 0; if (newtype->unkA >= 8) i = 1; if (newtype->unkA >= 16) i = 2; if (newtype->unkA >= 24) i = 3; *poffset += i; newtype->unkA -= 8 * i; newtype->bitfieldtype = is_unsigned(innertype) ? TYPE(&stunsignedchar) : TYPE(&stsignedchar); newtype->size = newtype->bitfieldtype->size; return; } if ((*ptype)->size != stsignedshort.size) { if (TYPE_BITFIELD(*ptype)->unkB < 16 && (TYPE_BITFIELD(*ptype)->unkA & 0xFFF0) == (i & 0xFFF0)) { newtype = galloc(sizeof(TypeBitfield)); *newtype = *TYPE_BITFIELD(*ptype); *ptype = TYPE(newtype); i = 0; if (newtype->unkA >= 16) i = stsignedshort.size; *poffset += i; newtype->unkA -= 8 * i; newtype->bitfieldtype = is_unsigned(innertype) ? TYPE(&stunsignedshort) : TYPE(&stsignedshort); newtype->size = newtype->bitfieldtype->size; return; } } } } ENode *CClass_AccessMember(ENode *classexpr, Type *type, UInt32 qual, SInt32 offset) { Type *innertype; UInt32 flags; innertype = NULL; if (IS_TYPE_CLASS(classexpr->rtype) && (TYPE_CLASS(classexpr->rtype)->flags & CLASS_FLAGS_1)) { classexpr = makemonadicnode(classexpr, EINDIRECT); classexpr->data.monadic->rtype = CDecl_NewPointerType(classexpr->rtype); } if (IS_TYPE_BITFIELD(type)) { innertype = TYPE_BITFIELD(type)->bitfieldtype; CClass_OptimizeBitFieldAccess(&type, &offset); } if (offset && !canadd(classexpr->data.monadic, offset)) { classexpr->data.monadic = makediadicnode( classexpr->data.monadic, intconstnode(TYPE(&stunsignedlong), offset), EADD); optimizecomm(classexpr->data.monadic); } if (innertype) { if (IS_TYPE_BITFIELD(type)) { classexpr->data.monadic = makemonadicnode(classexpr->data.monadic, EBITFIELD); classexpr->data.monadic->rtype = type; classexpr->rtype = TYPE_BITFIELD(type)->bitfieldtype; } else { classexpr->rtype = type; } } else { classexpr->rtype = type; } classexpr->rtype = CClass_CombineClassAccessQualifiers(classexpr->rtype, qual, ENODE_QUALS(classexpr), &flags); classexpr->flags = flags; return classexpr; }