diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CClass.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CClass.c | 2312 |
1 files changed, 2312 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CClass.c b/compiler_and_linker/FrontEnd/C/CClass.c new file mode 100644 index 0000000..fad276e --- /dev/null +++ b/compiler_and_linker/FrontEnd/C/CClass.c @@ -0,0 +1,2312 @@ +#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_DEFINED; + 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_CALL_CONV_MASK) != (b->flags & FUNC_CALL_CONV_MASK) || + !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_HAS_VBASES) && !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; + TypeMemberFunc *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_HAS_VBASES) && !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(TypeMemberFunc)); + memclrw(tmethod, sizeof(TypeMemberFunc)); + + tmethod->type = TYPEFUNC; + tmethod->functype = TYPE(&void_ptr); + tmethod->flags = FUNC_METHOD; + tmethod->theclass = tclass; + CDecl_SetFuncFlags(TYPE_FUNC(tmethod), 0); + + if ((tclass->flags & CLASS_HAS_VBASES) && !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_MANGLE_NAME; + 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_HAS_VBASES) && !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_HAS_VBASES) && !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_HAS_VBASES) { + 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_IS_CTOR); +} + +Boolean CClass_IsDestructor(Object *obj) { + return obj && IS_TYPE_FUNC(obj->type) && (TYPE_FUNC(obj->type)->flags & FUNC_IS_DTOR); +} + +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_AUTO_GENERATED) + ) + return 0; + } + + object = CClass_AssignmentOperator(tclass); + if (object && !(TYPE_FUNC(object->type)->flags & FUNC_AUTO_GENERATED)) + 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_AUTO_GENERATED)) + 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_AUTO_GENERATED)) + 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_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + 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_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + CDecl_CompleteType(TYPE(a)); + if ((b->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) + 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_SINGLE_OBJECT) && !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 TypeMemberFunc *CClass_GetCovariantType(TypeMemberFunc *tmethod, Type *type) { + TypePointer *tptr; + TypeMemberFunc *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(TypeMemberFunc)); + *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)->vtbl_index + 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_PURE)) { + 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_PURE)) { + 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_PURE) + 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_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)->vtbl_index + 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_PURE)) { + 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.RTTI && !(tclass->flags & (CLASS_SINGLE_OBJECT | CLASS_COM_OBJECT))) + 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->precompile != 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->precompile != 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)->bitlength == 8) { + switch (TYPE_BITFIELD(*ptype)->offset) { + 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)->bitlength == 16) { + switch (TYPE_BITFIELD(*ptype)->offset) { + 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)->bitlength == 32 && TYPE_BITFIELD(*ptype)->offset == 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)->offset + TYPE_BITFIELD(*ptype)->bitlength - 1; + + if (TYPE_BITFIELD(*ptype)->bitlength < 8 && (TYPE_BITFIELD(*ptype)->offset & 0xFFF8) == (i & 0xFFF8)) { + newtype = galloc(sizeof(TypeBitfield)); + *newtype = *TYPE_BITFIELD(*ptype); + *ptype = TYPE(newtype); + + i = 0; + if (newtype->offset >= 8) + i = 1; + if (newtype->offset >= 16) + i = 2; + if (newtype->offset >= 24) + i = 3; + *poffset += i; + newtype->offset -= 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)->bitlength < 16 && (TYPE_BITFIELD(*ptype)->offset & 0xFFF0) == (i & 0xFFF0)) { + newtype = galloc(sizeof(TypeBitfield)); + *newtype = *TYPE_BITFIELD(*ptype); + *ptype = TYPE(newtype); + + i = 0; + if (newtype->offset >= 16) + i = stsignedshort.size; + *poffset += i; + newtype->offset -= 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_HANDLEOBJECT)) { + 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; +} |