#include "compiler/CDecl.h" #include "compiler/CABI.h" #include "compiler/CBrowse.h" #include "compiler/CClass.h" #include "compiler/CError.h" #include "compiler/CException.h" #include "compiler/CExpr.h" #include "compiler/CFunc.h" #include "compiler/CInit.h" #include "compiler/CInline.h" #include "compiler/CInt64.h" #include "compiler/CMachine.h" #include "compiler/CMangler.h" #include "compiler/CObjC.h" #include "compiler/CParser.h" #include "compiler/CPrep.h" #include "compiler/CPrepTokenizer.h" #include "compiler/CSOM.h" #include "compiler/CTemplateClass.h" #include "compiler/CTemplateFunc.h" #include "compiler/CTemplateNew.h" #include "compiler/CTemplateTools.h" #include "compiler/CompilerTools.h" #include "compiler/objects.h" #include "compiler/scopes.h" #include "compiler/templates.h" #include "compiler/tokens.h" AccessType global_access; FileOffsetInfo member_fileoffset; // forward declarations static void scandirectdecl1(DeclInfo *declinfo); Type *CDecl_NewStructType(SInt32 size, SInt16 align) { TypeStruct *tstruct = galloc(sizeof(TypeStruct)); memclrw(tstruct, sizeof(TypeStruct)); tstruct->type = TYPESTRUCT; tstruct->size = size; tstruct->align = align; tstruct->stype = STRUCT_TYPE_STRUCT; return (Type *) tstruct; } Type *CDecl_NewArrayType(Type *type, SInt32 size) { TypePointer *tarray = galloc(sizeof(TypePointer)); memclrw(tarray, sizeof(TypePointer)); tarray->type = TYPEARRAY; tarray->size = size; tarray->target = type; tarray->qual = 0; return (Type *) tarray; } Type *CDecl_NewPointerType(Type *type) { TypePointer *tptr = galloc(sizeof(TypePointer)); memclrw(tptr, sizeof(TypePointer)); tptr->type = TYPEPOINTER; tptr->size = 4; tptr->target = type; return (Type *) tptr; } Type *CDecl_NewRefPointerType(Type *type) { TypePointer *tptr = galloc(sizeof(TypePointer)); memclrw(tptr, sizeof(TypePointer)); tptr->type = TYPEPOINTER; tptr->size = 4; tptr->target = type; tptr->qual = Q_REFERENCE; return (Type *) tptr; } Type *CDecl_NewTemplDepType(TypeTemplDepType tdt) { TypeTemplDep *t = galloc(sizeof(TypeTemplDep)); memclrw(t, sizeof(TypeTemplDep)); t->type = TYPETEMPLATE; t->size = 1; t->dtype = tdt; return (Type *) t; } void CDecl_SetResultReg(TypeFunc *tfunc) { } static void CDecl_SetFuncResultReg(TypeFunc *tfunc) { } void CDecl_SetFuncFlags(TypeFunc *tfunc, UInt32 flags) { CDecl_SetResultReg(tfunc); } static void CDecl_ParseCPPFuncDecl(TypeFunc *tfunc) { for (;;) { if (tk == TK_CONST) { if (tfunc->flags & FUNC_CONST) CError_Warning(CErrorStr313, "const"); tfunc->flags |= FUNC_CONST; tk = lex(); } else if (tk == TK_VOLATILE) { if (tfunc->flags & FUNC_VOLATILE) CError_Warning(CErrorStr313, "volatile"); tfunc->flags |= FUNC_VOLATILE; tk = lex(); } else { break; } } if (tk == TK_THROW) CExcept_ScanExceptionSpecification(tfunc); } void CDecl_NewConvFuncType(DeclInfo *declinfo) { TypeFunc *tfunc; if (tk != '(') CError_Error(CErrorStr114); else tk = lex(); if (tk == TK_VOID) tk = lex(); if (tk != ')') CError_Error(CErrorStr115); else tk = lex(); tfunc = galloc(sizeof(TypeFunc)); memclrw(tfunc, sizeof(TypeFunc)); declinfo->name = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual); tfunc->type = TYPEFUNC; tfunc->functype = declinfo->thetype; tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE); tfunc->flags = FUNC_CONVERSION; declinfo->x49 = 0; CDecl_SetFuncFlags(tfunc, 1); CDecl_ParseCPPFuncDecl(tfunc); declinfo->thetype = (Type *) tfunc; declinfo->qual &= ~(Q_CONST | Q_VOLATILE); declinfo->storageclass = 0; } void CDecl_CompleteType(Type *type) { switch (type->type) { case TYPEPOINTER: if ((TYPE_POINTER(type)->qual & Q_REFERENCE) && IS_TYPE_CLASS(TYPE_POINTER(type)->target)) { type = TYPE_POINTER(type)->target; break; } return; case TYPEARRAY: do { type = TYPE_POINTER(type)->target; } while (IS_TYPE_ARRAY(type)); if (IS_TYPE_CLASS(type)) break; return; case TYPECLASS: break; default: return; } if ((TYPE_CLASS(type)->flags & (CLASS_COMPLETED | CLASS_IS_TEMPL_INST)) == CLASS_IS_TEMPL_INST) CTempl_InstantiateTemplateClass(TYPE_CLASS(type)); } Boolean IsCompleteType(Type *type) { switch (type->type) { case TYPEVOID: CError_Error(CErrorStr126); return 0; case TYPEFUNC: CError_Error(CErrorStr146); return 0; case TYPESTRUCT: if (!type->size) { CError_Error(CErrorStr136, type, 0); return 0; } return 1; case TYPECLASS: if ( !(TYPE_CLASS(type)->flags & CLASS_COMPLETED) && ( !(TYPE_CLASS(type)->flags & CLASS_IS_TEMPL_INST) || !CTempl_InstantiateTemplateClass(TYPE_CLASS(type)) ) ) { CError_Error(CErrorStr136, type, 0); return 0; } return 1; default: if (!type->size) { CError_Error(CErrorStr145); return 0; } return 1; } } Boolean CanAllocObject(Type *type) { switch (type->type) { case TYPEVOID: CError_Error(CErrorStr126); return 0; case TYPEFUNC: CError_Error(CErrorStr146); return 0; case TYPECLASS: if (TYPE_CLASS(type)->flags & CLASS_ABSTRACT) { CError_AbstractClassError(TYPE_CLASS(type)); return 0; } default: return 1; } } Boolean CanCreateObject(Type *type) { if (!CanAllocObject(type)) return 0; if (IS_TYPE_CLASS(type)) { if (TYPE_CLASS(type)->flags & CLASS_HANDLEOBJECT) { CError_Error(CErrorStr191); return 0; } if (TYPE_CLASS(type)->objcinfo) { CError_Error(CErrorStr307); return 0; } } return 1; } static Boolean CanCreateHandleMemberObject(Type *type) { while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (!CanCreateObject(type)) return 0; if (IS_TYPE_CLASS(type)) { if (CClass_Destructor(TYPE_CLASS(type)) || CClass_Constructor(TYPE_CLASS(type))) { CError_Error(CErrorStr191); return 0; } } return 1; } void makethetypepointer(DeclInfo *declinfo, UInt32 qual) { declinfo->thetype = CDecl_NewPointerType(declinfo->thetype); TYPE_POINTER(declinfo->thetype)->qual = qual; } void CDecl_AddThisPointerArgument(TypeFunc *tfunc, TypeClass *tclass) { Type *ptype; FuncArg *arg; ptype = CDecl_NewPointerType(!tclass->sominfo ? (Type *) tclass : &stvoid); TYPE_POINTER(ptype)->qual = Q_CONST; arg = CParser_NewFuncArg(); arg->name = this_name_node; arg->type = ptype; if (tfunc->flags & FUNC_CONST) arg->qual |= Q_CONST; if (tfunc->flags & FUNC_VOLATILE) arg->qual |= Q_VOLATILE; arg->next = tfunc->args; tfunc->args = arg; } void CDecl_MakePTMFuncType(TypeFunc *tfunc) { Type *cvoidp; FuncArg *arg1; FuncArg *arg2; cvoidp = CDecl_NewPointerType(&stvoid); TYPE_POINTER(cvoidp)->qual = Q_CONST; arg1 = CParser_NewFuncArg(); arg1->name = this_name_node; arg1->type = cvoidp; if (tfunc->flags & FUNC_CONST) arg1->qual |= Q_CONST; if (tfunc->flags & FUNC_VOLATILE) arg1->qual |= Q_VOLATILE; arg2 = CParser_NewFuncArg(); arg2->name = this_name_node; arg2->type = cvoidp; arg2->qual = Q_CONST; arg1->next = tfunc->args; arg2->next = arg1; tfunc->args = arg2; tfunc->flags |= FUNC_FLAGS_80; } void CDecl_AddArgument(TypeFunc *tfunc, Type *argtype) { FuncArg *arg = CParser_NewFuncArg(); arg->type = argtype; arg->next = tfunc->args; tfunc->args = arg; if (arg->next && arg->next->type == &stvoid) arg->next = NULL; } Boolean CDecl_CheckArrayIntegr(Type *type) { if (!IsCompleteType(type)) return 0; if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) { CError_Error(CErrorStr289); return 0; } if (IS_TYPE_REFERENCE(type)) { CError_Error(CErrorStr196); return 0; } return CanCreateObject(type); } static Boolean checkfuncintegr(Type *type) { if (IS_TYPE_VOID(type)) return 1; if (IS_TYPE_CLASS(type) && TYPE_CLASS(type)->sominfo) { CError_Error(CErrorStr283); return 0; } return CanCreateObject(type); } void CDecl_ParseDirectFuncDecl(DeclInfo *declinfo) { FuncArg *list; TypeFunc *tfunc; if (tk == ')') { if (copts.cplusplus) list = NULL; else list = &oldstyle; tk = lex(); } else { list = parameter_type_list(declinfo); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); } tfunc = galloc(sizeof(TypeFunc)); memclrw(tfunc, sizeof(TypeFunc)); tfunc->type = TYPEFUNC; tfunc->args = list; if (declinfo->qual & Q_PASCAL) { declinfo->qual &= ~Q_PASCAL; tfunc->flags = FUNC_PASCAL; } if (copts.cplusplus) { CDecl_ParseCPPFuncDecl(tfunc); if (declinfo->storageclass == TK_TYPEDEF && tfunc->exspecs) CError_Error(CErrorStr264); } scandirectdecl1(declinfo); if (!checkfuncintegr(declinfo->thetype)) declinfo->thetype = &stvoid; tfunc->functype = declinfo->thetype; tfunc->qual = declinfo->qual & (Q_CONST | Q_VOLATILE); declinfo->thetype = (Type *) tfunc; declinfo->qual &= ~(Q_CONST | Q_VOLATILE); declinfo->x49 = 0; } static void scandirectdecl1(DeclInfo *declinfo) { Boolean flag; CInt64 len; ENode *expr; TypeTemplDep *ttempl; flag = 0; if (tk == '[') { if ((tk = lex()) == ']') { len = cint64_zero; tk = lex(); flag = 1; } else { if (!declinfo->x46 || declinfo->x47) { expr = CExpr_IntegralConstOrDepExpr(); if (!ENODE_IS(expr, EINTCONST)) { if (tk != ']') CError_ErrorSkip(CErrorStr125); else tk = lex(); declinfo->x47 = 1; scandirectdecl1(declinfo); if (!CDecl_CheckArrayIntegr(declinfo->thetype)) declinfo->thetype = (Type *) &stsignedchar; ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY); ttempl->u.array.type = declinfo->thetype; ttempl->u.array.index = CInline_CopyExpression(expr, CopyMode1); declinfo->thetype = (Type *) ttempl; return; } len = expr->data.intval; if (CInt64_IsNegative(&len)) { CError_Error(CErrorStr124); len = cint64_one; } else if (CInt64_IsZero(&len)) { if (!copts.ANSIstrict && declinfo->x50) { flag = 1; } else { CError_Error(CErrorStr124); len = cint64_one; } } } else { len = cint64_one; expr = expression(); if (IS_TYPE_INT(expr->rtype)) { if (!ENODE_IS(expr, EINTCONST)) declinfo->x24 = expr; else len = expr->data.intval; } else { CError_Error(CErrorStr124); } } if (tk != ']') CError_ErrorSkip(CErrorStr125); else tk = lex(); } declinfo->x47 = 1; scandirectdecl1(declinfo); if (!flag && !CDecl_CheckArrayIntegr(declinfo->thetype)) declinfo->thetype = (Type *) &stsignedchar; if (!declinfo->thetype->size && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) { ttempl = (TypeTemplDep *) CDecl_NewTemplDepType(TEMPLDEP_ARRAY); ttempl->u.array.type = declinfo->thetype; ttempl->u.array.index = CInline_CopyExpression(intconstnode((Type *) &stsignedint, CInt64_GetULong(&len)), CopyMode1); declinfo->thetype = (Type *) ttempl; } else { declinfo->thetype = CDecl_NewArrayType(declinfo->thetype, declinfo->thetype->size * CInt64_GetULong(&len)); } } else if (tk == '(') { if (!copts.cplusplus || !declinfo->name || IS_TYPE_VOID(declinfo->thetype) || CParser_TryParamList(!IS_TYPE_CLASS(declinfo->thetype))) { tk = lex(); CDecl_ParseDirectFuncDecl(declinfo); } } } static void substitute_type(Type *type1, Type *type2) { SInt32 oldsize; while (1) { switch (type1->type) { case TYPEPOINTER: if (TYPE_POINTER(type1)->target == &stillegal) { TYPE_POINTER(type1)->target = type2; type1->size = 4; return; } type1 = TYPE_POINTER(type1)->target; break; case TYPEMEMBERPOINTER: if (TYPE_MEMBER_POINTER(type1)->ty1 == &stillegal) { TYPE_MEMBER_POINTER(type1)->ty1 = type2; if (IS_TYPE_FUNC(type2)) { CDecl_MakePTMFuncType(TYPE_FUNC(type2)); type1->size = 12; } else { type1->size = 4; } return; } type1 = TYPE_MEMBER_POINTER(type1)->ty1; break; case TYPEARRAY: if (TYPE_POINTER(type1)->target == &stillegal) { if (!CDecl_CheckArrayIntegr(type2)) type2 = (Type *) &stsignedchar; type1->size *= type2->size; TYPE_POINTER(type1)->target = type2; return; } oldsize = TYPE_POINTER(type1)->target->size; substitute_type(TYPE_POINTER(type1)->target, type2); if (oldsize != TYPE_POINTER(type1)->target->size && oldsize != 0) type1->size = TYPE_POINTER(type1)->target->size * (type1->size / oldsize); return; case TYPEFUNC: if (TYPE_FUNC(type1)->functype == &stillegal) { if (!checkfuncintegr(type2)) type2 = &stvoid; TYPE_FUNC(type1)->functype = type2; CDecl_SetFuncResultReg((TypeFunc *) type1); return; } type1 = TYPE_FUNC(type1)->functype; break; case TYPETEMPLATE: if (TYPE_TEMPLATE(type1)->dtype == TEMPLDEP_ARRAY) { if (TYPE_TEMPLATE(type1)->u.array.type == &stillegal) { if (!CDecl_CheckArrayIntegr(type2)) type2 = (Type *) &stsignedchar; TYPE_TEMPLATE(type1)->u.array.type = type2; return; } type1 = TYPE_TEMPLATE(type1)->u.array.type; } else { CError_Error(CErrorStr146); return; } break; default: CError_Error(CErrorStr121); return; } } } static void scandecl(DeclInfo *declinfo) { Type *oldtype; Type *newtype; oldtype = declinfo->thetype; declinfo->thetype = &stillegal; scandeclarator(declinfo); if (tk != ')') CError_ErrorSkip(CErrorStr115); else tk = lex(); newtype = declinfo->thetype; if (newtype == &stillegal) { declinfo->thetype = oldtype; scandirectdecl1(declinfo); } else { declinfo->thetype = oldtype; scandirectdecl1(declinfo); substitute_type(newtype, declinfo->thetype); declinfo->thetype = newtype; } } static Boolean CDecl_ParseOperatorDecl(DeclInfo *declinfo) { if (declinfo->operator_token) { CError_Error(CErrorStr121); return 0; } declinfo->operator_token = 0; if (!CParser_ParseOperatorName(&declinfo->operator_token, declinfo->x4A && cscope_current->theclass, 0)) return 0; if (!declinfo->operator_token) { conversion_type_name(declinfo); tkidentifier = CMangler_ConversionFuncName(declinfo->thetype, declinfo->qual); declinfo->x54 = 1; } return 1; } static Boolean CDecl_IsEnumClassTypeOrRef(Type *type) { if (IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type)) return 1; if (!IS_TYPE_REFERENCE(type)) return 0; type = TYPE_POINTER(type)->target; return IS_TYPE_CLASS(type) || IS_TYPE_ENUM(type); } static Boolean CDecl_CheckOperatorType(DeclInfo *declinfo, Boolean flag) { FuncArg *args; FuncArg *secondarg; Type *functype; short argCount; Boolean isMethod; if (!IS_TYPE_FUNC(declinfo->thetype)) { CError_Error(CErrorStr193); return 0; } functype = TYPE_FUNC(declinfo->thetype)->functype; args = TYPE_FUNC(declinfo->thetype)->args; if (args) { if (args != &elipsis && args != &oldstyle) { argCount = 1; if (args->dexpr) { switch (declinfo->operator_token) { case TK_NEW: case TK_DELETE: case TK_NEW_ARRAY: case TK_DELETE_ARRAY: break; default: CError_Error(CErrorStr205); } } secondarg = args->next; if (secondarg) { argCount = ((secondarg != &elipsis && !secondarg->next) != 0) ? 2 : 3; if (secondarg->dexpr) { switch (declinfo->operator_token) { case '(': case TK_NEW: case TK_DELETE: case TK_NEW_ARRAY: case TK_DELETE_ARRAY: break; default: CError_Error(CErrorStr205); } } } } else { argCount = 3; } } else { CError_Error(CErrorStr193); return 0; } isMethod = flag && IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype)) && !TYPE_METHOD(declinfo->thetype)->is_static; switch (declinfo->operator_token) { case TK_NEW: case TK_NEW_ARRAY: if (isMethod || !is_typesame(functype, TYPE(&void_ptr)) || argCount < 1 || args->type != CABI_GetSizeTType()) { CError_Error(CErrorStr193); return 0; } return 1; case TK_DELETE: case TK_DELETE_ARRAY: if (isMethod || !IS_TYPE_VOID(functype) || argCount < 1 || !is_typesame(args->type, TYPE(&void_ptr))) { CError_Error(CErrorStr193); return 0; } return 1; case '=': if (!isMethod) { CError_Error(CErrorStr193); return 0; } break; case '(': if (!isMethod) { CError_Error(CErrorStr193); return 0; } return 1; case '[': if (!isMethod) { CError_Error(CErrorStr193); return 0; } break; case TK_ARROW: if (argCount != 1 || isMethod == 0) { CError_Error(CErrorStr193); return 0; } return 1; case TK_INCREMENT: case TK_DECREMENT: if (argCount == 2 && secondarg->type != TYPE(&stsignedint)) { CError_Error(CErrorStr193); return 0; } break; } if (flag && !isMethod) { CError_Error(CErrorStr193); return 0; } switch (declinfo->operator_token) { case '&': case '*': case '+': case '-': case TK_INCREMENT: case TK_DECREMENT: if (argCount != 1) goto whatever; case '!': case '~': if (argCount == 1) { if (flag || CDecl_IsEnumClassTypeOrRef(args->type)) return 1; } break; case '%': case ',': case '/': case '<': case '=': case '>': case '[': case '^': case '|': case TK_MULT_ASSIGN: case TK_DIV_ASSIGN: case TK_MOD_ASSIGN: case TK_ADD_ASSIGN: case TK_SUB_ASSIGN: case TK_SHL_ASSIGN: case TK_SHR_ASSIGN: case TK_AND_ASSIGN: case TK_XOR_ASSIGN: case TK_OR_ASSIGN: case TK_LOGICAL_OR: case TK_LOGICAL_AND: case TK_LOGICAL_EQ: case TK_LOGICAL_NE: case TK_LESS_EQUAL: case TK_GREATER_EQUAL: case TK_SHL: case TK_SHR: case TK_ARROW: case TK_DOT_STAR: case TK_ARROW_STAR: whatever: if (argCount == 2) { if (flag || CDecl_IsEnumClassTypeOrRef(args->type) || CDecl_IsEnumClassTypeOrRef(secondarg->type)) return 1; } break; } CError_Error(CErrorStr193); return 0; } static void scandirectdeclarator(DeclInfo *declinfo, NameSpace *nspace) { HashNameNode *saveident; CScopeSave scopesave; Boolean flag; if (nspace) CScope_SetNameSpaceScope(nspace, &scopesave); if (tk == '(') { if ((tk = lex()) == ')') { if (declinfo->x55) { CDecl_ParseDirectFuncDecl(declinfo); if (nspace) CScope_RestoreScope(&scopesave); return; } else { CError_Error(CErrorStr121); if (nspace) CScope_RestoreScope(&scopesave); return; } } if (!(tk >= TK_AUTO && tk <= TK_BYREF)) { if (!(tk == TK_IDENTIFIER && CScope_PossibleTypeName(tkidentifier))) { scandecl(declinfo); if (nspace) CScope_RestoreScope(&scopesave); return; } else { saveident = tkidentifier; switch (lookahead()) { case ')': case ',': break; default: tkidentifier = saveident; scandecl(declinfo); if (nspace) CScope_RestoreScope(&scopesave); return; } } } if (declinfo->name) CError_Error(CErrorStr121); CDecl_ParseDirectFuncDecl(declinfo); if (nspace) CScope_RestoreScope(&scopesave); return; } if (nspace) { if (tk == TK_OPERATOR) { if (!CDecl_ParseOperatorDecl(declinfo)) { CScope_RestoreScope(&scopesave); return; } if (declinfo->x54) { declinfo->nspace = nspace; declinfo->name = tkidentifier; if (nspace) CScope_RestoreScope(&scopesave); if (tk == '(') { tk = lex(); CDecl_ParseDirectFuncDecl(declinfo); if (IS_TYPE_FUNC(declinfo->thetype)) TYPE_FUNC(declinfo->thetype)->flags |= FUNC_CONVERSION; else CError_Error(CErrorStr121); } else { CError_Error(CErrorStr114); } return; } flag = 1; } else if (tk != TK_IDENTIFIER) { CError_Error(CErrorStr107); CScope_RestoreScope(&scopesave); return; } else { flag = 0; } if (declinfo->name) { CError_Error(CErrorStr121); CScope_RestoreScope(&scopesave); return; } declinfo->nspace = nspace; declinfo->name = tkidentifier; if (!flag) tk = lex(); } else if (tk == TK_IDENTIFIER) { if (declinfo->name) CError_Error(CErrorStr121); declinfo->name = tkidentifier; tk = lex(); } else if (tk == TK_OPERATOR) { if (!CDecl_ParseOperatorDecl(declinfo)) return; declinfo->name = tkidentifier; } if (tk == '<' && declinfo->x51) { declinfo->expltargs = CTempl_ParseUncheckTemplArgs(NULL, 0); declinfo->has_expltargs = 1; declinfo->x51 = 0; tk = lex(); } scandirectdecl1(declinfo); if (nspace) CScope_RestoreScope(&scopesave); } void makememberpointertype(DeclInfo *declinfo, TypeClass *tclass, UInt32 qual) { TypeMemberPointer *tmemp; TypeFunc *tfunc; if (tclass->flags & CLASS_HANDLEOBJECT) { CError_Error(CErrorStr191); declinfo->thetype = (Type *) &stsignedint; return; } if (tclass->sominfo) { CError_Error(CErrorStr290); declinfo->thetype = (Type *) &stsignedint; return; } tmemp = galloc(sizeof(TypeMemberPointer)); memclrw(tmemp, sizeof(TypeMemberPointer)); tmemp->type = TYPEMEMBERPOINTER; tmemp->ty2 = (Type *) tclass; tmemp->qual = qual; if (IS_TYPE_FUNC(declinfo->thetype)) { tfunc = galloc(sizeof(TypeFunc)); *tfunc = *TYPE_FUNC(declinfo->thetype); tmemp->ty1 = (Type *) tfunc; tmemp->size = 12; CDecl_MakePTMFuncType(tfunc); } else { tmemp->size = 4; tmemp->ty1 = declinfo->thetype; } declinfo->thetype = (Type *) tmemp; } void CDecl_ScanPointer(DeclInfo *declinfo, NameSpace *nspace, Boolean flag) { NameResult pr; UInt32 qual; while (1) { qual = (tk == '&') ? Q_REFERENCE : 0; for (tk = lex(); ; tk = lex()) { switch (tk) { case TK_CONST: if (qual & Q_CONST) CError_Error(CErrorStr121); qual |= Q_CONST; continue; case TK_VOLATILE: if (qual & Q_VOLATILE) CError_Error(CErrorStr121); qual |= Q_VOLATILE; continue; case TK_RESTRICT: if (qual & Q_RESTRICT) CError_Error(CErrorStr121); qual |= Q_RESTRICT; continue; default: break; } break; } if (IS_TYPE_REFERENCE(declinfo->thetype) || ((qual & Q_REFERENCE) && IS_TYPE_VOID(declinfo->thetype))) { CError_Error(CErrorStr196); return; } if (nspace) { makememberpointertype(declinfo, nspace->theclass, qual); nspace = NULL; } else { makethetypepointer(declinfo, qual); } switch (tk) { case '*': continue; case '&': if (!copts.cplusplus) { if (flag) scandirectdeclarator(declinfo, NULL); return; } continue; case TK_IDENTIFIER: if (!copts.cplusplus) break; if (copts.cpp_extensions && cscope_current->theclass && cscope_current->theclass->classname == tkidentifier && lookahead() == TK_COLON_COLON) { tk = lex(); tk = lex(); break; } case TK_COLON_COLON: if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) { if ((nspace = pr.nspace_0)) { if (nspace->theclass && tk == '*') continue; } else { if (pr.type && IS_TYPE_TEMPLATE(pr.type) && declinfo->x30) { if (CTempl_IsQualifiedMember(declinfo, pr.type, &nspace)) scandirectdeclarator(declinfo, nspace); else declinfo->x20 = pr.type; return; } CError_Error(CErrorStr121); } } break; } break; } if (flag) scandirectdeclarator(declinfo, nspace); } static void CDecl_TemplatePTM(DeclInfo *declinfo, Type *type) { TypeMemberPointer *tmemp = galloc(sizeof(TypeMemberPointer)); tmemp->type = TYPEMEMBERPOINTER; if (IS_TYPE_FUNC(declinfo->thetype)) { CDecl_MakePTMFuncType((TypeFunc *) declinfo->thetype); tmemp->size = 12; } else { tmemp->size = 4; } tmemp->ty1 = declinfo->thetype; tmemp->ty2 = type; tmemp->qual = 0; declinfo->thetype = (Type *) tmemp; } void scandeclarator(DeclInfo *declinfo) { NameResult pr; NameSpace *nspace; switch (tk) { case '&': if (!copts.cplusplus) break; case '*': CDecl_ScanPointer(declinfo, NULL, 1); if (tk == TK_UU_ATTRIBUTE_UU) CParser_ParseAttribute(NULL, declinfo); return; case TK_IDENTIFIER: if (!copts.cplusplus) break; case TK_COLON_COLON: if (CScope_ParseQualifiedNameSpace(&pr, 1, 0)) { nspace = pr.nspace_0; if (nspace) { if (nspace->theclass && tk == '*') CDecl_ScanPointer(declinfo, nspace, 1); else scandirectdeclarator(declinfo, nspace); return; } if (pr.type && IS_TYPE_TEMPLATE(pr.type)) { if (declinfo->x30 && CTempl_IsQualifiedMember(declinfo, pr.type, &nspace)) { scandirectdeclarator(declinfo, nspace); return; } else if (declinfo->x30 && tk == TK_OPERATOR) { declinfo->x20 = pr.type; return; } else if ((tk = lex()) == TK_COLON_COLON && (tk = lex()) == '*') { CDecl_TemplatePTM(declinfo, pr.type); tk = lex(); break; } else if (declinfo->x30) { declinfo->x20 = pr.type; return; } } CError_Error(CErrorStr121); } break; } scandirectdeclarator(declinfo, NULL); if (tk == TK_UU_ATTRIBUTE_UU) CParser_ParseAttribute(NULL, declinfo); } void conversion_type_name(DeclInfo *declinfo) { NameResult pr; DeclInfo subdeclinfo; memclrw(&subdeclinfo, sizeof(DeclInfo)); CParser_GetDeclSpecs(&subdeclinfo, 0); switch (tk) { case '&': case '*': CDecl_ScanPointer(&subdeclinfo, NULL, 0); break; case TK_IDENTIFIER: case TK_COLON_COLON: if (CScope_ParseQualifiedNameSpace(&pr, 0, 0)) { if (pr.nspace_0 && pr.nspace_0->theclass && tk == '*') CDecl_ScanPointer(&subdeclinfo, pr.nspace_0, 0); else CError_Error(CErrorStr121); } break; } declinfo->name = subdeclinfo.name; declinfo->thetype = subdeclinfo.thetype; declinfo->qual |= subdeclinfo.qual; } static void scaninlinefunc(Object *obj) { short array[256]; short r29; CInt64 val; if (tk == '{') { tk = lex(); r29 = 0; while (1) { if (r29 >= 256) { CError_Error(CErrorStr127); r29 = 255; } val = CExpr_IntegralConstExpr(); array[r29++] = CInt64_GetULong(&val); if (tk != '}') { if (tk != ',') CError_Error(CErrorStr116); tk = lex(); } else { tk = lex(); break; } } } else { val = CExpr_IntegralConstExpr(); array[0] = CInt64_GetULong(&val); r29 = 1; } obj->datatype = DINLINEFUNC; obj->u.ifunc.size = r29 * 2; obj->u.ifunc.data = galloc(obj->u.ifunc.size); obj->u.ifunc.xrefs = NULL; memcpy(obj->u.ifunc.data, array, obj->u.ifunc.size); if (tk != ';') CError_Error(CErrorStr123); } typedef enum { OverloadMode0, OverloadMode1, OverloadMode2, OverloadMode3 } OverloadMode; static Object *CDecl_OverloadFunctionObject(NameSpaceObjectList *list, DeclInfo *declinfo, Boolean *outflag, OverloadMode mode, Boolean flag2) { TypeFunc *scanfunc; NameSpaceObjectList *scan; TypeFunc *tfunc; FuncArg *args; FuncArg *scanargs; Object *obj; Boolean r24; short compareresult; if (outflag) *outflag = 0; tfunc = (TypeFunc *) declinfo->thetype; args = tfunc->args; r24 = 0; for (scan = list; scan; scan = scan->next) { obj = OBJECT(scan->object); if (obj->otype != OT_OBJECT) continue; scanfunc = TYPE_FUNC(obj->type); if (!IS_TYPE_FUNC(scanfunc)) continue; scanargs = scanfunc->args; if (scanfunc->flags & FUNC_IS_TEMPL) r24 = 1; if (IS_TYPEFUNC_METHOD(scanfunc)) { switch (mode) { case OverloadMode0: CError_Error(CErrorStr197); break; case OverloadMode1: if (!TYPE_METHOD(scanfunc)->is_static) continue; break; case OverloadMode2: if (TYPE_METHOD(scanfunc)->is_static) continue; break; case OverloadMode3: if (!TYPE_METHOD(scanfunc)->is_static) { if (scanargs->qual & Q_CV) continue; scanargs = scanargs->next; } break; } } else { if (mode) CError_Error(CErrorStr197); } compareresult = CParser_CompareArgLists(args, scanargs); if (compareresult == 1) { if (scanfunc->flags & FUNC_CONVERSION) { if (!(tfunc->flags & FUNC_CONVERSION)) { CError_Error(CErrorStr197); break; } if (!is_typesame(tfunc->functype, scanfunc->functype)) continue; if ((tfunc->qual & Q_CV) != (scanfunc->qual & Q_CV)) continue; if ((tfunc->flags & FUNC_CALL_CONV_MASK) != (scanfunc->flags & FUNC_CALL_CONV_MASK)) { CError_Error(CErrorStr197); break; } if (tfunc->exspecs || scanfunc->exspecs) CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs); return obj; } if (tfunc->flags & FUNC_CONVERSION) { CError_Error(CErrorStr197); break; } if ( !is_typesame(tfunc->functype, scanfunc->functype) || ((tfunc->qual & (Q_CONST | Q_PASCAL)) != (scanfunc->qual & (Q_CONST | Q_PASCAL))) || ((tfunc->flags & FUNC_CALL_CONV_MASK) != (scanfunc->flags & FUNC_CALL_CONV_MASK)) ) { CError_Error(CErrorStr197); break; } if (tfunc->exspecs || scanfunc->exspecs) { if (obj->name != newp_fobj->name && obj->name != newa_fobj->name && obj->name != delp_fobj->name && obj->name != dela_fobj->name) CExcept_CompareSpecifications(tfunc->exspecs, scanfunc->exspecs); } return obj; } else if (compareresult == 2) { CError_Error(CErrorStr197); break; } } if (r24 && (flag2 || declinfo->x3C)) { if ((obj = CTempl_TemplateFunctionCheck(declinfo, list))) return obj; } if (!outflag) { CError_Error(CErrorStr197); return NULL; } if (declinfo->nspace) CError_Error(CErrorStr336); *outflag = 1; obj = CParser_NewFunctionObject(declinfo); CheckDefaultArgs(TYPE_FUNC(obj->type)->args); if (tfunc->flags & FUNC_PASCAL) { for (scan = list; scan; scan = scan->next) { if (scan->object->otype == OT_OBJECT && IS_TYPE_FUNC(OBJECT(scan->object)->type)) { if (TYPE_FUNC(OBJECT(scan->object)->type)->flags & FUNC_PASCAL) CError_Error(CErrorStr226); } } } if (copts.cplusplus && declinfo->is_extern_c) { for (scan = list; scan; scan = scan->next) { if (scan->object->otype == OT_OBJECT && !(OBJECT(scan->object)->qual & Q_MANGLE_NAME)) CError_Error(CErrorStr197); } } CScope_AddObject(cscope_current, declinfo->name, OBJ_BASE(obj)); if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) CTemplClass_RegisterObjectDef(TEMPL_CLASS(cscope_current->theclass), OBJ_BASE(obj)); return obj; } void MergeDefaultArgs(FuncArg *a, FuncArg *b) { FuncArg *scan_a; FuncArg *scan_b; if (a == &oldstyle || b == &oldstyle) return; scan_a = a; scan_b = b; while (scan_a && scan_b) { if (scan_a->dexpr) { while (scan_b) { if (scan_b->dexpr) { while (a) { a->dexpr = NULL; a = a->next; } while (b) { b->dexpr = NULL; b = b->next; } CError_Error(CErrorStr205); return; } scan_b = scan_b->next; } break; } else if (scan_b->dexpr) { do { scan_a = scan_a->next; scan_b = scan_b->next; if (!scan_a) goto secondpart; if (scan_a == &elipsis) goto secondpart; if (scan_a->dexpr && scan_b->dexpr) break; } while (scan_a->dexpr || scan_b->dexpr); while (a) { a->dexpr = NULL; a = a->next; } while (b) { b->dexpr = NULL; b = b->next; } CError_Error(CErrorStr205); return; } else { scan_a = scan_a->next; scan_b = scan_b->next; } } secondpart: while (a && b) { if (b->dexpr) a->dexpr = b->dexpr; else b->dexpr = a->dexpr; a = a->next; b = b->next; } } void CheckDefaultArgs(FuncArg *args) { FuncArg *scan; scan = args; while (scan && !scan->dexpr) scan = scan->next; while (scan && scan != &elipsis && scan != &oldstyle) { if (!scan->dexpr) { while (args) { args->dexpr = NULL; args = args->next; } CError_Error(CErrorStr205); return; } scan = scan->next; } } static void CDecl_FuncRedeclCheck(Object *obj, DeclInfo *declinfo, Boolean flag) { if (declinfo->storageclass == TK_STATIC && obj->sclass != TK_STATIC) { if (copts.cplusplus) CError_Error(CErrorStr260); else obj->sclass = TK_STATIC; } obj->qual |= declinfo->qual; if (flag) CheckDefaultArgs(TYPE_FUNC(obj->type)->args); else MergeDefaultArgs(TYPE_FUNC(obj->type)->args, TYPE_FUNC(declinfo->thetype)->args); if (!declinfo->x45) TYPE_FUNC(obj->type)->args = TYPE_FUNC(declinfo->thetype)->args; } Object *CDecl_GetFunctionObject(DeclInfo *declinfo, NameSpace *nspace, Boolean *pflag, Boolean someotherflag) { NameSpace *nspace2; Type *type; Object *obj; NameSpaceObjectList *list; TypeMemberFunc tmp; Boolean r27; Boolean outflag; r27 = 0; if (pflag) *pflag = 0; nspace2 = declinfo->nspace; if (!nspace2) nspace2 = cscope_current; CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_INLINE | Q_PASCAL | Q_ASM | Q_VOLATILE | Q_CONST)); switch (TYPE_FUNC(declinfo->thetype)->functype->type) { case TYPEFUNC: case TYPEARRAY: CError_Error(CErrorStr128); TYPE_FUNC(declinfo->thetype)->functype = TYPE(&stsignedint); break; } if (nspace2->theclass) { CError_ASSERT(1969, declinfo->name); if (!nspace2->theclass->size) CDecl_CompleteType(TYPE(nspace2->theclass)); if (!(list = CScope_GetLocalObject(nspace2, declinfo->name))) { CError_Error(CErrorStr140, declinfo->name->name); return NULL; } obj = OBJECT(list->object); type = obj->type; if (!IS_TYPE_FUNC(type)) { CError_Error(CErrorStr249, CError_GetObjectName(obj), type, obj->qual, declinfo->thetype, declinfo->qual); return NULL; } if (declinfo->has_expltargs) return CTempl_TemplateFunctionCheck(declinfo, list); if (declinfo->x3C || (list->next && list->next->object->otype == OT_OBJECT)) { if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_CONST | FUNC_VOLATILE)) { CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass); obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode2, someotherflag); if (!obj) return NULL; } else { obj = CDecl_OverloadFunctionObject(list, declinfo, NULL, OverloadMode3, someotherflag); if (!obj) return NULL; if (!TYPE_METHOD(obj->type)->is_static) CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass); } } else { if (TYPE_METHOD(type)->is_static) { if (nspace2->theclass->sominfo) CSOM_FixNewDeleteFunctype(TYPE_FUNC(declinfo->thetype)); } else { CDecl_AddThisPointerArgument(TYPE_FUNC(declinfo->thetype), nspace2->theclass); } if (copts.cpp_extensions) { declinfo->qual |= obj->qual & (Q_PASCAL | Q_CONST); TYPE_FUNC(declinfo->thetype)->qual |= TYPE_FUNC(obj->type)->qual & (Q_PASCAL | Q_CONST); TYPE_FUNC(declinfo->thetype)->flags |= TYPE_FUNC(obj->type)->flags & (FUNC_FLAGS_4000000 | FUNC_FLAGS_10000000); } if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_PASCAL | Q_CONST)) != (obj->qual & (Q_PASCAL | Q_CONST))) { tmp = *TYPE_METHOD(obj->type); *(TYPE_FUNC(&tmp)) = *TYPE_FUNC(declinfo->thetype); tmp.flags |= FUNC_METHOD; CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, &tmp, declinfo->qual); } if (TYPE_FUNC(declinfo->thetype)->exspecs || TYPE_FUNC(obj->type)->exspecs) CExcept_CompareSpecifications(TYPE_FUNC(declinfo->thetype)->exspecs, TYPE_FUNC(obj->type)->exspecs); } CDecl_FuncRedeclCheck(obj, declinfo, 0); if (declinfo->x3C) { if (obj->nspace->theclass && !(obj->nspace->theclass->flags & CLASS_IS_TEMPL_INST)) CError_Error(CErrorStr335); declinfo->x3C = 0; } } else { if (TYPE_FUNC(declinfo->thetype)->flags & (FUNC_VOLATILE | FUNC_CONST)) CError_Error(CErrorStr384); if (declinfo->operator_token && !CDecl_CheckOperatorType(declinfo, 0)) return NULL; list = CScope_GetLocalObject(nspace2, declinfo->name); if (declinfo->has_expltargs) return CTempl_TemplateFunctionCheck(declinfo, list); if (list) { if (copts.cplusplus) { obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, OverloadMode0, someotherflag); if (!obj) return NULL; if (pflag) *pflag = outflag; if (nspace) obj->nspace = nspace; } else { obj = OBJECT(list->object); if (!is_typesame(declinfo->thetype, obj->type) || (declinfo->qual & (Q_CONST | Q_PASCAL)) != (obj->qual & (Q_CONST | Q_PASCAL))) { CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual); r27 = 1; if (!IS_TYPE_FUNC(obj->type)) return NULL; } } if (!r27 && pflag) CDecl_FuncRedeclCheck(obj, declinfo, *pflag); } else { if (declinfo->nspace) CError_Error(CErrorStr336); if (declinfo->has_expltargs) { if (declinfo->name) CError_Error(CErrorStr140, declinfo->name->name); else CError_Error(CErrorStr127); } obj = CParser_NewFunctionObject(declinfo); if (nspace) obj->nspace = nspace; if (pflag) *pflag = 1; else CError_Error(CErrorStr127); CheckDefaultArgs(TYPE_FUNC(obj->type)->args); CScope_AddObject(nspace2, declinfo->name, OBJ_BASE(obj)); } } return obj; } void CDecl_TypedefDeclarator(DeclInfo *declinfo) { NameSpace *nspace; NameSpaceObjectList *list; ObjType *objt; nspace = declinfo->nspace; if (!nspace) nspace = cscope_current; CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST)); if (declinfo->x48 || declinfo->x44) CError_Error(CErrorStr121); if (declinfo->operator_token) CError_Error(CErrorStr193); objt = NULL; list = CScope_FindName(nspace, declinfo->name); if (list) { switch (list->object->otype) { case OT_TYPE: objt = OBJ_TYPE(list->object); break; case OT_TYPETAG: break; case OT_NAMESPACE: CError_Error(CErrorStr321); return; case OT_ENUMCONST: case OT_OBJECT: CError_Error(CErrorStr322); return; default: CError_FATAL(2156); } } if (objt) { const UInt32 mask = Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST; if (!is_typesame(objt->type, declinfo->thetype) || (objt->qual & mask) != (declinfo->qual & mask)) { CError_Error(CErrorStr249, declinfo->name->name, objt->type, objt->qual, declinfo->thetype, declinfo->qual); } else if (!copts.cplusplus && (copts.pedantic || copts.ANSIstrict)) { if (copts.pedantic) CError_Warning(CErrorStr122, declinfo->name->name); else CError_Error(CErrorStr122, declinfo->name->name); } return; } objt = galloc(sizeof(ObjType)); memclrw(objt, sizeof(ObjType)); objt->otype = OT_TYPE; objt->access = ACCESSPUBLIC; objt->type = declinfo->thetype; objt->qual = declinfo->qual; CScope_AddObject(nspace, declinfo->name, OBJ_BASE(objt)); if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(objt)); if (copts.cplusplus) { if (IS_TYPE_CLASS(declinfo->thetype) && IsTempName(TYPE_CLASS(declinfo->thetype)->classname)) { TYPE_CLASS(declinfo->thetype)->classname = declinfo->name; TYPE_CLASS(declinfo->thetype)->nspace->name = declinfo->name; } if (IS_TYPE_ENUM(declinfo->thetype) && IsTempName(TYPE_ENUM(declinfo->thetype)->enumname)) { TYPE_ENUM(declinfo->thetype)->enumname = declinfo->name; } } if (cparamblkptr->browseoptions.recordTypedefs && declinfo->file->recordbrowseinfo) CBrowse_NewTypedef(nspace, declinfo->name, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset()); } static void CDecl_DataDeclarator(DeclInfo *declinfo, AccessType access, Boolean flag) { NameSpaceObjectList *list; Object *obj; NameSpace *nspace; Boolean tmpflag; ENode *expr; nspace = declinfo->nspace; if (!nspace) nspace = cscope_current; CError_QualifierCheck(declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST)); if (declinfo->x48 || declinfo->x44) CError_Error(CErrorStr121); if (declinfo->operator_token) CError_Error(CErrorStr193); obj = NULL; list = CScope_FindName(nspace, declinfo->name); if (list) { switch (list->object->otype) { case OT_OBJECT: obj = OBJECT(list->object); if (flag) CError_Error(CErrorStr122, declinfo->name->name); break; case OT_TYPETAG: break; case OT_NAMESPACE: CError_Error(CErrorStr321); return; case OT_ENUMCONST: case OT_TYPE: CError_Error(CErrorStr322); break; case OT_MEMBERVAR: CError_Error(CErrorStr221); break; default: CError_FATAL(2281); } } if (copts.cplusplus) { if (!flag) CDecl_CompleteType(declinfo->thetype); switch (declinfo->storageclass) { case TK_EXTERN: if (tk == '=' || tk == '(') declinfo->storageclass = 0; break; case 0: if (CParser_IsConst(declinfo->thetype, declinfo->qual)) { if ((!obj && !nspace->theclass) || (obj && obj->sclass != TK_EXTERN && !obj->nspace->theclass)) declinfo->storageclass = TK_STATIC; } break; } } else { if (declinfo->storageclass == TK_EXTERN && tk == '=') declinfo->storageclass = 0; } if (IS_TYPE_ARRAY(declinfo->thetype) && !declinfo->thetype->size && !declinfo->storageclass && tk != '=') declinfo->storageclass = TK_EXTERN; if (obj) { if ((!obj->type->size || !declinfo->thetype->size) && IS_TYPE_ARRAY(declinfo->thetype) && IS_TYPE_ARRAY(obj->type)) tmpflag = is_typesame(TYPE_POINTER(declinfo->thetype)->target, TYPE_POINTER(obj->type)->target); else tmpflag = is_typesame(declinfo->thetype, obj->type); if (!tmpflag || (obj->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST)) != (declinfo->qual & (Q_PASCAL | Q_VOLATILE | Q_CONST))) CError_Error(CErrorStr249, CError_GetObjectName(obj), obj->type, obj->qual, declinfo->thetype, declinfo->qual); if (obj->qual & Q_INLINE_DATA) { if (tk == ',' || tk == ';') return; CError_Error(CErrorStr333, obj); } if (declinfo->storageclass != TK_EXTERN) { if (obj->sclass != TK_EXTERN && declinfo->storageclass && obj->sclass != declinfo->storageclass) CError_Error(CErrorStr333, obj); if (tmpflag) { obj->sclass = declinfo->storageclass; obj->qual |= declinfo->qual; if (declinfo->thetype->size) obj->type = declinfo->thetype; } CParser_UpdateObject(obj, declinfo); } else { flag = 1; } } else { if (declinfo->nspace) CError_Error(CErrorStr336); if (IS_TYPE_CLASS(declinfo->thetype) && TYPE_CLASS(declinfo->thetype)->sominfo) CError_Error(CErrorStr288); if (!CanCreateObject(declinfo->thetype)) declinfo->thetype = TYPE(&stsignedint); obj = CParser_NewGlobalDataObject(declinfo); obj->access = access; CScope_AddObject(nspace, declinfo->name, OBJ_BASE(obj)); if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) CTemplClass_RegisterObjectDef(TEMPL_CLASS(nspace->theclass), OBJ_BASE(obj)); if (flag && nspace->theclass && cparamblkptr->browseoptions.recordClasses) CBrowse_AddClassMemberData(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); } if (!flag) { if (declinfo->nspace) { CScopeSave save; CScope_SetNameSpaceScope(declinfo->nspace, &save); CInit_InitializeData(obj); CScope_RestoreScope(&save); if (declinfo->x3C && obj->nspace->theclass && (TYPE_CLASS(obj->nspace->theclass)->flags & CLASS_IS_TEMPL_INST)) declinfo->x3C = 0; } else { CInit_InitializeData(obj); } if (declinfo->file->recordbrowseinfo && obj->sclass != TK_EXTERN) CBrowse_NewData(obj, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset()); } else if (tk == '=') { tk = lex(); expr = CExpr_IntegralConstOrDepExpr(); if (IS_TYPE_TEMPLATE(obj->type) || !ENODE_IS(expr, EINTCONST)) { CError_ASSERT(2426, nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)); CTemplClass_RegisterObjectInit(TEMPL_CLASS(nspace->theclass), obj, expr); } else if ((obj->qual & Q_CONST) && IS_TYPE_INT_OR_ENUM(obj->type)) { obj->u.data.u.intconst = expr->data.intval; obj->qual |= Q_INLINE_DATA | Q_20000; } else { CError_Error(CErrorStr354, obj->name->name); } } } Boolean CDecl_FunctionDeclarator(DeclInfo *declinfo, NameSpace *nspace, Boolean flag, Boolean flag2) { Object *obj; Boolean pflag; obj = CDecl_GetFunctionObject(declinfo, nspace, &pflag, 0); if (obj) { if (declinfo->x44 || tk == '{' || tk == TK_TRY || (declinfo->x4B && tk == ':') || (!copts.cplusplus && isdeclaration(0, 0, 0, 0))) { if (!flag || cscope_currentfunc) { CError_Error(CErrorStr127); if (cscope_currentfunc) return 0; } if (obj->nspace == cscope_root && !strcmp(obj->name->name, "main")) { if (obj->sclass == TK_STATIC || (copts.ANSIstrict && TYPE_FUNC(obj->type)->functype != (Type *) &stsignedint)) CError_Error(CErrorStr334); } else if (copts.checkprotos && (pflag || declinfo->x64)) { if (obj->sclass != TK_STATIC && !(obj->qual & Q_INLINE) && !obj->nspace->is_unnamed) CError_Warning(CErrorStr178); } CFunc_ParseFuncDef(obj, declinfo, NULL, 0, 0, NULL); if (declinfo->file->recordbrowseinfo) CBrowse_NewFunction( obj, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset()); if (copts.cplusplus && lookahead() == ';') tk = lex(); return 0; } } return 1; } static void CDecl_ParseSpecialMember(DeclInfo *declinfo, Boolean flag) { Object *r28; NameSpace *r25; if (!(r28 = declinfo->x10)) { CError_ASSERT(2544, declinfo->x14); r28 = OBJECT(declinfo->x14->object); CError_ASSERT(2546, r28->otype == OT_OBJECT); } if (!r28->nspace->theclass) { CError_Error(CErrorStr121); return; } if (IS_TYPE_FUNC(r28->type)) { if (TYPE_FUNC(r28->type)->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR)) { if (r28->nspace->theclass->sominfo) declinfo->thetype = TYPE(&stvoid); else declinfo->thetype = TYPE(&void_ptr); declinfo->nspace = r28->nspace; declinfo->name = r28->name; if (TYPE_FUNC(r28->type)->flags & FUNC_IS_CTOR) declinfo->x4B = 1; if ((tk = lex()) == '(') { tk = lex(); r25 = cscope_current; cscope_current = r28->nspace; CDecl_ParseDirectFuncDecl(declinfo); cscope_current = r25; if (IS_TYPE_FUNC(declinfo->thetype)) { if (TYPE_FUNC(r28->type)->flags & FUNC_IS_CTOR) { if ((r28->nspace->theclass->flags & CLASS_HAS_VBASES) && !r28->nspace->theclass->sominfo) CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort)); } else { if (!r28->nspace->theclass->sominfo) CDecl_AddArgument(TYPE_FUNC(declinfo->thetype), TYPE(&stsignedshort)); } if (flag) CDecl_FunctionDeclarator(declinfo, NULL, 1, 1); } else { CError_Error(CErrorStr121); } } else { CError_Error(CErrorStr114); } return; } else if (TYPE_FUNC(r28->type)->flags & FUNC_CONVERSION) { CError_FATAL(2603); declinfo->thetype = TYPE_FUNC(r28->type)->functype; declinfo->qual |= TYPE_FUNC(r28->type)->qual; declinfo->nspace = r28->nspace; declinfo->name = r28->name; if ((tk = lex()) == '(') { tk = lex(); CDecl_ParseDirectFuncDecl(declinfo); if (IS_TYPE_FUNC(declinfo->thetype)) { TYPE_FUNC(declinfo->thetype)->flags |= FUNC_CONVERSION; if (flag) CDecl_FunctionDeclarator(declinfo, NULL, 1, 1); } else { CError_Error(CErrorStr121); } } else { CError_Error(CErrorStr114); } return; } else { declinfo->thetype = TYPE(&stsignedint); declinfo->nspace = r28->nspace; declinfo->name = r28->name; if ((tk = lex()) == '(') { tk = lex(); r25 = cscope_current; cscope_current = r28->nspace; CDecl_ParseDirectFuncDecl(declinfo); cscope_current = r25; if (IS_TYPE_FUNC(declinfo->thetype)) { if (flag) CDecl_FunctionDeclarator(declinfo, NULL, 1, 1); return; } } else { CError_Error(CErrorStr114); } } } CError_Error(CErrorStr121); } void CDecl_ScanDeclarator(DeclInfo *declinfo) { if (declinfo->x14 || declinfo->x10) { CDecl_ParseSpecialMember(declinfo, 0); CDecl_GetFunctionObject(declinfo, NULL, NULL, 1); return; } if (IS_TYPE_FUNC(declinfo->thetype)) { TypeFunc *copy = galloc(sizeof(TypeFunc)); *copy = *TYPE_FUNC(declinfo->thetype); declinfo->thetype = TYPE(copy); } scandeclarator(declinfo); if (!declinfo->name) { CError_Error(CErrorStr121); return; } if (declinfo->storageclass && declinfo->storageclass != TK_EXTERN) CError_Error(CErrorStr177); if (IS_TYPE_FUNC(declinfo->thetype)) { CDecl_GetFunctionObject(declinfo, NULL, NULL, 1); return; } if (declinfo->x48 || declinfo->x44) CError_Error(CErrorStr121); if (declinfo->operator_token) CError_Error(CErrorStr193); if ( (declinfo->qual & ~(Q_ALIGNED_MASK | Q_WEAK | Q_20000 | Q_PASCAL | Q_VOLATILE | Q_CONST)) || (declinfo->storageclass == TK_TYPEDEF && (declinfo->qual & ~(Q_ALIGNED_MASK | Q_REFERENCE | Q_PASCAL | Q_VOLATILE | Q_CONST))) ) CError_Error(CErrorStr176); } void scandeclaratorlist(DeclInfo *declinfo) { CScopeSave savescope; Type *r30; UInt32 r29; Boolean r28; if (declinfo->x14 || declinfo->x10) { CDecl_ParseSpecialMember(declinfo, 1); return; } CScope_GetScope(&savescope); CError_ASSERT(2707, declinfo->thetype); r28 = 1; while (1) { r30 = declinfo->thetype; r29 = declinfo->qual; declinfo->nspace = NULL; declinfo->operator_token = 0; if (IS_TYPE_FUNC(r30)) { declinfo->thetype = galloc(sizeof(TypeFunc)); *TYPE_FUNC(declinfo->thetype) = *TYPE_FUNC(r30); } declinfo->name = NULL; scandeclarator(declinfo); if (!declinfo->name) { CError_Error(CErrorStr121); break; } if (declinfo->storageclass != TK_TYPEDEF) { if (IS_TYPE_FUNC(declinfo->thetype)) { if (!CDecl_FunctionDeclarator(declinfo, NULL, r28, 1)) return; } else { CDecl_DataDeclarator(declinfo, ACCESSPUBLIC, 0); } } else { CDecl_TypedefDeclarator(declinfo); } CScope_RestoreScope(&savescope); declinfo->thetype = r30; declinfo->qual = r29; if (tk != ',') break; tk = lex(); r28 = 0; } if (tk != ';') CError_Error(CErrorStr123); } static TypeIntegral *CDecl_FindSignedType(short size) { if (stsignedchar.size == size) return &stsignedchar; if (stsignedshort.size == size) return &stsignedshort; if (stsignedint.size == size) return &stsignedint; if (stsignedlong.size == size) return &stsignedlong; if (copts.longlong && copts.longlong_enums && stsignedlonglong.size == size) return &stsignedlonglong; return &stsignedlong; } static TypeIntegral *CDecl_FindUnsignedType(short size) { if (stunsignedchar.size == size) return &stunsignedchar; if (stunsignedshort.size == size) return &stunsignedshort; if (stunsignedint.size == size) return &stunsignedint; if (stunsignedlong.size == size) return &stunsignedlong; if (copts.longlong && copts.longlong_enums && stunsignedlonglong.size == size) return &stunsignedlonglong; return &stunsignedlong; } static TypeIntegral *CDecl_IterateIntegralEnumType(int *t) { switch (*t) { case 0: *t = 1; return &stsignedchar; case 1: if (stsignedshort.size > stsignedchar.size) { *t = 2; return &stsignedshort; } case 2: if (stsignedint.size > stsignedshort.size) { *t = 3; return &stsignedint; } case 3: if (stsignedlong.size > stsignedint.size) { *t = 4; return &stsignedlong; } case 4: *t = 5; if (stsignedlonglong.size > stsignedlong.size && copts.longlong && copts.longlong_enums) return &stsignedlonglong; default: return NULL; } } static TypeIntegral *CDecl_IterateUIntegralEnumType(int *t) { switch (*t) { case 0: *t = 1; return &stunsignedchar; case 1: if (stunsignedshort.size > stunsignedchar.size) { *t = 2; return &stunsignedshort; } case 2: if (stunsignedint.size > stunsignedshort.size) { *t = 3; return &stunsignedint; } case 3: if (stunsignedlong.size > stunsignedint.size) { *t = 4; return &stunsignedlong; } case 4: *t = 5; if (stunsignedlonglong.size > stunsignedlong.size && copts.longlong && copts.longlong_enums) return &stunsignedlonglong; default: return NULL; } } static TypeEnum *CDecl_OldParseEnumList(TypeEnum *tenum, HashNameNode *name) { AccessType access; Boolean has_template_value; Boolean r24; Boolean r23; ObjEnumConst *oec; ObjEnumConst *last; Boolean overflowed; CInt64 val; CInt64 minimum; CInt64 maximum; CInt64 var_74; CInt64 unused; Type *basetype; Type *basetype2; CPrepFileInfo *fileinfo; SInt32 offset; ENode *expr; Type *tmp; if (!tenum) { tenum = galloc(sizeof(TypeEnum)); memclrw(tenum, sizeof(TypeEnum)); tenum->type = TYPEENUM; tenum->nspace = cscope_current; if (name) { tenum->enumname = name; CScope_DefineTypeTag(cscope_current, name, TYPE(tenum)); } if (!cscope_current->is_global) { do { tenum->nspace = tenum->nspace->parent; } while (!tenum->nspace->is_global); if (tenum->enumname) tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name); } } if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL)) { CTemplClass_RegisterEnumType(TEMPL_CLASS(cscope_current->theclass), tenum); } access = cscope_current->theclass ? global_access : ACCESSPUBLIC; last = NULL; unused = cint64_zero; val = cint64_zero; minimum = cint64_zero; maximum = cint64_zero; r23 = 0; if (copts.enumsalwaysint) { basetype = TYPE(&stsignedint); r24 = 1; } else { basetype = TYPE(&stunsignedchar); r24 = 0; } tk = lex(); if (!copts.cplusplus || tk != '}') { do { if (tk != TK_IDENTIFIER) { if (tk == '}') { if (copts.cpp_extensions) break; if (!copts.warn_extracomma) break; } CError_Warning(CErrorStr107); break; } oec = galloc(sizeof(ObjEnumConst)); memclrw(oec, sizeof(ObjEnumConst)); oec->otype = OT_ENUMCONST; oec->access = access; oec->type = TYPE(tenum); oec->name = tkidentifier; CPrep_BrowserFilePosition(&fileinfo, &offset); overflowed = 0; if ((tk = lex()) == '=') { tk = lex(); val = CExpr_IntegralConstExprType(&basetype2); if (!CInt64_IsNegative(&val) || is_unsigned(basetype2)) { if (CInt64_GreaterU(val, minimum)) { minimum = val; overflowed = 1; } } else { if (CInt64_Less(val, maximum)) { maximum = val; overflowed = 1; } if (!r24) { basetype = TYPE(&stsignedchar); r24 = 1; } } r23 = 0; } else { if (r23) CError_Error(CErrorStr154); if (!r24 || !CInt64_IsNegative(&val)) { if (CInt64_GreaterU(val, minimum)) { minimum = val; overflowed = 1; } } else { if (CInt64_Less(val, maximum)) { maximum = val; overflowed = 1; } } } if (copts.enumsalwaysint) { if (copts.ANSIstrict) { if (!CInt64_IsInRange(val, stsignedint.size)) CError_Error(CErrorStr154); } else { if (!CInt64_IsInRange(val, stsignedint.size) && !CInt64_IsInURange(val, stunsignedint.size)) CError_Error(CErrorStr154); } } else if (r24) { switch (basetype->size) { case 1: if (CInt64_IsInRange(minimum, 1) && CInt64_IsInRange(maximum, 1)) break; basetype = TYPE(CDecl_FindSignedType(2)); case 2: if (CInt64_IsInRange(minimum, 2) && CInt64_IsInRange(maximum, 2)) break; basetype = TYPE(CDecl_FindSignedType(4)); case 4: if (CInt64_IsInRange(minimum, 4) && CInt64_IsInRange(maximum, 4)) break; basetype = TYPE(CDecl_FindSignedType(8)); if (basetype->size != 8) { if (!copts.ANSIstrict && CInt64_IsInRange(maximum, 4) && CInt64_IsInURange(minimum, 4)) break; if (overflowed) CError_Error(CErrorStr154); break; } case 8: if (CInt64_Equal(val, minimum) && CInt64_IsNegative(&val)) CError_Error(CErrorStr154); break; default: CError_FATAL(3071); } } else { switch (basetype->size) { case 1: if (CInt64_IsInURange(minimum, 1)) break; basetype = TYPE(CDecl_FindUnsignedType(2)); case 2: if (CInt64_IsInURange(minimum, 2)) break; basetype = TYPE(CDecl_FindUnsignedType(4)); case 4: if (CInt64_IsInURange(minimum, 4)) break; basetype = TYPE(CDecl_FindUnsignedType(8)); if (basetype->size != 8) { if (overflowed) CError_Error(CErrorStr154); break; } case 8: break; default: CError_FATAL(3099); } } tenum->size = basetype->size; tenum->enumtype = basetype; oec->val = val; CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec)); if (last) { last->next = oec; last = oec; } else { last = oec; tenum->enumlist = oec; } if (cparamblkptr->browseoptions.recordEnums) { CPrepFileInfo *f = CPrep_BrowserCurrentFile(); if (f->recordbrowseinfo) { CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset()); } } var_74 = CInt64_Add(val, cint64_one); if (r24) { if (CInt64_IsNegative(&var_74) && !CInt64_IsNegative(&val)) r23 = 1; } else { if (CInt64_IsZero(&var_74)) r23 = 1; } val = var_74; if (tk != ',') break; tk = lex(); } while (1); } tenum->size = basetype->size; tenum->enumtype = basetype; for (oec = tenum->enumlist; oec; oec = oec->next) oec->type = TYPE(tenum); if (tk != '}') CError_ErrorSkip(CErrorStr130); else tk = lex(); return tenum; } static Type *CDecl_MaxType(Type *a, Type *b) { if (a->size > b->size) return a; if (b->size > a->size) return b; if (is_unsigned(b)) return b; else return a; } void CDecl_ComputeUnderlyingEnumType(TypeEnum *tenum) { ObjEnumConst *oec; ObjEnumConst *oec2; Type *r26; int t; if (!copts.enumsalwaysint) { for (oec2 = tenum->enumlist; oec2; oec2 = oec2->next) { if (CInt64_IsNegative(&oec2->val) && !is_unsigned(oec2->type)) break; } if (oec2) { CInt64 unused = cint64_zero; CInt64 minimum = cint64_zero; CInt64 maximum = cint64_zero; for (oec = tenum->enumlist; oec; oec = oec->next) { if (CInt64_IsNegative(&oec->val) && !is_unsigned(oec->type)) { if (CInt64_Less(oec->val, minimum)) minimum = oec->val; } else { if (CInt64_GreaterU(oec->val, maximum)) maximum = oec->val; } } if (CInt64_IsNegative(&maximum)) CError_Error(CErrorStr154); t = 0; do { r26 = TYPE(CDecl_IterateIntegralEnumType(&t)); if (!r26) { r26 = TYPE(&stsignedlong); CError_Error(CErrorStr154); break; } if (CInt64_IsInRange(maximum, r26->size) && CInt64_IsInRange(minimum, r26->size)) break; if (r26->size == stsignedlong.size && !copts.ANSIstrict && CInt64_IsInRange(minimum, r26->size) && CInt64_IsInURange(maximum, r26->size)) break; } while (1); } else { CInt64 val = cint64_zero; for (oec = tenum->enumlist; oec; oec = oec->next) { if (CInt64_GreaterU(oec->val, val)) val = oec->val; } t = 0; do { r26 = TYPE(CDecl_IterateUIntegralEnumType(&t)); if (!r26) { r26 = TYPE(&stunsignedlong); CError_Error(CErrorStr154); break; } if (CInt64_IsInURange(val, r26->size)) break; } while (1); } } else { r26 = TYPE(&stsignedint); } tenum->size = r26->size; tenum->enumtype = r26; for (oec = tenum->enumlist; oec; oec = oec->next) oec->type = TYPE(tenum); } static Type *CDecl_FindUnderlyingType(short size, CInt64 *a, CInt64 *b) { if (CInt64_IsZero(a)) { if (size <= stsignedchar.size && CInt64_IsInURange(*b, stunsignedchar.size)) return TYPE(&stunsignedchar); if (size <= stsignedshort.size && CInt64_IsInURange(*b, stunsignedshort.size)) return TYPE(&stunsignedshort); if (size <= stsignedint.size && CInt64_IsInURange(*b, stunsignedint.size)) return TYPE(&stunsignedint); if (size <= stsignedlong.size && CInt64_IsInURange(*b, stunsignedlong.size)) return TYPE(&stunsignedlong); if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInURange(*b, stunsignedlonglong.size)) return TYPE(&stunsignedlonglong); } else { if (size <= stsignedchar.size && CInt64_IsInRange(*a, stsignedchar.size) && CInt64_IsInRange(*b, stsignedchar.size)) return TYPE(&stsignedchar); if (size <= stsignedshort.size && CInt64_IsInRange(*a, stsignedshort.size) && CInt64_IsInRange(*b, stsignedshort.size)) return TYPE(&stsignedshort); if (size <= stsignedint.size && CInt64_IsInRange(*a, stsignedint.size) && CInt64_IsInRange(*b, stsignedint.size)) return TYPE(&stsignedint); if (size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInRange(*b, stsignedlong.size)) return TYPE(&stsignedlong); if (size <= stsignedlonglong.size && copts.longlong && copts.longlong_enums && CInt64_IsInRange(*a, stsignedlonglong.size) && CInt64_IsInRange(*b, stsignedlonglong.size)) return TYPE(&stsignedlonglong); if (!copts.ANSIstrict && size <= stsignedlong.size && CInt64_IsInRange(*a, stsignedlong.size) && CInt64_IsInURange(*b, stunsignedlong.size)) return TYPE(&stsignedlong); } return NULL; } static TypeEnum *CDecl_ParseEnumList(TypeEnum *tenum, HashNameNode *name) { AccessType access; TemplClass *tmclass; ObjEnumConst *oec; Boolean has_template_value; Boolean overflowed; Boolean is_first; CInt64 val; CInt64 minimum; CInt64 maximum; CInt64 unused; Type *basetype; CPrepFileInfo *fileinfo; SInt32 offset; ENode *expr; Type *tmp; ObjEnumConst *last; if (!tenum) { tenum = galloc(sizeof(TypeEnum)); memclrw(tenum, sizeof(TypeEnum)); tenum->type = TYPEENUM; tenum->nspace = cscope_current; if (name) { tenum->enumname = name; CScope_DefineTypeTag(cscope_current, name, TYPE(tenum)); } if (!cscope_current->is_global) { do { tenum->nspace = tenum->nspace->parent; } while (!tenum->nspace->is_global); if (tenum->enumname) tenum->enumname = CParser_AppendUniqueNameFile(tenum->enumname->name); } } if (cscope_current->theclass && (cscope_current->theclass->flags & CLASS_IS_TEMPL)) { tmclass = TEMPL_CLASS(cscope_current->theclass); CTemplClass_RegisterEnumType(tmclass, tenum); } else { tmclass = NULL; } access = cscope_current->theclass ? global_access : ACCESSPUBLIC; last = NULL; is_first = 1; has_template_value = 0; unused = cint64_zero; val = cint64_zero; minimum = cint64_zero; maximum = cint64_zero; basetype = copts.enumsalwaysint ? TYPE(&stsignedint) : TYPE(&stsignedchar); tenum->size = basetype->size; tenum->enumtype = basetype; do { if ((tk = lex()) != TK_IDENTIFIER) { if (tk == '}') { if (is_first) { if (copts.cplusplus) break; } else { if (!copts.warn_extracomma) break; if (copts.c9x) break; if (copts.cpp_extensions) break; } CError_Warning(CErrorStr107); } else { CError_Error(CErrorStr107); } break; } oec = galloc(sizeof(ObjEnumConst)); memclrw(oec, sizeof(ObjEnumConst)); oec->otype = OT_ENUMCONST; oec->access = access; oec->name = tkidentifier; CPrep_BrowserFilePosition(&fileinfo, &offset); overflowed = 0; if ((tk = lex()) == '=') { tk = lex(); if (tmclass) { expr = CExpr_IntegralConstOrDepExpr(); if (ENODE_IS(expr, EINTCONST)) { val = expr->data.intval; basetype = expr->rtype; has_template_value = 0; } else { val = cint64_zero; basetype = TYPE(tenum); CTemplClass_RegisterEnumerator(tmclass, oec, expr); has_template_value = 1; } } else { val = CExpr_IntegralConstExprType(&basetype); has_template_value = 0; } } else if (has_template_value) { CTemplClass_RegisterEnumerator(tmclass, oec, NULL); } else if (!is_first) { if (is_unsigned(basetype)) { val = CInt64_Add(val, cint64_one); if (CInt64_IsZero(&val)) overflowed = 1; } else if (!CInt64_IsNegative(&val)) { val = CInt64_Add(val, cint64_one); if (CInt64_IsNegative(&val)) overflowed = 1; } else { val = CInt64_Add(val, cint64_one); } } if (!has_template_value) { if (copts.enumsalwaysint) { if (!CInt64_IsInRange(val, stsignedint.size) && (copts.ANSIstrict || !CInt64_IsInURange(val, stunsignedint.size))) overflowed = 1; basetype = TYPE(&stsignedint); } else if (CInt64_IsNegative(&val) && !is_unsigned(basetype)) { if (CInt64_Less(val, minimum)) { minimum = val; if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) { tenum->size = tmp->size; tenum->enumtype = tmp; } else { overflowed = 1; } } } else { if (CInt64_GreaterU(val, maximum)) { maximum = val; if ((tmp = CDecl_FindUnderlyingType(tenum->size, &minimum, &maximum))) { tenum->size = tmp->size; tenum->enumtype = tmp; } else { overflowed = 1; } } } } if (overflowed) CError_Error(CErrorStr154); oec->val = val; oec->type = basetype; CScope_AddObject(cscope_current, oec->name, OBJ_BASE(oec)); if (last) { last->next = oec; last = oec; } else { last = oec; tenum->enumlist = oec; } if (cparamblkptr->browseoptions.recordEnums) { CPrepFileInfo *f = CPrep_BrowserCurrentFile(); if (f->recordbrowseinfo) { CBrowse_NewEnumConstant(cscope_current, oec->name, f, fileinfo, offset, CPrep_BrowserFileOffset()); } } is_first = 0; } while (tk == ','); for (oec = tenum->enumlist; oec; oec = oec->next) oec->type = TYPE(tenum); if (tk != '}') CError_ErrorSkip(CErrorStr130); else tk = lex(); return tenum; } void scanenum(DeclInfo *declinfo) { HashNameNode *name; Type *type; NameResult pr; if (tk == '{') { declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL)); TYPE_ENUM(declinfo->thetype)->enumname = CParser_AppendUniqueNameFile("@enum"); return; } if (tk == TK_IDENTIFIER) { name = tkidentifier; if (lookahead() == '{') { type = CScope_GetLocalTagType(cscope_current, name); if (type) { lex(); do_shit: if (type->size || !IS_TYPE_ENUM(type)) { CError_Error(CErrorStr122, name->name); declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, NULL)); return; } declinfo->thetype = TYPE(CDecl_ParseEnumList(TYPE_ENUM(type), NULL)); } else { lex(); declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, name)); } if (cparamblkptr->browseoptions.recordEnums && declinfo->file->recordbrowseinfo) CBrowse_NewEnum( cscope_current, TYPE_ENUM(declinfo->thetype)->enumname, declinfo->file, declinfo->file2, declinfo->sourceoffset, CPrep_BrowserFileOffset()); return; } else { CError_ASSERT(3851, !copts.cplusplus || tk != ';'); tkidentifier = name; } } if (CScope_ParseElaborateName(&pr)) { if ((type = pr.type)) { if (!IS_TYPE_ENUM(type)) CError_Error(CErrorStr121); if ((tk = lex()) == '{') goto do_shit; declinfo->thetype = type; return; } else { CError_ASSERT(3865, pr.name_4); if ((tk = lex()) == '{') { declinfo->thetype = TYPE(CDecl_ParseEnumList(NULL, pr.name_4)); return; } else { CError_Error(CErrorStr140, pr.name_4->name); } } } else { CError_Error(CErrorStr121); } declinfo->thetype = TYPE(&stsignedint); } void CDecl_ScanStructDeclarator(BigDeclInfo *bde) { ENode *expr; short val; short bits; Boolean is_bitfield; TypeTemplDep *ttempl; TypeBitfield *tbitfield; Type *type; bde->declinfo2 = bde->declinfo; bde->declinfo2.name = NULL; bde->declinfo2.operator_token = 0; bde->xCD = 0; is_bitfield = 0; if (tk == ':') { bde->declinfo2.name = no_name_node; is_bitfield = 1; } else { bde->declinfo2.x50 = 1; scandeclarator(&bde->declinfo2); if (!bde->declinfo2.name) { CError_Error(CErrorStr131); return; } if ((!copts.ANSIstrict || copts.c9x) && !bde->declinfo2.thetype->size && IS_TYPE_ARRAY(bde->declinfo2.thetype)) { if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) { type = TYPE_POINTER(bde->declinfo2.thetype)->target; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (!IsCompleteType(type)) return; if (tk != ';' || lookahead() != '}') { CError_Error(CErrorStr145); return; } } } else { if (bde->declinfo2.storageclass != TK_STATIC && bde->declinfo2.storageclass != TK_TYPEDEF) { if (!IS_TYPE_FUNC(bde->declinfo2.thetype) && !IsCompleteType(bde->declinfo2.thetype)) return; } } if (IS_TYPE_CLASS(bde->declinfo2.thetype) && TYPE_CLASS(bde->declinfo2.thetype)->sominfo) { CError_Error(CErrorStr287); return; } if (tk != ':') goto not_a_bitfield; } if (!IS_TYPE_INT_OR_ENUM(bde->declinfo2.thetype)) { if (CTemplTool_IsTemplateArgumentDependentType(bde->declinfo2.thetype)) goto fuckup; CError_Error(CErrorStr138); bde->declinfo2.thetype = TYPE(&stunsignedint); } else if (copts.ANSIstrict && !copts.cplusplus) { if (bde->declinfo2.thetype != TYPE(&stsignedint) && bde->declinfo2.thetype != TYPE(&stunsignedint)) { CError_Error(CErrorStr138); bde->declinfo2.thetype = TYPE(&stunsignedint); } } switch (bde->declinfo2.thetype->size) { case 1: bits = 8; break; case 2: bits = 16; break; case 4: bits = 32; break; default: CError_Error(CErrorStr138); return; } fuckup: tk = lex(); expr = CExpr_IntegralConstOrDepExpr(); if (!ENODE_IS(expr, EINTCONST)) { ttempl = TYPE_TEMPLATE(CDecl_NewTemplDepType(TEMPLDEP_BITFIELD)); ttempl->u.bitfield.type = bde->declinfo2.thetype; ttempl->u.bitfield.size = CInline_CopyExpression(expr, CopyMode1); bde->declinfo2.thetype = TYPE(ttempl); bde->xCD = 1; return; } val = CInt64_GetULong(&expr->data.intval); if (is_bitfield) { if (val < 0 || val > bits) { CError_Error(CErrorStr138); return; } } else { if (val <= 0 || val > bits) { CError_Error(CErrorStr138); return; } } tbitfield = galloc(sizeof(TypeBitfield)); memclrw(tbitfield, sizeof(TypeBitfield)); tbitfield->type = TYPEBITFIELD; tbitfield->size = bde->declinfo2.thetype->size; tbitfield->bitfieldtype = bde->declinfo2.thetype; tbitfield->bitlength = val; bde->declinfo2.thetype = TYPE(tbitfield); if (tk == TK_UU_ATTRIBUTE_UU) CParser_ParseAttribute(NULL, &bde->declinfo2); not_a_bitfield: bde->xCD = 1; } static void CDecl_LayoutStruct(TypeStruct *tstruct) { StructMember *member; SInt32 r28; StructMember *innermember; SInt32 innerbase; StructMember *newmember; StructMember **memberp; TypeBitfield *bf; SInt32 r24; Boolean r23; SInt32 tmp; r28 = 0; r23 = 0; CMach_StructLayoutInitOffset(0); for (member = tstruct->members; member; member = member->next) { if (tstruct->stype == STRUCT_TYPE_UNION) CMach_StructLayoutInitOffset(0); if (IS_TYPE_BITFIELD(member->type)) member->offset = CMach_StructLayoutBitfield(TYPE_BITFIELD(member->type), member->qual); else member->offset = CMach_StructLayoutGetOffset(member->type, member->qual); if (tstruct->stype == STRUCT_TYPE_UNION) { tmp = CMach_StructLayoutGetCurSize(); if (tmp > r28) r28 = tmp; } if (member->name == no_name_node) r23 = 1; if (!member->name) { CError_ASSERT(4064, IS_TYPE_STRUCT(member->type)); innerbase = member->offset; innermember = TYPE_STRUCT(member->type)->members; r23 = 1; while (innermember) { if (ismember(tstruct, innermember->name)) CError_Error(CErrorStr133, innermember->name->name); if (r23) { member->type = innermember->type; member->name = innermember->name; member->qual = innermember->qual; member->offset = innerbase + innermember->offset; } else { newmember = galloc(sizeof(StructMember)); memclrw(newmember, sizeof(StructMember)); newmember->next = member->next; newmember->type = innermember->type; newmember->name = innermember->name; newmember->qual = innermember->qual | Q_WEAK; newmember->offset = innerbase + innermember->offset; member->next = newmember; member = newmember; } if (copts.reverse_bitfields && IS_TYPE_BITFIELD(member->type)) { bf = galloc(sizeof(TypeBitfield)); *bf = *TYPE_BITFIELD(member->type); CABI_ReverseBitField(bf); member->type = TYPE(bf); } r23 = 0; innermember = innermember->next; } r23 = 1; } } if (r23) { memberp = &tstruct->members; while (*memberp) { if ((*memberp)->name == no_name_node || !(*memberp)->name) *memberp = (*memberp)->next; else memberp = &(*memberp)->next; } } if (tstruct->stype == STRUCT_TYPE_UNION) r24 = r28; else r24 = CMach_StructLayoutGetCurSize(); tstruct->size = r24; tstruct->align = CMach_GetStructAlign(tstruct); tstruct->size = r24 + CABI_StructSizeAlignValue(TYPE(tstruct), r24); if (copts.reverse_bitfields) { for (member = tstruct->members; member; member = member->next) { if (IS_TYPE_BITFIELD(member->type)) CABI_ReverseBitField(TYPE_BITFIELD(member->type)); } } if (copts.warn_padding && tstruct->stype != STRUCT_TYPE_UNION) { StructMember *prev; member = tstruct->members; prev = NULL; while (member) { if (prev && (prev->offset + prev->type->size) < member->offset) { CError_Warning(CErrorStr350, member->offset - (prev->offset + prev->type->size), prev->name->name); } prev = member; member = member->next; } if (prev && (prev->offset + prev->type->size) < tstruct->size) { CError_Warning(CErrorStr350, tstruct->size - (prev->offset + prev->type->size), prev->name->name); } } } static SInt32 scanstructdeclarationlist(TypeStruct *tstruct, Boolean flag) { SInt32 offset; StructMember *member; BigDeclInfo bde; offset = -1; memclrw(&bde, sizeof(BigDeclInfo)); if (tk == TK_AT_DEFS) { CPrep_NewFileOffsetInfo(&member_fileoffset, NULL); CObjC_ParseDefs(tstruct); if ((tk = lex()) != '}') CError_Error(CErrorStr130); } else { do { CPrep_NewFileOffsetInfo(&member_fileoffset, NULL); memclrw(&bde.declinfo, sizeof(DeclInfo)); CParser_GetDeclSpecs(&bde.declinfo, 0); if (bde.declinfo.storageclass || bde.declinfo.x44) { CError_Error(CErrorStr131); tstruct->members = NULL; return -1; } if (tk != ';') { while (1) { CDecl_ScanStructDeclarator(&bde); if (!CanCreateObject(bde.declinfo2.thetype)) { CError_Error(CErrorStr131); bde.xCD = 0; } if (bde.declinfo2.operator_token) { CError_Error(CErrorStr131); bde.xCD = 0; } if (bde.xCD) { if (bde.declinfo2.name == no_name_node || !ismember(tstruct, bde.declinfo2.name)) { member = galloc(sizeof(StructMember)); memclrw(member, sizeof(StructMember)); member->type = bde.declinfo2.thetype; member->name = bde.declinfo2.name; member->qual = bde.declinfo2.qual; appendmember(tstruct, member); if (flag) { CBrowse_AddStructMember(member, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); } } else { CError_Error(CErrorStr133, bde.declinfo2.name->name); } } if (tk != ',') break; tk = lex(); } } else if (!copts.ANSIstrict && IS_TYPE_STRUCT(bde.declinfo.thetype)) { member = galloc(sizeof(StructMember)); memclrw(member, sizeof(StructMember)); member->type = bde.declinfo.thetype; appendmember(tstruct, member); } else { CError_Error(CErrorStr131); } if (tk != ';') { tstruct->members = NULL; CError_Error(CErrorStr123); return -1; } CPrep_TokenStreamFlush(); } while ((tk = lex()) != '}'); CDecl_LayoutStruct(tstruct); } if (flag) { offset = CPrep_BrowserFileOffset(); if (tk == ';') offset++; } tk = lex(); return offset; } static TypeStruct *CDecl_DefineStruct(HashNameNode *name, short stype) { TypeStruct *tstruct; tstruct = galloc(sizeof(TypeStruct)); memclrw(tstruct, sizeof(TypeStruct)); tstruct->type = TYPESTRUCT; tstruct->align = 1; tstruct->stype = stype; if (name) { tstruct->name = name; CScope_DefineTypeTag((in_func_arglist && !copts.cplusplus) ? cscope_root : cscope_current, name, (Type *) tstruct); } return tstruct; } void scanstruct(DeclInfo *declinfo, short structtype) { Type *type; HashNameNode *name; TypeStruct typecopy; Boolean add_to_browse; GList gl; SInt32 offset; if (copts.cplusplus) { CDecl_ParseClass(declinfo, structtype, 1, 0); return; } if (tk == TK_IDENTIFIER) { name = tkidentifier; type = CScope_GetTagType(cscope_current, name); if (type) { if (IS_TYPE_CLASS(type)) { CDecl_ParseClass(declinfo, structtype, 1, 0); return; } tk = lex(); if (!CScope_GetLocalTagType(cscope_current, name) && (tk == ';' || tk == '{')) type = (Type *) CDecl_DefineStruct(name, structtype); if (!IS_TYPE_STRUCT(type) || TYPE_STRUCT(type)->stype != structtype) { CError_Error(CErrorStr132, name->name); declinfo->thetype = type; return; } if (tk != '{') { declinfo->thetype = type; return; } if (type->size) { CError_Error(CErrorStr132, name->name); type = (Type *) CDecl_DefineStruct(NULL, structtype); } } else { type = (Type *) CDecl_DefineStruct(name, structtype); if ((tk = lex()) != '{') { declinfo->thetype = type; return; } } } else if (tk != '{') { CError_Error(CErrorStr131); declinfo->thetype = (Type *) &stsignedint; return; } else { type = (Type *) CDecl_DefineStruct(NULL, structtype); } if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo)) CBrowse_BeginStruct(declinfo, TYPE_STRUCT(type), &gl); typecopy = *TYPE_STRUCT(type); tk = lex(); offset = scanstructdeclarationlist(&typecopy, add_to_browse); *TYPE_STRUCT(type) = typecopy; declinfo->thetype = type; if (add_to_browse) CBrowse_EndStruct(offset, &gl); } static void InlineFunctionObject(Object *obj, TypeClass *tclass) { TokenStream stream; CPrepFileInfo *file; obj->qual |= Q_INLINE; TYPE_FUNC(obj->type)->flags |= FUNC_DEFINED; CPrep_StreamGetBlock(&stream, NULL, 1); if (stream.tokens) { if (IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type)) && (TYPE_METHOD(obj->type)->theclass->flags & CLASS_IS_TEMPL)) { TYPE_FUNC(obj->type)->flags |= FUNC_IS_TEMPL_INSTANCE; CTemplClass_DefineMember(TEMPL_CLASS(TYPE_METHOD(obj->type)->theclass), obj, &member_fileoffset, &stream); } else { CInline_AddInlineFunctionAction(obj, tclass, &member_fileoffset, &stream, 0); } } file = CPrep_BrowserCurrentFile(); if (file->recordbrowseinfo) { CBrowse_NewFunction( obj, file, member_fileoffset.file, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); } if (lookahead() == ';') tk = lex(); else tk = ';'; } void CDecl_ExtractClassExportFlags(DeclInfo *declinfo, UInt8 flags) { if (flags & CLASS_EFLAGS_INTERNAL) declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_INTERNAL; if (flags & CLASS_EFLAGS_IMPORT) declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_IMPORT; if (flags & CLASS_EFLAGS_EXPORT) declinfo->exportflags = declinfo->exportflags | EXPORT_FLAGS_EXPORT; } TypeMemberFunc *CDecl_MakeTypeMemberFunc(TypeFunc *tfunc, TypeClass *tclass, Boolean flag) { TypeMemberFunc *method; method = galloc(sizeof(TypeMemberFunc)); memclrw(method, sizeof(TypeMemberFunc)); *TYPE_FUNC(method) = *tfunc; method->theclass = tclass; method->is_static = flag; method->flags |= FUNC_METHOD; if (!flag) CDecl_AddThisPointerArgument(TYPE_FUNC(method), tclass); if ((flag || (tfunc->flags & (FUNC_IS_CTOR | FUNC_IS_DTOR))) && (tfunc->flags & (FUNC_CONST | FUNC_VOLATILE))) CError_Error(CErrorStr384); return method; } static void CDecl_MakeFunctionVirtual(TypeClass *tclass, Object *func) { if (is_pascal_object(func)) CError_Error(CErrorStr219); if (tclass->mode == CLASS_MODE_UNION) CError_Error(CErrorStr352, func); func->datatype = DVFUNC; } static void CDecl_AddFunctionMember(ClassLayout *decle, TypeClass *tclass, DeclInfo *declinfo, AccessType access, Boolean flag1, Boolean flag2, Boolean flag3, Boolean flag4) { NameSpaceObjectList *list; // r20 Object *obj; // also r20 TypeMemberFunc *tfunc; // r19 Boolean r31; Boolean outflag; if (IS_TYPE_ARRAY(TYPE_FUNC(declinfo->thetype)->functype) || IS_TYPE_FUNC(TYPE_FUNC(declinfo->thetype)->functype)) { CError_Error(CErrorStr128); TYPE_FUNC(declinfo->thetype)->functype = (Type *) &stsignedint; } if (tclass->sominfo) CSOM_CheckFuncType(TYPE_FUNC(declinfo->thetype)); r31 = 0; if (declinfo->qual & Q_VIRTUAL) { declinfo->qual &= ~Q_VIRTUAL; r31 = 1; flag1 = 1; } if ((list = CScope_FindName(tclass->nspace, declinfo->name))) { if (list->object->otype != OT_TYPETAG) { if (list->object->otype != OT_OBJECT || !IS_TYPE_FUNC(OBJECT(list->object)->type)) CError_Error(CErrorStr133, declinfo->name->name); } else { list = NULL; } } if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(declinfo->thetype))) { tfunc = CDecl_MakeTypeMemberFunc(TYPE_FUNC(declinfo->thetype), tclass, flag4); declinfo->thetype = (Type *) tfunc; } else { tfunc = TYPE_METHOD(declinfo->thetype); CError_ASSERT(4579, !tclass->sominfo); } CDecl_ExtractClassExportFlags(declinfo, tclass->eflags); CError_ASSERT(4597, cscope_current == tclass->nspace); if (list) { obj = CDecl_OverloadFunctionObject(list, declinfo, &outflag, flag4 ? OverloadMode1 : OverloadMode2, 0); if (!obj) return; if (outflag) tfunc->vtbl_index = ++decle->lex_order_count; else CError_Error(CErrorStr133, CError_GetObjectName(obj)); } else { tfunc->vtbl_index = ++decle->lex_order_count; obj = CParser_NewFunctionObject(declinfo); if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(declinfo->thetype)) CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(obj)); CScope_AddObject(tclass->nspace, declinfo->name, OBJ_BASE(obj)); } obj->access = access; CheckDefaultArgs(TYPE_FUNC(obj->type)->args); if (flag2) { tfunc->flags |= FUNC_CONVERSION; tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE; } if (r31) { CDecl_MakeFunctionVirtual(tclass, obj); decle->has_vtable = 1; } if ((flag1 || r31) && flag3 && (tk == '=')) { if ((tk = lex()) == TK_INTCONST) { if (!CInt64_IsZero(&tkintconst)) CError_Error(CErrorStr121); tfunc->flags |= FUNC_PURE; tclass->flags = tclass->flags | CLASS_ABSTRACT; tk = lex(); } else { CError_Error(CErrorStr121); } } if (flag3 && ((tk == '{') || (tk == TK_TRY) || ((tk == ':') && CClass_IsConstructor(obj)))) { if (declinfo->x49) CError_Error(CErrorStr127); InlineFunctionObject(obj, NULL); } if (cparamblkptr->browseoptions.recordClasses) CBrowse_AddClassMemberFunction(obj, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); } static Boolean CDecl_IsAccessDeclaration(TypeClass *tclass, AccessType access) { SInt32 state; Boolean flag; CPrep_TokenStreamGetState(&state); flag = 0; restart: switch (tk) { case TK_IDENTIFIER: if ((tk = lex()) != ';') break; case TK_OPERATOR: CPrep_TokenStreamSetCurState(&state); if (flag) { CScope_ParseUsingDeclaration(tclass->nspace, access, 1); return 1; } return 0; default: CPrep_TokenStreamSetCurState(&state); return 0; } switch (tk) { case TK_COLON_COLON: flag = 1; tk = lex(); goto restart; case '<': tk = lex(); while (1) { switch (tk) { case 0: case ';': case '{': case '}': CPrep_TokenStreamSetCurState(&state); return 0; case '>': if ((tk = lex()) == TK_COLON_COLON) { flag = 1; tk = lex(); goto restart; } default: tk = lex(); } } } CPrep_TokenStreamSetCurState(&state); return 0; } void CDecl_PackDeclInfo(PackedDeclInfo *packed, DeclInfo *declinfo) { packed->thetype = declinfo->thetype; packed->qual = declinfo->qual; packed->nspace = declinfo->nspace; packed->name = declinfo->name; packed->expltargs = CTemplTool_MakeGlobalTemplArgCopy(declinfo->expltargs); packed->storageclass = declinfo->storageclass; packed->section = declinfo->section; packed->exportflags = declinfo->exportflags; packed->has_expltargs = declinfo->has_expltargs; } void CDecl_UnpackDeclInfo(DeclInfo *declinfo, PackedDeclInfo *packed) { memclrw(declinfo, sizeof(DeclInfo)); declinfo->thetype = packed->thetype; declinfo->qual = packed->qual; declinfo->nspace = packed->nspace; declinfo->name = packed->name; declinfo->expltargs = packed->expltargs; declinfo->storageclass = packed->storageclass; declinfo->section = packed->section; declinfo->exportflags = packed->exportflags; declinfo->has_expltargs = packed->has_expltargs; } void CDecl_AddFriend(TypeClass *tclass, Object *friendfunc, TypeClass *friendclass) { ClassFriend *scan; ClassFriend *newfriend; if (friendfunc) { for (scan = tclass->friends; scan; scan = scan->next) { if (!scan->isclass && scan->u.obj == friendfunc) break; } if (!scan) { newfriend = galloc(sizeof(ClassFriend)); memclrw(newfriend, sizeof(ClassFriend)); newfriend->next = tclass->friends; tclass->friends = newfriend; newfriend->u.obj = friendfunc; newfriend->isclass = 0; } } if (friendclass) { for (scan = tclass->friends; scan; scan = scan->next) { if (scan->isclass && scan->u.theclass == friendclass) break; } if (!scan) { newfriend = galloc(sizeof(ClassFriend)); memclrw(newfriend, sizeof(ClassFriend)); newfriend->next = tclass->friends; tclass->friends = newfriend; newfriend->u.theclass = friendclass; newfriend->isclass = 1; } } } static void CDecl_ParseFriendDecl(TypeClass *tclass) { DeclInfo declinfo; DeclInfo declinfo_copy; Boolean is_templ; Boolean r27; Boolean pflag; CScopeSave save; Object *obj; NameSpace *nspace; is_templ = (tclass->flags & CLASS_IS_TEMPL) != 0; r27 = (tk == TK_CLASS || tk == TK_STRUCT || tk == TK_UNION); memclrw(&declinfo, sizeof(DeclInfo)); declinfo.in_friend_decl = 1; CParser_GetDeclSpecs(&declinfo, 1); if (declinfo.storageclass) { CError_Error(CErrorStr177); declinfo.storageclass = 0; } declinfo.in_friend_decl = 0; if (tk == ';') { if (!r27) CError_Error(CErrorStr201); if (IS_TYPE_CLASS(declinfo.thetype)) { if (!(TYPE_CLASS(declinfo.thetype)->flags & CLASS_IS_TEMPL) || CParser_CheckTemplateClassUsage(TEMPL_CLASS(declinfo.thetype), 1)) { if (!is_templ) CDecl_AddFriend(tclass, NULL, TYPE_CLASS(declinfo.thetype)); else CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo); } } else { if (IS_TYPE_TEMPLATE(declinfo.thetype) && is_templ) CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo); else CError_Error(CErrorStr201); } } else { if (declinfo.x14 || declinfo.x10) { CDecl_ParseSpecialMember(&declinfo, 0); if (declinfo.name) { obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0); if (obj) CDecl_AddFriend(tclass, obj, NULL); if (tk != ';') CError_Error(CErrorStr123); else tk = lex(); } return; } else { nspace = CScope_FindGlobalNS(cscope_current); declinfo_copy = declinfo; while (1) { declinfo = declinfo_copy; declinfo.x4D = 1; declinfo.x51 = 1; scandeclarator(&declinfo); if (IS_TYPE_FUNC(declinfo.thetype)) { if (!is_templ) { CScope_SetNameSpaceScope(nspace, &save); obj = CDecl_GetFunctionObject(&declinfo, NULL, &pflag, 0); CScope_RestoreScope(&save); if (obj) { CDecl_AddFriend(tclass, obj, NULL); if (!declinfo.nspace && tk == '{') { InlineFunctionObject(obj, tclass); } else { if (!obj->sclass) obj->sclass = TK_EXTERN; } } } else { CTemplClass_RegisterFriend(TEMPL_CLASS(tclass), &declinfo); } } else { CError_Error(CErrorStr201); } if (tk != ',') break; tk = lex(); } } } if (tk == ';') tk = lex(); else CError_Error(CErrorStr123); } static ObjMemberVar *CDecl_InstanceDataDeclarator(ClassLayout *decle, TypeClass *tclass, Type *type, UInt32 qual, HashNameNode *name, AccessType access) { NameSpaceObjectList *list; ObjMemberVar *ivar; ObjMemberVar *scan; if (name && (list = CScope_FindName(tclass->nspace, name))) { switch (list->object->otype) { case OT_NAMESPACE: CError_Error(CErrorStr321); return NULL; case OT_ENUMCONST: case OT_TYPE: case OT_OBJECT: CError_Error(CErrorStr322); return NULL; case OT_MEMBERVAR: CError_Error(CErrorStr122, name->name); return NULL; case OT_TYPETAG: break; default: CError_FATAL(4989); } } ivar = galloc(sizeof(ObjMemberVar)); memclrw(ivar, sizeof(ObjMemberVar)); ivar->otype = OT_MEMBERVAR; ivar->access = access; ivar->name = name; ivar->type = type; ivar->qual = qual; if (!tclass->sominfo) decle->lex_order_count++; if ((scan = tclass->ivars)) { while (scan->next) scan = scan->next; scan->next = ivar; } else { tclass->ivars = ivar; } if (name && name != no_name_node) { CScope_AddObject(tclass->nspace, name, OBJ_BASE(ivar)); if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(type)) CTemplClass_RegisterObjectDef(TEMPL_CLASS(tclass), OBJ_BASE(ivar)); if (cparamblkptr->browseoptions.recordClasses) CBrowse_AddClassMemberVar(ivar, CPrep_BrowserTokenOffset(&member_fileoffset) + 1, CPrep_BrowserFileOffset()); } return ivar; } void CDecl_CheckCtorIntegrity(FuncArg *args, TypeClass *tclass) { if (args && args->type == TYPE(tclass)) { if (!args->next || args->next->dexpr) { CError_Error(CErrorStr239); args->type = &stvoid; } } } static void CDecl_ParseClassMembers(ClassLayout *decle, TypeClass *tclass, short mode) { AccessType access; Boolean r17; BigDeclInfo bde; DeclInfo declinfo; //Type *newtype ObjMemberVar *ivar; ObjMemberVar *scanivar; Type *tmptype; UInt32 r22; UInt32 r21; UInt8 r20; UInt8 r18; Boolean r19; short t; r17 = (tclass->flags & CLASS_IS_TEMPL) && TEMPL_CLASS(tclass)->pspec_owner; memclrw(&bde, sizeof(BigDeclInfo)); access = (mode == CLASS_MODE_CLASS) ? ACCESSPRIVATE : ACCESSPUBLIC; global_access = access; restart: while (tk != '}') { CPrep_NewFileOffsetInfo(&member_fileoffset, NULL); r21 = 0; r22 = 0; r20 = 0; r18 = 0; if (tk == TK_TEMPLATE) { NameSpace *nspace = cscope_current; TemplClass *tmclass; if (nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) { tmclass = TEMPL_CLASS(nspace->theclass); } else { for (; nspace; nspace = nspace->parent) { if (!nspace->name && !nspace->theclass && nspace->parent && !nspace->is_templ) { CError_Error(CErrorStr347); break; } } } CTempl_Parse(TEMPL_CLASS(tclass), access); tk = lex(); continue; } restart2: r19 = 0; switch (tk) { case TK_UU_DECLSPEC: if ((tk = lex()) != '(') CError_Error(CErrorStr114); memclrw(&declinfo, sizeof(DeclInfo)); CParser_ParseDeclSpec(&declinfo, 1); r21 |= declinfo.qual; r20 |= declinfo.exportflags; r18 = declinfo.section; if ((tk = lex()) != ')') CError_Error(CErrorStr115); tk = lex(); goto restart2; case TK_PRIVATE: global_access = access = ACCESSPRIVATE; goto check_access; case TK_PROTECTED: global_access = access = ACCESSPROTECTED; goto check_access; case TK_PUBLIC: global_access = access = ACCESSPUBLIC; check_access: if (r22 || r20) CError_Error(CErrorStr121); if ((tk = lex()) != ':') CError_Error(CErrorStr170); else tk = lex(); goto restart; case TK_EXPLICIT: CError_QualifierCheck(r22 & Q_EXPLICIT); r22 |= Q_EXPLICIT; tk = lex(); goto restart2; case TK_INLINE: CError_QualifierCheck(r22 & Q_INLINE); r22 |= Q_INLINE; tk = lex(); goto restart2; case TK_ASM: CError_QualifierCheck(r22 & Q_ASM); r22 |= Q_ASM; tk = lex(); goto restart2; case TK_VIRTUAL: CError_QualifierCheck(r22 & Q_VIRTUAL); r22 |= Q_VIRTUAL; tk = lex(); goto restart2; case TK_IDENTIFIER: while (1) { if (tkidentifier == tclass->classname) { t = lookahead(); tkidentifier = tclass->classname; r19 = 1; if (copts.cpp_extensions && t == TK_COLON_COLON) { lex(); tk = lex(); if (tk == TK_IDENTIFIER) continue; if (tk == '~') goto restart2; CError_Error(CErrorStr107); } if (t == '(') { redo_thing: CError_QualifierCheck(r22 & ~(Q_EXPLICIT | Q_INLINE | Q_ASM)); memclrw(&bde.declinfo2, sizeof(DeclInfo)); if (tclass->sominfo) bde.declinfo2.thetype = &stvoid; else bde.declinfo2.thetype = TYPE(&void_ptr); bde.declinfo2.qual = r22; bde.declinfo2.exportflags = r20; bde.declinfo2.section = r18; bde.declinfo2.x4B = 1; scandeclarator(&bde.declinfo2); if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { if (r17) bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual); if (tclass->sominfo) { if (TYPE_FUNC(bde.declinfo2.thetype)->args) CError_Error(CErrorStr272); bde.declinfo2.qual |= Q_VIRTUAL; } else { CDecl_CheckCtorIntegrity(TYPE_FUNC(bde.declinfo2.thetype)->args, tclass); if (tclass->flags & CLASS_HAS_VBASES) CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort)); bde.declinfo2.qual &= ~Q_VIRTUAL; } TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_IS_CTOR; bde.declinfo2.name = constructor_name_node; bde.declinfo2.qual |= r21; CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 0); } else { CError_Error(CErrorStr241); } if (tk == ';') tk = lex(); else CError_Error(CErrorStr123); goto restart; } } // 6F8D8 if (!r22 && CDecl_IsAccessDeclaration(tclass, access)) { tk = lex(); goto restart; } break; } break; case TK_USING: CError_QualifierCheck(r22); tk = lex(); CScope_ParseUsingDeclaration(tclass->nspace, access, 0); tk = lex(); goto restart; case '~': if ((tk = lex()) != TK_IDENTIFIER || tkidentifier != tclass->classname) { CError_Error(CErrorStr241); goto restart; } CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM)); if (tclass->flags & CLASS_IS_TEMPL_ANY) { t = lookahead(); tkidentifier = tclass->classname; if (t == '<') { memclrw(&bde.declinfo, sizeof(DeclInfo)); CParser_GetDeclSpecs(&bde.declinfo, 0); if (tk != '(' || bde.declinfo.thetype != TYPE(tclass) || bde.declinfo.nspace) { CError_Error(CErrorStr241); goto restart; } CPrep_UnLex(); tk = TK_IDENTIFIER; tkidentifier = tclass->classname; } } memclrw(&bde.declinfo2, sizeof(DeclInfo)); bde.declinfo2.qual = r22; bde.declinfo2.exportflags = r20; bde.declinfo2.section = r18; if (tclass->sominfo) bde.declinfo2.thetype = &stvoid; else bde.declinfo2.thetype = TYPE(&void_ptr); scandeclarator(&bde.declinfo2); if (IS_TYPE_FUNC(bde.declinfo2.thetype) && !TYPE_FUNC(bde.declinfo2.thetype)->args) { if (!CScope_FindName(tclass->nspace, destructor_name_node)) { if (tclass->sominfo) bde.declinfo2.qual |= Q_VIRTUAL; else CDecl_AddArgument(TYPE_FUNC(bde.declinfo2.thetype), TYPE(&stsignedshort)); bde.declinfo2.name = destructor_name_node; TYPE_FUNC(bde.declinfo2.thetype)->flags |= FUNC_IS_DTOR; bde.declinfo2.qual |= r21; CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0); } else { CError_Error(CErrorStr133, CError_GetFunctionName(tclass->nspace, destructor_name_node, NULL)); } } else { CError_Error(CErrorStr146); } if (tk == ';') tk = lex(); else CError_Error(CErrorStr123); goto restart; case TK_OPERATOR: if (CMangler_OperatorName(lookahead())) { memclrw(&bde.declinfo, sizeof(DeclInfo)); bde.declinfo.thetype = TYPE(&stsignedint); goto after_various_things; } else { tk = lex(); CError_QualifierCheck(r22 & ~(Q_VIRTUAL | Q_INLINE | Q_ASM)); memclrw(&bde.declinfo2, sizeof(DeclInfo)); bde.declinfo2.qual = r22; bde.declinfo2.exportflags = r20; bde.declinfo2.section = r18; conversion_type_name(&bde.declinfo2); bde.declinfo2.qual |= r21; tmptype = bde.declinfo2.thetype; CDecl_NewConvFuncType(&bde.declinfo2); if ((tclass->flags & CLASS_IS_TEMPL) && CTemplTool_IsTemplateArgumentDependentType(tmptype)) bde.declinfo2.name = CParser_GetUniqueName(); CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 1, 1, 0); if (tk == ';') tk = lex(); else CError_Error(CErrorStr123); goto restart; } case TK_FRIEND: tk = lex(); CDecl_ParseFriendDecl(tclass); goto restart; } CError_QualifierCheck(r22 & Q_EXPLICIT); global_access = access; memclrw(&bde.declinfo, sizeof(DeclInfo)); bde.declinfo.qual = r22; bde.declinfo.exportflags = r20; bde.declinfo.section = r18; CParser_GetDeclSpecs(&bde.declinfo, 0); if (r19 && tk == '(' && (tclass->flags & CLASS_IS_TEMPL_ANY) && bde.declinfo.thetype == TYPE(tclass) && !bde.declinfo.nspace) { CPrep_UnLex(); tk = TK_IDENTIFIER; tkidentifier = tclass->classname; r22 = bde.declinfo.qual; goto redo_thing; } after_various_things: switch (bde.declinfo.storageclass) { case 0: case TK_STATIC: case TK_TYPEDEF: case TK_MUTABLE: break; default: CError_Error(CErrorStr177); bde.declinfo.storageclass = 0; } if (tk != ';') { while (1) { CDecl_ScanStructDeclarator(&bde); if (r17) bde.declinfo2.thetype = CTemplTool_ResolveMemberSelfRefs(TEMPL_CLASS(tclass), bde.declinfo2.thetype, &bde.declinfo2.qual); if (bde.declinfo2.nspace) CError_Error(CErrorStr200); if (bde.declinfo2.operator_token) { if (bde.declinfo.storageclass == TK_MUTABLE) CError_QualifierCheck(Q_MUTABLE); r19 = 0; switch (bde.declinfo2.operator_token) { case TK_NEW: case TK_NEW_ARRAY: CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); r19 = 1; break; case TK_DELETE: case TK_DELETE_ARRAY: CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); r19 = 1; break; default: if (bde.declinfo2.storageclass == TK_STATIC) CError_Error(CErrorStr193); if (tclass->sominfo) CError_Error(CErrorStr193); } bde.declinfo2.storageclass = 0; if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { bde.declinfo2.qual |= r21; CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, r19 == 0, 0, 1, r19); CDecl_CheckOperatorType(&bde.declinfo2, 1); if (tclass->sominfo) CSOM_FixNewDeleteFunctype(TYPE_FUNC(bde.declinfo2.thetype)); } else { CError_Error(CErrorStr121); } } else if (bde.xCD) { if (bde.declinfo2.name == constructor_name_node || bde.declinfo2.name == destructor_name_node) CError_Error(CErrorStr241); switch (bde.declinfo2.storageclass) { case TK_TYPEDEF: CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); CDecl_TypedefDeclarator(&bde.declinfo2); break; case TK_STATIC: CError_QualifierCheck(bde.declinfo2.qual & Q_VIRTUAL); if (tclass->sominfo) CError_Error(CErrorStr271); if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { bde.declinfo2.qual |= r21; bde.declinfo2.storageclass = 0; if (bde.declinfo2.name == tclass->classname) CError_Error(CErrorStr241); CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 0, 0, 1, 1); } else { CDecl_ExtractClassExportFlags(&bde.declinfo2, tclass->eflags); bde.declinfo2.storageclass = 0; CDecl_DataDeclarator(&bde.declinfo2, access, 1); } break; case 0: case TK_MUTABLE: if (IS_TYPE_FUNC(bde.declinfo2.thetype)) { if (bde.declinfo2.name == tclass->classname) CError_Error(CErrorStr241); if (bde.declinfo.storageclass == TK_MUTABLE) CError_QualifierCheck(Q_MUTABLE); bde.declinfo2.qual |= r21; CDecl_AddFunctionMember(decle, tclass, &bde.declinfo2, access, 1, 0, 1, 0); } else { CDecl_CompleteType(bde.declinfo2.thetype); CanCreateObject(bde.declinfo2.thetype); CError_QualifierCheck(bde.declinfo2.qual & (Q_VIRTUAL | Q_INLINE)); if (bde.declinfo2.storageclass == TK_MUTABLE) bde.declinfo2.qual |= Q_MUTABLE; CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo2.thetype, bde.declinfo2.qual, bde.declinfo2.name, access); } break; default: CError_Error(CErrorStr177); } } // this should be 70058 if (tk != ',') break; // goes to 70148 tk = lex(); } } else if (CParser_IsAnonymousUnion(&bde.declinfo, 1)) { if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, bde.declinfo.thetype, 0, NULL, access))) ivar->anonunion = 1; for (scanivar = TYPE_CLASS(bde.declinfo.thetype)->ivars; scanivar; scanivar = scanivar->next) { tmptype = scanivar->type; if (IS_TYPE_BITFIELD(tmptype) && copts.reverse_bitfields) { TypeBitfield *newtype = galloc(sizeof(TypeBitfield)); *newtype = *TYPE_BITFIELD(tmptype); CABI_ReverseBitField(newtype); tmptype = TYPE(newtype); } if ((ivar = CDecl_InstanceDataDeclarator(decle, tclass, tmptype, scanivar->qual, scanivar->name, access))) ivar->offset = scanivar->offset | 0x80000000; } } // this should be 70148 i think if (tk != ';') { CError_Error(CErrorStr123); return; } CPrep_TokenStreamFlush(); tk = lex(); } } static VClassList *AddVBaseToList(TypeClass *tclass, TypeClass *baseclass) { VClassList *scan; VClassList *vbase; for (scan = tclass->vbases; scan; scan = scan->next) { if (scan->base == baseclass) return NULL; } vbase = galloc(sizeof(VClassList)); memclrw(vbase, sizeof(VClassList)); vbase->base = baseclass; if ((scan = tclass->vbases)) { while (scan->next) scan = scan->next; scan->next = vbase; } else { tclass->vbases = vbase; } return vbase; } void CDecl_MakeVBaseList(TypeClass *tclass) { ClassList *base; VClassList *vbase; VClassList *new_vbase; SInt32 offset; if (copts.vbase_ctor_offset) tclass->flags = tclass->flags | CLASS_FLAGS_8000; for (base = tclass->bases, offset = tclass->size; base; base = base->next) { for (vbase = base->base->vbases; vbase; vbase = vbase->next) { if ((new_vbase = AddVBaseToList(tclass, vbase->base))) { new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(vbase->base), offset); offset = new_vbase->offset + vbase->base->size; } } if (base->is_virtual && (new_vbase = AddVBaseToList(tclass, base->base))) { new_vbase->offset = offset + CMach_MemberAlignValue(TYPE(base->base), offset); offset = new_vbase->offset + base->base->size; } } } Boolean CDecl_CheckNewBase(TypeClass *tclass, TypeClass *baseclass, Boolean is_virtual) { ClassList *scan; if (tclass == baseclass) { CError_Error(CErrorStr131); return 0; } if (!(baseclass->flags & CLASS_COMPLETED)) { CError_Error(CErrorStr136, baseclass, 0); return 0; } if (baseclass->flags & CLASS_SINGLE_OBJECT) { if (is_virtual || tclass->bases) { CError_Error(CErrorStr191); return 0; } tclass->flags = tclass->flags | CLASS_SINGLE_OBJECT; } if (baseclass->flags & CLASS_HANDLEOBJECT) { if (is_virtual || tclass->bases) { CError_Error(CErrorStr191); return 0; } tclass->flags = tclass->flags | CLASS_HANDLEOBJECT; } if (baseclass->sominfo) { if (!is_virtual) CError_Error(CErrorStr268); CSOM_MakeSOMClass(tclass); } else if (tclass->sominfo) { CError_Error(CErrorStr267); } if (tclass->bases && (tclass->flags & CLASS_SINGLE_OBJECT) && (tclass->flags & CLASS_SINGLE_OBJECT)) { CError_Error(CErrorStr131); return 0; } if (copts.ecplusplus && (is_virtual || tclass->bases)) { CError_Error(CErrorStr339); return 0; } for (scan = tclass->bases; scan; scan = scan->next) { if (scan->base == baseclass) { CError_Error(CErrorStr131); return 0; } } if (baseclass->flags & CLASS_COM_OBJECT) tclass->flags = tclass->flags | CLASS_COM_OBJECT; if (baseclass->flags & CLASS_IS_CONVERTIBLE) tclass->flags = tclass->flags | CLASS_IS_CONVERTIBLE; if (baseclass->flags & CLASS_HAS_VBASES) tclass->flags = tclass->flags | CLASS_HAS_VBASES; if (is_virtual) tclass->flags = tclass->flags | CLASS_HAS_VBASES; return 1; } static void CDecl_ParseBaseClassList(TypeClass *tclass, short mode, Boolean is_templ) { Boolean is_virtual; AccessType access; NameResult pr; ObjType *inherited_type; ClassList *base; ClassList *scan; TypeClass *baseclass; do { if (mode == CLASS_MODE_CLASS) access = ACCESSPRIVATE; else access = ACCESSPUBLIC; is_virtual = 0; if ((tk = lex()) == TK_VIRTUAL) { tk = lex(); is_virtual = 1; } switch (tk) { case TK_PRIVATE: access = ACCESSPRIVATE; tk = lex(); break; case TK_PUBLIC: access = ACCESSPUBLIC; tk = lex(); break; case TK_PROTECTED: if (!copts.ARMconform) { access = ACCESSPROTECTED; tk = lex(); } break; } if (tk == TK_VIRTUAL) { if (is_virtual) CError_Error(CErrorStr121); is_virtual = 1; tk = lex(); } if (CScope_ParseDeclName(&pr)) { if (!pr.type) { if (!pr.name_4) { CError_Error(CErrorStr121); } else if (tk == TK_IDENTIFIER && pr.name_4 == tkidentifier) { goto special_parsing; } CError_Error(CErrorStr140, tkidentifier->name); continue; } CDecl_CompleteType(pr.type); if (is_templ && CTemplTool_IsTemplateArgumentDependentType(pr.type)) { if (!IS_TYPE_CLASS(pr.type) || !(TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL) || CParser_CheckTemplateClassUsage(TEMPL_CLASS(pr.type), 1)) { CTemplClass_RegisterBaseClass(TEMPL_CLASS(tclass), pr.type, access, is_virtual); if (is_virtual) tclass->flags = tclass->flags | CLASS_HAS_VBASES; } continue; } if (!IS_TYPE_CLASS(pr.type) || (TYPE_CLASS(pr.type)->flags & CLASS_IS_TEMPL)) { CError_Error(CErrorStr131); continue; } baseclass = TYPE_CLASS(pr.type); } else { special_parsing: if (!strcmp(tkidentifier->name, "HandleObject")) { if (tclass->bases) CError_Error(CErrorStr191); tclass->flags |= CLASS_SINGLE_OBJECT | CLASS_HANDLEOBJECT; tk = lex(); break; } if (!strcmp(tkidentifier->name, "SingleObject") || !strcmp(tkidentifier->name, "SingleInheritance")) { if (tclass->bases) CError_Error(CErrorStr191); tclass->flags = tclass->flags | CLASS_SINGLE_OBJECT; tk = lex(); break; } if (!strcmp(tkidentifier->name, "__comobject")) { tclass->flags = tclass->flags | CLASS_COM_OBJECT; tk = lex(); break; } if (!strcmp(tkidentifier->name, "__somobject")) { if (!is_virtual) CError_Error(CErrorStr268); CSOM_MakeSOMClass(tclass); tk = lex(); break; } if (!strcmp(tkidentifier->name, "__javaobject")) { tk = lex(); tclass->action = CLASS_ACTION_3; break; } CError_Error(CErrorStr140, tkidentifier->name); continue; } if (CDecl_CheckNewBase(tclass, baseclass, is_virtual)) { base = galloc(sizeof(ClassList)); memclrw(base, sizeof(ClassList)); base->base = baseclass; base->access = access; base->is_virtual = is_virtual; if ((scan = tclass->bases)) { while (scan->next) scan = scan->next; scan->next = base; } else { tclass->bases = base; } } } while ((tk = lex()) == ','); if (tclass->flags & CLASS_HAS_VBASES) CDecl_MakeVBaseList(tclass); if (copts.def_inherited && tclass->bases && !tclass->bases->next) { inherited_type = galloc(sizeof(ObjType)); memclrw(inherited_type, sizeof(ObjType)); inherited_type->otype = OT_TYPE; inherited_type->access = ACCESSPUBLIC; inherited_type->type = TYPE(tclass->bases->base); CScope_AddObject(tclass->nspace, GetHashNameNodeExport("inherited"), OBJ_BASE(inherited_type)); } } static AccessType getaccesstype(AccessType a, AccessType b, AccessType c) { if (a == ACCESSNONE || b == ACCESSNONE || b == ACCESSPRIVATE) return ACCESSNONE; if (c == ACCESSPUBLIC && b != ACCESSPUBLIC) return ACCESSNONE; return ACCESSPUBLIC; } static TypeMemberFunc *CDecl_MakeDefaultCtorType(TypeClass *tclass) { TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); memclrw(tmeth, sizeof(TypeMemberFunc)); tmeth->type = TYPEFUNC; tmeth->functype = TYPE(&void_ptr); tmeth->flags = FUNC_IS_CTOR | FUNC_AUTO_GENERATED | FUNC_METHOD; tmeth->theclass = tclass; CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); if (tclass->flags & CLASS_HAS_VBASES) CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort)); CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); return tmeth; } static void CDecl_AddDefArgConstructor(TypeClass *tclass) { // empty } static void CDecl_AddMemberFunctionObject(TypeClass *tclass, HashNameNode *name, TypeMemberFunc *tmeth, AccessType access) { Object *obj = CParser_NewCompilerDefFunctionObject(); obj->name = name; obj->type = TYPE(tmeth); obj->qual = Q_MANGLE_NAME; obj->access = access; obj->nspace = tclass->nspace; obj->qual = obj->qual | Q_INLINE; CScope_AddObject(tclass->nspace, obj->name, OBJ_BASE(obj)); } static void CDecl_AddDefaultConstructor(ClassLayout *decle, TypeClass *tclass) { ClassList *base; ObjMemberVar *ivar; Object *obj; Boolean has_ctor; if (CClass_Constructor(tclass)) { CDecl_AddDefArgConstructor(tclass); return; } has_ctor = 0; if (tclass->flags & CLASS_HAS_VBASES) has_ctor = 1; if (decle->has_vtable) has_ctor = 1; for (base = tclass->bases; base; base = base->next) { if (CClass_Constructor(base->base)) has_ctor = 1; } for (ivar = tclass->ivars; ivar; ivar = ivar->next) { Type *type = ivar->type; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (IS_TYPE_CLASS(type) && CClass_Constructor(TYPE_CLASS(type))) has_ctor = 1; } if (has_ctor) { CDecl_AddMemberFunctionObject( tclass, constructor_name_node, CDecl_MakeDefaultCtorType(tclass), ACCESSPUBLIC ); } } static TypeMemberFunc *CDecl_MakeCopyCtorType(TypeClass *tclass, Boolean is_const) { FuncArg *arg; TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); memclrw(tmeth, sizeof(TypeMemberFunc)); tmeth->type = TYPEFUNC; tmeth->functype = TYPE(&void_ptr); tmeth->flags = FUNC_IS_CTOR | FUNC_AUTO_GENERATED | FUNC_METHOD; tmeth->theclass = tclass; CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); arg = CParser_NewFuncArg(); if (is_const) arg->qual = Q_CONST; arg->type = CDecl_NewRefPointerType(TYPE(tclass)); tmeth->args = arg; if (tclass->flags & CLASS_HAS_VBASES) CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort)); CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); return tmeth; } static void CDecl_AddDefaultCopyConstructor(ClassLayout *decle, TypeClass *tclass) { ClassList *base; ObjMemberVar *ivar; Object *obj; AccessType access; Boolean has_copyctor; Boolean is_const; FuncArg *arg; if (CClass_CopyConstructor(tclass)) return; access = ACCESSPUBLIC; is_const = 1; has_copyctor = 0; if (CClass_Constructor(tclass)) has_copyctor = 1; if ((tclass->flags & CLASS_HAS_VBASES) || decle->has_vtable) has_copyctor = 1; for (base = tclass->bases; base; base = base->next) { if ((obj = CClass_CopyConstructor(base->base))) { has_copyctor = 1; access = getaccesstype(access, obj->access, ACCESSPRIVATE); arg = TYPE_FUNC(obj->type)->args->next; if (base->base->flags & CLASS_HAS_VBASES) arg = arg->next; if (!(arg->qual & Q_CONST)) is_const = 0; } } for (ivar = tclass->ivars; ivar; ivar = ivar->next) { Type *type = ivar->type; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (IS_TYPE_CLASS(type) && (obj = CClass_CopyConstructor(TYPE_CLASS(type)))) { has_copyctor = 1; access = getaccesstype(access, obj->access, ACCESSPUBLIC); arg = TYPE_FUNC(obj->type)->args->next; if (TYPE_CLASS(type)->flags & CLASS_HAS_VBASES) arg = arg->next; if (!(arg->qual & Q_CONST)) is_const = 0; } } if (has_copyctor) { CDecl_AddMemberFunctionObject( tclass, constructor_name_node, CDecl_MakeCopyCtorType(tclass, is_const), access ); } } static TypeMemberFunc *CDecl_MakeAssignmentOperatorType(TypeClass *tclass, Boolean is_const) { FuncArg *arg; TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); memclrw(tmeth, sizeof(TypeMemberFunc)); tmeth->type = TYPEFUNC; tmeth->functype = CDecl_NewRefPointerType(TYPE(tclass)); tmeth->flags = FUNC_AUTO_GENERATED | FUNC_METHOD; tmeth->theclass = tclass; CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); arg = CParser_NewFuncArg(); if (is_const) arg->qual = Q_CONST; arg->type = CDecl_NewRefPointerType(TYPE(tclass)); tmeth->args = arg; CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); return tmeth; } static void CDecl_AddDefaultAssignmentOperator(ClassLayout *decle, TypeClass *tclass) { ClassList *base; ObjMemberVar *ivar; Object *obj; AccessType access; Boolean is_const; Boolean has_ass; DeclInfo declinfo; is_const = 1; has_ass = 0; access = ACCESSPUBLIC; if (!CClass_AssignmentOperator(tclass)) { if (!copts.old_argmatch) has_ass = 1; if ((tclass->flags & CLASS_HAS_VBASES) || decle->has_vtable || CClass_MemberObject(tclass, asop_name_node)) has_ass = 1; for (base = tclass->bases; base; base = base->next) { if ((obj = CClass_AssignmentOperator(base->base))) { has_ass = 1; access = getaccesstype(access, obj->access, ACCESSPRIVATE); if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST)) is_const = 0; } } for (ivar = tclass->ivars; ivar; ivar = ivar->next) { Type *type = ivar->type; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (IS_TYPE_CLASS(type) && (obj = CClass_AssignmentOperator(TYPE_CLASS(type)))) { has_ass = 1; access = getaccesstype(access, obj->access, ACCESSPUBLIC); if (!(TYPE_FUNC(obj->type)->args->next->qual & Q_CONST)) is_const = 0; } } } if (has_ass) { memclrw(&declinfo, sizeof(DeclInfo)); declinfo.qual |= Q_INLINE; declinfo.thetype = (Type *) CDecl_MakeAssignmentOperatorType(tclass, is_const); declinfo.name = asop_name_node; CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0); } } TypeMemberFunc *CDecl_MakeDefaultDtorType(TypeClass *tclass, Boolean is_virtual) { TypeMemberFunc *tmeth = galloc(sizeof(TypeMemberFunc)); memclrw(tmeth, sizeof(TypeMemberFunc)); tmeth->type = TYPEFUNC; tmeth->functype = (Type *) &void_ptr; tmeth->flags = FUNC_IS_DTOR | FUNC_AUTO_GENERATED | FUNC_METHOD; tmeth->theclass = tclass; CDecl_SetFuncFlags(TYPE_FUNC(tmeth), 1); if (is_virtual) CDecl_AddArgument(TYPE_FUNC(tmeth), TYPE(&stsignedshort)); CDecl_AddThisPointerArgument(TYPE_FUNC(tmeth), tclass); return tmeth; } static void CDecl_AddDefaultDestructor(ClassLayout *decle, TypeClass *tclass) { ClassList *base; ObjMemberVar *ivar; Object *obj; AccessType access; Boolean has_dtor; Boolean is_virtual; DeclInfo declinfo; if (CClass_Destructor(tclass)) return; has_dtor = 0; is_virtual = 0; access = ACCESSPUBLIC; for (base = tclass->bases; base; base = base->next) { if ((obj = CClass_Destructor(base->base))) { has_dtor = 1; if (obj->datatype == DVFUNC) is_virtual = 1; access = getaccesstype(access, obj->access, ACCESSPRIVATE); } } for (ivar = tclass->ivars; ivar; ivar = ivar->next) { Type *type = ivar->type; while (IS_TYPE_ARRAY(type)) type = TYPE_POINTER(type)->target; if (IS_TYPE_CLASS(type) && (obj = CClass_Destructor(TYPE_CLASS(type)))) { has_dtor = 1; access = getaccesstype(access, obj->access, ACCESSPUBLIC); } } if (has_dtor) { memclrw(&declinfo, sizeof(DeclInfo)); declinfo.qual |= Q_INLINE; if (is_virtual) declinfo.qual |= Q_VIRTUAL; declinfo.thetype = (Type *) CDecl_MakeDefaultDtorType(tclass, 1); declinfo.name = destructor_name_node; CDecl_AddFunctionMember(decle, tclass, &declinfo, access, 1, 0, 0, 0); } } static void CDecl_SetupClassLayout(ClassLayout *decle, TypeClass *tclass, ObjBase **objbuf) { SInt32 index; SInt32 i; Object *obj; CScopeObjectIterator iter; ObjMemberVar *ivar; SInt32 bufsize; if (decle->lex_order_count > 32) { bufsize = decle->lex_order_count * sizeof(ObjBase *); objbuf = lalloc(bufsize); } else { bufsize = 32 * sizeof(ObjBase *); } memclrw(objbuf, bufsize); decle->objlist = objbuf; CScope_InitObjectIterator(&iter, tclass->nspace); index = 0; while (1) { obj = OBJECT(CScope_NextObjectIteratorObject(&iter)); if (!obj) break; if (!IS_TYPE_FUNC(obj->type)) continue; if (!IS_TYPEFUNC_METHOD(TYPE_FUNC(obj->type))) continue; if (obj->datatype == DALIAS) continue; i = TYPE_METHOD(obj->type)->vtbl_index; if (i > 0) { CError_ASSERT(6363, (i - 1) < decle->lex_order_count && !objbuf[(int) (i - 1)]); objbuf[(int) (i - 1)] = OBJ_BASE(obj); index++; if (obj->datatype != DVFUNC && !TYPE_METHOD(obj->type)->is_static && CClass_OverridesBaseMember(tclass, obj->name, obj)) CDecl_MakeFunctionVirtual(tclass, obj); if (obj->datatype == DVFUNC) { decle->has_vtable = 1; if (!tclass->vtable) { CABI_AddVTable(tclass); decle->xA = i - 1; } else { if ((i - 1) < decle->xA) decle->xA = i - 1; } } else if (TYPE_FUNC(obj->type)->flags & FUNC_PURE) { CError_Error(CErrorStr351, obj); TYPE_FUNC(obj->type)->flags &= ~FUNC_PURE; } } else { CError_ASSERT(6412, i == 0); } if (!tclass->sominfo) TYPE_METHOD(obj->type)->vtbl_index = 0; } if (!tclass->action) { for (i = 0; i < decle->lex_order_count; i++) { Object *obj2 = OBJECT(objbuf[i]); if (obj2 && obj2->datatype == DVFUNC && !(obj2->qual & Q_INLINE) && !(TYPE_FUNC(obj2->type)->flags & FUNC_PURE)) { tclass->action = CLASS_ACTION_1; TYPE_FUNC(obj2->type)->flags |= FUNC_FLAGS_4; break; } } } if (!tclass->sominfo) { for (i = 0, ivar = tclass->ivars; i < decle->lex_order_count; i++) { if (!objbuf[i]) { CError_ASSERT(6449, ivar); objbuf[i] = OBJ_BASE(ivar); ivar = ivar->next; index++; } } CError_ASSERT(6455, ivar == NULL); } CError_ASSERT(6458, index == decle->lex_order_count); } void CDecl_CompleteClass(ClassLayout *decle, TypeClass *tclass) { ClassList *base; ObjBase *buf[32]; for (base = tclass->bases; base; base = base->next) { if (base->base->vtable) decle->has_vtable = 1; } if (!tclass->sominfo) { CDecl_AddDefaultDestructor(decle, tclass); CDecl_AddDefaultAssignmentOperator(decle, tclass); CDecl_AddDefaultConstructor(decle, tclass); CDecl_AddDefaultCopyConstructor(decle, tclass); } CDecl_SetupClassLayout(decle, tclass, buf); if (decle->has_vtable) CClass_CheckOverrides(tclass); CABI_LayoutClass(decle, tclass); if (tclass->sominfo) CSOM_ClassComplete(tclass); if ((tclass->flags & CLASS_IS_TEMPL_INST) && !TEMPL_CLASS_INST(tclass)->is_specialized) tclass->action = CLASS_ACTION_0; if (!tclass->action) CClass_MakeStaticActionClass(tclass); CClass_ClassDefaultFuncAction(tclass); } TypeClass *CDecl_DefineClass(NameSpace *nspace, HashNameNode *name, TypeClass *tclass, short mode, Boolean flag2, Boolean flag3) { NameSpace *mynspace; ObjType *objtype; if (!tclass && nspace->theclass && (nspace->theclass->flags & CLASS_IS_TEMPL)) { CError_ASSERT(6556, !flag2); return TYPE_CLASS(CTemplClass_DefineNestedClass(TEMPL_CLASS(nspace->theclass), name, mode)); } mynspace = CScope_NewListNameSpace(name, 1); if (!tclass) { tclass = galloc(sizeof(TypeClass)); memclrw(tclass, sizeof(TypeClass)); } tclass->type = TYPECLASS; tclass->align = 1; tclass->mode = mode; tclass->action = CLASS_ACTION_0; if (name) { tclass->classname = name; if (flag3) { if (flag2) { objtype = galloc(sizeof(ObjType)); memclrw(objtype, sizeof(ObjType)); objtype->otype = OT_TYPE; objtype->access = ACCESSPUBLIC; objtype->type = (Type *) tclass; CScope_AddObject(nspace, name, OBJ_BASE(objtype)); } else { CScope_DefineTypeTag(nspace, name, (Type *) tclass); } } CScope_DefineTypeTag(mynspace, name, (Type *) tclass); if (cscope_currentfunc) mynspace->name = CParser_AppendUniqueNameFile(name->name); if (copts.direct_to_som && nspace == cscope_root && !strcmp(name->name, "SOMObject")) CSOM_MakeSOMClass(tclass); } else { tclass->classname = CParser_AppendUniqueNameFile("@class"); mynspace->name = tclass->classname; } tclass->nspace = mynspace; mynspace->theclass = tclass; mynspace->parent = nspace; if (!nspace->is_global) CParser_RegisterNonGlobalClass(tclass); return tclass; } void CDecl_ParseClassDeclSpec(UInt8 *declspec) { DeclInfo declinfo; if ((tk = lex()) == '(') { memclrw(&declinfo, sizeof(DeclInfo)); CParser_ParseDeclSpec(&declinfo, 1); if (declinfo.exportflags & EXPORT_FLAGS_INTERNAL) *declspec = *declspec | CLASS_EFLAGS_INTERNAL; if (declinfo.exportflags & EXPORT_FLAGS_IMPORT) *declspec = *declspec | CLASS_EFLAGS_IMPORT; if (declinfo.exportflags & EXPORT_FLAGS_EXPORT) *declspec = *declspec | CLASS_EFLAGS_EXPORT; if ((tk = lex()) != ')') CError_Error(CErrorStr115); else tk = lex(); } else { CError_Error(CErrorStr114); } } static TemplClass *CDecl_SpecializeTemplateClass(TemplClass *tmclass) { tmclass->theclass.nspace->names = 0; tmclass->theclass.nspace->data.list = NULL; tmclass->theclass.ivars = NULL; tmclass->theclass.bases = NULL; tmclass->theclass.vbases = NULL; tmclass->theclass.friends = NULL; tmclass->theclass.vtable = NULL; tmclass->members = NULL; tmclass->instances = NULL; tmclass->pspec_owner = NULL; tmclass->pspecs = NULL; tmclass->actions = NULL; tmclass->lex_order_count = 0; tmclass->align = 0; tmclass->flags = TEMPLCLASS_FLAGS_2; return tmclass; } void CDecl_ParseClass(DeclInfo *declinfo, short mode, Boolean flag1, UInt8 class_declspec) { ClassLayout decle; TypeClass *tclass; HashNameNode *classname; Type *search; short t; NameSpace *nspace; NameResult pr; CScopeSave scopesave; GList gl; FileOffsetInfo offsetsave; SInt32 offset; Boolean is_templ; Boolean add_to_browse; memclrw(&decle, sizeof(ClassLayout)); if (declinfo->x28) { tclass = TYPE_CLASS(declinfo->x28); } else { if (tk == TK_UU_DECLSPEC) CDecl_ParseClassDeclSpec(&class_declspec); switch (tk) { case ':': case '{': tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); tclass->eflags |= class_declspec; break; case TK_IDENTIFIER: classname = tkidentifier; if (!declinfo->in_friend_decl && !declinfo->x4F && ((t = lookahead()) == ':' || t == ';' || t == '{')) { tk = lex(); search = CScope_GetLocalTagType(cscope_current, classname); if (search) { tagtype_search: if (!IS_TYPE_CLASS(search)) { if ((IS_TYPE_TEMPLATE(search) || IS_TYPE_STRUCT(search)) && tk != '{' && tk != ':') { declinfo->thetype = search; return; } if (!IS_TYPE_TEMPLATE(search) || !(tclass = TYPE_CLASS(CTemplTool_GetSelfRefTemplate(search)))) { CError_Error(CErrorStr132, classname->name); tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); break; } } else { tclass = TYPE_CLASS(search); } if (tclass->mode != mode) { if ( (mode == CLASS_MODE_CLASS && tclass->mode == CLASS_MODE_STRUCT) || (mode == CLASS_MODE_STRUCT && tclass->mode == CLASS_MODE_CLASS) ) { if (copts.warn_structclass) CError_Warning(CErrorStr343); } else { CError_Error(CErrorStr132, classname); } } tclass->eflags |= class_declspec; break; } else { tclass = CDecl_DefineClass(cscope_current, classname, NULL, mode, 0, 1); tclass->eflags |= class_declspec; break; } } else { tkidentifier = classname; } default: if (!CScope_ParseElaborateName(&pr)) { CError_Error(CErrorStr121); declinfo->thetype = TYPE(&stsignedint); return; } tk = lex(); if ((search = pr.type)) { goto tagtype_search; } CError_ASSERT(6786, pr.name_4); tclass = CDecl_DefineClass(CScope_FindNonClassNonFunctionNS(cscope_current), pr.name_4, NULL, mode, 0, 1); tclass->eflags |= class_declspec; } } declinfo->thetype = TYPE(tclass); if (tk == ':' || tk == '{') { if (declinfo->in_friend_decl) CError_Error(CErrorStr201); if (tclass->flags & CLASS_COMPLETED) { if ( (tclass->flags & CLASS_IS_TEMPL) && !TEMPL_CLASS(tclass)->instances && !(TEMPL_CLASS(tclass)->flags & TEMPLCLASS_FLAGS_2) ) { tclass = TYPE_CLASS(CDecl_SpecializeTemplateClass(TEMPL_CLASS(tclass))); } else { CError_Error(CErrorStr132, tclass->classname->name); tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); } } for (nspace = cscope_current; nspace; nspace = nspace->parent) { if (nspace == tclass->nspace) { CError_Error(CErrorStr132, tclass->classname->name); tclass = CDecl_DefineClass(cscope_current, NULL, NULL, mode, 0, 1); break; } } is_templ = (tclass->flags & CLASS_IS_TEMPL) != 0; if (tclass->flags & CLASS_IS_TEMPL_INST) { TEMPL_CLASS_INST(tclass)->is_instantiated = 1; if (!declinfo->x28) TEMPL_CLASS_INST(tclass)->is_specialized = 1; } CError_ASSERT(6853, copts.structalignment >= 0 && copts.structalignment <= 14); tclass->eflags = tclass->eflags | (((copts.structalignment + 1) << 4) & 0xF0); if (tk == ':') CDecl_ParseBaseClassList(tclass, mode, is_templ); CScope_SetClassDefScope(tclass, &scopesave); if (tk == '{') { tk = lex(); if ((add_to_browse = cparamblkptr->browseoptions.recordClasses && declinfo->file->recordbrowseinfo)) { offsetsave = member_fileoffset; CBrowse_BeginClass(declinfo, &gl); } CDecl_ParseClassMembers(&decle, tclass, mode); offset = CPrep_BrowserFileOffset(); if (flag1) tk = lex(); if (add_to_browse) { member_fileoffset = offsetsave; if (flag1 && tk == ';') CPrep_BrowserFileOffset(); CBrowse_EndClass(offset, &gl); } } else { CError_Error(CErrorStr135); } if (is_templ) CTemplClass_CompleteClass(TEMPL_CLASS(tclass), &decle); else CDecl_CompleteClass(&decle, tclass); CScope_RestoreScope(&scopesave); } }