mirror of https://git.wuffs.org/MWCC
941 lines
27 KiB
C
941 lines
27 KiB
C
#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;
|
|
}
|