MWCC/compiler_and_linker/unsorted/CClass.c

2313 lines
68 KiB
C

#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.RTTI && !(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->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)->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;
}