|
|
1.1 ! root 1: /* This may look like C code, but it is really -*- C++ -*- */ ! 2: ! 3: /* ! 4: $Source: /usr3/lang/benson/work/stripped_cfront/RCS/template.c,v $ $RCSfile: template.c,v $ ! 5: $Revision: 1.4 $ $Date: 90/04/02 11:32:09 $ ! 6: $Author: sam $ $Locker: $ ! 7: $State: Exp $ ! 8: */ ! 9: #include "tree_copy.H" ! 10: #include "cfront.h" ! 11: #include <string.h> ! 12: #include "dump_tree.H" ! 13: #include "template.h" ! 14: #include <stdlib.h> ! 15: #include <ctype.h> ! 16: #include "hash.h" ! 17: ! 18: /***************************************************************************** ! 19: * * ! 20: * This file contains most of the implementation for a subset of parametrized * ! 21: * types as defined by the BS paper 1989 JOOP paper. The subset chosen here * ! 22: * was the subset relevant to the implementation of aggregates in * ! 23: * ObjectStore. * ! 24: * * ! 25: * * ! 26: * The following is a list of features supported by the implementation. The * ! 27: * list of features parallels the description of templates in the JOOP paper. * ! 28: * * ! 29: * a) Class templates supported. * ! 30: * * ! 31: * b) Member function templates supported. Type-specific member * ! 32: * functions as described at the end of the "Outline of an * ! 33: * implementation" section are also supported. Non-member function * ! 34: * templates are not supported. * ! 35: * * ! 36: * c) Template arguments may be of type "type" or simple integral, * ! 37: * real, double and pointer types that are compile-time constants. * ! 38: * Deafult arguments are not suported. * ! 39: * * ! 40: * * ! 41: * Restrictions: * ! 42: * * ! 43: * a) template definitions may not be nested. * ! 44: * * ! 45: * b) enums, or class definitions may not be nested within a template * ! 46: * class definition. * ! 47: * * ! 48: * This file also supports an internal template facility to facilitate the * ! 49: * implementation of ObjectStore data model features. The internal template * ! 50: * facility is only used by compiler implementors, and is not user visible. * ! 51: * * ! 52: *****************************************************************************/ ! 53: ! 54: ! 55: /***************************************************************************** ! 56: * * ! 57: * TBD * ! 58: * * ! 59: * 1) Error recovery, a never ending task, could stand improvement. * ! 60: * * ! 61: * 2) The template copying process could probably be speeded up * ! 62: * substantially, by only placing "graph-like" nodes in the hash table. The * ! 63: * current implementation plays it safe, and places all nodes in the hash * ! 64: * table. * ! 65: * * ! 66: * 3) Clean up $name processing, it needs to be remodularized so that class * ! 67: * templates and tree templates share the code. * ! 68: * * ! 69: * 4) Permit parametrized name default names within member functions. Gordon * ! 70: * needs this, for inverse templates. * ! 71: * * ! 72: *****************************************************************************/ ! 73: ! 74: ! 75: extern int bound ; // is not mentioned in the header file ! 76: ! 77: const int max_string_size = 1024 ; ! 78: ! 79: const int default_copy_hash_size = 1000 ; ! 80: ! 81: // Save and restore global state around a template instantiation ! 82: void state::save() { ! 83: ! 84: Cdcl = ::Cdcl ; ! 85: Cstmt = ::Cstmt ; ! 86: curloc = ::curloc ; ! 87: ! 88: curr_file = ::curr_file ; ! 89: curr_expr = ::curr_expr ; ! 90: curr_icall = ::curr_icall ; ! 91: curr_loop = ::curr_loop; ! 92: curr_block = ::curr_block; ! 93: curr_switch = ::curr_switch; ! 94: ! 95: bound = ::bound ; ! 96: inline_restr = ::inline_restr ; ! 97: last_line = ::last_line ; ! 98: ! 99: no_of_badcall = ::no_of_badcall; ! 100: no_of_undcl = ::no_of_undcl ; ! 101: ! 102: badcall = ::badcall ; ! 103: undcl = ::undcl ; ! 104: } ; ! 105: ! 106: ! 107: void state::restore() { ! 108: ::Cdcl = Cdcl ; ! 109: ::Cstmt = Cstmt ; ! 110: ::curloc = curloc ; ! 111: ! 112: ::curr_file = curr_file ; ! 113: ::curr_expr = curr_expr ; ! 114: ::curr_icall = curr_icall ; ! 115: ::curr_loop = curr_loop; ! 116: ::curr_block = curr_block; ! 117: ::curr_switch = curr_switch; ! 118: ! 119: ::bound = bound ; ! 120: ::inline_restr = inline_restr ; ! 121: ::last_line = last_line ; ! 122: ! 123: ::no_of_badcall = no_of_badcall; ! 124: ::no_of_undcl = no_of_undcl ; ! 125: ! 126: ::badcall = badcall ; ! 127: ::undcl = undcl ; ! 128: } ; ! 129: ! 130: ! 131: void state::init() { ! 132: ::bound = 0 ; ! 133: ::inline_restr = 0 ; ! 134: ::no_of_badcall = ::no_of_undcl = 0 ; ! 135: ::undcl = ::badcall = NULL ; ! 136: // lastline needs to be initialized probaly via a call to putline ! 137: ! 138: } ! 139: ! 140: ! 141: bit basetype::parametrized_class() ! 142: { return ((base == COBJ) && ! 143: Ptclass(Pbase(this)->b_name->tp)->class_base == uninstantiated_template_class) ; ! 144: } ! 145: ! 146: class_type_enum get_class_base (Pbase b) { ! 147: if (b->base != COBJ) error('i', "bad argument top ::get_class_type") ; ! 148: return Ptclass(Pbase(b)->b_name->tp)->class_base ; ! 149: } ! 150: ! 151: Ptclass get_template_class (Pbase b) { ! 152: class_type_enum t = get_class_base(b) ; ! 153: ! 154: if (! ((t == instantiated_template_class) || ! 155: (t == uninstantiated_template_class))) ! 156: error ('i', "class is not a template class") ; ! 157: ! 158: return Ptclass(Pbase(b)->b_name->tp) ; ! 159: } ! 160: ! 161: ! 162: Ptempl_inst get_templ_inst(Pbase b) { ! 163: ! 164: return (get_template_class(b))->inst ; ! 165: } ! 166: ! 167: ! 168: bit classdef::parametrized_class() ! 169: { return (class_base == uninstantiated_template_class) ; ! 170: } ! 171: ! 172: // Predicate to determine whether two classes are indeed the same. cfront ! 173: // normally relies on pointer identity, however this test is insufficient when ! 174: // parametrized class instantiationa are involved, since there are potentially ! 175: // many instances of a COBJ and CLASS for a given instantiation. ! 176: bit classdef::same_class(Pclass pc) ! 177: { ! 178: if (this == pc) return true ; ! 179: ! 180: // An intermediate test to compensate for the fact that instantiations do ! 181: // not cause a copy of the syntax tree to be generated. This kludge should ! 182: // not be necessary once the template implementation is complete, and tree ! 183: // copying is implemented. ! 184: // Later, Sam: tree copying is now implemented, i need to remove the ! 185: // following two statements and rerun the test suite. ! 186: ! 187: if ((this->class_base == template_class) && ! 188: (pc->class_base == instantiated_template_class) && ! 189: (Ptclass(pc)->inst->def_basetype()->b_name->tp == this)) ! 190: return true ; ! 191: // The inverse symmetric test ! 192: if ((pc->class_base == template_class) && ! 193: (this->class_base == instantiated_template_class) && ! 194: (Ptclass(this)->inst->def_basetype()->b_name->tp == pc)) ! 195: return true ; ! 196: ! 197: // Check whether the templates were determined to be identical after ! 198: // instantiation. ! 199: if ((pc->class_base == instantiated_template_class) && ! 200: (this->class_base == instantiated_template_class) && ! 201: (Ptclass(this)->inst->same(Ptclass(pc)->inst))) ! 202: return true ; ! 203: return false ; ! 204: } ! 205: ! 206: // determine whether two instantiations are identical; the test asumes that ! 207: // the templates have been instantiated. ! 208: bool templ_inst::same(Ptempl_inst t) ! 209: { ! 210: return ((forward && (forward == t->forward)) || ! 211: (forward == t) || (t->forward == this)) ? true : false ; ! 212: } ! 213: ! 214: ! 215: /* Template parsing support */ ! 216: ! 217: // The canonical template compilation instance. ! 218: ! 219: templ_compilation *templp ; ! 220: ! 221: templ_compilation::templ_compilation() ! 222: { templates = new table(128, NULL, NULL) ; ! 223: any_type = new basetype(ANY, NULL); ! 224: PERM(any_type) ; ! 225: } ! 226: ! 227: ! 228: // determine whether the string corresponds to a tree formal parameter ! 229: Pname templ_compilation::tree_parameter(char *s) { ! 230: for (Plist formal = params ; formal ; formal = formal->l) ! 231: if (strcmp(formal->f->string, s) == 0) { ! 232: formal->f->n_used++ ; ! 233: return formal->f ; ! 234: } ! 235: return 0 ; ! 236: } ! 237: ! 238: ! 239: // Determine whether the name refers to the canonical template class during ! 240: // syntax analysis. ! 241: Ptempl templ_compilation::is_template(Pname p) { ! 242: if (p->tp && (p->tp->base == COBJ) && ! 243: (get_class_base(Pbase(p->tp)) == template_class)) ! 244: { Pname n = templates->look(p->string, 0) ; ! 245: return (n ? Ptempl(n->tp) : 0) ; ! 246: } ! 247: return 0 ; ! 248: } ! 249: ! 250: ! 251: // determine whether the string names a template ! 252: Ptempl templ_compilation::is_template(char *s) { ! 253: Pname n = templates->look(s,0) ; ! 254: return (n ? Ptempl(n->tp) : 0) ; ! 255: } ! 256: ! 257: ! 258: // Set up the environment for parsing a template. This involves setting up a ! 259: // new nesting level into which the "type type" parameters of the template can ! 260: // be entered, so that the lexer can find them as TNAMES. The scope is ! 261: // deallocated by end(). ! 262: void templ_compilation::start() ! 263: { templp->in_progress = true ; ! 264: // Reinitialize the state. ! 265: params = param_end = NULL ; owner = NULL ; ! 266: modified_tn = 0 ; // Initialize it here, since ::collect adds new types ! 267: } ! 268: ! 269: ! 270: ! 271: // Collect each parameter as it is parsed, and add it to the list of parms. ! 272: // Validate each parameter to make sure that it is one of the acceptable ! 273: // types. ! 274: void templ_compilation::collect(TOK parm_type, Pname n) ! 275: { ! 276: switch (parm_type) { ! 277: case CLASS: ! 278: // A "type type" parameter, give it the "ANY" type normally used as a ! 279: // wildcard match internally by the compiler in cases of error. ! 280: n->tp = new basetype(ANY, 0); ! 281: n = n->tdef() ; // Set it up to be a typedef. ! 282: n->lex_level = bl_level + 1 ; // Inner scope, so restore() can hack it ! 283: n->n_template_arg = name::template_type_formal ; ! 284: PERM(n) ; PERM(n->tp) ; ! 285: break ; ! 286: case STATEMENT: ! 287: case EXPRESSION: ! 288: // the argument is a post-syntax expression tree ! 289: n->n_template_arg = ! 290: ((parm_type == EXPRESSION) ? ! 291: name::template_expr_tree_formal : name::template_stmt_tree_formal) ; ! 292: // canonical any_type is ok here ! 293: n->tp = any_type ; ! 294: PERM(n) ; ! 295: break ; ! 296: default: ! 297: error("the parameter type for %n must be CLASS, not %k", ! 298: n, parm_type) ; ! 299: } ! 300: append_parameter(n) ; ! 301: } ! 302: ! 303: // append the "non-type" parameter to the end of the list ! 304: void templ_compilation::append_parameter(Pname n) ! 305: { ! 306: if (params){ ! 307: param_end->l = new name_list(n, NULL) ; ! 308: param_end = param_end->l ; ! 309: }else params = param_end = new name_list(n, NULL) ; ! 310: PERM(n) ; PERM(n->tp) ; ! 311: } ! 312: ! 313: ! 314: // collect non "type type" parameters. The tp field of the name ! 315: // indicates the type of the formal parameter. ! 316: void templ_compilation::collect(Pname n) ! 317: { ! 318: // The grammar alone should be sufficient to protect against undesirable ! 319: // types. Any additional checks go here. ! 320: n->n_template_arg = name::template_expr_formal ; ! 321: append_parameter(n) ; ! 322: } ! 323: ! 324: ! 325: ! 326: // validate the type for a non-type formal, and make it a const. ! 327: static void check_non_type_formal(Pname n) { ! 328: ! 329: switch (n->tp->base) { ! 330: case ZTYPE: ! 331: case CHAR: ! 332: case SHORT: ! 333: case INT: ! 334: case LONG: ! 335: case FLOAT: ! 336: case DOUBLE: ! 337: case FIELD: ! 338: case EOBJ: ! 339: case COBJ: ! 340: case TYPE: ! 341: case ANY: ! 342: { // a basetype node ! 343: TOK bad_base = 0 ; ! 344: ! 345: if (Pbase(n->tp)->b_volatile) ! 346: bad_base = VOLATILE ; ! 347: if (Pbase(n->tp)->b_typedef) ! 348: bad_base = TYPEDEF ; ! 349: if (Pbase(n->tp)->b_inline) ! 350: bad_base = INLINE ; ! 351: if (Pbase(n->tp)->b_virtual) ! 352: bad_base = VIRTUAL ; ! 353: if (bad_base) ! 354: error ("bad %k declarator for template formal %n", bad_base, n) ; ! 355: ! 356: Pbase b = new basetype(0, 0) ; ! 357: *b= *Pbase(n->tp) ; ! 358: b->b_const = 1 ; ! 359: n->tp = b ; ! 360: break ; ! 361: } ! 362: case PTR: ! 363: { Pptr b = new ptr(0,0) ; ! 364: *b = *Pptr(n->tp) ; ! 365: ! 366: b->rdo = 1; ! 367: n->tp = b ; ! 368: break ; ! 369: } ! 370: case RPTR: ! 371: case VEC: ! 372: break; // constant by definition ! 373: default: ! 374: error ("bad parameter type %t for formal parameter %n", n->tp, n) ; ! 375: } ! 376: return ; ! 377: } ! 378: ! 379: ! 380: ! 381: // The template parameters if any, have been parsed. Member function templates ! 382: // may choose to default their template arguments to the class arguments, if ! 383: // so, make the defaulting happen. ! 384: void templ_compilation::enter_parameters() ! 385: { ! 386: for (Plist list = params ; list ; list = list->l) { ! 387: Pname n = list->f ; ! 388: switch(n->n_template_arg) { ! 389: case name::template_type_formal: ! 390: // Set them up for restoration ! 391: modified_tn = new name_list(n,modified_tn); ! 392: // Bring the names out of hiding ! 393: n->n_key = 0 ; ! 394: break ; ! 395: case name::template_expr_formal: ! 396: check_non_type_formal(n) ; ! 397: n->tp->dcl(gtbl) ; ! 398: break ; ! 399: case name::template_expr_tree_formal: ! 400: case name::template_stmt_tree_formal: ! 401: // simply note it, the guts of the processing takes place when the ! 402: // copy of the syntax tree is generated. ! 403: break ; ! 404: default: ! 405: error ('i', "bad template formal" ) ; ! 406: } ! 407: } ! 408: // Save away the list of modified_tn, since the body processing will clobber ! 409: // it. ! 410: param_tn = modified_tn ; ! 411: modified_tn = 0 ; ! 412: } ! 413: ! 414: ! 415: ! 416: // Resolve the forward declaration of a template to its true definition. The ! 417: // template and class type data structures must be reused, since there may be ! 418: // outstanding references to them. ! 419: void templ::resolve_forward_decl(Plist params, Pclass c) { ! 420: check_formals(params) ; ! 421: formals = params ; ! 422: defined = true ; ! 423: definition_number = ++ definition_tick ; ! 424: members = c->mem_list ; ! 425: } ! 426: ! 427: void templ::instantiate_forward_decl() { ! 428: for (Ptempl_inst i = insts ; i ; i = i->next) ! 429: if (Ptclass(Pbase(i->tname->tp)->b_name->tp)->class_base == ! 430: instantiated_template_class && ! 431: ! i->forward) ! 432: { // reinstantiate it ! 433: i->instantiate(true) ; ! 434: } ! 435: } ! 436: ! 437: ! 438: ! 439: // verify thet the qualifier used to declare the member function matches the ! 440: // template arguments in name, ie. ! 441: // template <class P, class Q, ..> c<P,Q,..>::member_function() {} ! 442: // match it's Ps and Qs. ! 443: bool templ_inst::check_qualifier(Plist formals) ! 444: { ! 445: Pexpr actual = actuals ; ! 446: for (Plist formal = formals ; formal && actual ; formal = formal->l, ! 447: actual = actual->e2) ! 448: ! 449: switch (formal->f->n_template_arg) { ! 450: ! 451: case name::template_type_formal: ! 452: { Pbase b = Pbase(actual->e1->tp) ; ! 453: ! 454: if (! ((b->base == TYPE) && ! 455: (b->b_name->base == TNAME) && ! 456: (strcmp (Pname(b->b_name)->string, formal->f->string) == 0))) ! 457: return false ; ! 458: break ; ! 459: } ! 460: ! 461: case name::template_expr_formal: ! 462: if (! ((actual->e1->base == NAME) && ! 463: (strcmp(Pname(actual->e1)->string, formal->f->string) == 0))) ! 464: return false ; ! 465: break ; ! 466: ! 467: case name::template_expr_tree_formal: ! 468: case name::template_stmt_tree_formal: ! 469: default: ! 470: error ('i',"bad template formal") ; ! 471: } ! 472: ! 473: return true ; ! 474: } ! 475: ! 476: ! 477: // make the class template visible when compiling the template class ! 478: // defintion, so that it can be refernced while compiling the class body. ! 479: void templ_compilation::introduce_class_templ(Pname namep) ! 480: { ! 481: owner = is_template(namep) ; ! 482: // create a template definition if one did not already exist, due to a ! 483: // forward declaration ! 484: if (!owner){ ! 485: owner = new templ(params, namep) ; ! 486: Pname lookup_name = templp->templates->insert(new name(namep->string), 0); ! 487: lookup_name->tp = Ptype(owner) ; // lie, to permit use of the table ! 488: } ! 489: } ! 490: ! 491: ! 492: // The body of the template has been parsed. Finish the definition of the ! 493: // template class. ! 494: void templ_compilation::end(Pname p) ! 495: { ! 496: bool forward_definition = false ; ! 497: // Restore the name environment to the state before the template parameters ! 498: // were processed. ! 499: modified_tn = param_tn ; ! 500: restore() ; ! 501: modified_tn = 0 ; ! 502: ! 503: if (curr_tree_template) { ! 504: // create an expression template ! 505: new tree_template(curr_tree_template, ! 506: p->string, params, p->n_initializer, templ_refs) ; ! 507: }else { ! 508: if (!p->tp) { ! 509: error ("a class, or member function definition was expected") ; ! 510: return ; ! 511: } ! 512: switch(p->tp->base){ ! 513: ! 514: case CLASS: ! 515: // Create the template type to represent the parsed template, and enter it ! 516: // into the global table. This is achieved simply by modifying the TNAME ! 517: // that was entered into ktbl to represent the class definition. ! 518: Pname namep = ktbl->look(p->string, 0) ; ! 519: ! 520: // check for nested definitions, they aren't supported currently. 2.1 is ! 521: // a good time to start supporting them, since they are nested for real. ! 522: for (Pname nn = Pclass(p->tp)->mem_list ; nn ; nn = nn->n_list) ! 523: switch (nn->base) { ! 524: case NAME: ! 525: switch(nn->tp->base) { ! 526: case CLASS: ! 527: error("class declaration %s not permitted within a parametrized\ ! 528: class", nn->string) ; ! 529: break ; ! 530: case ENUM: ! 531: error("enum declaration %s not permitted within a parametrized\ ! 532: class", nn->string) ; ! 533: break ; ! 534: } ! 535: break ; ! 536: ! 537: case TNAME: ! 538: error("typedef %s not permitted within a parametrized class", ! 539: nn->string) ; ! 540: break ; ! 541: } ! 542: ! 543: owner = is_template(namep); ! 544: if (owner) { ! 545: Pclass c = Pclass(owner->basetype()->b_name->tp) ; ! 546: // ignore it, if it is a forward declaration following a real ! 547: // definition ! 548: if (owner->defined && (Pclass(p->tp)->mem_list != owner->members)) ! 549: error("template class %s multiply defined", p->string) ; ! 550: ! 551: forward_definition=bool((c->defined & DEF_SEEN) && (!owner->defined)); ! 552: if (forward_definition) owner->resolve_forward_decl(params, c) ; ! 553: }else ! 554: // a forward declaration ! 555: introduce_class_templ(namep) ; ! 556: ! 557: if (templ_refs) owner->templ_refs = templ_refs ; ! 558: break ; ! 559: ! 560: case FCT: ! 561: { Pname qual = p->n_qualifier ; ! 562: // the function must belong to a declared template class ! 563: if (! qual) { ! 564: error('s', "only template member functions may be parametrized currently") ; ! 565: return ; ! 566: } ! 567: if (qual->tp && (qual->tp->base == COBJ)) ! 568: switch (get_class_base(Pbase(qual->tp))) { ! 569: case uninstantiated_template_class: ! 570: owner = Ptclass(Pbase(qual->tp)->b_name->tp)->inst->def ; ! 571: // verify that the formals specified, match the template formals ! 572: // in name, note that the length was already matched when the ! 573: // instantiation was generated. ! 574: if (!get_template_class ! 575: (Pbase(qual->tp))->inst->check_qualifier(params)) ! 576: error ("qualifier parameters must match the template formals") ; ! 577: break ; ! 578: case template_class: ! 579: // the template reference was without any of the formals ! 580: owner = is_template(qual) ; ! 581: if (! owner->has_tree_expr_formals()) ! 582: error('w',"qualifier %n for %n must specify template parameters", ! 583: qual, p) ; ! 584: break ; ! 585: default: ! 586: error ("qualifier %n for %n wasn't a template class", qual, p) ; ! 587: return ; ! 588: } ! 589: Pfunt ft= owner->collect_function_member(p) ; ! 590: if (! Pfct(p->tp)->body) ! 591: error ("the template function member %n must have a body", p) ; ! 592: ft->templ_refs = templ_refs ; ! 593: ft->formals = params ; ! 594: owner->check_formals(params) ; ! 595: break ; ! 596: } ! 597: default: error ("class, or member function definition expected.") ; ! 598: } ! 599: } ! 600: // Note the template references from this definition ! 601: ! 602: clear_ref_templ() ; ! 603: param_end = params = 0; // Indicates the end of template processing. ! 604: curr_tree_template = 0 ; ! 605: ! 606: if (forward_definition) owner->instantiate_forward_decl() ; ! 607: owner = 0 ; ! 608: } ! 609: ! 610: ! 611: ! 612: ! 613: // Clear the list of templates referenced during the syntax analysis of a top ! 614: // level definition. Note that since this list is produced during syntax ! 615: // analysis, it does not recognize instantiations that may actualy turn out to ! 616: // be identical at instantiation after the substitution of actual parameters. ! 617: // Thus, the list may be longer than it would be after actual argument ! 618: // substitution. ! 619: void templ_compilation::clear_ref_templ() { ! 620: for (Pcons p = templ_refs ; p ; p = p->cdr) ! 621: Ptempl_inst(p->car)->refp = false ; ! 622: templ_refs = 0 ; last_cons = 0 ; ! 623: } ! 624: ! 625: ! 626: // Instantiate templates that were referenced by a non-template definition, ! 627: // after syntax analysis has been completed on it. ! 628: void templ_compilation::instantiate_ref_templ() { ! 629: for (Pcons p = templ_refs ; p ; p = p->cdr) ! 630: Ptempl_inst(p->car)->instantiate() ; ! 631: clear_ref_templ() ; ! 632: } ! 633: ! 634: ! 635: ! 636: ! 637: // Compile all template member body instantiations. Set in motion the ! 638: // compilation of the graph of instantiation bodies. Note that compilation of ! 639: // a body may in turn initiate the instantiation of templates that had not ! 640: // previously been instantiated. ! 641: void templ_compilation::end_of_compilation() { ! 642: bool change = false ; ! 643: do { ! 644: change = false ; ! 645: for (Ptempl p = list ; p ; p = p->next) ! 646: change = ( change | p->instantiate_bodies() ? true : false); ! 647: } while (change) ; ! 648: } ! 649: ! 650: ! 651: // A predicate to validate that a tname without template parameters is legit ! 652: // in the scope, ie. that it does not need actual template arguments. ! 653: // Currently, a tname without parameters is ok within the class definition, ! 654: // but parameters are required within the member definition. They should not ! 655: // be required within the member function either to be consonance with their ! 656: // use in the class definition. ! 657: Pname templ_compilation::check_tname(Pname p) { ! 658: Ptempl t = is_template(p) ; ! 659: ! 660: if (p->n_template_arg) p->n_used++ ; ! 661: if (!t) return p ; ! 662: if (in_progress && ((owner && (owner->namep == p)) || ! 663: (!owner && t->basetype()->b_name->tp == ccl))) ! 664: return p ; ! 665: error ("%n needs template instantiation arguments.", p) ; ! 666: return p ; ! 667: } ! 668: ! 669: ! 670: // This function determine when the parameters specified to a template are ! 671: // redundant, and really refer to the current template class. Thus, ! 672: // ! 673: // template c<class p1, class p2> c<p1,p2>::foo { ... } ; ! 674: // has the redundant template specification c<p1, p2> and can simply be a ! 675: // reference to a "c" instead, ! 676: bool templ_compilation::current_template(Pname p, Pexpr actuals) { ! 677: if (in_progress && ! 678: ((owner && (owner->namep == p)) || ! 679: (!owner && ((p->tp->base == COBJ) && ! 680: (Pbase(p->tp)->b_name->tp == ccl))))) ! 681: { // Check whether the formal and actual types are identical ! 682: Pexpr actual = actuals; ! 683: for (Plist formal = params ; formal && actual ; formal = formal->l, ! 684: actual = actual->e2) ! 685: if ((formal->f->tp == actual->e1->tp) || ! 686: ((actual->e1->tp && (actual->e1->tp->base == TYPE)) && ! 687: (Pbase(actual->e1->tp)->b_name->tp == formal->f->tp))) ! 688: continue ; ! 689: else break ; ! 690: if (!formal && !actual) return true ; ! 691: } ! 692: return false ; ! 693: } ! 694: ! 695: ! 696: ! 697: // Add a new member function to the list of functions for the template class. ! 698: Pfunt templ::collect_function_member(Pname fname) { ! 699: PERM(fname) ; PERM(fname->tp) ; PERM(Pfct(fname->tp)->body) ; ! 700: return new function_template (*this, templp->params, fname) ; ! 701: } ! 702: ! 703: ! 704: // Check the formals specified for a member function or a forward definition ! 705: // of a class, against the formals for the class. ! 706: void basic_template::check_formals(Plist f2) { ! 707: ! 708: for (Plist f1 = formals; f1 && f2 ; f1 = f1->l, f2 = f2->l) ! 709: if (f1->f->base != f2->f->base) ! 710: switch (f1->f->n_template_arg) { ! 711: case name::template_type_formal: ! 712: error ("template formal parameter mismatch,\ ! 713: %n must be a type formal parameter.", f2->f) ; ! 714: break ; ! 715: case name::template_expr_formal: ! 716: error ("formal parameter mismatch, %n must be a parameter of type %t", ! 717: f2->f, f2->f->tp) ; ! 718: break ; ! 719: case name::template_expr_tree_formal: ! 720: case name::template_stmt_tree_formal: ! 721: error ("formal parameter mismatch, %n must be an expression formal parameter", ! 722: f2->f) ; ! 723: break ; ! 724: default: ! 725: error ("formal parameter mismatch between class formal: %n,\ ! 726: and member formal: %n", ! 727: f1->f, f2->f) ; ! 728: }else if (f1->f->n_template_arg == name::template_expr_formal) { ! 729: // the types should be identical ! 730: if (f1->f->tp->check(f2->f->tp, 0) == 1) ! 731: error ("type mismatch between member formal %n, and class formal %n", ! 732: f2->f, f1->f) ; ! 733: } ! 734: if (f1) ! 735: error ("insufficient formal parameters, \ ! 736: class parameter %n onwards are missing", f1->f) ; ! 737: if (f2) ! 738: error ("excess formal parameters, \ ! 739: parameter %n onwards is not defined for the class", f2->f) ; ! 740: ! 741: } ! 742: ! 743: // predicate to determine whether the template has expression tree formals ! 744: bool templ::has_tree_expr_formals() { ! 745: ! 746: for (Plist formal= formals; formal ; formal = formal->l) ! 747: if (formal->f->n_template_arg == name::template_expr_tree_formal) ! 748: return true ; ! 749: ! 750: return false ; ! 751: } ! 752: ! 753: ! 754: // Check that those formals that require class actual arguments, due to their ! 755: // use in member function bodies get them. ! 756: bool basic_template::check_constraints(Pexpr actual) ! 757: ! 758: { ! 759: bool ret = true ; ! 760: ! 761: for (Plist formal = formals ; formal && actual ; formal = formal->l, ! 762: actual = actual->e2) ! 763: if ((formal->f->n_template_arg == name::template_type_formal) && ! 764: formal->f->n_template_formal_must_be_class) { ! 765: ! 766: Pname n = Pname(actual->e1) ; ! 767: ! 768: if (n && n->tp && n->tp->is_cl_obj()) ! 769: continue ; ! 770: error("expected a class type actual, not %t, for the \"type type\" formal %s", ! 771: n->tp, formal->f->string); ! 772: ret = false ; ! 773: } ! 774: return ret ; ! 775: } ! 776: ! 777: ! 778: // Check actual template arguments, against the formals. ! 779: bool templ::check_actual_args(Pexpr actual) ! 780: { ! 781: for (Plist formal = formals ; formal && actual ; formal = formal->l, ! 782: actual = actual->e2) ! 783: switch (formal->f->n_template_arg) { ! 784: case name::template_type_formal: ! 785: { ! 786: // A "type type" parameter, any actual type that was accepted by the ! 787: // parse is acceptable here, just make sure that it is indeed a type. ! 788: // If it was parsed as a type, the grammar should have created a name ! 789: // node, and attached the type to it, having marked the name as a ! 790: // template_actual_arg_dummy. ! 791: ! 792: Pname n = Pname(actual->e1) ; ! 793: ! 794: if (!((n->base == NAME) && ! 795: (n->n_template_arg == name::template_actual_arg_dummy))) { ! 796: error ("template %s argument mismatch, the template formal:%n\ ! 797: required a type actual parameter.", namep->string, formal->f) ; ! 798: // recover from the error with a safe expression ! 799: n = new name("") ; ! 800: n->tp = any_type ; ! 801: actual->e1 = n ; ! 802: } ! 803: if ((formal->f->n_template_formal_must_be_class) && ! 804: !(n->tp && n->tp->is_cl_obj())) ! 805: error("expected a class type actual, not %t, for the \"type type\" formal %s", ! 806: n->tp, formal->f->string) ; ! 807: break ; ! 808: } ! 809: case name::template_expr_formal: ! 810: // checking can only be done at instantiation, so postpone it ! 811: break ; ! 812: case name::template_expr_tree_formal: ! 813: case name::template_stmt_tree_formal: ! 814: // anything is acceptable, it is a case of "implementor beware". Any ! 815: // illegalities will only be detected when dcl processing takes place. ! 816: break ; ! 817: default: ! 818: error ('i',"bad template formal") ; ! 819: } ! 820: // If we provide for optionals, this is where the processing should get done. ! 821: if (formal) ! 822: error ("too few arguments supplied for template %s", namep->string) ; ! 823: if (actual && actual->e1) { ! 824: error ("too many arguments supplied for template %s", namep->string) ; ! 825: } ! 826: return bool(~(formal || actual)) ; ! 827: } ! 828: ! 829: ! 830: ! 831: ! 832: // Append to the list of references. ! 833: void templ_compilation::append_ref(Ptempl_inst ref) ! 834: { cons *p = new cons(ref,0) ; ! 835: if (last_cons) ! 836: last_cons->cdr = p ; ! 837: else templ_refs = p ; ! 838: last_cons = p ; ! 839: } ; ! 840: ! 841: ! 842: // Note the reference by a definition to the template, so that the template ! 843: // can be instantiated before the definition is processed. ! 844: Ptempl_inst templ_inst::note_ref() ! 845: { if ((! refp)) { ! 846: refp = true ; ! 847: templp->append_ref(this) ; ! 848: } ! 849: return this ; ! 850: } ! 851: ! 852: ! 853: ! 854: // Get an instantiation for the template with the given set of actuals. If one ! 855: // exists, return it, otherwise create a new one. ! 856: Ptempl_inst templ::get_inst(Pexpr actuals, Ptempl_inst exclude) ! 857: { Ptempl_inst inst = get_match(actuals, exclude, false) ; ! 858: ! 859: return (inst ? inst : new templ_inst(actuals, this))->note_ref() ; ! 860: } ! 861: ! 862: ! 863: // Find an instantiation that has the same set of actuals, exclude the ! 864: // instantaition passed in from the set of candidates ! 865: Ptempl_inst templ::get_match(Pexpr actuals, ! 866: Ptempl_inst exclude, // don't match this one ! 867: // Only instantiated templates match ! 868: bool match_instantiated_only) ! 869: { ! 870: for (Ptempl_inst p = insts ; p ; p = p->next) ! 871: if ((p != exclude) && ! 872: (p->actuals_match(actuals)) && ! 873: (match_instantiated_only ? ! 874: (Pclass(Pbase(p->tname->tp)->b_name->tp)->class_base == ! 875: instantiated_template_class) ! 876: : true)) ! 877: return (p->forward ? p->forward : p) ; ! 878: return NULL ; ! 879: } ! 880: ! 881: ! 882: // provides the basetype created for a given set of actuals. ! 883: Pbase templ::inst_basetype(Pexpr actuals) ! 884: { ! 885: return (check_actual_args(actuals) ? ! 886: Pbase(get_inst(actuals)->tname->tp) : basep) ; ! 887: } ! 888: ! 889: ! 890: // Validate that the name denotes a parametrized type, and prodouce a TNAME ! 891: // for the instantiation. ! 892: Pname parametrized_typename (Pname p, Pexpr actuals) ! 893: { ! 894: Ptempl t = templp->is_template(p) ; ! 895: // A template instantiation with redundant actuals identical to the formals ! 896: // of the current template ! 897: if (templp->current_template(p, actuals)) return p ; ! 898: if (t) { ! 899: Pname tname = t->typename(actuals) ; ! 900: return (tname ? tname : p) ; ! 901: } ! 902: error ("%n has type arguments but is not a parametrized class", p) ; ! 903: return p ; ! 904: } ! 905: ! 906: ! 907: Pbase parametrized_basetype (Pname p, Pexpr actuals) ! 908: { Ptempl t = templp->is_template(p) ; ! 909: // A template instantiation with redundant actuals identical to the formals ! 910: // of the current template ! 911: if (templp->current_template(p, actuals)) return Pbase(p->tp) ; ! 912: if (t) return t->inst_basetype(actuals) ; ! 913: error ("%n is not a parametrized class", p) ; ! 914: return new basetype(TYPE, p); ! 915: } ! 916: ! 917: ! 918: // Similar primitive for obtaining the typename associated with an ! 919: // instantiation. ! 920: Pname templ::typename(Pexpr actuals) ! 921: { ! 922: return (check_actual_args(actuals) ? get_inst(actuals)->tname : 0) ; ! 923: } ! 924: ! 925: // predicate to get past all the type nodes ! 926: static Ptype real_type (Ptype t) ! 927: { ! 928: while (t->base == TYPE) t = Pbase(t)->b_name->tp ; ! 929: return t ; ! 930: } ! 931: ! 932: static int expr_match(Pexpr a1, Pexpr a2) ; ! 933: ! 934: // Check whether the actuals provided match the actuals for this instantiation. ! 935: // The actuals match the formals, iff they are the same type or parametrized ! 936: // type. ! 937: bool templ_inst::actuals_match(Pexpr check_actuals) ! 938: { Pexpr ae1, ae2 ; // the cons cells ! 939: Plist formal = def->formals ; ! 940: ! 941: // The lists should be the same length, since check_actuals will have taken ! 942: // appropriate action. ! 943: for (ae1=actuals, ae2=check_actuals ; formal && ae1 && ae2 ; ! 944: ae1=ae1->e2, ae2=ae2->e2, formal = formal->l) ! 945: ! 946: switch (formal->f->n_template_arg) { ! 947: ! 948: case name::template_type_formal: ! 949: { Ptype t1 = ae1->e1->tp, t2 = ae2->e1->tp ; ! 950: if (t1->check(t2,255) == 1) ! 951: return false ; ! 952: break ; ! 953: } ! 954: case name::template_expr_formal: ! 955: if (! expr_match(ae1->e1, ae2->e1)) return false ; ! 956: break ; ! 957: ! 958: case name::template_expr_tree_formal: ! 959: case name::template_stmt_tree_formal: ! 960: // these are internal instantiations and consequently never match ! 961: return false ; ! 962: ! 963: default: ! 964: error ('i', "bad template formal") ; ! 965: } ! 966: return true ; ! 967: } ! 968: ! 969: ! 970: extern char emode ; ! 971: ! 972: ! 973: // This set of overloaded fuctions are used to accumulate name strings ! 974: void stradd(char *&target, char *source) { ! 975: while (*target++ = *source++) ; ! 976: target-- ; ! 977: } ! 978: ! 979: void stradd(char *&p, long i) { ! 980: if (!emode) { ! 981: *p++ = 'L' ; ! 982: } ! 983: char s[16] ; ! 984: ! 985: sprintf(s,"%ld", i) ; ! 986: stradd(p,s) ; ! 987: } ! 988: ! 989: void stradd(char *&p, Pname n) { ! 990: if (!emode){ ! 991: char s[256] ; ! 992: ! 993: sprintf(s,"%d", strlen(n->string)) ; ! 994: stradd(p,s) ; ! 995: } ! 996: stradd(p, n->string) ; ! 997: } ! 998: ! 999: ! 1000: ! 1001: // produce a unique string suitable for use within a name; if in emode ie. ! 1002: // printing in the context of an error, print a pretty name instead. ! 1003: char * mangled_expr(char *p, Pexpr e, bool mangle_for_address = false) ! 1004: { ! 1005: static int mangle_address = 0 ; ! 1006: if (e == 0) return p; ! 1007: ! 1008: switch (e->base) { ! 1009: case ADDROF: ! 1010: case G_ADDROF: ! 1011: // unary using e2 ! 1012: // rely on the ! 1013: mangle_address++ ; ! 1014: p = mangled_expr(p, e->e2) ; ! 1015: mangle_address -- ; ! 1016: break ; ! 1017: ! 1018: case NAME: ! 1019: if (mangle_address || mangle_for_address) ! 1020: stradd(p, Pname(e)) ; ! 1021: else if (Pname(e)->n_evaluated) ! 1022: stradd(p, Pname(e)->n_val) ; ! 1023: else if (Pname(e)->n_initializer) ! 1024: p = mangled_expr(p, Pname(e)->n_initializer, mangle_for_address) ; ! 1025: else error ('i', "couldn't mangle %n", e) ; ! 1026: break ; ! 1027: ! 1028: case IVAL: ! 1029: stradd(p, ((ival *)e)->i1) ; ! 1030: break ; ! 1031: ! 1032: case CAST: ! 1033: { // an IVAL hiding below the cast ? ! 1034: if (e->e1->base == IVAL) ! 1035: stradd(p, ((ival *)e->e1)->i1) ; ! 1036: else error ('i', "unexpected cast") ; ! 1037: break ; ! 1038: } ! 1039: case ICON: ! 1040: case CCON: ! 1041: case FCON: ! 1042: *p++ = 'L' ; ! 1043: strcpy(p, e->string) ; ! 1044: // Sam: there needs to be a better encoding scheme, but it can wait. ! 1045: if (!emode) ! 1046: while (*p) ! 1047: if (! (isalnum(*p))) ! 1048: switch(*p) { ! 1049: case '+': ! 1050: *p++ = 'p' ; ! 1051: break ; ! 1052: ! 1053: case '-': ! 1054: *p++ = 'm' ; ! 1055: break ; ! 1056: ! 1057: case '.': ! 1058: *p++ = 'D' ; ! 1059: break ; ! 1060: ! 1061: case 'e': ! 1062: *p++ = 'E' ; ! 1063: break ; ! 1064: ! 1065: default: ! 1066: error ('i', "bad character in constant") ; ! 1067: break ; ! 1068: } else p++ ; ! 1069: break ; ! 1070: ! 1071: case ZERO: ! 1072: *p++ = '0' ; ! 1073: break ; ! 1074: ! 1075: default: ! 1076: error ('i', "can't mangle %k", e->base) ; ! 1077: } ! 1078: return p ; ! 1079: } ! 1080: ! 1081: // this function is invoked once at the top level ! 1082: char *mangled_expr(char *p, Pname n) { ! 1083: if (n->n_evaluated) { ! 1084: stradd(p, n->n_val) ; ! 1085: return p ; ! 1086: } ! 1087: return mangled_expr(p, n->n_initializer, ! 1088: (real_type(n->tp)->base == PTR ? true : false)) ; ! 1089: } ! 1090: ! 1091: // Generate a template instantiation name suitable for printing when it is ! 1092: // presented to the user. ! 1093: void templ_inst::print_pretty_name() ! 1094: { ! 1095: extern char emode ; ! 1096: ! 1097: fprintf(out_file, " %s<", (def->namep ? def->namep->string : "?")) ; ! 1098: Plist formal = inst_formals ; ! 1099: emode ++ ; // so that dcl_print generates c++ rather than c names ! 1100: ! 1101: for (Pexpr ae1=actuals; formal && ae1 ; ae1=ae1->e2, formal = formal->l) { ! 1102: switch (formal->f->n_template_arg) { ! 1103: case name::template_type_formal: ! 1104: ae1->e1->tp->dcl_print(0) ; ! 1105: break ; ! 1106: case name::template_expr_formal: ! 1107: { char buff[256] ; ! 1108: ! 1109: mangled_expr(buff, ae1->e1) ; ! 1110: fprintf(out_file, "%s", buff) ; ! 1111: break ; ! 1112: } ! 1113: case name::template_expr_tree_formal: ! 1114: case name::template_stmt_tree_formal: ! 1115: // doesn't participate in the name generation ! 1116: break ; ! 1117: default: ! 1118: error ('i', "unexpected formal") ; ! 1119: } ! 1120: ! 1121: // this comma is unfortunately misplaced, since it follows a space printed ! 1122: // out by dcl_print ! 1123: if (formal->l) fprintf(out_file, ", ") ; ! 1124: } ! 1125: fprintf(out_file, ">") ; ! 1126: emode -- ; ! 1127: } ! 1128: ! 1129: ! 1130: ! 1131: // there are different representations for ICON based upon whether it has been ! 1132: // evaluated. ! 1133: int check_for_const(Pexpr a1, Pexpr a2) { ! 1134: Neval = 0 ; ! 1135: if ((a1->base == NAME) && ! 1136: ((a2->base == ICON) || (a2->base == IVAL) || (a2->base == ZERO))) ! 1137: { Pname n = Pname(a1) ; ! 1138: return (n->n_evaluated && (n->n_val == a2->eval())) ; ! 1139: }else if (((a1->base == ICON) || (a1->base == IVAL) || (a1->base == ZERO)) ! 1140: && (a2->base == NAME)) ! 1141: { Pname n = Pname(a2) ; ! 1142: return (n->n_evaluated && (n->n_val == a1->eval())) ; ! 1143: } ! 1144: return false ; ! 1145: } ! 1146: ! 1147: ! 1148: // get past the template parameter names to get the the real expression ! 1149: static Pexpr real_expression(Pexpr e) ! 1150: { ! 1151: while (e && (e->base == NAME) && ! 1152: (Pname(e)->n_template_arg == name::template_expr_formal) && ! 1153: (! Pname(e)->n_evaluated) && Pname(e)->n_initializer) ! 1154: e = Pname(e)->n_initializer ; ! 1155: return e ; ! 1156: } ! 1157: ! 1158: ! 1159: // determine whether two expressions supplied as actual arguments to ! 1160: // a "template_expr_formal" formal argument match. ! 1161: static int expr_match(Pexpr a1, Pexpr a2) ! 1162: { ! 1163: static int addr_of = 0 ; ! 1164: ! 1165: a1 = (addr_of ? a1 : real_expression(a1)) ; ! 1166: a2 = (addr_of ? a2 : real_expression(a2)) ; ! 1167: ! 1168: if (a1 == a2) return true; ! 1169: ! 1170: // ! 1171: if (a1->base != a2->base) return check_for_const(a1, a2) ; ! 1172: ! 1173: switch (a1->base) { ! 1174: case QUEST: ! 1175: // a ternary operator ! 1176: return ( expr_match(a1->cond, a2->cond) && ! 1177: expr_match(a1->e1, a2->e1) && ! 1178: expr_match(a1->e2, a2->e2)) ; ! 1179: ! 1180: case PLUS: case MINUS: case MUL: case DIV: case MOD: ! 1181: case ER: case OR: case ANDAND: case OROR: ! 1182: case LS: case RS: ! 1183: case EQ: case NE: case LT: case LE: case GT: case GE: ! 1184: // binary operator ! 1185: return (expr_match(a1->e1, a2->e1) && ! 1186: expr_match(a1->e2, a2->e2)) ; ! 1187: case UMINUS: case UPLUS: ! 1188: case NOT: case COMPL: ! 1189: return (expr_match(a1->e2, a2->e2)) ; ! 1190: case ADDROF: ! 1191: { ! 1192: // unary using e2 ! 1193: addr_of ++ ; ! 1194: int result = (expr_match(a1->e2, a2->e2)) ; ! 1195: addr_of -- ; ! 1196: return result ; ! 1197: } ! 1198: case CAST: ! 1199: return (expr_match(a1->e1, a2->e1)) ; ! 1200: case NAME: ! 1201: if (! addr_of) { ! 1202: Pname n1 = Pname(a1), n2 = Pname(a2) ; ! 1203: ! 1204: if ((n1->n_evaluated) && n2->n_evaluated && (n1->n_val == n2->n_val)) ! 1205: return true ; ! 1206: if (n1->n_initializer && (! n2->n_initializer)) ! 1207: return check_for_const(n2, n1->n_initializer) ; ! 1208: if (n2->n_initializer && (! n1->n_initializer)) ! 1209: return check_for_const(n1, n2->n_initializer) ; ! 1210: if (n1->n_initializer && n2->n_initializer) ! 1211: return expr_match(n1->n_initializer, n2->n_initializer) ; ! 1212: } ! 1213: return false ; ! 1214: case DOT: ! 1215: return (expr_match(a1->e1, a2->e1)) ; ! 1216: case REF: ! 1217: return (expr_match(a1->e1, a2->e1)) ; ! 1218: case IVAL: ! 1219: return (ival *)a1->i1 == (ival *)a2->i1 ; ! 1220: case ICON: ! 1221: case CCON: ! 1222: case FCON: ! 1223: case STRING: ! 1224: return (strcmp (a1->string, a2->string) == 0) ; ! 1225: case ZERO: ! 1226: return true ; ! 1227: case SIZEOF: ! 1228: { long l1 = a1->eval(), l2 = a2->eval() ; ! 1229: return (l1 == l2) ; ! 1230: } ! 1231: } ! 1232: return false ; ! 1233: } ! 1234: ! 1235: ! 1236: static char * non_type_argument_signature(Pexpr e, char *p) { ! 1237: p = e->tp->signature(p) ; ! 1238: return mangled_expr(p, e) ; ! 1239: } ! 1240: ! 1241: ! 1242: ! 1243: // generate array suffix information for an array signature. cfront does not ! 1244: // normally generate this as part of the type signature, since it only deals ! 1245: // with argument signatures, and arrays can't be arguments. ! 1246: static void add_array_type_suffix(char *&s, Ptype t) { ! 1247: t = real_type(t) ; ! 1248: if (t->base == VEC) { ! 1249: Pvec v = Pvec(t); ! 1250: int dim; ! 1251: char a[32] ; ! 1252: Neval = 0 ; ! 1253: if(v->dim == 0) ! 1254: dim = v->size / v->typ->tsizeof(); ! 1255: else dim = (int)v->dim->eval(); ! 1256: sprintf(a, "A%d", dim) ; ! 1257: stradd(s,a) ; ! 1258: add_array_type_suffix(s, Pvec(t)->typ); ! 1259: } ! 1260: } ! 1261: ! 1262: ! 1263: ! 1264: // Generate a mangled template instantiation name. The syntax of as template ! 1265: // mangled class name is of the form: ! 1266: // original_name__<argument type signatures>__unique_id ! 1267: // Each non-type argument is replaced by a unique id. ! 1268: char *templ_inst::mangled_name(char *ip) ! 1269: { static tree_formal_id = 0 ; ! 1270: ! 1271: char *start = ip ; ! 1272: ip = start ; ! 1273: strcpy(ip, (def->namep ? def->namep->string : "?")) ; ! 1274: ip= start + strlen(start) ; ! 1275: stradd(ip, "__pt__") ; ! 1276: ! 1277: { ! 1278: char a [max_string_size], *p = a ; ! 1279: ! 1280: Plist formal = inst_formals ; ! 1281: ! 1282: for (Pexpr ae1=actuals ; ae1 ; ae1=ae1->e2, formal = formal->l) ! 1283: switch (formal->f->n_template_arg) { ! 1284: case name::template_expr_formal: ! 1285: *p++ = 'X' ; ! 1286: // the formal must have been bound ! 1287: p = non_type_argument_signature(formal->f, p) ; ! 1288: break ; ! 1289: ! 1290: case name::template_type_formal: ! 1291: p = ae1->e1->tp->signature(p) ; ! 1292: add_array_type_suffix(p,ae1->e1->tp) ; ! 1293: break ; ! 1294: ! 1295: case name::template_expr_tree_formal: ! 1296: case name::template_stmt_tree_formal: ! 1297: *p++ = 'Y' ; ! 1298: stradd(p, tree_formal_id++) ; ! 1299: break ; ! 1300: ! 1301: default: ! 1302: error ("bad template formal:%d", formal->f->base) ; ! 1303: break ; ! 1304: } ! 1305: ! 1306: *p = 0 ; ! 1307: sprintf(ip, "%d_", strlen(a)+1) ; ! 1308: ip = start + strlen(start) ; ! 1309: strcpy(ip,a) ; ! 1310: } ! 1311: ! 1312: return start ; ! 1313: } ! 1314: ! 1315: ! 1316: ! 1317: // The C compiler barfs when it is passed on through C++ as an automatic ! 1318: // variable ! 1319: const char leader[]= "\t" ; ! 1320: ! 1321: // Explain the location of an instantiation in greater detail, since it may be ! 1322: // far removed from it's textual definition. ! 1323: void templ_inst::print_error_loc() { ! 1324: if (! head) return ; // No active instantiations ! 1325: ! 1326: extern void print_loc() ; ! 1327: state current_state ; ! 1328: char buffer[max_string_size] ; ! 1329: ! 1330: for (int i = 0 ; i < max_string_size; i++) buffer[i] = 0 ; ! 1331: ! 1332: current_state.save() ; ! 1333: fprintf (out_file, "%sanomaly detected during the instantiation of", ! 1334: leader) ; ! 1335: print_pretty_name() ; ! 1336: fprintf(out_file, "\n") ; ! 1337: if (!head->next_active) { ! 1338: // A more compact message for a single level of instantiation ! 1339: context.restore() ; ! 1340: fprintf (out_file, leader) ; ! 1341: print_loc() ; ! 1342: fprintf (out_file, "was the site of the instantiation\n") ; ! 1343: }else { ! 1344: // The instantiation chain is longer than one ! 1345: fprintf (out_file, "%sthe instantiation path was:\n", leader) ; ! 1346: for (Ptempl_inst p = head ; p ; p = p->next_active) { ! 1347: p->context.restore() ; ! 1348: print_loc() ; ! 1349: fprintf (out_file, " template:") ; ! 1350: p->print_pretty_name() ; ! 1351: fprintf(out_file, "\n") ; ! 1352: } ! 1353: } ! 1354: current_state.restore() ; ! 1355: } ! 1356: ! 1357: ! 1358: ! 1359: // Generate a class name for the instantiated class. It is constructed in a ! 1360: // manner similar to the names used in the construction of overloaded functions ! 1361: char *templ_inst::instantiation_string() { ! 1362: char inst_name[max_string_size] ; ! 1363: for (int i = 0 ; i < max_string_size; i++) inst_name[i] = 0 ; ! 1364: mangled_name(inst_name) ; ! 1365: return strdup(inst_name) ; ! 1366: } ! 1367: ! 1368: ! 1369: ! 1370: // Change the names for the class, constructors, and destructors to reflect ! 1371: // the new class instantiation name. ! 1372: void classdef::modify_inst_names(char *s) ! 1373: { ! 1374: char *old = string ; ! 1375: string = s ; // Change the class name ! 1376: // Change the constructor names ! 1377: for (Pname p=mem_list; p; p=p->n_list) ! 1378: if (p->tp && (p->tp->base==FCT) && (!strcmp(old, p->string))) ! 1379: p->string = s ; ! 1380: } ! 1381: ! 1382: // Get past the fake template argument name typename types ! 1383: Ptype non_template_arg_type(Pbase t) { ! 1384: if ((t->base == TYPE) && ! 1385: (t->b_name->n_template_arg == name::template_type_formal)) ! 1386: return non_template_arg_type(Pbase(t->b_name->tp)) ; ! 1387: else return t ; ! 1388: } ! 1389: ! 1390: // follow the chain until we hit a non ! 1391: void non_template_arg_non_type(Pname n) { ! 1392: Pexpr i = n->n_initializer; ! 1393: while (i && ! 1394: (i->base == NAME) && ! 1395: (Pname(i)->n_template_arg == name::template_expr_formal)) ! 1396: { ! 1397: if (Pname(i)->n_initializer) { ! 1398: n->n_initializer = Pname(i)->n_initializer ; ! 1399: i = n->n_initializer ; ! 1400: continue ; ! 1401: } ! 1402: if (Pname(i)->n_evaluated) { ! 1403: n->n_evaluated = 1 ; ! 1404: n->n_val = Pname(i)->n_val ; ! 1405: return ; ! 1406: } ! 1407: } ! 1408: return ; ! 1409: } ! 1410: ! 1411: ! 1412: ! 1413: // Now that the actuals are truly resolved, ie. semantics is complete, and the ! 1414: // template is about to be instantiated. ! 1415: void forward_template_arg_types(Plist formal, Pexpr actuals) ! 1416: { ! 1417: for (Pexpr actual = actuals ; formal && actual ; ! 1418: formal = formal->l, actual = actual->e2) ! 1419: switch(formal->f->n_template_arg){ ! 1420: case name::template_type_formal: ! 1421: actual->e1->tp = non_template_arg_type(Pbase(actual->e1->tp)) ; ! 1422: break ; ! 1423: case name::template_expr_formal: ! 1424: break ; ! 1425: case name::template_expr_tree_formal: ! 1426: case name::template_stmt_tree_formal: ! 1427: break ; ! 1428: default: ! 1429: error ('i', "bad template formal") ; ! 1430: } ! 1431: } ! 1432: ! 1433: // determine whether the expression supplied as an actual argument to ! 1434: // atemplate formal of type "template_expr_formal" is suitable. We are nore ! 1435: // restrictive than we need to be, simply so that the debugger can have an ! 1436: // easier time. All expressions must be of the form constant integer ! 1437: // expression, a float or double literal, or the address of a variable, or an ! 1438: // array, or function ! 1439: static int suitable_const_expr(Pname n) ! 1440: { ! 1441: if (n->n_evaluated) return 1 ; ! 1442: ! 1443: if (!n->n_initializer) return 0 ; ! 1444: ! 1445: switch (n->n_initializer->base) { ! 1446: ! 1447: case CAST: ! 1448: { // if it is a cast of an integer value, it's fine. ! 1449: if (n->n_initializer->e1->base == IVAL) ! 1450: return 1 ; ! 1451: else return 0 ; ! 1452: } ! 1453: ! 1454: case FCON: ! 1455: case ZERO: ! 1456: return 1 ; ! 1457: ! 1458: case ADDROF: ! 1459: case G_ADDROF: ! 1460: { ! 1461: Pname an = Pname(n->n_initializer->e2) ; ! 1462: if (an->base != NAME) return 0 ; ! 1463: if (an->n_stclass == STATIC) return 1 ; ! 1464: return 0 ; ! 1465: } ! 1466: case NAME: ! 1467: { ! 1468: Pname an = Pname(n->n_initializer) ; ! 1469: if ((an->n_stclass == STATIC) && ! 1470: (an->tp->base == VEC)) ! 1471: // assumes that decl processing won, so that the formal could only ! 1472: // have been apointer ! 1473: return 1 ; ! 1474: return 0 ; ! 1475: } ! 1476: default: ! 1477: return 0 ; ! 1478: } ! 1479: } ! 1480: ! 1481: ! 1482: ! 1483: static bool is_stmt_node(Pnode p) { ! 1484: if (!p) return false ; ! 1485: switch(p->base) { ! 1486: case BREAK: case CONTINUE: case DEFAULT: ! 1487: case SM: case WHILE: case DO: case SWITCH: case RETURN: case CASE: ! 1488: case FOR: ! 1489: case IF: ! 1490: case BLOCK: ! 1491: case PAIR: // ? ! 1492: return true ; ! 1493: } ! 1494: return false ; ! 1495: } ! 1496: ! 1497: ! 1498: ! 1499: static void bind_tree_expr_formal(Pname f, Pexpr actual) ! 1500: { ! 1501: if (actual->e1->base == TNAME) ! 1502: error ('i', "a TNAME is not a valid argument for the formal %n", ! 1503: f) ; ! 1504: if (is_stmt_node(actual->e1)) { ! 1505: error ("an expression node was expected for the expression formal parameter %n", f) ; ! 1506: actual->e1 = zero ; ! 1507: } ! 1508: // bind the formal to the expression, it will be accessed from here by ! 1509: // the hook function during the copy ! 1510: f->n_initializer = actual->e1 ; ! 1511: } ! 1512: ! 1513: ! 1514: ! 1515: // Bind the formals to the types passed in as the actuals, for the ! 1516: // instantiation, bind the non-type names to their expressions. ! 1517: void templ_inst::bind_formals() ! 1518: { Pexpr actual ; ! 1519: Plist formal ; ! 1520: ! 1521: for (formal = inst_formals, actual = actuals ; ! 1522: formal && actual ; formal = formal->l, actual = actual->e2) ! 1523: switch (formal->f->n_template_arg) { ! 1524: case name::template_type_formal: ! 1525: { ! 1526: formal->f->tp = non_template_arg_type(Pbase(actual->e1->tp)) ; ! 1527: PERM(formal->f->tp) ; ! 1528: break ; ! 1529: } ! 1530: ! 1531: case name::template_expr_formal: ! 1532: { ! 1533: actual->e1 = actual->e1->typ(gtbl); ! 1534: if (formal->f->tp->check(actual->e1->tp,ASSIGN) == 1) ! 1535: error("template argument mismatch, expected %t for formal %n, not %t", ! 1536: formal->f->tp, formal->f, actual->e1->tp) ; ! 1537: // hide the global name around decl processing of the formal name ! 1538: Pname g = gtbl->look (formal->f->string, 0) ; ! 1539: if (g) g->n_key = HIDDEN ; ! 1540: // bind the non type arguments to their expressions ! 1541: // parameters that are bound at syntax analysis, these parameters are ! 1542: // bound during dcl processing, so ensure that they can be found. ! 1543: formal->f->n_initializer = actual->e1 ; ! 1544: formal->f->simpl() ; ! 1545: formal->f = formal->f->dcl(gtbl, STATIC) ; ! 1546: formal->f->n_key = HIDDEN ; ! 1547: ! 1548: PERM(formal->f) ; ! 1549: non_template_arg_non_type(formal->f) ; ! 1550: if (!suitable_const_expr(formal->f)) ! 1551: error("template argument for formal:%s, is not a suitable constant.", ! 1552: formal->f->string) ; ! 1553: if (g) g->n_key = 0 ; ! 1554: break ; ! 1555: } ! 1556: ! 1557: case name::template_expr_tree_formal: ! 1558: { ! 1559: bind_tree_expr_formal(formal->f, actual) ; ! 1560: break ; ! 1561: } ! 1562: case name::template_stmt_tree_formal: ! 1563: { ! 1564: error("a statement tree may not be specified for a class template") ; ! 1565: break ; ! 1566: } ! 1567: ! 1568: default: ! 1569: error ('i', "bad template formal") ; ! 1570: } ! 1571: ! 1572: // now that the formals are bound, compute the instantiation string ! 1573: char *inst_name = instantiation_string() ; ! 1574: tname->string = instantiation_string() ; ! 1575: ! 1576: for (formal = inst_formals; formal ; formal = formal->l) ! 1577: if (formal->f->n_template_arg_string) ! 1578: error('i', "attempt to bind a template parameter multiple times") ; ! 1579: else ! 1580: formal->f->n_template_arg_string = ! 1581: strcat(strcpy(calloc(strlen(formal->f->string)+strlen(inst_name)+1,1), ! 1582: formal->f->string), inst_name) ; ! 1583: } ! 1584: ! 1585: ! 1586: // Expose the non-type parameter names so that they are visible during decl ! 1587: // processing. Conflicting global names are hidden, so that they are not ! 1588: // found. ! 1589: void templ_inst::expose_parameter_names() { ! 1590: ! 1591: if (hidden_globals) ! 1592: error ('i', "an expose without a hide of global names") ; ! 1593: ! 1594: for (Plist formal = inst_formals ; formal ; formal = formal->l) ! 1595: if (formal->f->n_template_arg == name::template_expr_formal) { ! 1596: // Hide any visible globals ! 1597: Pname gname = gtbl->look(formal->f->string, 0) ; ! 1598: if (gname) { ! 1599: // an existing global name, hide it ! 1600: gname->n_key = HIDDEN ; ! 1601: // note them for future restoration ! 1602: hidden_globals = new name_list(gname,hidden_globals); ! 1603: } ! 1604: formal->f->n_key = 0 ; // bring it out of hiding ! 1605: if (formal->f != gtbl->look(formal->f->string,0)) ! 1606: error('i', "parameter could not be located in the global table") ; ! 1607: } ! 1608: } ! 1609: ! 1610: ! 1611: // Hide the non-type parameter names after an instantiation, and restore any ! 1612: // globals that may have been hidden during the process. ! 1613: void templ_inst::hide_parameter_names() { ! 1614: ! 1615: for (Plist formal = inst_formals ; formal ; formal = formal->l) ! 1616: if (formal->f->n_template_arg == name::template_expr_formal) { ! 1617: formal->f->n_key = HIDDEN ; ! 1618: } ! 1619: for (; hidden_globals; hidden_globals= hidden_globals->l) ! 1620: hidden_globals->f->n_key= 0 ; ! 1621: hidden_globals = 0 ; ! 1622: } ! 1623: ! 1624: ! 1625: ! 1626: // Primitives for saving and restoring the compilation state around a template ! 1627: // instantiation. It also maintains the stack of template instantiations. ! 1628: void templ_inst::save_state(Pname p) { ! 1629: if (next_active) error ('i', "circular instantiation of a template") ; ! 1630: context.save() ; ! 1631: if (templ_inst::head) ! 1632: templ_inst::head->hide_parameter_names() ; ! 1633: next_active = templ_inst::head ; templ_inst::head = this ; ! 1634: context.init() ; ! 1635: Cdcl = p ; Cstmt = NULL ; ! 1636: curr_file = (Cdcl) ? Cdcl->where.file : 0; ! 1637: expose_parameter_names() ; ! 1638: } ! 1639: ! 1640: ! 1641: void templ_inst::restore_state() { ! 1642: context.restore() ; ! 1643: hide_parameter_names() ; ! 1644: templ_inst::head = next_active ; next_active = NULL ; ! 1645: if (templ_inst::head) ! 1646: templ_inst::head->expose_parameter_names() ; ! 1647: } ! 1648: ! 1649: ! 1650: // Copy over the class definition subtree starting from COBJ down to the ! 1651: // CLASSDEF node. This minimal subtree has to exist during syntax analysis, ! 1652: // and already contains pointers into it. ! 1653: void templ_inst::kludge_copy(Pbase pbc) ! 1654: { ! 1655: // copy just the COBJ ->b_name NAME ->tp CLASS path for now, note that the ! 1656: // preceding path of the tree is pre-allocated, since syntax analysis needs ! 1657: // to generate pointers to these objects. ! 1658: Pbase pb = Pbase(tname->tp) ; ! 1659: Pname save_b_name = pb->b_name ; ! 1660: Ptype save_tp = pb->b_name->tp ; ! 1661: ! 1662: if ((pb->base != COBJ) || (pbc->base != COBJ)) ! 1663: error ('i', "cobj nodes were expected here") ; ! 1664: ! 1665: *pb = *pbc ; ! 1666: pb->b_name = save_b_name ; ! 1667: *pb->b_name = *pbc->b_name ; ! 1668: pb->b_name->tp = save_tp ; ! 1669: *Pclass(pb->b_name->tp) = *Pclass(pbc->b_name->tp) ; ! 1670: Pclass(pb->b_name->tp)->class_base = instantiated_template_class ; ! 1671: ! 1672: } ! 1673: ! 1674: ! 1675: // these statics probably belong in templ_inst and shouldn't be dangling ! 1676: // around ! 1677: ! 1678: static Pbase cobj_node ; ! 1679: static Pname cname_node ; ! 1680: static Pclass class_node ; ! 1681: ! 1682: static void syntax_tree_copy_hook(void *, ! 1683: Pnode &, ! 1684: node_class, ! 1685: tree_node_action &action, ! 1686: int& never_see_again) ! 1687: { ! 1688: never_see_again = 1; ! 1689: action = tna_continue; ! 1690: return; ! 1691: } ! 1692: ! 1693: ! 1694: // create a copy of the expression tree ! 1695: static Pnode copy_syntax_tree(Pnode n, int no_types = 0) { ! 1696: pointer_hash cht(default_copy_hash_size) ; ! 1697: ! 1698: tree_copy_info info ; ! 1699: ! 1700: if(no_types) info.node_hook = syntax_tree_copy_hook; ! 1701: ! 1702: copy_tree (n, info, &cht); ! 1703: ! 1704: return n ; ! 1705: } ! 1706: ! 1707: ! 1708: ! 1709: // hook to perform the copying of the pre-allocated class subtree ! 1710: bool templ_inst::copy_hook(Pnode &node) ! 1711: { ! 1712: switch (node->base) { ! 1713: case COBJ: ! 1714: if (node == cobj_node) return false ; ! 1715: ! 1716: if (node == def->namep->tp) { ! 1717: *cobj_node = *Pbase(node) ; ! 1718: node = cobj_node ; ! 1719: } ! 1720: break ; ! 1721: case NAME: ! 1722: if (node == cname_node) return false ; ! 1723: if (node == sta_name) return false ; ! 1724: ! 1725: if (node == Pbase(def->namep->tp)->b_name) { ! 1726: *cname_node= *Pname(node) ; ! 1727: node = cname_node ; ! 1728: }else { // check for tree expression formals ! 1729: char *s = Pname(node)->string ; ! 1730: Pname f = 0 ; ! 1731: if (s && (*s == '$') && (f = get_parameter(s+1))) ! 1732: { ! 1733: if(Pname(node)->n_list) ! 1734: error ('i', "n_list set in tree template formal."); ! 1735: node = copy_syntax_tree(Pname(f)->n_initializer) ; ! 1736: return false ; ! 1737: } ! 1738: } ! 1739: break ; ! 1740: case CLASS: ! 1741: if (node == class_node) return false ; ! 1742: ! 1743: if (node == Pbase(def->namep->tp)->b_name->tp) { ! 1744: *class_node = *Pclass(node) ; ! 1745: node = class_node ; ! 1746: } ! 1747: break ; ! 1748: } ! 1749: return true ; ! 1750: } ! 1751: ! 1752: ! 1753: /* ! 1754: ! 1755: This hook function used during a class copy. ! 1756: ! 1757: */ ! 1758: static void copy_hook(void /* Ptempl_inst */ *p, Pnode &node, ! 1759: node_class, tree_node_action &action, ! 1760: int& never_see_again) ! 1761: { ! 1762: action = (Ptempl_inst(p)->copy_hook(node) ? tna_continue : tna_stop ) ; ! 1763: never_see_again = (action != tna_stop); ! 1764: return ; ! 1765: } ! 1766: ! 1767: ! 1768: ! 1769: void establish_class_subtree_correspondence(pointer_hash &h, Pname key_tname, ! 1770: Pname value_tname) ! 1771: { ! 1772: h[int(key_tname)] = int(value_tname) ; ! 1773: h[int(key_tname->tp)] = int(value_tname->tp) ; ! 1774: h[int(Pbase(key_tname->tp)->b_name)] = ! 1775: int(Pbase(value_tname->tp)->b_name) ; ! 1776: h[int(Pbase(key_tname->tp)->b_name->tp)] = ! 1777: int(Pbase(value_tname->tp)->b_name->tp) ; ! 1778: } ! 1779: ! 1780: ! 1781: ! 1782: ! 1783: Pcons make_ref_copy(pointer_hash &h, tree_copy_info &info, Pcons old_templ_refs) ! 1784: { ! 1785: cons dummy(0,0), *last = &dummy ; ! 1786: ! 1787: for (Pcons pc = old_templ_refs ; pc ; pc = pc->cdr) { ! 1788: ! 1789: Ptempl_inst t = Ptempl_inst(pc->car) ; ! 1790: expr dummy(ELIST, 0, 0) ; ! 1791: elist list(&dummy) ; ! 1792: ! 1793: // copy the trees corresponding to the actuals ! 1794: for (Pexpr actual = t->actuals ; actual ; actual = actual->e2) { ! 1795: Pnode root = actual->e1 ; ! 1796: copy_tree (root, info, &h); ! 1797: // make sure that references to enclosing formals are resolved ! 1798: root = Pexpr(root)->typ(gtbl); ! 1799: list.add(new expr(ELIST, Pexpr(root), 0)) ; ! 1800: } ! 1801: Pexpr new_actuals = list.head->e2 ; ! 1802: ! 1803: // get one if it exists, create one otherwise. ! 1804: Ptempl_inst treal = t->def->get_inst(new_actuals, t) ; ! 1805: Pname new_tname = treal->tname ; ! 1806: ! 1807: last = last->cdr = new cons(treal,0); ! 1808: ! 1809: establish_class_subtree_correspondence(h, t->tname, new_tname) ; ! 1810: } ! 1811: ! 1812: return dummy.cdr ; ! 1813: } ! 1814: ! 1815: ! 1816: ! 1817: ! 1818: /* ! 1819: Remap the template references from within the body of the template. This ! 1820: action is similar to the normal tree copy operation; it would normally have ! 1821: been done during the syntax phase, that produced the tree, but since there ! 1822: isn't one, for the instantiated body, it must be done here. ! 1823: ! 1824: */ ! 1825: Pcons templ_inst::ref_copy(pointer_hash &h, tree_copy_info &info, Pcons old_templ_refs) ! 1826: { ! 1827: expose_parameter_names() ; ! 1828: Pcons new_refs = make_ref_copy(h,info,old_templ_refs) ; ! 1829: hide_parameter_names() ; ! 1830: return new_refs ; ! 1831: } ! 1832: ! 1833: static bool is_forward_instantiation(Pbase b_base, Pbase f_base) ! 1834: { ! 1835: return bool(b_base->b_name->tp->defined && f_base->b_name->tp->defined) ; ! 1836: } ! 1837: ! 1838: ! 1839: /***************************************************************************** ! 1840: * * ! 1841: * If the template instantiation is found to be unique after the decl * ! 1842: * processing of the actuals, create a copy of the post syntax graph for the * ! 1843: * class. The edges of the graph are determined by "type nodes" that have * ! 1844: * already been defined, and TNAME nodes that are in the global keyword * ! 1845: * table. Special care is also taken to avoid copying nodes whose identity * ! 1846: * must be maintained, since cfront uses them for fast type checks, these * ! 1847: * nodes always have the "defined" flag turned on and so are never copied. * ! 1848: * * ! 1849: * Copying of the pre-allocated class sub-tree for the template: COBJ * ! 1850: * ->b_name NAME ->tp CLASS * ! 1851: * * ! 1852: * is handled by the class_copy hook above, that is invoked during the course * ! 1853: * of the copy. * ! 1854: * * ! 1855: * * ! 1856: * Template references from within the class need special handling, since * ! 1857: * each instantiation of the class, results in a potentially new template * ! 1858: * instantiation. * ! 1859: * * ! 1860: *****************************************************************************/ ! 1861: Ptempl_inst templ_inst::class_copy(Pcons &templ_refs, bool recopy) ! 1862: { ! 1863: bool forward = false ; // a forward class is instantiated twice ! 1864: ! 1865: // associate the formals with their types, and their expressions ! 1866: if (recopy) { ! 1867: // remove the class def node from the table, so that it's attributes are ! 1868: // copied. ! 1869: corr->del(int(Pbase(def->namep->tp)->b_name->tp)) ; ! 1870: corr->del(int(Pbase(def->namep->tp)->b_name)) ; ! 1871: corr->del(int(def->namep->tp)) ; ! 1872: ! 1873: corr->del(int(tname->tp)) ; ! 1874: corr->del(int(Pbase(tname->tp)->b_name)) ; ! 1875: corr->del(int(Pbase(tname->tp)->b_name->tp)) ; ! 1876: }else corr = new pointer_hash(default_copy_hash_size) ; ! 1877: ! 1878: { // copy the formals & install them in the correspondence table ! 1879: name_list dummy_formal(0,0) ; ! 1880: Plist last = &dummy_formal ; ! 1881: ! 1882: for (Plist formal = def->formals ; formal ; formal = formal->l) { ! 1883: Pname copy_name = new name("") ; ! 1884: *copy_name = *formal->f ; ! 1885: copy_name->n_tbl_list = 0 ; ! 1886: last = last->l = new name_list(copy_name, 0) ; ! 1887: (*corr)[int(formal->f)] = (int)copy_name ; ! 1888: } ! 1889: inst_formals = dummy_formal.l ; ! 1890: } ! 1891: ! 1892: bind_formals() ; ! 1893: if ( ! recopy && ktbl->look(tname->string, 0)) { ! 1894: // formal binding may result in detecting identical instantiations ! 1895: Ptempl_inst ti = def->get_match(actuals, this, true) ; ! 1896: if (ti) return ti ; ! 1897: error('i', "Generated template instantiation name %swas not unique", ! 1898: tname->string) ; ! 1899: } ! 1900: ! 1901: { ! 1902: tree_copy_info info ; ! 1903: info.node_hook = ::copy_hook ; ! 1904: info.hook_info = this ; ! 1905: ! 1906: (*corr)[int(def->namep)] = int(tname) ; // make the tnames correspond ! 1907: ! 1908: templ_refs = ref_copy(*corr, info, templ_refs) ; ! 1909: Pnode root = def->basep ; // start the copy at the cobj node ! 1910: ! 1911: // deal with these nodes differently during the copy, ie. the nodes ! 1912: // themselves are not copied, but their attributes are. ! 1913: cobj_node = (Pbase)tname->tp ; ! 1914: cname_node = Pbase( tname->tp)->b_name ; ! 1915: class_node = Pclass(Pbase( tname->tp)->b_name->tp) ; ! 1916: ! 1917: copy_tree (root, info, corr); ! 1918: ! 1919: { // dump the tree if the flag is set ! 1920: extern int dump_tree ; ! 1921: extern dcn_arg dump_tree_arg; ! 1922: ! 1923: if (dump_tree) display_cfront_node (dump_tree_arg, root); ! 1924: } ! 1925: } ! 1926: // Perform name modifications for the class, so that it is an ! 1927: // instantiation-specific name. ! 1928: cname_node->string = tname->string ; ! 1929: if (!recopy) ! 1930: namep = ktbl->insert(tname, 0) ; ! 1931: else class_node->defined &= ~(DEFINED|SIMPLIFIED) ; ! 1932: namep->tp = cobj_node; ! 1933: ! 1934: class_node->modify_inst_names(cname_node->string) ; ! 1935: return 0 ; ! 1936: } ! 1937: ! 1938: ! 1939: /* ! 1940: This hook function is responsible for the replacement of references to ! 1941: expression when copying function bodies ! 1942: */ ! 1943: static void function_copy_hook(void *current_templ_inst, ! 1944: Pnode &node, ! 1945: node_class, ! 1946: tree_node_action &action, ! 1947: int& never_see_again) ! 1948: { ! 1949: never_see_again = 1; ! 1950: ! 1951: switch (node->base) { ! 1952: case SM_PARAM: ! 1953: error ('i', "statement parameters not permitted for member functions") ; ! 1954: break ; ! 1955: ! 1956: case NAME: ! 1957: { ! 1958: if(node == sta_name) { ! 1959: action = tna_stop; ! 1960: return; ! 1961: } ! 1962: char *s = Pname(node)->string ; ! 1963: Pname f = 0 ; ! 1964: if (s && (*s == '$') && ! 1965: (f = Ptempl_inst(current_templ_inst)->get_parameter(s+1))) { ! 1966: if(Pname(node)->n_list) ! 1967: error ('i', "n_list set in tree template formal."); ! 1968: node = copy_syntax_tree(Pname(f)->n_initializer) ; ! 1969: action = tna_stop ; ! 1970: never_see_again = 0; ! 1971: }else action = tna_continue ; ! 1972: return ; ! 1973: } ! 1974: default: ! 1975: action = tna_continue ; ! 1976: return ; ! 1977: } ! 1978: } ! 1979: ! 1980: ! 1981: ! 1982: /* ! 1983: ! 1984: Create a copy of a function member, as part of the instantiation of a function ! 1985: body. The correspondence table is first initialized with the contents of the ! 1986: correspondence table used to instantiate the class. Copying is initiated ! 1987: in this context. ! 1988: ! 1989: */ ! 1990: ! 1991: Pname templ_inst::function_copy(Pfunt fnt, Pcons &templ_refs) ! 1992: { ! 1993: pointer_hash fcorr(*corr) ; // initialize it with the old hash table ! 1994: ! 1995: { ! 1996: tree_copy_info info ; ! 1997: Pnode root = fnt->fn ; ! 1998: ! 1999: // establish a correspondence between the formals used for the class ! 2000: // template, andthe formals used for the function template, all references ! 2001: // to the function template formals will be replaced by references to the ! 2002: // instantiated class template formals after the copy has been completed. ! 2003: ! 2004: for (Plist fformal = fnt->formals, cformal = inst_formals ; ! 2005: fformal ; fformal = fformal->l, cformal = cformal->l) ! 2006: { ! 2007: fcorr[int(fformal->f)] = int(cformal->f) ; ! 2008: if (fcorr[int(fformal->f)] != int(cformal->f)) ! 2009: error ('i', "hash table bug") ; ! 2010: } ! 2011: ! 2012: info.node_hook = ::function_copy_hook ; ! 2013: info.hook_info = this ; ! 2014: ! 2015: templ_refs = ref_copy(fcorr, info, templ_refs) ; ! 2016: if (fcorr[int(def->namep)] != int(tname)) ! 2017: error ('i', "template to instantiation typename correspondence is missing") ; ! 2018: ! 2019: copy_tree (root, info, &fcorr); ! 2020: ! 2021: { // dump the tree if the flag is set ! 2022: extern int dump_tree ; ! 2023: extern dcn_arg dump_tree_arg; ! 2024: ! 2025: if (dump_tree) ! 2026: display_cfront_node (dump_tree_arg, root); ! 2027: } ! 2028: return Pname(root) ; ! 2029: } ! 2030: } ! 2031: ! 2032: ! 2033: /***************************************************************************** ! 2034: * * ! 2035: * A matching template was found at instantiation time, which was not * ! 2036: * detected at syntax analysis time. This can happen, when an instantiation * ! 2037: * has as its arguments not real types but template arguments, so that * ! 2038: * matches cannot be detected until the templates are bound. Note that it is * ! 2039: * also possible to match a template that is in the process of being * ! 2040: * instantiated further up the instantiation call chain. In such cases, the * ! 2041: * kludge_copy operation will copy over an incomplete class subtree, which * ! 2042: * will be recopied with the completed one after the instantiation is * ! 2043: * completed, in templ_inst::instantiate. * ! 2044: * * ! 2045: *****************************************************************************/ ! 2046: void templ_inst::instantiate_match(Ptempl_inst match) ! 2047: { Pbase pb = Pbase(match->tname->tp) ; ! 2048: kludge_copy(pb) ; ! 2049: forward = match ; // Note the fact that this template was matched ! 2050: } ! 2051: ! 2052: ! 2053: Pclass current_instantiation = 0 ; ! 2054: ! 2055: // Do the class declaration instantiation. ! 2056: void templ_inst::instantiate(bool reinstantiate) ! 2057: { ! 2058: Pcons templ_refs = def->templ_refs ; ! 2059: if (! reinstantiate) { ! 2060: switch (Ptclass(Pbase(tname->tp)->b_name->tp)->class_base) { ! 2061: case instantiated_template_class: ! 2062: return ; ! 2063: case uninstantiated_template_class: ! 2064: break ; ! 2065: case vanilla_class: ! 2066: case template_class: // the canonical template class ! 2067: default: ! 2068: error ('i', "attempt to instantiate a non-template class") ; ! 2069: } ! 2070: status = class_instantiated ; ! 2071: // Check whether, the template has already been instantiated, if so use it. ! 2072: forward_template_arg_types(def->formals, actuals) ; ! 2073: Ptempl_inst match = def->get_match(actuals, this, true) ; ! 2074: ! 2075: if (match || (match = class_copy(templ_refs, false))){ ! 2076: instantiate_match(match) ; ! 2077: return ; ! 2078: } ! 2079: }else class_copy(templ_refs, true) ; ! 2080: ! 2081: Pbase pb = Pbase(tname->tp) ; ! 2082: ! 2083: // Save the state around decl processing ! 2084: { save_state(def->namep) ; ! 2085: ! 2086: if (def->open_instantiations++ > 1) { ! 2087: error ("an infinite instantiation sequence was initiated") ; ! 2088: def->open_instantiations-- ; ! 2089: return ; ! 2090: } ! 2091: // Mark the class as instantiated so that there are no circular ! 2092: // instantiations. ! 2093: Pclass(pb->b_name->tp)->class_base = instantiated_template_class ; ! 2094: ! 2095: // if it is a forward reference, rely on the usual compilation to ! 2096: // provide an error message, if indeed it is an error, and not a ! 2097: // benign forward reference such as: friend class foo<X,Y> ! 2098: ! 2099: if (def->basep->b_name->tp->defined) { ! 2100: ! 2101: // Put out the typedefs for the template parameters do this before the ! 2102: // call to name::dcl below, since dcl processing will emit c declarations ! 2103: // that make use of the type ! 2104: for (Plist formal = inst_formals; formal ; formal = formal->l) ! 2105: switch(formal->f->n_template_arg) { ! 2106: case name::template_expr_tree_formal: ! 2107: case name::template_stmt_tree_formal: ! 2108: break ; ! 2109: default: ! 2110: formal->f->dcl_print(0) ; ! 2111: } ! 2112: // Instantiate the parametrized types referenced by this template ! 2113: for (Pcons pc = templ_refs ; pc ; pc = pc->cdr) ! 2114: Ptempl_inst(pc->car)->instantiate() ; ! 2115: ! 2116: if (!((pb->b_name->dcl(gtbl, EXTERN) == 0 ) || error_count)) { ! 2117: pb->b_name->simpl() ; ! 2118: ! 2119: if (pb->b_name->tp->base != CLASS) ! 2120: error('i', "a classdef was expected in templ_inst::instantiate") ; ! 2121: ! 2122: current_instantiation = Pclass(pb->b_name->tp) ; ! 2123: pb->b_name->dcl_print(0) ; ! 2124: if (! (pb->b_name->tp->defined & DEFINED)) ! 2125: error ('i', "dcl class is not yet defined") ; ! 2126: current_instantiation = 0 ; ! 2127: } ! 2128: } ! 2129: ! 2130: // bash every template instantiation class that has been forwarded to ! 2131: // it, with the decl processed version. ! 2132: for (Ptempl_inst clone = def->insts ; clone ; clone = clone->next) ! 2133: if (clone != this) { ! 2134: if (clone->forward == this) ! 2135: clone->kludge_copy(Pbase(tname->tp)) ; ! 2136: else { ! 2137: // resolve references to forward declarations ! 2138: if (this == def->get_match(clone->actuals, clone, true)) { ! 2139: clone->kludge_copy(Pbase(tname->tp)) ; ! 2140: clone->forward = this ; ! 2141: } ! 2142: } ! 2143: } ! 2144: Pclass result = Pclass(pb->b_name->tp); ! 2145: ! 2146: // dcl_print the member functions, so that they can be referenced ! 2147: int i = 0 ; ! 2148: for (Pname fn= Pclass(pb->b_name->tp)->memtbl->get_mem(i=1); fn; ! 2149: fn=Pclass(pb->b_name->tp)->memtbl->get_mem(++i)) ! 2150: if ((fn->base == NAME) && (fn->tp->base == FCT)) ! 2151: fn->dcl_print(0) ; ! 2152: ! 2153: restore_state() ; ! 2154: def->open_instantiations-- ; ! 2155: } ! 2156: } ! 2157: ! 2158: /* Template Constructors */ ! 2159: ! 2160: ! 2161: templ::templ(Plist parms, Pname p) { ! 2162: namep = p ; ! 2163: formals = parms ; ! 2164: ! 2165: if (!formals) error ("a parametrized type must have parameters !") ; ! 2166: ! 2167: basep = Pbase(namep->tp) ; ! 2168: ! 2169: Pclass(basep->b_name->tp)->class_base = template_class ; ! 2170: defined = ((basep->b_name->tp->defined & DEF_SEEN) ? true : false) ; ! 2171: if (defined) ! 2172: members = Pclass(basep->b_name->tp)->mem_list ; ! 2173: ! 2174: PERM(namep) ; PERM(namep->tp) ; ! 2175: // Chain on to the list of templates for the compilation. ! 2176: next = templp->list ; ! 2177: templp->list = this ; ! 2178: } ! 2179: ! 2180: ! 2181: templ_inst::templ_inst (Pexpr act, Ptempl owner) ! 2182: { ! 2183: // Set up the basetype for the class, so that nodes that need to point to it ! 2184: // during syntax processing can do so. Theese objects are merely ! 2185: // place-holders during syntax analysis, and are actually filled in during ! 2186: // the copy phase of instantiation. ! 2187: Pclass c ; ! 2188: ! 2189: def = owner ; ! 2190: tname = new name(def->namep->string) ; ! 2191: tname->base = TNAME ; ! 2192: tname->tp = new basetype(COBJ, new name(def->namep->string)) ; ! 2193: Pbase(tname->tp)->b_name->tp = c = new templ_classdef(this) ; ! 2194: PERM(tname) ; PERM(tname->tp) ; PERM(Pbase(tname->tp)->b_name) ; ! 2195: PERM(Pbase(tname->tp)->b_name->tp) ; ! 2196: ! 2197: // initialize the member list so that set_scope can do the right thing ! 2198: c->mem_list = Pclass(def->basetype()->b_name->tp)->mem_list ; ! 2199: ! 2200: actuals = act ; ! 2201: next = owner->insts ; ! 2202: owner->insts = this ; ! 2203: } ! 2204: ! 2205: ! 2206: templ_classdef::templ_classdef(Ptempl_inst i): (CLASS) { ! 2207: inst = i ; ! 2208: class_base = uninstantiated_template_class ; ! 2209: string = unparametrized_tname()->string ; ! 2210: } ! 2211: ! 2212: ! 2213: // Create a new function template. ! 2214: function_template::function_template (templ &owner, Plist params, Pname n) ! 2215: { ! 2216: definition_number = ++definition_tick ; ! 2217: ! 2218: if (owner.fns_end) ! 2219: owner.fns_end->next = this ; ! 2220: else owner.fns = this ; ! 2221: owner.fns_end = this ; ! 2222: formals = params ; ! 2223: fn = n ; ! 2224: PERM(n) ; PERM(n->tp) ; ! 2225: } ! 2226: ! 2227: ! 2228: // create the tree template ! 2229: tree_template::tree_template(TOK tree_kind, char *s, Plist params, Pnode tree, ! 2230: Pcons references) ! 2231: { ! 2232: string = s ; ! 2233: formals = params; ! 2234: e = tree ; ! 2235: if (!e) ! 2236: error('w', "the internal template %s does not have an associated body", s); ! 2237: templ_refs = references ; ! 2238: kind = tree_kind ; ! 2239: ! 2240: // add the expression template too the list of known templates ! 2241: if (get(s)) { ! 2242: error ("duplicate definition of the internal template %s", s) ; ! 2243: return ; ! 2244: } ! 2245: // link it in ! 2246: next = templ_compilation::tree_templates ; ! 2247: templ_compilation::tree_templates = this ; ! 2248: ! 2249: // check that formals weren't misspelt ! 2250: for (Plist formal = formals ; formal ; formal = formal->l) ! 2251: if (! formal->f->n_used) ! 2252: error('w', "the formal parameter %n was not referenced within the template body",formal->f) ; ! 2253: } ! 2254: ! 2255: ! 2256: // lookup an internal expression template ! 2257: Ptreet tree_template::get(char *s) { ! 2258: for (Ptreet o = templ_compilation::tree_templates ; o ; o = o->next) ! 2259: if (strcmp(o->string, s) == 0) return o ; ! 2260: return 0 ; ! 2261: } ! 2262: ! 2263: ! 2264: Pname tree_template::get_parameter(char *s) { ! 2265: for (Plist formal = formals ; formal ; formal = formal->l) { ! 2266: if (strcmp(formal->f->string, s)== 0) ! 2267: return formal->f ; ! 2268: } ! 2269: return 0 ; ! 2270: } ! 2271: ! 2272: ! 2273: ! 2274: // Sam: some remodularization seems to be in order here, so that this method ! 2275: // can be shared ! 2276: Pname templ_inst::get_parameter(char *s) { ! 2277: for (Plist formal = inst_formals ; formal ; formal = formal->l) { ! 2278: if (strcmp(formal->f->string, s)== 0) ! 2279: return formal->f ; ! 2280: } ! 2281: return 0 ; ! 2282: } ! 2283: ! 2284: Pexpr tree_template::expand(Pexpr) ! 2285: { ! 2286: error('i', "no support for tree templates") ; ! 2287: return 0 ; ! 2288: } ! 2289: ! 2290: ! 2291: // Instantiate each function member body. It assumes that the class ! 2292: // declaration has been instantiated. The return value indicates whether an ! 2293: // instantiation of bodies actually took place. This function is only invoked ! 2294: // at the end of a file compilation, after all source text has been processed. ! 2295: bool templ::instantiate_bodies(){ ! 2296: bool change = false ; ! 2297: // Perform the instantiation of the member function bodies. ! 2298: if (!fns) return change ; ! 2299: ! 2300: for (Ptempl_inst inst = insts ; inst ; inst = inst->next) ! 2301: if (!inst->forward && (inst->status == class_instantiated)) { ! 2302: // Set up the environment for the declaration, and subsequent compilation ! 2303: // of the function bodies. ! 2304: inst->status = body_instantiated ; change = true ; ! 2305: ! 2306: { Pclass ic = inst->get_class() ; int i ; ! 2307: // note all the overriding definitions explicitly provided by the user ! 2308: for (Pname fn= ic->memtbl->get_mem(i=1); fn; fn=ic->memtbl->get_mem(++i)) ! 2309: if ((fn->base == NAME) && (fn->tp->base == FCT) && Pfct(fn->tp)->body) ! 2310: fn->n_redefined = 1 ; ! 2311: } ! 2312: ! 2313: for (Pfunt fnt = fns; fnt ; fnt = fnt->next) { ! 2314: Pcons templ_ref_copy = fnt->templ_refs ; ! 2315: Pname fn = inst->function_copy(fnt, templ_ref_copy) ; ! 2316: ! 2317: // Change the qualifier to be the name of the instantiated, rather than ! 2318: // the parametrized class name ! 2319: fn->n_qualifier = inst->namep ; ! 2320: fn->n_table = 0; fn->n_tbl_list = 0 ; ! 2321: ! 2322: // Note that the formals were bound to the actuals when the class decl ! 2323: // was instantiated, so the binding is not redone. ! 2324: ! 2325: // Modify constructor and destructor names. ! 2326: if (!strcmp(fn->string, namep->string)) ! 2327: fn->string = inst->namep->string ; ! 2328: { inst->save_state(fn) ; ! 2329: // Instantiate the parametrized types referenced by this template ! 2330: for (Pcons pc = templ_ref_copy ; pc ; pc = pc->cdr) ! 2331: Ptempl_inst(pc->car)->instantiate() ; ! 2332: ! 2333: // ensure that "type type" formals constrained to be class definitions are ! 2334: if (!fnt->check_constraints(inst->actuals))continue ; ! 2335: ! 2336: if ( ((fn = fn->dcl(gtbl, EXTERN)) == 0) || error_count) { ! 2337: inst->restore_state() ; ! 2338: continue ; ! 2339: } ! 2340: fn->simpl() ; ! 2341: fn->dcl_print(0) ; ! 2342: inst->restore_state() ; ! 2343: } ! 2344: } ! 2345: } ! 2346: return change ; ! 2347: } ! 2348: ! 2349: ! 2350: ! 2351: static char rcsinfo[] = "$Header: /usr3/lang/benson/work/stripped_cfront/RCS/template.c,v 1.4 90/04/02 11:32:09 sam Exp $"; ! 2352: ! 2353: ! 2354: /* ! 2355: $Log: template.c,v $ ! 2356: * Revision 1.4 90/04/02 11:32:09 sam ! 2357: * 1) Made comments current. ! 2358: * 2) Removed some references to tree_templates. ! 2359: * ! 2360: * Revision 1.3 90/03/30 20:13:40 sam ! 2361: * The focal point for all the changes: ! 2362: * 1) increased the table size for tables used to maintain templates ! 2363: * 2) Declare a class template immediately after the class name has been ! 2364: * encountered, rather than at the end of the class definition. ! 2365: * 3) Support overiding member definitions ! 2366: * 4) Enforce class constraints on template formals, so that type type arguments ! 2367: * can be used to declare variables with constructor arguments. ! 2368: * 5) Lay the groundwork for solving the circular instantiation problem. ! 2369: * ! 2370: * Revision 1.2 90/03/27 10:17:27 sam ! 2371: * merged in revisions: 1.28, 1.30, 1.32, 1.33 from the main devo line ! 2372: * ! 2373: * Revision 1.1 89/11/20 08:50:56 benson ! 2374: * Initial revision ! 2375: * ! 2376: * Revision 1.20 89/11/01 14:16:30 sam ! 2377: * 1) set mem_list for an instantiated class, so that set_scope can setup scope ! 2378: * correctly. ! 2379: * 2) fix the bug where templ_refs were getting smashed by an incomplete ! 2380: * template definition that followed a complete definition. ! 2381: * ! 2382: * Revision 1.19 89/10/31 14:43:46 benson ! 2383: * 1) Fix name mangling for arrays with no dim field. ! 2384: * 2) fix the spelling of parameter in an error message. ! 2385: * ! 2386: * Revision 1.18 89/10/16 15:20:09 sam ! 2387: * 1) make use of the new pointer hash tables. ! 2388: * 2) fix a bug where the type definitions of formals were sometimes dcl_printed ! 2389: * after references to them in the generated c code. ! 2390: * ! 2391: * Revision 1.17 89/10/10 08:42:39 benson ! 2392: * manage emode with ++ and --.` ! 2393: * ! 2394: * Revision 1.16 89/09/26 16:45:11 sam ! 2395: * fix the forward declaration of template classes ! 2396: * ! 2397: * Revision 1.15 89/09/22 14:03:47 benson ! 2398: * add a way to ahve an expr formal of an internal template that is ! 2399: * not copied. ! 2400: * ! 2401: * Revision 1.14 89/09/18 16:38:44 sam ! 2402: * provide for error recovery upon argument mismatch in a template instantiation ! 2403: * ! 2404: * ! 2405: * Revision 1.13 89/09/15 09:32:09 benson ! 2406: * ! 2407: * Support the magic variable __current_template_name. ! 2408: * In an internal (expr or stmt) template, this is replaced ! 2409: * by a char constant containing the template name. Handy for ! 2410: * tracing. ! 2411: * ! 2412: * Revision 1.12 89/09/13 09:20:24 benson ! 2413: * rename aggregate to collection. ! 2414: * ! 2415: * Revision 1.11 89/09/12 12:57:14 sam ! 2416: * 1) suppressed arguments for zero argument internal templates. ! 2417: * 2) account for "zero" base nodes when matching actual arguments. ! 2418: * 3) fix bad %d format effector in generation of unique type names for internal ! 2419: * internal templates. ! 2420: * ! 2421: * Revision 1.10 89/09/06 16:23:26 sam ! 2422: * parametrized names are now mangled in a form that can be demangled by the ! 2423: * debugger, demangler etc. ! 2424: * ! 2425: * Revision 1.9 89/09/02 22:05:48 benson ! 2426: * bug fixes in the area of multiple use of formals in internal ! 2427: * templates. ! 2428: * ! 2429: * Revision 1.8 89/08/30 13:03:54 sam ! 2430: * added support for dealing with __expressions in class formal templates ! 2431: * ! 2432: * Revision 1.7 89/08/29 13:40:04 benson ! 2433: * disentangle the character string name of a generic function ! 2434: * from n_table_list. ! 2435: * ! 2436: * Revision 1.6 89/08/28 09:43:47 sam ! 2437: * refer to comments in 1.6 of templates.h ! 2438: * ! 2439: * Revision 1.5 89/08/23 10:20:04 sam ! 2440: * Changes in three major areas: ! 2441: * ! 2442: * 1) The syntax for formal parameters has been brought into alignment with the BS syntax. ! 2443: * ! 2444: * 2) The name encryption has been modified so that the debugger can unmung template ! 2445: * names. ! 2446: * ! 2447: * 3) Restrictions have been placed on non-type formals to facilitate their ! 2448: * handling. They may be integer expressions, float or double literals, or ! 2449: * pointers to static variables. ! 2450: * ! 2451: * 4) Gyrations in the code from the days of single instantiation templates ! 2452: * have been removed. ! 2453: * ! 2454: * Revision 1.4 89/08/11 14:56:29 sam ! 2455: * implementation of multiple instantiation templates. ! 2456: * ! 2457: * Revision 1.3 89/07/27 11:29:17 sam ! 2458: * Major changes were made her. They covered the following general area: ! 2459: * 1) Support for type expression actuals ! 2460: * 2) Support "normal" formal parameters. ! 2461: * 3) Support for tree templates ! 2462: * 4) statement and expression tree formals for tree templates. They are ! 2463: * incomplete for the regular templates. ! 2464: * ! 2465: * Revision 1.2 89/07/07 14:31:41 sam ! 2466: * The check in templ_inst::same did not cover all cases, this fixes it. ! 2467: * Also added a guard the is_template predicate to protect against user errors. ! 2468: * ! 2469: ! 2470: end_log ! 2471: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.