summaryrefslogtreecommitdiff
path: root/compiler_and_linker/FrontEnd/C/CRTTI.c
diff options
context:
space:
mode:
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CRTTI.c')
-rw-r--r--compiler_and_linker/FrontEnd/C/CRTTI.c940
1 files changed, 940 insertions, 0 deletions
diff --git a/compiler_and_linker/FrontEnd/C/CRTTI.c b/compiler_and_linker/FrontEnd/C/CRTTI.c
new file mode 100644
index 0000000..3881153
--- /dev/null
+++ b/compiler_and_linker/FrontEnd/C/CRTTI.c
@@ -0,0 +1,940 @@
+#include "compiler/CRTTI.h"
+#include "compiler/CClass.h"
+#include "compiler/CDecl.h"
+#include "compiler/CError.h"
+#include "compiler/CExpr.h"
+#include "compiler/CInit.h"
+#include "compiler/CInt64.h"
+#include "compiler/CMachine.h"
+#include "compiler/CMangler.h"
+#include "compiler/CParser.h"
+#include "compiler/CScope.h"
+#include "compiler/CompilerTools.h"
+#include "compiler/objects.h"
+#include "compiler/scopes.h"
+#include "compiler/types.h"
+#include "compiler/CPrepTokenizer.h"
+#include "compiler/CPrep.h"
+
+typedef struct Offset {
+ struct Offset *next;
+ SInt32 offset;
+} Offset;
+
+static Offset *crtti_offsets;
+static OLinkList *crtti_olinks;
+
+// forward decls
+static Object *CRTTI_ConstructTypeInfoObject(Type *type, UInt32 qual);
+
+typedef struct RTTISubClassList {
+ struct RTTISubClassList *next;
+ TypeClass *base;
+ SInt32 voffset;
+} RTTISubClassList;
+
+typedef struct RTTIBaseList {
+ struct RTTIBaseList *next;
+ TypeClass *base;
+ RTTISubClassList *subclasses;
+ SInt32 voffset;
+ short numsubclasses;
+ Boolean x12;
+ Boolean x13;
+} RTTIBaseList;
+
+static RTTIBaseList *CRTTI_CreateBaseList(TypeClass *tclass, TypeClass *tclassbase, RTTIBaseList *list, SInt32 voffset, Boolean flag) {
+ RTTIBaseList *scan;
+ ClassList *base;
+ Boolean flag27;
+ SInt32 newvoffset;
+
+ if (tclass != tclassbase) {
+ flag27 = 0;
+
+ for (scan = list; scan; scan = scan->next) {
+ if (scan->base == tclassbase) {
+ if (scan->voffset == voffset) {
+ if (!flag)
+ scan->x12 = 0;
+ flag27 = 0;
+ } else {
+ scan->x13 = 1;
+ flag27 = 1;
+ }
+ break;
+ }
+ }
+
+ if (!scan || flag27) {
+ scan = lalloc(sizeof(RTTIBaseList));
+ memclrw(scan, sizeof(RTTIBaseList));
+
+ scan->next = list;
+ list = scan;
+ scan->base = tclassbase;
+ scan->voffset = voffset;
+ scan->x12 = flag;
+ scan->x13 = flag27;
+ }
+ }
+
+ for (base = tclassbase->bases; base; base = base->next) {
+ if (base->is_virtual)
+ newvoffset = CClass_VirtualBaseOffset(tclass, base->base);
+ else
+ newvoffset = voffset + base->offset;
+
+ list = CRTTI_CreateBaseList(tclass, base->base, list, newvoffset, flag || base->access == ACCESSPRIVATE);
+ }
+
+ return list;
+}
+
+static void CRTTI_CreateSubClassList(TypeClass *tclass, RTTIBaseList *baselist, TypeClass *tclassbase, SInt32 voffset, Boolean flag) {
+ ClassList *base;
+ RTTISubClassList *scan;
+ SInt32 newvoffset;
+
+ if (baselist->base != tclassbase) {
+ for (scan = baselist->subclasses; scan; scan = scan->next) {
+ if (scan->base == tclassbase && scan->voffset == voffset)
+ break;
+ }
+
+ if (!scan) {
+ scan = lalloc(sizeof(RTTISubClassList));
+ scan->next = baselist->subclasses;
+ baselist->subclasses = scan;
+
+ scan->base = tclassbase;
+ scan->voffset = voffset;
+ baselist->numsubclasses++;
+ }
+ }
+
+ for (base = tclassbase->bases; base; base = base->next) {
+ if (base->access == ACCESSPUBLIC) {
+ if (base->is_virtual) {
+ if (!flag)
+ continue;
+ newvoffset = CClass_VirtualBaseOffset(tclass, base->base);
+ } else {
+ newvoffset = voffset + base->offset;
+ }
+
+ CRTTI_CreateSubClassList(tclass, baselist, base->base, newvoffset, flag);
+ }
+ }
+}
+
+static Object *CRTTI_CreateBaseListObject(TypeClass *tclass) {
+ RTTIBaseList *baselist;
+ OLinkList *refs;
+ Object *object;
+ SInt32 *buf;
+ SInt32 size;
+ short count1;
+ short count2;
+ short total;
+ OLinkList *ref;
+ RTTIBaseList *scan;
+ RTTISubClassList *subclass;
+ SInt32 *work;
+ SInt32 *work2;
+
+ baselist = CRTTI_CreateBaseList(tclass, tclass, NULL, 0, 0);
+ if (!baselist)
+ return NULL;
+
+ count1 = 0;
+ count2 = 0;
+ total = 0;
+
+ for (scan = baselist; scan; scan = scan->next) {
+ if (scan->x13 || scan->x12) {
+ CRTTI_CreateSubClassList(tclass, scan, scan->base, scan->voffset, scan->x13 == 0);
+ if (scan->numsubclasses) {
+ total += scan->numsubclasses;
+ count2++;
+ }
+ } else {
+ count1++;
+ }
+ }
+
+ if (!count1 && !count2)
+ return NULL;
+
+ size = (count1 + total) * 8 + count2 * 12 + 4;
+ buf = lalloc(size);
+ memclrw(buf, size);
+
+ object = CParser_NewCompilerDefDataObject();
+ object->name = CParser_GetUniqueName();
+ object->type = CDecl_NewStructType(size, 4);
+ object->qual = Q_CONST;
+ object->sclass = TK_STATIC;
+ refs = NULL;
+
+ work = buf;
+
+ if (count1) {
+ for (scan = baselist; scan; scan = scan->next) {
+ if (!scan->x12 && !scan->x13) {
+ ref = lalloc(sizeof(OLinkList));
+ ref->next = refs;
+ refs = ref;
+
+ ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(scan->base), 0);
+ ref->offset = ((char *) work) - ((char *) buf);
+ ref->somevalue = 0;
+
+ work[1] = CTool_EndianConvertWord32(scan->voffset);
+ work += 2;
+ }
+ }
+ }
+
+ if (count2) {
+ for (scan = baselist; scan; scan = scan->next) {
+ if (scan->numsubclasses) {
+ ref = lalloc(sizeof(OLinkList));
+ ref->next = refs;
+ refs = ref;
+
+ ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(scan->base), 0);
+ ref->offset = ((char *) work) - ((char *) buf);
+ ref->somevalue = 0;
+
+ work[1] = CTool_EndianConvertWord32(scan->voffset | 0x80000000);
+ work[2] = CTool_EndianConvertWord32(scan->numsubclasses);
+ work2 = work + 3;
+
+ for (subclass = scan->subclasses; subclass; subclass = subclass->next) {
+ ref = lalloc(sizeof(OLinkList));
+ ref->next = refs;
+ refs = ref;
+
+ ref->obj = CRTTI_ConstructTypeInfoObject(TYPE(subclass->base), 0);
+ ref->offset = ((char *) work2) - ((char *) buf);
+ ref->somevalue = 0;
+
+ work2[1] = CTool_EndianConvertWord32(subclass->voffset);
+ work2 += 2;
+ }
+
+ work = work2;
+ }
+ }
+ }
+
+ CInit_DeclareData(object, buf, refs, object->type->size);
+ return object;
+}
+
+static Object *CRTTI_ConstructTypeInfoObject(Type *type, UInt32 qual) {
+ Object *baselistobj;
+ Object *nameobj;
+ HashNameNode *rttiname;
+ OLinkList *refs;
+ char *namestr;
+ int namelen;
+ Object *object;
+ NameSpaceObjectList *list;
+ TypePointer tptr_copy;
+ TypeMemberPointer tmemptr_copy;
+ UInt32 data[2];
+
+ switch (type->type) {
+ case TYPEPOINTER:
+ if (TPTR_QUAL(type) & (Q_CONST | Q_VOLATILE)) {
+ tptr_copy = *TYPE_POINTER(type);
+ tptr_copy.qual &= ~(Q_CONST | Q_VOLATILE);
+ type = TYPE(&tptr_copy);
+ }
+ break;
+ case TYPEMEMBERPOINTER:
+ if (TYPE_MEMBER_POINTER(type)->qual & (Q_CONST | Q_VOLATILE)) {
+ tmemptr_copy = *TYPE_MEMBER_POINTER(type);
+ tmemptr_copy.qual &= ~(Q_CONST | Q_VOLATILE);
+ type = TYPE(&tmemptr_copy);
+ }
+ break;
+ default:
+ qual = 0;
+ }
+
+ if (IS_TYPE_CLASS(type) && type->size == 0) {
+ CDecl_CompleteType(type);
+ if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED))
+ CError_Error(CErrorStr136, type, 0);
+ }
+
+ rttiname = CMangler_RTTIObjectName(type, qual);
+ list = CScope_FindName(cscope_root, rttiname);
+
+ if (!list || (object = OBJECT(list->object))->otype != OT_OBJECT || object->datatype != DDATA) {
+ namestr = CError_GetTypeName(type, qual, 0);
+ namelen = strlen(namestr) + 1;
+ nameobj = CInit_DeclareString(namestr, namelen, 0, 0);
+
+ baselistobj = NULL;
+ if (IS_TYPE_CLASS(type))
+ baselistobj = CRTTI_CreateBaseListObject(TYPE_CLASS(type));
+
+ memclrw(data, sizeof(data));
+
+ object = CParser_NewCompilerDefDataObject();
+ object->name = rttiname;
+ object->type = CDecl_NewStructType(sizeof(data), 4);
+ object->qual = Q_CONST;
+ object->sclass = TK_STATIC;
+
+ refs = lalloc(sizeof(OLinkList));
+ refs->next = NULL;
+ refs->obj = nameobj;
+ refs->offset = 0;
+ refs->somevalue = 0;
+
+ if (baselistobj) {
+ refs->next = lalloc(sizeof(OLinkList));
+ refs->next->next = NULL;
+ refs->next->obj = baselistobj;
+ refs->next->offset = 4;
+ refs->next->somevalue = 0;
+ }
+
+ CScope_AddGlobalObject(object);
+ CInit_DeclareData(object, data, refs, object->type->size);
+ }
+
+ return object;
+}
+
+static void CRTTI_ConstructVTableHeader(TypeClass *tclass1, TypeClass *tclass2, Object *typeinfoObj, char *data, SInt32 offset, SInt32 voffset) {
+ ClassList *base;
+ Offset *o;
+ OLinkList *olink;
+ SInt32 tmp;
+ SInt32 newoffset;
+ SInt32 newvoffset;
+
+ if (tclass2->vtable->owner == tclass2) {
+ for (o = crtti_offsets; o; o = o->next) {
+ if (o->offset == voffset)
+ break;
+ }
+
+ if (!o) {
+ o = lalloc(sizeof(Offset));
+ o->next = crtti_offsets;
+ o->offset = voffset;
+ crtti_offsets = o;
+
+ olink = lalloc(sizeof(OLinkList));
+ olink->next = crtti_olinks;
+ olink->obj = typeinfoObj;
+ olink->offset = voffset;
+ olink->somevalue = 0;
+ crtti_olinks = olink;
+
+ *((SInt32 *) (data + voffset + 4)) = CTool_EndianConvertWord32(-offset);
+ } else {
+ tmp = *((SInt32 *) (data + voffset + 4));
+ CError_ASSERT(404, tmp == CTool_EndianConvertWord32(-offset));
+ }
+ }
+
+ for (base = tclass2->bases; base; base = base->next) {
+ if (base->base->vtable) {
+ if (base->is_virtual) {
+ newoffset = CClass_VirtualBaseOffset(tclass1, base->base);
+ newvoffset = CClass_VirtualBaseVTableOffset(tclass1, base->base);
+ } else {
+ newoffset = offset + base->offset;
+ newvoffset = voffset + base->voffset;
+ }
+
+ CRTTI_ConstructVTableHeader(tclass1, base->base, typeinfoObj, data, newoffset, newvoffset);
+ }
+ }
+}
+
+OLinkList *CRTTI_ConstructVTableHeaders(TypeClass *tclass, void *data, OLinkList *links) {
+ crtti_offsets = NULL;
+ crtti_olinks = links;
+
+ CRTTI_ConstructVTableHeader(
+ tclass, tclass,
+ CRTTI_ConstructTypeInfoObject(TYPE(tclass), 0),
+ data, 0, 0);
+
+ return crtti_olinks;
+}
+
+static Type *CRTTI_FindTypeInfoType(void) {
+ NameSpace *nspace;
+ NameSpaceObjectList *list;
+ Type *type;
+
+ if ((list = CScope_FindName(cscope_root, GetHashNameNodeExport("std"))) && list->object->otype == OT_NAMESPACE)
+ nspace = OBJ_NAMESPACE(list->object)->nspace;
+ else
+ nspace = cscope_root;
+
+ type = CScope_GetLocalTagType(nspace, GetHashNameNodeExport("type_info"));
+ if (type && IS_TYPE_CLASS(type) && type->size)
+ return type;
+
+ CError_Error(CErrorStr140, "::std::type_info");
+ return TYPE(&stchar);
+}
+
+ENode *CRTTI_ParseTypeID(void) {
+ ENode *expr;
+ Type *type;
+ Type *typeinfoType;
+ UInt32 qual;
+
+ if (!copts.RTTI)
+ CError_Warning(CErrorStr257);
+
+ typeinfoType = CRTTI_FindTypeInfoType();
+
+ if (lex() != '(') {
+ CError_Error(CErrorStr114);
+ return nullnode();
+ }
+
+ tk = lex();
+ if ((type = CParser_ParseTypeID(&qual, NULL))) {
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+ } else {
+ expr = s_expression();
+
+ if (tk != ')')
+ CError_ErrorSkip(CErrorStr115);
+ else
+ tk = lex();
+
+ type = expr->rtype;
+ qual = ENODE_QUALS(expr);
+
+ if (IS_TYPE_REFERENCE(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->vtable) {
+ expr = funccallexpr(
+ Rgtid_func,
+ getnodeaddress(expr, 0),
+ intconstnode(TYPE(&stsignedlong), TYPE_CLASS(type)->vtable->offset),
+ NULL,
+ NULL);
+ expr->rtype = CDecl_NewPointerType(typeinfoType);
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = typeinfoType;
+ expr->flags = ENODE_FLAG_CONST;
+ return expr;
+ }
+ }
+
+ expr = create_objectrefnode(CRTTI_ConstructTypeInfoObject(type, qual));
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = typeinfoType;
+ expr->flags = ENODE_FLAG_CONST;
+ return expr;
+}
+
+static void CRTTI_ConstCastQualCheck(UInt32 qual1, UInt32 qual2) {
+ if (
+ ((qual1 & Q_CONST) && !(qual2 & Q_CONST)) ||
+ ((qual1 & Q_VOLATILE) && !(qual2 & Q_VOLATILE))
+ )
+ CError_Error(CErrorStr258);
+}
+
+static void CRTTI_ConstCastCheck(Type *type1, UInt32 qual1, Type *type2, UInt32 qual2) {
+ Boolean flag = 1;
+ if (IS_TYPE_REFERENCE(type2)) {
+ type2 = TPTR_TARGET(type2);
+ flag = 0;
+ }
+
+ while (1) {
+ if (type1->type != type2->type)
+ break;
+
+ switch (type1->type) {
+ case TYPEPOINTER:
+ if (!flag)
+ CRTTI_ConstCastQualCheck(TPTR_QUAL(type1), TPTR_QUAL(type2));
+ type1 = TPTR_TARGET(type1);
+ type2 = TPTR_TARGET(type2);
+ flag = 0;
+ continue;
+
+ case TYPEMEMBERPOINTER:
+ if (!flag)
+ CRTTI_ConstCastQualCheck(TYPE_MEMBER_POINTER(type1)->qual, TYPE_MEMBER_POINTER(type2)->qual);
+ type1 = TYPE_MEMBER_POINTER(type1)->ty1;
+ type2 = TYPE_MEMBER_POINTER(type2)->ty1;
+ flag = 0;
+ continue;
+ }
+
+ break;
+ }
+
+ if (!flag && !IS_TYPE_FUNC(type1) && !IS_TYPE_FUNC(type2))
+ CRTTI_ConstCastQualCheck(CParser_GetCVTypeQualifiers(type1, qual1), CParser_GetCVTypeQualifiers(type2, qual2));
+}
+
+static ENode *CRTTI_ParseCast(DeclInfo *di) {
+ ENode *expr;
+
+ if (lex() != '<') {
+ CError_Error(CErrorStr230);
+ return NULL;
+ }
+
+ tk = lex();
+
+ memclrw(di, sizeof(DeclInfo));
+ CParser_GetDeclSpecs(di, 0);
+ scandeclarator(di);
+
+ if (di->name)
+ CError_Error(CErrorStr164);
+
+ if (tk != '>') {
+ CError_Error(CErrorStr231);
+ return NULL;
+ }
+
+ if (lex() != '(') {
+ CError_Error(CErrorStr114);
+ return NULL;
+ }
+
+ tk = lex();
+ expr = s_expression();
+ if (!IS_TYPE_REFERENCE(di->thetype))
+ expr = pointer_generation(expr);
+
+ if (tk != ')') {
+ CError_Error(CErrorStr115);
+ return NULL;
+ }
+
+ tk = lex();
+ return expr;
+}
+
+static void CRTTI_IncompleteCheck(Type *type) {
+ if (IS_TYPE_POINTER_ONLY(type))
+ type = TPTR_TARGET(type);
+
+ if (IS_TYPE_CLASS(type) && type->size == 0) {
+ CDecl_CompleteType(type);
+ if (!(TYPE_CLASS(type)->flags & CLASS_COMPLETED))
+ CError_Error(CErrorStr136, type, 0);
+ }
+}
+
+static Boolean CRTTI_IsSameType(Type *a, Type *b) {
+ while (1) {
+ if (a->type != b->type)
+ return 0;
+
+ switch (a->type) {
+ case TYPEVOID:
+ return 1;
+ case TYPEINT:
+ case TYPEFLOAT:
+ case TYPEENUM:
+ case TYPESTRUCT:
+ return a == b;
+ case TYPEPOINTER:
+ a = TPTR_TARGET(a);
+ b = TPTR_TARGET(b);
+ continue;
+ default:
+ return is_typesame(a, b);
+ }
+ }
+}
+
+static ENode *CRTTI_UniversalCast(ENode *expr, Type *type, UInt32 qual, UInt8 mode) {
+ // type/qual are the target type
+ Boolean isSimpleCast;
+ Boolean needsTypcon;
+ Boolean failed;
+
+ if (ENODE_IS(expr, EOBJLIST))
+ return CExpr_AssignmentPromotion(expr, type, qual & (Q_CONST | Q_VOLATILE), 1);
+
+ isSimpleCast = needsTypcon = failed = 0;
+
+ switch (type->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ if (mode == 2 && IS_TYPE_POINTER_ONLY(expr->rtype) && type != TYPE(&stbool))
+ failed = 1;
+ break;
+
+ case TYPEPOINTER:
+ if (TPTR_QUAL(type) & Q_REFERENCE) {
+ if (
+ !CRTTI_IsSameType(TPTR_TARGET(type), expr->rtype) &&
+ mode == 2 &&
+ !(
+ IS_TYPE_CLASS(TPTR_TARGET(type)) &&
+ IS_TYPE_CLASS(expr->rtype) &&
+ (
+ CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(type)), TYPE_CLASS(expr->rtype), NULL, 0, 1) ||
+ CClass_IsBaseClass(TYPE_CLASS(expr->rtype), TYPE_CLASS(TPTR_TARGET(type)), NULL, 0, 1)
+ )
+ )
+ )
+ {
+ failed = 1;
+ }
+ } else if (IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ if (
+ mode == 3 ||
+ CRTTI_IsSameType(type, expr->rtype) ||
+ IS_TYPE_VOID(TPTR_TARGET(type)) ||
+ IS_TYPE_VOID(TPTR_TARGET(expr->rtype))
+ )
+ {
+ isSimpleCast = needsTypcon = 1;
+ }
+ else if (
+ mode == 2 &&
+ !(
+ IS_TYPE_CLASS(TPTR_TARGET(type)) &&
+ IS_TYPE_CLASS(TPTR_TARGET(expr->rtype)) &&
+ (
+ CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(type)), TYPE_CLASS(TPTR_TARGET(expr->rtype)), NULL, 0, 1) ||
+ CClass_IsBaseClass(TYPE_CLASS(TPTR_TARGET(expr->rtype)), TYPE_CLASS(TPTR_TARGET(type)), NULL, 0, 1)
+ )
+ )
+ )
+ {
+ failed = 1;
+ }
+ } else {
+ if (IS_TYPE_ENUM(expr->rtype))
+ expr->rtype = TYPE_ENUM(expr->rtype)->enumtype;
+
+ if (IS_TYPE_INT(expr->rtype)) {
+ if (ENODE_IS(expr, EINTCONST) && CInt64_IsZero(&expr->data.intval)) {
+ isSimpleCast = 1;
+ break;
+ }
+
+ if (mode != 2)
+ break;
+ }
+
+ if (IS_TYPE_CLASS(expr->rtype)) {
+ if (mode == 2)
+ break;
+ }
+
+ failed = 1;
+ }
+ break;
+ }
+
+ if (failed) {
+ CError_Error(CErrorStr247, expr->rtype, ENODE_QUALS(expr), type, qual);
+ return expr;
+ }
+
+ if (isSimpleCast) {
+ if (needsTypcon && ENODE_IS(expr, EINDIRECT) && (copts.pointercast_lvalue || !copts.ANSIstrict))
+ expr = makemonadicnode(expr, ETYPCON);
+
+ expr->rtype = type;
+ expr->flags = qual & ENODE_FLAG_QUALS;
+ return expr;
+ }
+
+ if (copts.old_argmatch)
+ return do_typecast(expr, type, qual);
+
+ return CExpr_Convert(expr, type, qual, 1, 1);
+}
+
+ENode *CRTTI_Parse_dynamic_cast(void) {
+ Boolean isRef;
+ ENode *expr;
+ TypeClass *srcclass;
+ TypeClass *destclass;
+ ENode *typeinfo;
+ DeclInfo di;
+
+ expr = CRTTI_ParseCast(&di);
+ if (!expr)
+ return nullnode();
+
+ if (!copts.RTTI)
+ CError_Warning(CErrorStr257);
+
+ CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual);
+ if (!IS_TYPE_POINTER_ONLY(di.thetype)) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ isRef = (TPTR_QUAL(di.thetype) & Q_REFERENCE) != 0;
+
+ if (IS_TYPE_CLASS(TPTR_TARGET(di.thetype))) {
+ destclass = TYPE_CLASS(TPTR_TARGET(di.thetype));
+ CDecl_CompleteType(TYPE(destclass));
+ if (!(destclass->flags & CLASS_COMPLETED)) {
+ CError_Error(CErrorStr136, destclass, 0);
+ return expr;
+ }
+ } else if (!IS_TYPE_VOID(TPTR_TARGET(di.thetype))) {
+ CError_Error(CErrorStr164);
+ return expr;
+ } else {
+ destclass = NULL;
+ }
+
+ if (isRef) {
+ if (!IS_TYPE_CLASS(expr->rtype)) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ srcclass = TYPE_CLASS(expr->rtype);
+ if (destclass) {
+ if (srcclass == destclass || CClass_IsBaseClass(srcclass, destclass, NULL, 0, 1))
+ return do_typecast(expr, di.thetype, di.qual);
+ }
+
+ expr = getnodeaddress(expr, 1);
+ } else {
+ if (!IS_TYPE_POINTER_ONLY(expr->rtype) || !IS_TYPE_CLASS(TPTR_TARGET(expr->rtype))) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ srcclass = TYPE_CLASS(TPTR_TARGET(expr->rtype));
+ if (destclass) {
+ if (srcclass == destclass || CClass_IsBaseClass(srcclass, destclass, NULL, 0, 1))
+ return do_typecast(expr, di.thetype, di.qual);
+ }
+ }
+
+ if (!(srcclass->flags & CLASS_COMPLETED)) {
+ CError_Error(CErrorStr136, srcclass, 0);
+ return expr;
+ }
+
+ if (!srcclass->vtable) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ if (srcclass->sominfo) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+
+ if (destclass) {
+ typeinfo = create_objectrefnode(CRTTI_ConstructTypeInfoObject(TYPE(destclass), 0));
+ if (destclass->sominfo) {
+ CError_Error(CErrorStr164);
+ return expr;
+ }
+ } else {
+ typeinfo = nullnode();
+ }
+
+ expr = CExpr_FuncCallSix(
+ Rdync_func,
+ expr,
+ intconstnode(TYPE(&stsignedlong), srcclass->vtable->offset),
+ typeinfo,
+ create_objectrefnode(CRTTI_ConstructTypeInfoObject(TYPE(srcclass), 0)),
+ intconstnode(TYPE(&stsignedshort), isRef),
+ NULL
+ );
+
+ if (isRef) {
+ expr->rtype = CDecl_NewPointerType(TYPE(destclass));
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TYPE(destclass);
+ } else {
+ expr->rtype = di.thetype;
+ }
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ return expr;
+}
+
+ENode *CRTTI_Parse_static_cast(void) {
+ ENode *expr;
+ DeclInfo di;
+
+ expr = CRTTI_ParseCast(&di);
+ if (!expr)
+ return nullnode();
+
+ CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual);
+
+ if (IS_TYPE_REFERENCE(di.thetype)) {
+ if (IS_TYPE_CLASS(expr->rtype) && CExpr_CanImplicitlyConvert(expr, di.thetype, di.qual)) {
+ expr = CExpr_Convert(expr, di.thetype, di.qual, 0, 1);
+ CError_ASSERT(959, IS_TYPE_POINTER_ONLY(expr->rtype));
+
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(di.thetype);
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ return expr;
+ }
+ } else {
+ if (CExpr_CanImplicitlyConvert(expr, di.thetype, di.qual))
+ return CExpr_Convert(expr, di.thetype, di.qual, 1, 1);
+ }
+
+ if (!IS_TYPE_VOID(di.thetype) && !(IS_TYPE_POINTER_ONLY(expr->rtype) && IS_TYPE_VOID(TPTR_TARGET(expr->rtype)))) {
+ CRTTI_IncompleteCheck(di.thetype);
+ CRTTI_IncompleteCheck(expr->rtype);
+ }
+
+ return CRTTI_UniversalCast(expr, di.thetype, di.qual, 2);
+}
+
+ENode *CRTTI_Parse_reinterpret_cast(void) {
+ ENode *expr;
+ Type *origtype;
+ ENode *lvalue;
+ DeclInfo di;
+
+ expr = CRTTI_ParseCast(&di);
+ if (!expr)
+ return nullnode();
+
+ CRTTI_ConstCastCheck(expr->rtype, expr->flags, di.thetype, di.qual);
+
+ if (IS_TYPE_REFERENCE(di.thetype)) {
+ lvalue = CExpr_LValue(expr, 0, 1);
+ if (!ENODE_IS(lvalue, EINDIRECT))
+ return lvalue;
+
+ lvalue->data.monadic->rtype = CDecl_NewPointerType(lvalue->rtype);
+ expr = lvalue->data.monadic;
+ origtype = di.thetype;
+ di.thetype = CDecl_NewPointerType(TPTR_TARGET(di.thetype));
+ } else {
+ origtype = NULL;
+ }
+
+ switch (di.thetype->type) {
+ case TYPEINT:
+ switch (expr->rtype->type) {
+ case TYPEMEMBERPOINTER:
+ case TYPEPOINTER:
+ expr = do_typecast(expr, di.thetype, di.qual);
+ break;
+ default:
+ CError_Error(CErrorStr164);
+ }
+ break;
+ case TYPEPOINTER:
+ switch (expr->rtype->type) {
+ case TYPEINT:
+ case TYPEENUM:
+ if (origtype)
+ di.thetype = origtype;
+ expr = do_typecast(expr, di.thetype, di.qual);
+ break;
+ case TYPEPOINTER:
+ expr = makemonadicnode(expr, ETYPCON);
+ expr->rtype = di.thetype;
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ break;
+ default:
+ CError_Error(CErrorStr164);
+ }
+ break;
+ case TYPEMEMBERPOINTER:
+ if (IS_TYPE_MEMBERPOINTER(expr->rtype)) {
+ if (IS_TYPE_FUNC(TYPE_MEMBER_POINTER(di.thetype)->ty1)) {
+ if (IS_TYPE_FUNC(TYPE_MEMBER_POINTER(expr->rtype)->ty1)) {
+ expr->rtype = di.thetype;
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ break;
+ }
+ } else {
+ if (!IS_TYPE_FUNC(TYPE_MEMBER_POINTER(expr->rtype)->ty1)) {
+ expr->rtype = di.thetype;
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ break;
+ }
+ }
+ }
+ expr = do_typecast(expr, di.thetype, di.qual);
+ break;
+ default:
+ CError_Error(CErrorStr164);
+ }
+
+ if (origtype && IS_TYPE_POINTER_ONLY(expr->rtype)) {
+ expr = makemonadicnode(expr, EINDIRECT);
+ expr->rtype = TPTR_TARGET(di.thetype);
+ }
+
+ return expr;
+}
+
+ENode *CRTTI_Parse_const_cast(void) {
+ DeclInfo di;
+ ENode *expr;
+
+ if (!(expr = CRTTI_ParseCast(&di)))
+ return nullnode();
+
+ if (IS_TYPE_POINTER_ONLY(di.thetype)) {
+ if (TPTR_QUAL(di.thetype) & Q_REFERENCE) {
+ if (!iscpp_typeequal(TPTR_TARGET(di.thetype), expr->rtype))
+ CError_Error(CErrorStr164);
+
+ if (ENODE_IS(expr, EINDIRECT)) {
+ expr->rtype = TPTR_TARGET(di.thetype);
+ expr->flags = di.qual & ENODE_FLAG_QUALS;
+ } else {
+ CError_Error(CErrorStr142);
+ }
+ } else {
+ if (!iscpp_typeequal(di.thetype, expr->rtype))
+ CError_Error(CErrorStr164);
+
+ expr = do_typecast(expr, di.thetype, di.qual);
+ }
+ } else if (IS_TYPE_MEMBERPOINTER(di.thetype)) {
+ if (!iscpp_typeequal(di.thetype, expr->rtype))
+ CError_Error(CErrorStr164);
+
+ expr = do_typecast(expr, di.thetype, di.qual);
+ } else {
+ if (!is_typesame(di.thetype, expr->rtype))
+ CError_Error(CErrorStr164);
+ else
+ expr = do_typecast(expr, di.thetype, di.qual);
+ }
+
+ return expr;
+}