#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_FLAGS_2)) 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.useRTTI) 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_FLAGS_2)) 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.ANSI_strict)) 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.useRTTI) 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_FLAGS_2)) { 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_FLAGS_2)) { 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; }