void visit(TypeFunction *t) { size_t nparams = Parameter::dim(t->parameters); type *tmp[10]; type **ptypes = tmp; if (nparams > 10) ptypes = (type **)malloc(sizeof(type*) * nparams); for (size_t i = 0; i < nparams; i++) { Parameter *p = Parameter::getNth(t->parameters, i); type *tp = Type_toCtype(p->type); if (p->storageClass & (STCout | STCref)) tp = type_allocn(TYref, tp); else if (p->storageClass & STClazy) { // Mangle as delegate type *tf = type_function(TYnfunc, NULL, 0, false, tp); tp = type_delegate(tf); } ptypes[i] = tp; } t->ctype = type_function(totym(t), ptypes, nparams, t->varargs == 1, Type_toCtype(t->next)); if (nparams > 10) free(ptypes); }
static gboolean process_open_channel (CockpitRouter *self, const gchar *channel, JsonObject *options, GBytes *data, gpointer user_data) { GType (* type_function) (void) = user_data; GType channel_type = 0; const gchar *group; if (!cockpit_json_get_string (options, "group", "default", &group)) g_warning ("%s: caller specified invalid 'group' field in open message", channel); g_assert (type_function != NULL); channel_type = type_function (); if (g_str_equal (group, "fence")) g_hash_table_add (self->fences, g_strdup (channel)); g_hash_table_insert (self->groups, g_strdup (channel), g_strdup (group)); create_channel (self, channel, options, channel_type); return TRUE; }
type default_conversion_for_assignment(expression e) { if (type_array(e->type) || type_function(e->type)) return default_conversion(e); else return e->type; }
type *TypeFunction::toCtype() { if (!ctype) { size_t nparams = Parameter::dim(parameters); type *tmp[10]; type **ptypes = tmp; if (nparams > 10) ptypes = (type **)malloc(sizeof(type*) * nparams); for (size_t i = 0; i < nparams; i++) { Parameter *arg = Parameter::getNth(parameters, i); type *tp = arg->type->toCtype(); if (arg->storageClass & (STCout | STCref)) tp = type_allocn(TYref, tp); ptypes[i] = tp; } type* tnext = next ? next->toCtype() : tsvoid; ctype = type_function(totym(), ptypes, nparams, varargs == 1, tnext); if (nparams > 10) free(ptypes); } return ctype; }
static bool voidstar_conditional(type t1, type t2) { if (type_void(t1)) { if (pedantic && type_function(t2)) pedwarn("ANSI C forbids conditional expr between `void *' and function pointer"); return TRUE; } return FALSE; }
bool valid_compare(type t1, type t2, expression e1) { if (type_void(type_points_to(t1))) { if (pedantic && type_function(type_points_to(t2)) && !definite_null(e1)) pedwarn("ANSI C forbids comparison of `void *' with function pointer"); return TRUE; } return FALSE; }
symbol *callFuncsAndGates(Module *m, symbols *sctors, StaticDtorDeclarations *ectorgates, const char *id) { symbol *sctor = NULL; if ((sctors && sctors->dim) || (ectorgates && ectorgates->dim)) { static type *t; if (!t) { /* t will be the type of the functions generated: * extern (C) void func(); */ t = type_function(TYnfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_c; } localgot = NULL; sctor = toSymbolX(m, id, SCglobal, t, "FZv"); cstate.CSpsymtab = &sctor->Sfunc->Flocsym; elem *ector = NULL; if (ectorgates) { for (size_t i = 0; i < ectorgates->dim; i++) { StaticDtorDeclaration *f = (*ectorgates)[i]; Symbol *s = toSymbol(f->vgate); elem *e = el_var(s); e = el_bin(OPaddass, TYint, e, el_long(TYint, 1)); ector = el_combine(ector, e); } } if (sctors) { for (size_t i = 0; i < sctors->dim; i++) { symbol *s = (*sctors)[i]; elem *e = el_una(OPucall, TYvoid, el_var(s)); ector = el_combine(ector, e); } } block *b = block_calloc(); b->BC = BCret; b->Belem = ector; sctor->Sfunc->Fstartline.Sfilename = m->arg; sctor->Sfunc->Fstartblock = b; writefunc(sctor); } return sctor; }
Symbol *Module::toModuleAssert() { if (!massert) { type *t = type_function(TYjfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_d; massert = toSymbolX("__assert", SCextern, t, "FiZv"); massert->Sfl = FLextern; massert->Sflags |= SFLnodebug; slist_add(massert); } return massert; }
Symbol *Module::toModuleUnittest() { if (!munittest) { type *t = type_function(TYjfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_d; munittest = toSymbolX("__unittest_fail", SCextern, t, "FiZv"); munittest->Sfl = FLextern; munittest->Sflags |= SFLnodebug; slist_add(munittest); } return munittest; }
Symbol *Module::toModuleArray() { if (!marray) { type *t = type_function(TYjfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_d; marray = toSymbolX("__array", SCextern, t, "Z"); marray->Sfl = FLextern; marray->Sflags |= SFLnodebug; slist_add(marray); } return marray; }
type default_conversion(expression e) { type from = e->type; if (type_enum(from)) from = type_tag(from)->reptype; if (type_smallerthanint(from)) { /* Traditionally, unsignedness is preserved in default promotions. */ if (flag_traditional && type_unsigned(from)) return unsigned_int_type; else return int_type; } if (flag_traditional && !flag_allow_single_precision && type_float(from)) return double_type; if (type_void(from)) { error("void value not ignored as it ought to be"); return error_type; } if (type_function(from)) { assert(!e->cst); e->cst = e->static_address; return make_pointer_type(from); } if (type_array(from)) { if (!e->lvalue) { error("invalid use of non-lvalue array"); return error_type; } assert(!e->cst); e->cst = e->static_address; /* It's being used as a pointer, so is not an lvalue */ e->lvalue = FALSE; return make_pointer_type(type_array_of(from)); } return from; }
void check_sizeof(expression result, type stype) { if (type_function(stype)) { if (pedantic || warn_pointer_arith) pedwarn("sizeof applied to a function type"); } else if (type_void(stype)) { if (pedantic || warn_pointer_arith) pedwarn("sizeof applied to a void type"); } else if (type_incomplete(stype)) error("sizeof applied to an incomplete type"); result->type = size_t_type; result->cst = fold_sizeof(result, stype); }
type pointer_int_sum(type ptype, type itype) { type pointed = type_points_to(ptype); if (type_void(pointed)) { if (pedantic || warn_pointer_arith) pedwarn("pointer of type `void *' used in arithmetic"); } else if (type_function(pointed)) { if (pedantic || warn_pointer_arith) pedwarn("pointer to a function used in arithmetic"); } else if (type_incomplete(pointed)) error("arithmetic on pointer to an incomplete type"); return ptype; }
Symbol *aaGetSymbol(TypeAArray *taa, const char *func, int flags) { #ifdef DEBUG assert((flags & ~1) == 0); #endif // Dumb linear symbol table - should use associative array! static Symbols *sarray = NULL; //printf("aaGetSymbol(func = '%s', flags = %d, key = %p)\n", func, flags, key); char *id = (char *)alloca(3 + strlen(func) + 1); sprintf(id, "_aa%s", func); if (!sarray) sarray = Symbols_create(); // See if symbol is already in sarray for (size_t i = 0; i < sarray->dim; i++) { Symbol *s = (*sarray)[i]; if (strcmp(id, s->Sident) == 0) { #ifdef DEBUG assert(s); #endif return s; // use existing Symbol } } // Create new Symbol Symbol *s = symbol_calloc(id); slist_add(s); s->Sclass = SCextern; s->Ssymnum = -1; symbol_func(s); type *t = type_function(TYnfunc, NULL, 0, false, Type_toCtype(taa->next)); t->Tmangle = mTYman_c; s->Stype = t; sarray->push(s); // remember it return s; }
/* Declare a new temporary that can be assigned a value of type t. Place the declaration at the start of block. XXX: See discussion in types.c:tag2ast about the (lack of) correctness of this approach. Return it's declaration */ data_decl build_declaration(region r, struct environment *e, type t, const char *name, expression init, data_declaration *oddecl) { struct data_declaration tempdecl; identifier_declarator id; variable_decl vd; data_decl dd; declarator tdeclarator; type_element tmodifiers; /* Compute real type, name */ if (type_array(t)) t = make_pointer_type(type_array_of(t)); else if (type_function(t)) t = make_pointer_type(t); /* Qualifiers must not be present on the temp (the qualifiers of t apply to the original location we are building a temp) */ t = make_qualified_type(t, no_qualifiers); /* Build AST for the declaration */ id = new_identifier_declarator(r, dummy_location, str2cstring(r, name)); type2ast(r, dummy_location, t, CAST(declarator, id), &tdeclarator, &tmodifiers); vd = new_variable_decl(r, dummy_location, tdeclarator, NULL, init, NULL, NULL); vd->declared_type = t; dd = new_data_decl(r, dummy_location, tmodifiers, CAST(declaration, vd)); if (e) /* Declare the variable */ { init_data_declaration(&tempdecl, CAST(declaration, vd), id->cstring.data, t); tempdecl.kind = decl_variable; tempdecl.vtype = variable_normal; tempdecl.islocal = TRUE; *oddecl = vd->ddecl = declare(e, &tempdecl, FALSE); } return dd; }
expression make_address_of(location loc, expression e) { expression result = CAST(expression, new_address_of(parse_region, loc, e)); result->type = error_type; if (e->type == error_type) ; else if (e->bitfield) error("attempt to take address of a bit-field structure member"); else { if (e->isregister) pedwarn("address of a register variable requested"); if (!(type_function(e->type) || e->lvalue)) error("invalid lvalue in unary `&'"); result->type = make_pointer_type(e->type); result->cst = e->static_address; } return result; }
void visit(TypeFunction *t) { size_t nparams = Parameter::dim(t->parameters); type *tmp[10]; type **ptypes = tmp; if (nparams > 10) ptypes = (type **)malloc(sizeof(type*) * nparams); for (size_t i = 0; i < nparams; i++) { Parameter *arg = Parameter::getNth(t->parameters, i); type *tp = Type_toCtype(arg->type); if (arg->storageClass & (STCout | STCref)) tp = type_allocn(TYref, tp); ptypes[i] = tp; } t->ctype = type_function(t->totym(), ptypes, nparams, t->varargs == 1, Type_toCtype(t->next)); if (nparams > 10) free(ptypes); }
static void ptrconversion_warnings(type ttl, type ttr, expression rhs, const char *context, const char *funname, int parmnum, bool pedantic) { if (pedantic && ((type_void(ttl) && type_function(ttr)) || (type_function(ttl) && type_void(ttr) && !(rhs && definite_null(rhs))))) warn_for_assignment("ANSI forbids %s between function pointer and `void *'", context, funname, parmnum); /* Const and volatile mean something different for function types, so the usual warnings are not appropriate. */ else if (type_function(ttl) && type_function(ttr)) { /* Because const and volatile on functions are restrictions that say the function will not do certain things, it is okay to use a const or volatile function where an ordinary one is wanted, but not vice-versa. */ if (type_const(ttl) && !type_const(ttr)) warn_for_assignment("%s makes `const *' function pointer from non-const", context, funname, parmnum); if (type_volatile(ttl) && !type_volatile(ttr)) warn_for_assignment("%s makes `volatile *' function pointer from non-volatile", context, funname, parmnum); } else if (!type_function(ttl) && !type_function(ttr)) { if (!type_const(ttl) && type_const(ttr)) warn_for_assignment("%s discards `const' from pointer target type", context, funname, parmnum); if (!type_volatile(ttl) && type_volatile(ttr)) warn_for_assignment("%s discards `volatile' from pointer target type", context, funname, parmnum); /* If this is not a case of ignoring a mismatch in signedness, no warning. */ if (!assignable_pointer_targets(ttl, ttr, FALSE) && pedantic) warn_for_assignment("pointer targets in %s differ in signedness", context, funname, parmnum); } }
void genObjFile(Module *m, bool multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, m->toChars()); if (m->ident == Id::entrypoint) { bool v = global.params.verbose; global.params.verbose = false; for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *member = (*m->members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); toObjFile(member, global.params.multiobj); } global.params.verbose = v; return; } lastmname = m->srcfile->toChars(); objmod->initfile(lastmname, NULL, m->toPrettyChars()); eictor = NULL; ictorlocalgot = NULL; sctors.setDim(0); ectorgates.setDim(0); sdtors.setDim(0); ssharedctors.setDim(0); esharedctorgates.setDim(0); sshareddtors.setDim(0); stests.setDim(0); if (m->doppelganger) { /* Generate a reference to the moduleinfo, so the module constructors * and destructors get linked in. */ Module *mod = m->aimports[0]; assert(mod); if (mod->sictor || mod->sctor || mod->sdtor || mod->ssharedctor || mod->sshareddtor) { Symbol *s = toSymbol(mod); //objextern(s); //if (!s->Sxtrnnum) objextdef(s->Sident); if (!s->Sxtrnnum) { //printf("%s\n", s->Sident); #if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s->Sident); #else Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr)); sref->Sfl = FLdata; dtxoff(&sref->Sdt, s, 0, TYnptr); outdata(sref); #endif } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ m->cov = symbol_calloc("__coverage"); m->cov->Stype = type_fake(TYint); m->cov->Stype->Tmangle = mTYman_c; m->cov->Stype->Tcount++; m->cov->Sclass = SCstatic; m->cov->Sfl = FLdata; dtnzeros(&m->cov->Sdt, 4 * m->numlines); outdata(m->cov); slist_add(m->cov); m->covb = (unsigned *)calloc((m->numlines + 32) / 32, sizeof(*m->covb)); } for (size_t i = 0; i < m->members->dim; i++) { Dsymbol *member = (*m->members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); toObjFile(member, multiobj); } if (global.params.cov) { /* Generate * bit[numlines] __bcoverage; */ Symbol *bcov = symbol_calloc("__bcoverage"); bcov->Stype = type_fake(TYuint); bcov->Stype->Tcount++; bcov->Sclass = SCstatic; bcov->Sfl = FLdata; dtnbytes(&bcov->Sdt, (m->numlines + 32) / 32 * sizeof(*m->covb), (char *)m->covb); outdata(bcov); free(m->covb); m->covb = NULL; /* Generate: * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); * and prepend it to the static constructor. */ /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_function(TYnfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_c; m->sictor = toSymbolX(m, "__modictor", SCglobal, t, "FZv"); cstate.CSpsymtab = &m->sictor->Sfunc->Flocsym; localgot = ictorlocalgot; elem *ecov = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(m->cov)); elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, m->numlines), el_ptr(bcov)); if (config.exe == EX_WIN64) { ecov = addressElem(ecov, Type::tvoid->arrayOf(), false); ebcov = addressElem(ebcov, Type::tvoid->arrayOf(), false); } elem *efilename = toEfilename(m); if (config.exe == EX_WIN64) efilename = addressElem(efilename, Type::tstring, true); elem *e = el_params( el_long(TYuchar, global.params.covPercent), ecov, ebcov, efilename, NULL); e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER2]), e); eictor = el_combine(e, eictor); ictorlocalgot = localgot; } // If coverage / static constructor / destructor / unittest calls if (eictor || sctors.dim || ectorgates.dim || sdtors.dim || ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim) { if (eictor) { localgot = ictorlocalgot; block *b = block_calloc(); b->BC = BCret; b->Belem = eictor; m->sictor->Sfunc->Fstartline.Sfilename = m->arg; m->sictor->Sfunc->Fstartblock = b; writefunc(m->sictor); } m->sctor = callFuncsAndGates(m, &sctors, &ectorgates, "__modctor"); m->sdtor = callFuncsAndGates(m, &sdtors, NULL, "__moddtor"); m->ssharedctor = callFuncsAndGates(m, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); m->sshareddtor = callFuncsAndGates(m, &sshareddtors, NULL, "__modshareddtor"); m->stest = callFuncsAndGates(m, &stests, NULL, "__modtest"); if (m->doppelganger) genModuleInfo(m); } if (m->doppelganger) { objmod->termfile(); return; } if (global.params.multiobj) { /* This is necessary because the main .obj for this module is written * first, but determining whether marray or massert or munittest are needed is done * possibly later in the doppelganger modules. * Another way to fix it is do the main one last. */ toModuleAssert(m); toModuleUnittest(m); toModuleArray(m); } /* Always generate module info, because of templates and -cov. * But module info needs the runtime library, so disable it for betterC. */ if (!global.params.betterC /*|| needModuleInfo()*/) genModuleInfo(m); genhelpers(m, false); objmod->termfile(); }
/* Return TRUE if no error and lhstype and rhstype are not error_type */ bool check_assignment(type lhstype, type rhstype, expression rhs, const char *context, data_declaration fundecl, const char *funname, int parmnum) { bool zerorhs = rhs && definite_zero(rhs); if (lhstype == error_type || rhstype == error_type) return FALSE; if (type_void(rhstype)) { error("void value not ignored as it ought to be"); return FALSE; } if (type_equal_unqualified(lhstype, rhstype)) return TRUE; if (type_arithmetic(lhstype) && type_arithmetic(rhstype)) { if (rhs) constant_overflow_warning(rhs->cst); return check_conversion(lhstype, rhstype); } if (parmnum && (type_qualifiers(lhstype) & transparent_qualifier)) { /* See if we can match any field of lhstype */ tag_declaration tag = type_tag(lhstype); field_declaration fields, marginal_field = NULL; /* I blame gcc for this horrible mess (and it's minor inconsistencies with the regular rules) */ /* pedantic warnings are skipped in here because we're already issuing a warning for the use of this construct */ for (fields = tag->fieldlist; fields; fields = fields->next) { type ft = fields->type; if (type_compatible(ft, rhstype)) break; if (!type_pointer(ft)) continue; if (type_pointer(rhstype)) { type ttl = type_points_to(ft), ttr = type_points_to(rhstype); bool goodmatch = assignable_pointer_targets(ttl, ttr, FALSE); /* Any non-function converts to a [const][volatile] void * and vice versa; otherwise, targets must be the same. Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if (goodmatch) { /* If this type won't generate any warnings, use it. */ if ((type_function(ttr) && type_function(ttl)) ? (((!type_const(ttl)) | type_const(ttr)) & ((!type_volatile(ttl)) | type_volatile(ttr))) : (((type_const(ttl)) | (!type_const(ttr))) & (type_volatile(ttl) | (!type_volatile(ttr))))) break; /* Keep looking for a better type, but remember this one. */ if (!marginal_field) marginal_field = fields; } } /* Can convert integer zero to any pointer type. */ /* Note that this allows passing *any* null pointer (gcc bug?) */ if (zerorhs) break; } if (fields || marginal_field) { if (!fields) { /* We have only a marginally acceptable member type; it needs a warning. */ type ttl = type_points_to(marginal_field->type), ttr = type_points_to(rhstype); ptrconversion_warnings(ttl, ttr, rhs, context, funname, parmnum, FALSE); } if (pedantic && !(fundecl && fundecl->in_system_header)) pedwarn("ANSI C prohibits argument conversion to union type"); return TRUE; } } if (type_pointer(lhstype) && type_pointer(rhstype)) { type ttl = type_points_to(lhstype), ttr = type_points_to(rhstype); bool goodmatch = assignable_pointer_targets(ttl, ttr, pedantic); /* Any non-function converts to a [const][volatile] void * and vice versa; otherwise, targets must be the same. Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if (goodmatch || (type_equal_unqualified(make_unsigned_type(ttl), make_unsigned_type(ttr)))) ptrconversion_warnings(ttl, ttr, rhs, context, funname, parmnum, pedantic); else warn_for_assignment("%s from incompatible pointer type", context, funname, parmnum); return check_conversion(lhstype, rhstype); } /* enum = ptr and ptr = enum counts as an error, so use type_integral */ else if (type_pointer(lhstype) && type_integral(rhstype)) { if (!zerorhs) warn_for_assignment("%s makes pointer from integer without a cast", context, funname, parmnum); return check_conversion(lhstype, rhstype); } else if (type_integral(lhstype) && type_pointer(rhstype)) { warn_for_assignment("%s makes integer from pointer without a cast", context, funname, parmnum); return check_conversion(lhstype, rhstype); } if (!context) if (funname) error("incompatible type for argument %d of `%s'", parmnum, funname); else error("incompatible type for argument %d of indirect function call", parmnum); else error("incompatible types in %s", context); return FALSE; }
expression make_cast(location loc, asttype t, expression e) { expression result = CAST(expression, new_cast(parse_region, loc, e, t)); type castto = t->type; if (castto == error_type || type_void(castto)) ; /* Do nothing */ else if (type_array(castto)) { error("cast specifies array type"); castto = error_type; } else if (type_function(castto)) { error("cast specifies function type"); castto = error_type; } else if (type_equal_unqualified(castto, e->type)) { if (pedantic && type_aggregate(castto)) pedwarn("ANSI C forbids casting nonscalar to the same type"); } else { type etype = e->type; /* Convert functions and arrays to pointers, but don't convert any other types. */ if (type_function(etype) || type_array(etype)) etype = default_conversion(e); if (type_union(castto)) { tag_declaration utag = type_tag(castto); field_declaration ufield; /* Look for etype as a field of the union */ for (ufield = utag->fieldlist; ufield; ufield = ufield->next) if (ufield->name && type_equal_unqualified(ufield->type, etype)) { if (pedantic) pedwarn("ANSI C forbids casts to union type"); break; } if (!ufield) error("cast to union type from type not present in union"); } else { /* Optionally warn about potentially worrisome casts. */ if (warn_cast_qual && type_pointer(etype) && type_pointer(castto)) { type ep = type_points_to(etype), cp = type_points_to(castto); if (type_volatile(ep) && !type_volatile(cp)) pedwarn("cast discards `volatile' from pointer target type"); if (type_const(ep) && !type_const(cp)) pedwarn("cast discards `const' from pointer target type"); } /* This warning is weird */ if (warn_bad_function_cast && is_function_call(e) && !type_equal_unqualified(castto, etype)) warning ("cast does not match function type"); #if 0 /* Warn about possible alignment problems. */ if (STRICT_ALIGNMENT && warn_cast_align && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (otype) == POINTER_TYPE && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE /* Don't warn about opaque types, where the actual alignment restriction is unknown. */ && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE) && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode) && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype))) warning ("cast increases required alignment of target type"); if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (otype) == POINTER_TYPE && TYPE_PRECISION (type) != TYPE_PRECISION (otype) && !TREE_CONSTANT (value)) warning ("cast from pointer to integer of different size"); if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (otype) == INTEGER_TYPE && TYPE_PRECISION (type) != TYPE_PRECISION (otype) #if 0 /* Don't warn about converting 0 to pointer, provided the 0 was explicit--not cast or made by folding. */ && !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value)) #endif /* Don't warn about converting any constant. */ && !TREE_CONSTANT (value)) warning ("cast to pointer from integer of different size"); #endif check_conversion(castto, etype); } } result->lvalue = !pedantic && e->lvalue; result->isregister = e->isregister; result->bitfield = e->bitfield; result->static_address = e->static_address; result->type = castto; result->cst = fold_cast(result); return result; }
void Module::genobjfile(int multiobj) { //EEcontext *ee = env->getEEcontext(); //printf("Module::genobjfile(multiobj = %d) %s\n", multiobj, toChars()); lastmname = srcfile->toChars(); objmod->initfile(lastmname, NULL, toPrettyChars()); eictor = NULL; ictorlocalgot = NULL; sctors.setDim(0); ectorgates.setDim(0); sdtors.setDim(0); ssharedctors.setDim(0); esharedctorgates.setDim(0); sshareddtors.setDim(0); stests.setDim(0); dtorcount = 0; shareddtorcount = 0; if (doppelganger) { /* Generate a reference to the moduleinfo, so the module constructors * and destructors get linked in. */ Module *m = aimports[0]; assert(m); if (m->sictor || m->sctor || m->sdtor || m->ssharedctor || m->sshareddtor) { Symbol *s = m->toSymbol(); //objextern(s); //if (!s->Sxtrnnum) objextdef(s->Sident); if (!s->Sxtrnnum) { //printf("%s\n", s->Sident); #if 0 /* This should work, but causes optlink to fail in common/newlib.asm */ objextdef(s->Sident); #else Symbol *sref = symbol_generate(SCstatic, type_fake(TYnptr)); sref->Sfl = FLdata; dtxoff(&sref->Sdt, s, 0, TYnptr); outdata(sref); #endif } } } if (global.params.cov) { /* Create coverage identifier: * private uint[numlines] __coverage; */ cov = symbol_calloc("__coverage"); cov->Stype = type_fake(TYint); cov->Stype->Tmangle = mTYman_c; cov->Stype->Tcount++; cov->Sclass = SCstatic; cov->Sfl = FLdata; dtnzeros(&cov->Sdt, 4 * numlines); outdata(cov); slist_add(cov); covb = (unsigned *)calloc((numlines + 32) / 32, sizeof(*covb)); } for (size_t i = 0; i < members->dim; i++) { Dsymbol *member = (*members)[i]; //printf("toObjFile %s %s\n", member->kind(), member->toChars()); member->toObjFile(multiobj); } if (global.params.cov) { /* Generate * bit[numlines] __bcoverage; */ Symbol *bcov = symbol_calloc("__bcoverage"); bcov->Stype = type_fake(TYuint); bcov->Stype->Tcount++; bcov->Sclass = SCstatic; bcov->Sfl = FLdata; dtnbytes(&bcov->Sdt, (numlines + 32) / 32 * sizeof(*covb), (char *)covb); outdata(bcov); free(covb); covb = NULL; /* Generate: * _d_cover_register(uint[] __coverage, BitArray __bcoverage, string filename); * and prepend it to the static constructor. */ /* t will be the type of the functions generated: * extern (C) void func(); */ type *t = type_function(TYnfunc, NULL, 0, false, tsvoid); t->Tmangle = mTYman_c; sictor = toSymbolX("__modictor", SCglobal, t, "FZv"); cstate.CSpsymtab = &sictor->Sfunc->Flocsym; localgot = ictorlocalgot; elem *ecov = el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(cov)); elem *ebcov = el_pair(TYdarray, el_long(TYsize_t, numlines), el_ptr(bcov)); if (config.exe == EX_WIN64) { ecov = addressElem(ecov, Type::tvoid->arrayOf(), false); ebcov = addressElem(ebcov, Type::tvoid->arrayOf(), false); } elem *e = el_params( el_long(TYuchar, global.params.covPercent), ecov, ebcov, toEfilename(), NULL); e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_DCOVER2]), e); eictor = el_combine(e, eictor); ictorlocalgot = localgot; } // If coverage / static constructor / destructor / unittest calls if (eictor || sctors.dim || ectorgates.dim || sdtors.dim || ssharedctors.dim || esharedctorgates.dim || sshareddtors.dim || stests.dim) { if (eictor) { localgot = ictorlocalgot; block *b = block_calloc(); b->BC = BCret; b->Belem = eictor; sictor->Sfunc->Fstartline.Sfilename = arg; sictor->Sfunc->Fstartblock = b; writefunc(sictor); } sctor = callFuncsAndGates(this, &sctors, &ectorgates, "__modctor"); sdtor = callFuncsAndGates(this, &sdtors, NULL, "__moddtor"); #if DMDV2 ssharedctor = callFuncsAndGates(this, &ssharedctors, (StaticDtorDeclarations *)&esharedctorgates, "__modsharedctor"); sshareddtor = callFuncsAndGates(this, &sshareddtors, NULL, "__modshareddtor"); #endif stest = callFuncsAndGates(this, &stests, NULL, "__modtest"); if (doppelganger) genmoduleinfo(); } if (doppelganger) { objmod->termfile(); return; } if (global.params.multiobj) { /* This is necessary because the main .obj for this module is written * first, but determining whether marray or massert or munittest are needed is done * possibly later in the doppelganger modules. * Another way to fix it is do the main one last. */ toModuleAssert(); toModuleUnittest(); toModuleArray(); } /* Always generate module info, because of templates and -cov. * But module info needs the runtime library, so disable it for betterC. */ if (!global.params.betterC /*|| needModuleInfo()*/) genmoduleinfo(); // If module assert for (int i = 0; i < 3; i++) { Symbol *ma; unsigned rt; unsigned bc; switch (i) { case 0: ma = marray; rt = RTLSYM_DARRAY; bc = BCexit; break; case 1: ma = massert; rt = RTLSYM_DASSERTM; bc = BCexit; break; case 2: ma = munittest; rt = RTLSYM_DUNITTESTM; bc = BCret; break; default: assert(0); } if (ma) { elem *elinnum; localgot = NULL; // Call dassert(filename, line) // Get sole parameter, linnum { Symbol *sp = symbol_calloc("linnum"); sp->Stype = type_fake(TYint); sp->Stype->Tcount++; sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar; FuncParamRegs fpr(TYjfunc); fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2); sp->Sflags &= ~SFLspill; sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast; cstate.CSpsymtab = &ma->Sfunc->Flocsym; symbol_add(sp); elinnum = el_var(sp); } elem *efilename = el_ptr(toSymbol()); elem *e = el_var(rtlsym[rt]); e = el_bin(OPcall, TYvoid, e, el_param(elinnum, efilename)); block *b = block_calloc(); b->BC = bc; b->Belem = e; ma->Sfunc->Fstartline.Sfilename = arg; ma->Sfunc->Fstartblock = b; ma->Sclass = SCglobal; ma->Sfl = 0; ma->Sflags |= rtlsym[rt]->Sflags & SFLexit; writefunc(ma); } } objmod->termfile(); }
type check_binary(int binop, expression e1, expression e2) { type t1 = default_conversion(e1), t2 = default_conversion(e2); type rtype = NULL; bool common = FALSE; /* XXX: Misc warnings (see build_binary_op) */ if (t1 == error_type || t2 == error_type) rtype = error_type; else switch(binop) { case kind_plus: if (type_pointer(t1) && type_integer(t2)) rtype = pointer_int_sum(t1, t2); else if (type_pointer(t2) && type_integer(t1)) rtype = pointer_int_sum(t2, t1); else common = TRUE; break; case kind_minus: if (type_pointer(t1) && type_integer(t2)) rtype = pointer_int_sum(t1, t2); else if (type_pointer(t1) && type_pointer(t2) && compatible_pointer_types(t1, t2)) rtype = ptrdiff_t_type; else common = TRUE; break; case kind_plus_assign: case kind_minus_assign: if (type_pointer(t1) && type_integer(t2)) rtype = pointer_int_sum(t1, t2); else common = TRUE; break; case kind_times: case kind_divide: case kind_times_assign: case kind_divide_assign: common = TRUE; break; case kind_modulo: case kind_bitand: case kind_bitor: case kind_bitxor: case kind_lshift: case kind_rshift: case kind_modulo_assign: case kind_bitand_assign: case kind_bitor_assign: case kind_bitxor_assign: case kind_lshift_assign: case kind_rshift_assign: if (type_integer(t1) && type_integer(t2)) rtype = common_type(t1, t2); break; case kind_leq: case kind_geq: case kind_lt: case kind_gt: rtype = int_type; /* Default to assuming success */ if (type_real(t1) && type_real(t2)) ; else if (type_pointer(t1) && type_pointer(t2)) { if (compatible_pointer_types(t1, t2)) { /* XXX: how can this happen ? */ if (type_incomplete(t1) != type_incomplete(t2)) pedwarn("comparison of complete and incomplete pointers"); else if (pedantic && type_function(type_points_to(t1))) pedwarn("ANSI C forbids ordered comparisons of pointers to functions"); } else pedwarn("comparison of distinct pointer types lacks a cast"); } /* XXX: Use of definite_zero may lead to extra warnings when !extra_warnings */ else if ((type_pointer(t1) && definite_zero(e2)) || (type_pointer(t2) && definite_zero(e1))) { if (pedantic || extra_warnings) pedwarn("ordered comparison of pointer with integer zero"); } else if ((type_pointer(t1) && type_integer(t2)) || (type_pointer(t2) && type_integer(t1))) { if (!flag_traditional) pedwarn("comparison between pointer and integer"); } else rtype = NULL; /* Force error */ break; case kind_eq: case kind_ne: rtype = int_type; /* Default to assuming success */ if (type_arithmetic(t1) && type_arithmetic(t2)) ; else if (type_pointer(t1) && type_pointer(t2)) { if (!compatible_pointer_types(t1, t2) && !valid_compare(t1, t2, e1) && !valid_compare(t2, t1, e2)) pedwarn("comparison of distinct pointer types lacks a cast"); } else if ((type_pointer(t1) && definite_null(e2)) || (type_pointer(t2) && definite_null(e1))) ; else if ((type_pointer(t1) && type_integer(t2)) || (type_pointer(t2) && type_integer(t1))) { if (!flag_traditional) pedwarn("comparison between pointer and integer"); } else rtype = NULL; /* Force error */ break; case kind_andand: case kind_oror: if (type_scalar(t1) && type_scalar(t2)) rtype = int_type; break; default: assert(0); break; } if (common && type_arithmetic(t1) && type_arithmetic(t2)) rtype = common_type(t1, t2); if (!rtype) { error("invalid operands to binary %s", binary_op_name(binop)); rtype = error_type; } return rtype; }