static void createCaller(void) { FUNCTIONCALL *params = Alloc(sizeof(FUNCTIONCALL)); TYPE *args = realArgs(lambdas->func); SYMBOL *func = makeID(sc_member, args, NULL, overloadNameTab[CI_FUNC]); SYMBOL *lambdaCall = search(isstructured(basetype(lambdas->func->tp)->btp) ? "__lambdaCallS" : "__lambdaCall", globalNameSpace->syms); BLOCKDATA block1, block2; STATEMENT *st; lambdaCall = (SYMBOL *)lambdaCall->tp->syms->table[0]->p; func->parentClass = lambdas->cls; func->linkage = lk_virtual; func->isInline = FALSE; func->omitFrame = TRUE; memset(&block1, 0, sizeof(BLOCKDATA)); memset(&block2, 0, sizeof(BLOCKDATA)); insertFunc(lambdas->cls, func); InsertInline(func); st = stmtNode(NULL, &block2, isstructured(basetype(lambdas->func->tp)->btp) ? st_expr : st_return); st->select = varNode(en_func, NULL); st->select->v.func = params; params->arguments = Alloc(sizeof(INITLIST)); params->arguments->exp = varNode(en_pc, lambdas->func); params->arguments->tp = &stdpointer; params->ascall = TRUE; params->sp = func; params->fcall = varNode(en_pc, lambdaCall); params->functp = func->tp; st = stmtNode(NULL, &block1, st_block); st->lower = block2.head; st->blockTail = block2.blockTail; func->inlineFunc.stmt = stmtNode(NULL, NULL, st_block); func->inlineFunc.stmt->lower = block1.head; func->inlineFunc.stmt->blockTail = block1.blockTail; }
EXPRESSION *anonymousVar(enum e_sc storage_class, TYPE *tp) { static int anonct = 1; char buf[256]; SYMBOL *rv = (SYMBOL *)Alloc(sizeof(SYMBOL)); // if ((storage_class == sc_localstatic || storage_class == sc_auto) && !theCurrentFunc) // { // storage_class = sc_static; // insertInitSym(rv); // } if (tp->size == 0 && isstructured(tp)) tp = basetype(tp)->sp->tp; rv->storage_class = storage_class; rv->tp = tp; rv->anonymous = TRUE; rv->allocate = !anonymousNotAlloc; rv->assigned = TRUE; rv->used = TRUE; if (theCurrentFunc) rv->value.i = theCurrentFunc->value.i; sprintf(buf,"$anontemp%d", anonct++); rv->name = litlate(buf); tp->size = basetype(tp)->size; if (theCurrentFunc && !inDefaultParam) InsertSymbol(rv, storage_class, FALSE, FALSE); SetLinkerNames(rv, lk_none); return varNode(storage_class == sc_auto || storage_class == sc_parameter ? en_auto : storage_class == sc_localstatic ? en_label : en_global, rv); }
static BOOLEAN trivialDestructor(TYPE *tp) { if (isstructured(tp)) { HASHREC *hr; SYMBOL *ovl; BASECLASS *bc; ovl = search(overloadNameTab[CI_DESTRUCTOR ], basetype(tp)->syms); if (ovl) { ovl = (SYMBOL *)ovl->tp->syms->table[0]->p; if (!ovl->defaulted) return FALSE; } bc = basetype(tp)->sp->baseClasses; while (bc) { if (!trivialDestructor(bc->cls->tp)) return FALSE; bc = bc->next; } hr = basetype(tp)->syms->table[0]; while (hr) { SYMBOL *sym = (SYMBOL *)hr->p; if (sym->storage_class == sc_mutable || sym->storage_class == sc_member) if (!trivialDestructor(sym->tp)) return FALSE; hr = hr->next; } } return TRUE; }
static BOOLEAN nothrowConstructible(TYPE *tp) { if (isstructured(tp)) { SYMBOL *ovl; // recursion will have been taken care of elsewhere... ovl = search(overloadNameTab[CI_CONSTRUCTOR ], basetype(tp)->syms); if (ovl) { HASHREC *hr = ovl->tp->syms->table[0]; hr = basetype(ovl->tp)->syms->table[0]; while (hr) { SYMBOL *sp = (SYMBOL *)hr->p; HASHREC *hr1 = basetype(sp->tp)->syms->table[0]; if (matchesCopy(sp, FALSE) || matchesCopy(sp, TRUE) || !hr1->next || !hr1->next->next || ((SYMBOL *)hr1->next->next->p)->tp->type == bt_void) { if (sp->xcMode != xc_none) return FALSE; } hr = hr->next; } } } return TRUE; }
static BOOLEAN trivialCopyAssignable(TYPE *tp) { if (isstructured(tp)) { HASHREC *hr; SYMBOL *ovl; BASECLASS * bc; ovl = search(overloadNameTab[assign - kw_new + CI_NEW ], basetype(tp)->syms); if (ovl) { if (!trivialFunc(ovl, FALSE) || !trivialFunc(ovl, TRUE)) return FALSE; } bc = basetype(tp)->sp->baseClasses; while (bc) { if (!trivialCopyAssignable(bc->cls->tp)) return FALSE; bc = bc->next; } hr = basetype(tp)->syms->table[0]; while (hr) { SYMBOL *sym = (SYMBOL *)hr->p; if (sym->storage_class == sc_mutable || sym->storage_class == sc_member) if (!trivialCopyAssignable(sym->tp)) return FALSE; hr = hr->next; } } return TRUE; }
int link_BasicType(TYPE *tp) { static int basicTypes[] = { 35,34,40,48,41,46,49,45,0,42,47,50,43,51,44,52,72,73,74,80,81,82,88,89,90,32 } ; static int pointedTypes[] = { 0,0,40+16,48+16,41+16,46+16,49+16,45+16,0,42+16,47+16,50+16,43+16,51+16,44+16,52+16,72+16,73+16,74+16,80+16,81+16,82+16,88+16,89+16,90+16,33 }; int n = 0; TYPE *tp1 = basetype(tp); if( tp1->type <= bt_void) { n = basicTypes[tp1->type]; } else if (tp1->type == bt_pointer && !tp1->array && !tp1->vla && !tp1->bits) { TYPE *tp2 = basetype(tp1->btp); if (tp2->type <= bt_void) { n = pointedTypes[tp2->type]; } } return n; }
BOOLEAN assignDiscardsConst(TYPE *dest, TYPE *source) { source = basetype(source); dest = basetype(dest); if (!ispointer(source) || !ispointer(dest)) return FALSE; while (TRUE) { BOOLEAN destc = FALSE; BOOLEAN sourcc = FALSE; BOOLEAN done = FALSE; while (!done) { switch(dest->type) { case bt_const: destc = TRUE; case bt_restrict: case bt_volatile: case bt_static: case bt_typedef: case bt_lrqual: case bt_rrqual: case bt_derivedfromtemplate: dest = dest->btp; break; default: done = TRUE; break; } } done = FALSE; while (!done) { switch(source->type) { case bt_const: sourcc = TRUE; case bt_restrict: case bt_volatile: case bt_static: case bt_typedef: case bt_lrqual: case bt_rrqual: source = source->btp; break; default: done = TRUE; break; } } if (sourcc && !destc) return TRUE; if (source->type != bt_pointer || dest->type != bt_pointer) return FALSE; dest = dest->btp; source = source->btp; } }
static BOOLEAN isStandardLayout(TYPE *tp, SYMBOL **result) { if (isstructured(tp) && !hasVTab(basetype(tp)->sp) && !basetype(tp)->sp->vbaseEntries ) { int n; int access = -1; SYMBOL *found = NULL, *first; HASHREC *hr; n = FindBaseClassWithData(tp->sp, &found); if (n > 1) return FALSE; if (n) { SYMBOL *first = NULL; hr = basetype(found->tp)->syms->table[0]; while (hr) { SYMBOL *sp = (SYMBOL *)hr->p; if (!first) first = sp; if (sp->storage_class == sc_member || sp->storage_class == sc_mutable) { if (isstructured(sp->tp) && !isStandardLayout(sp->tp, NULL)) return FALSE; if (access != -1) { if (access != sp->access) return FALSE; } access = sp->access; } hr = hr->next; } if (first && isstructured(first->tp)) { BASECLASS *bc = found->baseClasses; while (bc) { if (comparetypes(bc->cls->tp, first->tp, TRUE)) return FALSE; bc = bc->next; } } } if (result) *result = found; return TRUE; } return FALSE; /* hasnonon-staticdatamembersoftypenon-standard-layoutclass(orarrayofsuchtypes)orreference, — has no virtual functions (10.3) and no virtual base classes (10.1), — has the same access control (Clause 11) for all non-static data members, — has no non-standard-layout base classes, — either has no non-static data members in the most derived class and at most one base class with non-static data members, or has no base classes with non-static data members, and — has no base classes of the same type as the ?rst non-static data member. */ }
BOOLEAN matchOverload(TYPE *tnew, TYPE *told) { HASHREC *hnew = basetype(tnew)->syms->table[0]; HASHREC *hold = basetype(told)->syms->table[0]; // if (snew->templateLevel != sold->templateLevel) // return FALSE; if (isconst(tnew) != isconst(told)) return FALSE; while (hnew && hold) { SYMBOL *snew = (SYMBOL *)hnew->p; SYMBOL *sold = (SYMBOL *)hold->p; if (sold->thisPtr) { hold = hold->next; if (!hold) break; sold = hold->p; } if (snew->thisPtr) { hnew = hnew->next; if (!hnew) break; snew = hnew->p; } if (snew->tp->type == bt_templateparam) { if (sold->tp->type != bt_templateparam || snew->tp->templateParam->p->type != sold->tp->templateParam->p->type || snew->tp->templateParam->p->type != kw_typename || (snew->tp->templateParam->p->byClass.dflt || sold->tp->templateParam->p->byClass.dflt) && (!snew->tp->templateParam->p->byClass.dflt || !sold->tp->templateParam->p->byClass.dflt || !comparetypes(sold->tp->templateParam->p->byClass.dflt, snew->tp->templateParam->p->byClass.dflt, TRUE))) break; } else if (sold->tp->type == bt_any || snew->tp->type == bt_any) // packed template param break; else if (!comparetypes(sold->tp, snew->tp, TRUE) && !sameTemplate(sold->tp, snew->tp) || basetype(sold->tp)->type != basetype(snew->tp)->type) break; else { TYPE *tps = sold->tp; TYPE *tpn = snew->tp; if (isref(tps)) tps = basetype(tps)->btp; if (isref(tpn)) tpn = basetype(tpn)->btp; if (isconst(tpn) != isconst(tps) || isvolatile(tpn) != isvolatile(tps)) break; } hold = hold->next; hnew = hnew->next; } if (!hold && !hnew) return TRUE; return NULL; }
EXPRESSION *doinline(FUNCTIONCALL *params, SYMBOL *funcsp) { static SYMBOL *curfunc; STATEMENT *stmt = NULL, **stp = &stmt; EXPRESSION *newExpression; BOOL allocated = FALSE; if (funcsp) curfunc = funcsp; if (!isfunction(params->functp)) return NULL; if (params->sp->linkage != lk_inline) return NULL; if (!params->sp->inlineFunc.syms) return NULL; if (!localNameSpace->syms) { allocated = TRUE; AllocateLocalContext(NULL, NULL); } stmt = SetupArguments(params); SetupVariables(params->sp); while (*stp) stp = &(*stp)->next; *stp = inlinestmt(params->sp->inlineFunc.stmt); newExpression = exprNode(en_stmt, NULL, NULL); newExpression->v.stmt = stmt; if (params->sp->retcount == 1) { /* optimization for simple inline functions that only have * one return statement, don't save to an intermediate variable */ newExpression->left = scanReturn(stmt, basetype(params->sp->tp)->btp); } else { newExpression->left = newReturn(basetype(params->sp->tp)->btp); reduceReturns(stmt, params->sp->tp->btp, newExpression->left); } if (params->sp->storage_class == sc_virtual || params->sp->storage_class == sc_member) thisptrs = thisptrs->next; if (allocated) { FreeLocalContext(NULL, NULL); } if (funcsp) curfunc = NULL; return newExpression; }
// create new type in extracter void extracter_t::find_type(const char *tname1, const char *varname) { char *tname = new char [255]; strcpy(tname, tname1); //cout << tname << endl; if (typexist(tname)) return; if (typexist(nop(tname))) return; char bf[255]; char bf1[255]; char bf2[255]; if (instring("vector<", tname)) { tospace('<', tname); tospace('>', tname); sscanf(tname,"%s %s", bf1, bf); type_t *t = new type_t(-1, tname1, type); t->vec = 1; t->basetype = basetype(nop(bf)); t->addfield(bf, varname); // cout << bf; type->push_back(t); //find_type(nop(bf), varname); find_type(nop(bf), varname); //return; } //else cout << bf << endl; else find_type_infile(nop(tname1)); }
BOOLEAN isint(TYPE *tp) { tp = basetype(tp); switch(tp->type) { case bt_bool: case bt_int: case bt_char16_t: case bt_char32_t: case bt_unsigned: case bt_short: case bt_unsigned_short: case bt_char: case bt_unsigned_char: case bt_signed_char: case bt_long: case bt_unsigned_long: case bt_long_long: case bt_unsigned_long_long: case bt_wchar_t: return TRUE; case bt_templateparam: if (tp->templateParam->p->type == kw_int) return isint(tp->templateParam->p->byNonType.tp); return FALSE; default: if (tp->type == bt_enum && !cparams.prm_cplusplus) return TRUE; return FALSE; } }
static BOOLEAN is_polymorphic(LEXEME **lex, SYMBOL *funcsp, SYMBOL *sym, TYPE **tp, EXPRESSION **exp) { INITLIST *lst; BOOLEAN rv = FALSE; FUNCTIONCALL funcparams; memset(&funcparams, 0, sizeof(funcparams)); funcparams.sp = sym; *lex = getTypeList(*lex, funcsp, &funcparams.arguments); lst = funcparams.arguments; while (lst) { lst->tp = PerformDeferredInitialization(lst->tp, NULL); lst = lst->next; } if (funcparams.arguments && !funcparams.arguments-> next) { // yes references are literal types... if (isstructured(funcparams.arguments->tp)) rv = !! hasVTab(basetype(funcparams.arguments->tp)->sp); } *exp = intNode(en_c_i, rv); *tp = &stdint; return TRUE; }
// these next two rely on the CONST specifier on the func not being set up yet. static SYMBOL *createPtrCaller(SYMBOL *self) { // if the closure is copied then used on another thread yes the resulting // code can get into a race condition... INITLIST *args; FUNCTIONCALL *params = Alloc(sizeof(FUNCTIONCALL)); TYPE *pargs = realArgs(lambdas->func); SYMBOL *func = makeID(sc_static, pargs, NULL, "$ptrcaller"); SYMBOL *lambdaCall = search(isstructured(basetype(lambdas->func->tp)->btp) ? "__lambdaPtrCallS" : "__lambdaPtrCall", globalNameSpace->syms); BLOCKDATA block1, block2; STATEMENT *st; EXPRESSION *exp = varNode(en_label, self); lambdaCall = (SYMBOL *)lambdaCall->tp->syms->table[0]->p; func->parentClass = lambdas->cls; func->linkage = lk_virtual; func->isInline = FALSE; func->omitFrame = TRUE; deref(&stdpointer, &exp); memset(&block1, 0, sizeof(BLOCKDATA)); memset(&block2, 0, sizeof(BLOCKDATA)); insertFunc(lambdas->cls, func); st = stmtNode(NULL, &block2, isstructured(basetype(lambdas->func->tp)->btp) ? st_expr : st_return); st->select = varNode(en_func, NULL); st->select->v.func = params; params->arguments = Alloc(sizeof(INITLIST)); params->arguments->exp = varNode(en_pc, lambdas->func); params->arguments->tp = &stdpointer; args = Alloc(sizeof(INITLIST)); args->next = params->arguments; params->arguments = args; params->arguments->exp = exp; params->arguments->tp = &stdpointer; params->ascall = TRUE; params->sp = func; params->fcall = varNode(en_pc, lambdaCall); params->functp = func->tp; st = stmtNode(NULL, &block1, st_block); st->lower = block2.head; st->blockTail = block2. blockTail; func->inlineFunc.stmt = stmtNode(NULL, NULL, st_block); func->inlineFunc.stmt->lower = block1.head; func->inlineFunc.stmt->blockTail = block1.blockTail; return func; }
SYMBOL *getFunctionSP(TYPE **tp) { TYPE *btp = basetype(*tp); BOOLEAN pointer = ispointer(btp); if (pointer) { btp = basetype(btp)->btp; } if (isfunction(btp)) { *tp = btp; return basetype(btp)->sp; } else if (btp->type == bt_aggregate) { return btp->sp; } return NULL; }
static BOOLEAN trivialDefaultConstructor(TYPE *tp) { if (isstructured(tp)) { HASHREC *hr; SYMBOL *ovl; BASECLASS *bc; ovl = search(overloadNameTab[CI_CONSTRUCTOR ], basetype(tp)->syms); if (ovl) { HASHREC *hr = ovl->tp->syms->table[0]; while (hr) { SYMBOL *sym = (SYMBOL *)hr->p; HASHREC *hr1 = basetype(sym->tp)->syms->table[0]; if (!hr1->next || !hr1->next->next || ((SYMBOL *)hr1->next->next->p)->tp->type == bt_void) if (!sym->defaulted) return FALSE; else break; hr = hr->next; } } bc = basetype(tp)->sp->baseClasses; while (bc) { if (!trivialDefaultConstructor(bc->cls->tp)) return FALSE; bc = bc->next; } hr = basetype(tp)->syms->table[0]; while (hr) { SYMBOL *sym = (SYMBOL *)hr->p; if (sym->storage_class == sc_mutable || sym->storage_class == sc_member) if (!trivialDefaultConstructor(sym->tp)) return FALSE; hr = hr->next; } } return TRUE; }
BOOL checktypeassign(TYPE *typ1, TYPE *typ2) { /* this is so we can put an ampersand in front of a func name we are using */ if (isfuncptr(typ1) && isfuncptr(typ2)) return TRUE; while (typ1 && typ2) { typ1 = basetype(typ1); typ2 = basetype(typ2); if (isarithmetic(typ1) && isarithmetic(typ2)) return TRUE; if (isstructured(typ1) && comparetypes(typ1, typ2, TRUE)) return TRUE; typ1 = typ1->btp; typ2 = typ2->btp; } if (!typ1 && !typ2) return (TRUE); return (FALSE); }
BOOLEAN isimaginary(TYPE *tp) { tp = basetype(tp); switch (tp->type) { case bt_float_imaginary: case bt_double_imaginary: case bt_long_double_imaginary: return TRUE; default: return FALSE; } }
BOOLEAN iscomplex(TYPE *tp) { tp = basetype(tp); switch (tp->type) { case bt_float_complex: case bt_double_complex: case bt_long_double_complex: return TRUE; default: return FALSE; } }
BOOLEAN isfloat(TYPE *tp) { tp = basetype(tp); switch (tp->type) { case bt_float: case bt_double: case bt_long_double: return TRUE; default: return FALSE; } }
BOOLEAN isstructured(TYPE *tp) { tp = basetype(tp); switch(tp->type) { case bt_struct: case bt_union: case bt_class: return TRUE; default: return FALSE; } }
/*-------------------------------------------------------------------------*/ static void InsertParameterThunks(SYMBOL *funcsp, BLOCK *b) { HASHREC *hr = basetype(funcsp->tp)->syms->table[0]; QUAD *old , *oldit; BLOCK *ocb = currentBlock; old = b->head->fwd; while (old != b->tail && old->dc.opcode != i_label) old = old->fwd; old = old->fwd; oldit = intermed_tail; intermed_tail = old->back; intermed_tail->fwd = NULL; currentBlock = b; while (hr) { SYMBOL *sp = (SYMBOL *)hr->p; if (sp->tp->type == bt_void || sp->tp->type == bt_ellipse || isstructured(sp->tp)) { hr = hr->next; continue; } if (!sp->imvalue || sp->imaddress) { hr = hr->next; continue; } if (funcsp->oldstyle && sp->tp->type == bt_float) { IMODE *right = (IMODE *)Alloc(sizeof(IMODE)); *right = *sp->imvalue; right->size = ISZ_DOUBLE; if (!chosenAssembler->arch->hasFloatRegs) { IMODE *dp = tempreg(ISZ_DOUBLE, 0); IMODE *fp = tempreg(ISZ_FLOAT, 0); /* oldstyle float gets promoted from double */ gen_icode(i_assn, dp, right, 0); gen_icode(i_assn, fp, dp, 0); gen_icode(i_assn, sp->imvalue, fp, 0); } } hr = hr->next; } currentBlock = ocb; if (old->back == b->tail) { b->tail = intermed_tail; } old->back = intermed_tail; intermed_tail->fwd = old; intermed_tail = oldit; }
int dumpFunction(TYPE *tp) { char buf[2048], *bptr; HASHREC *hr; int n; int m = link_puttype(basetype(tp)->btp); int v,i; int types[32]; int count = 0; hr = basetype(tp)->syms->table[0]; while (hr && count < sizeof(types)/sizeof(types[0])) { SYMBOL *s = hr->p; types[count++] = link_puttype(s->tp); hr = hr->next; } switch (basetype(tp)->sp->linkage) { default: case lk_cdecl: v = 1; break; case lk_stdcall: v = 2; break; case lk_pascal: v = 3; break; } sprintf(buf,"T2,T%X,%X",m, v); bptr = buf + strlen(buf); for (i=0; i < count; i++) { sprintf(bptr,",T%X", types[i]); bptr += strlen(bptr); } return emit_type_ieee(buf); }
static BOOLEAN trivialFunc(SYMBOL *func, BOOLEAN move) { HASHREC *hr = basetype(func->tp)->syms->table[0]; while (hr) { SYMBOL *sp = (SYMBOL *)hr->p; if (matchesCopy(sp, move)) { return sp->defaulted; } hr = hr->next; } return TRUE; }
static BOOLEAN is_empty(LEXEME **lex, SYMBOL *funcsp, SYMBOL *sym, TYPE **tp, EXPRESSION **exp) { INITLIST *lst; BOOLEAN rv = FALSE; FUNCTIONCALL funcparams; memset(&funcparams, 0, sizeof(funcparams)); funcparams.sp = sym; *lex = getTypeList(*lex, funcsp, &funcparams.arguments); lst = funcparams.arguments; while (lst) { lst->tp = PerformDeferredInitialization(lst->tp, NULL); lst = lst->next; } if (funcparams.arguments && !funcparams.arguments-> next) { if (isstructured(funcparams.arguments->tp)) rv = !basetype(funcparams.arguments->tp)->syms->table[0] || !basetype(funcparams.arguments->tp)->syms->table[0]->next; } *exp = intNode(en_c_i, rv); *tp = &stdint; return TRUE; }
static TYPE *lambda_type(TYPE *tp, enum e_cm mode) { if (mode == cmRef) { TYPE *tp1; tp = basetype(tp); if (isref(tp)) { tp = tp->btp; } tp1 = Alloc(sizeof(TYPE)); tp1->type = bt_lref; tp1->size = getSize(bt_pointer); tp1->btp = tp; tp = tp1; } else // cmValue { TYPE *tp1; tp = basetype(tp); if (isref(tp)) { tp = tp->btp; } tp = basetype(tp); if (!lambdas->isMutable) { tp1 = Alloc(sizeof(TYPE)); tp1->type = bt_const; tp1->size = tp->size; tp1->btp = tp; tp = tp1; } } return tp; }
static BOOLEAN is_union(LEXEME **lex, SYMBOL *funcsp, SYMBOL *sym, TYPE **tp, EXPRESSION **exp) { INITLIST *lst; BOOLEAN rv = FALSE; FUNCTIONCALL funcparams; memset(&funcparams, 0, sizeof(funcparams)); funcparams.sp = sym; *lex = getTypeList(*lex, funcsp, &funcparams.arguments); if (funcparams.arguments && !funcparams.arguments-> next) { rv = basetype(funcparams.arguments->tp)->type == bt_union; } *exp = intNode(en_c_i, rv); *tp = &stdint; return TRUE; }
BOOLEAN isunsigned(TYPE *tp) { tp = basetype(tp); switch (tp->type) { case bt_bool: case bt_unsigned: case bt_unsigned_short: case bt_unsigned_char: case bt_unsigned_long: case bt_unsigned_long_long: case bt_wchar_t: return TRUE; default: return FALSE; } }
BOOLEAN ispointer(TYPE *tp) { tp = basetype(tp); switch(tp->type) { case bt_far: case bt_pointer: case bt_seg: return TRUE; case bt_templateparam: if (tp->templateParam->p->type == kw_int) return ispointer(tp->templateParam->p->byNonType.tp); return FALSE; default: return FALSE; } }
BOOLEAN isref(TYPE *tp) { tp = basetype(tp); switch(tp->type) { case bt_lref: return TRUE; case bt_rref: return TRUE; case bt_templateparam: if (tp->templateParam->p->type == kw_int) return isref(tp->templateParam->p->byNonType.tp); return FALSE; default: return FALSE; } }