diff options
Diffstat (limited to 'compiler_and_linker/FrontEnd/C/CRTTI.c')
-rw-r--r-- | compiler_and_linker/FrontEnd/C/CRTTI.c | 940 |
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; +} |