Mercurial > projects > ldc
comparison dmd/func.c @ 1587:def7a1d494fd
Merge DMD 1.051
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Fri, 06 Nov 2009 23:58:01 +0100 |
parents | 05c235309d6f |
children | a413ae7329bf |
comparison
equal
deleted
inserted
replaced
1586:7f728c52e63c | 1587:def7a1d494fd |
---|---|
1 // Compiler implementation of the D programming language | 1 // Compiler implementation of the D programming language |
2 // Copyright (c) 1999-2008 by Digital Mars | 2 // Copyright (c) 1999-2009 by Digital Mars |
3 // All Rights Reserved | 3 // All Rights Reserved |
4 // written by Walter Bright | 4 // written by Walter Bright |
5 // http://www.digitalmars.com | 5 // http://www.digitalmars.com |
6 // License for redistribution is by either the Artistic License | 6 // License for redistribution is by either the Artistic License |
7 // in artistic.txt, or the GNU General Public License in gnu.txt. | 7 // in artistic.txt, or the GNU General Public License in gnu.txt. |
33 | 33 |
34 FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) | 34 FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) |
35 : Declaration(id) | 35 : Declaration(id) |
36 { | 36 { |
37 //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); | 37 //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); |
38 //printf("storage_class = x%x\n", storage_class); | |
38 this->storage_class = storage_class; | 39 this->storage_class = storage_class; |
39 this->type = type; | 40 this->type = type; |
40 this->loc = loc; | 41 this->loc = loc; |
41 this->endloc = endloc; | 42 this->endloc = endloc; |
42 fthrows = NULL; | 43 fthrows = NULL; |
43 frequire = NULL; | 44 frequire = NULL; |
45 fdrequire = NULL; | |
46 fdensure = NULL; | |
44 outId = NULL; | 47 outId = NULL; |
45 vresult = NULL; | 48 vresult = NULL; |
46 returnLabel = NULL; | 49 returnLabel = NULL; |
47 fensure = NULL; | 50 fensure = NULL; |
48 fbody = NULL; | 51 fbody = NULL; |
61 inlineStatus = ILSuninitialized; | 64 inlineStatus = ILSuninitialized; |
62 inlineNest = 0; | 65 inlineNest = 0; |
63 inlineAsm = 0; | 66 inlineAsm = 0; |
64 cantInterpret = 0; | 67 cantInterpret = 0; |
65 semanticRun = 0; | 68 semanticRun = 0; |
69 #if DMDV1 | |
66 nestedFrameRef = 0; | 70 nestedFrameRef = 0; |
71 #endif | |
67 fes = NULL; | 72 fes = NULL; |
68 introducing = 0; | 73 introducing = 0; |
69 tintro = NULL; | 74 tintro = NULL; |
70 /* The type given for "infer the return type" is a TypeFunction with | 75 /* The type given for "infer the return type" is a TypeFunction with |
71 * NULL for the return type. | 76 * NULL for the return type. |
72 */ | 77 */ |
73 inferRetType = (type && type->nextOf() == NULL); | 78 inferRetType = (type && type->nextOf() == NULL); |
74 scope = NULL; | |
75 hasReturnExp = 0; | 79 hasReturnExp = 0; |
76 nrvo_can = 1; | 80 nrvo_can = 1; |
77 nrvo_var = NULL; | 81 nrvo_var = NULL; |
78 #if IN_DMD | 82 #if IN_DMD |
79 shidden = NULL; | 83 shidden = NULL; |
84 #endif | |
85 | |
86 #if DMDV2 | |
87 builtin = BUILTINunknown; | |
88 tookAddressOf = 0; | |
80 #endif | 89 #endif |
81 | 90 |
82 #if IN_LLVM | 91 #if IN_LLVM |
83 // LDC | 92 // LDC |
84 isArrayOp = false; | 93 isArrayOp = false; |
140 | 149 |
141 #if 0 | 150 #if 0 |
142 printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); | 151 printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); |
143 if (isFuncLiteralDeclaration()) | 152 if (isFuncLiteralDeclaration()) |
144 printf("\tFuncLiteralDeclaration()\n"); | 153 printf("\tFuncLiteralDeclaration()\n"); |
145 printf("sc->parent = %s\n", sc->parent->toChars()); | 154 printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : ""); |
146 printf("type: %p, %s\n", type, type->toChars()); | 155 printf("type: %p, %s\n", type, type->toChars()); |
147 #endif | 156 #endif |
148 | 157 |
149 if (semanticRun && isFuncLiteralDeclaration()) | 158 if (semanticRun && isFuncLiteralDeclaration()) |
150 { | 159 { |
156 return; | 165 return; |
157 } | 166 } |
158 assert(semanticRun <= 1); | 167 assert(semanticRun <= 1); |
159 semanticRun = 1; | 168 semanticRun = 1; |
160 | 169 |
161 if (type->nextOf()) | 170 if (!type->deco) |
171 { | |
162 type = type->semantic(loc, sc); | 172 type = type->semantic(loc, sc); |
173 } | |
163 //type->print(); | 174 //type->print(); |
164 if (type->ty != Tfunction) | 175 if (type->ty != Tfunction) |
165 { | 176 { |
166 error("%s must be a function", toChars()); | 177 error("%s must be a function", toChars()); |
167 return; | 178 return; |
247 if (id) | 258 if (id) |
248 { | 259 { |
249 storage_class |= STCabstract; | 260 storage_class |= STCabstract; |
250 | 261 |
251 if (isCtorDeclaration() || | 262 if (isCtorDeclaration() || |
263 #if DMDV2 | |
264 isPostBlitDeclaration() || | |
265 #endif | |
252 isDtorDeclaration() || | 266 isDtorDeclaration() || |
253 isInvariantDeclaration() || | 267 isInvariantDeclaration() || |
254 isUnitTestDeclaration() || isNewDeclaration() || isDelete()) | 268 isUnitTestDeclaration() || isNewDeclaration() || isDelete()) |
255 error("special function not allowed in interface %s", id->toChars()); | 269 error("special function not allowed in interface %s", id->toChars()); |
256 if (fbody) | 270 if (fbody) |
395 error("multiple overrides of same function"); | 409 error("multiple overrides of same function"); |
396 } | 410 } |
397 cd->vtbl.data[vi] = (void *)this; | 411 cd->vtbl.data[vi] = (void *)this; |
398 vtblIndex = vi; | 412 vtblIndex = vi; |
399 | 413 |
414 /* Remember which functions this overrides | |
415 */ | |
416 foverrides.push(fdv); | |
417 | |
400 /* This works by whenever this function is called, | 418 /* This works by whenever this function is called, |
401 * it actually returns tintro, which gets dynamically | 419 * it actually returns tintro, which gets dynamically |
402 * cast to type. But we know that tintro is a base | 420 * cast to type. But we know that tintro is a base |
403 * of type, so we could optimize it by not doing a | 421 * of type, so we could optimize it by not doing a |
404 * dynamic cast, but just subtracting the isBaseOf() | 422 * dynamic cast, but just subtracting the isBaseOf() |
441 return; | 459 return; |
442 | 460 |
443 default: | 461 default: |
444 { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; | 462 { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; |
445 Type *ti = NULL; | 463 Type *ti = NULL; |
464 | |
465 /* Remember which functions this overrides | |
466 */ | |
467 foverrides.push(fdv); | |
446 | 468 |
447 if (fdv->tintro) | 469 if (fdv->tintro) |
448 ti = fdv->tintro; | 470 ti = fdv->tintro; |
449 else if (!type->equals(fdv->type)) | 471 else if (!type->equals(fdv->type)) |
450 { | 472 { |
598 | 620 |
599 default: | 621 default: |
600 goto Lmainerr; | 622 goto Lmainerr; |
601 } | 623 } |
602 | 624 |
603 if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) | 625 if (!f->nextOf()) |
626 error("must return int or void"); | |
627 else if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) | |
604 error("must return int or void, not %s", f->nextOf()->toChars()); | 628 error("must return int or void, not %s", f->nextOf()->toChars()); |
605 if (f->varargs) | 629 if (f->varargs) |
606 { | 630 { |
607 Lmainerr: | 631 Lmainerr: |
608 error("parameters must be main() or main(char[][] args)"); | 632 error("parameters must be main() or main(char[][] args)"); |
633 goto Lassignerr; | 657 goto Lassignerr; |
634 } | 658 } |
635 } | 659 } |
636 } | 660 } |
637 | 661 |
662 if (isVirtual()) | |
663 { | |
664 /* Rewrite contracts as nested functions, then call them. | |
665 * Doing it as nested functions means that overriding functions | |
666 * can call them. | |
667 */ | |
668 if (frequire) | |
669 { /* in { ... } | |
670 * becomes: | |
671 * void __require() { ... } | |
672 * __require(); | |
673 */ | |
674 Loc loc = frequire->loc; | |
675 TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd); | |
676 FuncDeclaration *fd = new FuncDeclaration(loc, loc, | |
677 Id::require, STCundefined, tf); | |
678 fd->fbody = frequire; | |
679 Statement *s1 = new DeclarationStatement(loc, fd); | |
680 Expression *e = new CallExp(loc, new VarExp(loc, fd), (Expressions *)NULL); | |
681 Statement *s2 = new ExpStatement(loc, e); | |
682 frequire = new CompoundStatement(loc, s1, s2); | |
683 fdrequire = fd; | |
684 } | |
685 | |
686 if (fensure) | |
687 { /* out (result) { ... } | |
688 * becomes: | |
689 * tret __ensure(ref tret result) { ... } | |
690 * __ensure(result); | |
691 */ | |
692 if (!outId && f->nextOf()->toBasetype()->ty != Tvoid) | |
693 outId = Id::result; // provide a default | |
694 | |
695 Loc loc = fensure->loc; | |
696 Arguments *arguments = new Arguments(); | |
697 Argument *a = NULL; | |
698 if (outId) | |
699 { a = new Argument(STCref, f->nextOf(), outId, NULL); | |
700 arguments->push(a); | |
701 } | |
702 TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); | |
703 FuncDeclaration *fd = new FuncDeclaration(loc, loc, | |
704 Id::ensure, STCundefined, tf); | |
705 fd->fbody = fensure; | |
706 Statement *s1 = new DeclarationStatement(loc, fd); | |
707 Expression *eresult = NULL; | |
708 if (outId) | |
709 eresult = new IdentifierExp(loc, outId); | |
710 Expression *e = new CallExp(loc, new VarExp(loc, fd), eresult); | |
711 Statement *s2 = new ExpStatement(loc, e); | |
712 fensure = new CompoundStatement(loc, s1, s2); | |
713 fdensure = fd; | |
714 } | |
715 } | |
716 | |
638 Ldone: | 717 Ldone: |
639 /* Save scope for possible later use (if we need the | 718 /* Save scope for possible later use (if we need the |
640 * function internals) | 719 * function internals) |
641 */ | 720 */ |
642 scope = new Scope(*sc); | 721 scope = new Scope(*sc); |
653 | 732 |
654 // Do the semantic analysis on the internals of the function. | 733 // Do the semantic analysis on the internals of the function. |
655 | 734 |
656 void FuncDeclaration::semantic3(Scope *sc) | 735 void FuncDeclaration::semantic3(Scope *sc) |
657 { TypeFunction *f; | 736 { TypeFunction *f; |
658 AggregateDeclaration *ad; | |
659 VarDeclaration *argptr = NULL; | 737 VarDeclaration *argptr = NULL; |
660 VarDeclaration *_arguments = NULL; | 738 VarDeclaration *_arguments = NULL; |
661 | 739 |
662 if (!parent) | 740 if (!parent) |
663 { | 741 { |
666 //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); | 744 //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); |
667 assert(0); | 745 assert(0); |
668 } | 746 } |
669 //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); | 747 //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); |
670 //fflush(stdout); | 748 //fflush(stdout); |
749 //printf("storage class = x%x %x\n", sc->stc, storage_class); | |
671 //{ static int x; if (++x == 2) *(char*)0=0; } | 750 //{ static int x; if (++x == 2) *(char*)0=0; } |
672 //printf("\tlinkage = %d\n", sc->linkage); | 751 //printf("\tlinkage = %d\n", sc->linkage); |
673 | 752 |
674 //printf(" sc->incontract = %d\n", sc->incontract); | 753 //printf(" sc->incontract = %d\n", sc->incontract); |
675 if (semanticRun >= 3) | 754 if (semanticRun >= 3) |
681 availableExternally = false; | 760 availableExternally = false; |
682 | 761 |
683 if (!type || type->ty != Tfunction) | 762 if (!type || type->ty != Tfunction) |
684 return; | 763 return; |
685 f = (TypeFunction *)(type); | 764 f = (TypeFunction *)(type); |
686 size_t nparams = Argument::dim(f->parameters); | |
687 | 765 |
688 // Check the 'throws' clause | 766 // Check the 'throws' clause |
689 if (fthrows) | 767 if (fthrows) |
690 { | 768 { |
691 for (int i = 0; i < fthrows->dim; i++) | 769 for (int i = 0; i < fthrows->dim; i++) |
695 t = t->semantic(loc, sc); | 773 t = t->semantic(loc, sc); |
696 if (!t->isClassHandle()) | 774 if (!t->isClassHandle()) |
697 error("can only throw classes, not %s", t->toChars()); | 775 error("can only throw classes, not %s", t->toChars()); |
698 } | 776 } |
699 } | 777 } |
778 | |
779 frequire = mergeFrequire(frequire); | |
780 fensure = mergeFensure(fensure); | |
700 | 781 |
701 if (fbody || frequire) | 782 if (fbody || frequire) |
702 { | 783 { |
703 /* Symbol table into which we place parameters and nested functions, | 784 /* Symbol table into which we place parameters and nested functions, |
704 * solely to diagnose name collisions. | 785 * solely to diagnose name collisions. |
725 sc2->enclosingFinally = NULL; | 806 sc2->enclosingFinally = NULL; |
726 sc2->enclosingScopeExit = NULL; | 807 sc2->enclosingScopeExit = NULL; |
727 sc2->noctor = 0; | 808 sc2->noctor = 0; |
728 | 809 |
729 // Declare 'this' | 810 // Declare 'this' |
730 ad = isThis(); | 811 AggregateDeclaration *ad = isThis(); |
731 if (ad) | 812 if (ad) |
732 { VarDeclaration *v; | 813 { VarDeclaration *v; |
733 | 814 |
734 if (isFuncLiteralDeclaration() && isNested()) | 815 if (isFuncLiteralDeclaration() && isNested()) |
735 { | 816 { |
764 vthis = v; | 845 vthis = v; |
765 } | 846 } |
766 | 847 |
767 // Declare hidden variable _arguments[] and _argptr | 848 // Declare hidden variable _arguments[] and _argptr |
768 if (f->varargs == 1) | 849 if (f->varargs == 1) |
769 { Type *t; | 850 { |
851 #if TARGET_NET | |
852 varArgs(sc2, f, argptr, _arguments); | |
853 #else | |
854 Type *t; | |
770 | 855 |
771 if (f->linkage == LINKd) | 856 if (f->linkage == LINKd) |
772 { // Declare _arguments[] | 857 { // Declare _arguments[] |
773 #if BREAKABI | 858 #if BREAKABI |
774 v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); | 859 v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); |
801 argptr = new VarDeclaration(0, t, Id::_argptr, NULL); | 886 argptr = new VarDeclaration(0, t, Id::_argptr, NULL); |
802 argptr->semantic(sc2); | 887 argptr->semantic(sc2); |
803 sc2->insert(argptr); | 888 sc2->insert(argptr); |
804 argptr->parent = this; | 889 argptr->parent = this; |
805 } | 890 } |
891 #endif | |
806 } | 892 } |
807 | 893 |
808 #if IN_LLVM | 894 #if IN_LLVM |
809 // LDC make sure argument type is semanticed. | 895 // LDC make sure argument type is semanticed. |
810 // Turns TypeTuple!(int, int) into two int parameters, for instance. | 896 // Turns TypeTuple!(int, int) into two int parameters, for instance. |
822 // FIXME: Maybe we only need to do this for tuples, | 908 // FIXME: Maybe we only need to do this for tuples, |
823 // and can add tuple.length after decrement? | 909 // and can add tuple.length after decrement? |
824 i--; | 910 i--; |
825 } | 911 } |
826 } | 912 } |
827 // update nparams to include expanded tuples | |
828 nparams = Argument::dim(f->parameters); | |
829 } | 913 } |
830 #endif | 914 #endif |
831 | 915 |
832 // Propagate storage class from tuple parameters to their element-parameters. | 916 // Propagate storage class from tuple parameters to their element-parameters. |
833 if (f->parameters) | 917 if (f->parameters) |
834 { | 918 { |
835 for (size_t i = 0; i < f->parameters->dim; i++) | 919 for (size_t i = 0; i < f->parameters->dim; i++) |
836 { Argument *arg = (Argument *)f->parameters->data[i]; | 920 { Argument *arg = (Argument *)f->parameters->data[i]; |
837 | 921 |
922 //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); | |
838 if (arg->type->ty == Ttuple) | 923 if (arg->type->ty == Ttuple) |
839 { TypeTuple *t = (TypeTuple *)arg->type; | 924 { TypeTuple *t = (TypeTuple *)arg->type; |
840 size_t dim = Argument::dim(t->arguments); | 925 size_t dim = Argument::dim(t->arguments); |
841 for (size_t j = 0; j < dim; j++) | 926 for (size_t j = 0; j < dim; j++) |
842 { Argument *narg = Argument::getNth(t->arguments, j); | 927 { Argument *narg = Argument::getNth(t->arguments, j); |
844 } | 929 } |
845 } | 930 } |
846 } | 931 } |
847 } | 932 } |
848 | 933 |
849 // Declare all the function parameters as variables | 934 /* Declare all the function parameters as variables |
935 * and install them in parameters[] | |
936 */ | |
937 size_t nparams = Argument::dim(f->parameters); | |
850 if (nparams) | 938 if (nparams) |
851 { /* parameters[] has all the tuples removed, as the back end | 939 { /* parameters[] has all the tuples removed, as the back end |
852 * doesn't know about tuples | 940 * doesn't know about tuples |
853 */ | 941 */ |
854 parameters = new Dsymbols(); | 942 parameters = new Dsymbols(); |
862 /* Generate identifier for un-named parameter, | 950 /* Generate identifier for un-named parameter, |
863 * because we need it later on. | 951 * because we need it later on. |
864 */ | 952 */ |
865 arg->ident = id = Identifier::generateId("_param_", i); | 953 arg->ident = id = Identifier::generateId("_param_", i); |
866 } | 954 } |
867 VarDeclaration *v = new VarDeclaration(loc, arg->type, id, NULL); | 955 Type *vtype = arg->type; |
956 VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL); | |
868 //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); | 957 //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); |
869 v->storage_class |= STCparameter; | 958 v->storage_class |= STCparameter; |
870 if (f->varargs == 2 && i + 1 == nparams) | 959 if (f->varargs == 2 && i + 1 == nparams) |
871 v->storage_class |= STCvariadic; | 960 v->storage_class |= STCvariadic; |
872 v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy); | 961 v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy); |
933 } | 1022 } |
934 | 1023 |
935 if (fensure || addPostInvariant()) | 1024 if (fensure || addPostInvariant()) |
936 { /* fensure is composed of the [out] contracts | 1025 { /* fensure is composed of the [out] contracts |
937 */ | 1026 */ |
1027 if (!type->nextOf()) | |
1028 { // Have to do semantic() on fbody first | |
1029 error("post conditions are not supported if the return type is inferred"); | |
1030 return; | |
1031 } | |
1032 | |
938 ScopeDsymbol *sym = new ScopeDsymbol(); | 1033 ScopeDsymbol *sym = new ScopeDsymbol(); |
939 sym->parent = sc2->scopesym; | 1034 sym->parent = sc2->scopesym; |
940 sc2 = sc2->push(sym); | 1035 sc2 = sc2->push(sym); |
941 | 1036 |
942 assert(type->nextOf()); | 1037 assert(type->nextOf()); |
959 if (fensure) | 1054 if (fensure) |
960 loc = fensure->loc; | 1055 loc = fensure->loc; |
961 | 1056 |
962 v = new VarDeclaration(loc, type->nextOf(), outId, NULL); | 1057 v = new VarDeclaration(loc, type->nextOf(), outId, NULL); |
963 v->noscope = 1; | 1058 v->noscope = 1; |
1059 #if DMDV2 | |
1060 if (f->isref) | |
1061 { | |
1062 v->storage_class |= STCref | STCforeach; | |
1063 } | |
1064 #endif | |
964 sc2->incontract--; | 1065 sc2->incontract--; |
965 v->semantic(sc2); | 1066 v->semantic(sc2); |
966 sc2->incontract++; | 1067 sc2->incontract++; |
967 if (!sc2->insert(v)) | 1068 if (!sc2->insert(v)) |
968 error("out result %s is already defined", v->toChars()); | 1069 error("out result %s is already defined", v->toChars()); |
1009 e = e->semantic(sc2); | 1110 e = e->semantic(sc2); |
1010 } | 1111 } |
1011 } | 1112 } |
1012 else | 1113 else |
1013 { // Call invariant virtually | 1114 { // Call invariant virtually |
1014 ThisExp *v = new ThisExp(0); | 1115 Expression *v = new ThisExp(0); |
1015 v->type = vthis->type; | 1116 v->type = vthis->type; |
1117 #if STRUCTTHISREF | |
1118 if (ad->isStructDeclaration()) | |
1119 v = v->addressOf(sc); | |
1120 #endif | |
1016 e = new AssertExp(0, v); | 1121 e = new AssertExp(0, v); |
1017 } | 1122 } |
1018 if (e) | 1123 if (e) |
1019 { | 1124 { |
1020 ExpStatement *s = new ExpStatement(0, e); | 1125 ExpStatement *s = new ExpStatement(0, e); |
1132 } | 1237 } |
1133 else if (!hasReturnExp && type->nextOf()->ty != Tvoid) | 1238 else if (!hasReturnExp && type->nextOf()->ty != Tvoid) |
1134 error("expected to return a value of type %s", type->nextOf()->toChars()); | 1239 error("expected to return a value of type %s", type->nextOf()->toChars()); |
1135 else if (!inlineAsm) | 1240 else if (!inlineAsm) |
1136 { | 1241 { |
1242 #if DMDV2 | |
1243 int blockexit = fbody ? fbody->blockExit() : BEfallthru; | |
1244 if (f->isnothrow && blockexit & BEthrow) | |
1245 error("'%s' is nothrow yet may throw", toChars()); | |
1246 | |
1247 int offend = blockexit & BEfallthru; | |
1248 #endif | |
1137 if (type->nextOf()->ty == Tvoid) | 1249 if (type->nextOf()->ty == Tvoid) |
1138 { | 1250 { |
1139 if (offend && isMain()) | 1251 if (offend && isMain()) |
1140 { // Add a return 0; statement | 1252 { // Add a return 0; statement |
1141 Statement *s = new ReturnStatement(0, new IntegerExp(0)); | 1253 Statement *s = new ReturnStatement(0, new IntegerExp(0)); |
1144 } | 1256 } |
1145 else | 1257 else |
1146 { | 1258 { |
1147 if (offend) | 1259 if (offend) |
1148 { Expression *e; | 1260 { Expression *e; |
1149 | 1261 #if DMDV1 |
1150 warning(loc, "no return at end of function"); | 1262 warning(loc, "no return exp; or assert(0); at end of function"); |
1151 | 1263 #else |
1264 error("no return exp; or assert(0); at end of function"); | |
1265 #endif | |
1152 if (global.params.useAssert && | 1266 if (global.params.useAssert && |
1153 !global.params.useInline) | 1267 !global.params.useInline) |
1154 { /* Add an assert(0, msg); where the missing return | 1268 { /* Add an assert(0, msg); where the missing return |
1155 * should be. | 1269 * should be. |
1156 */ | 1270 */ |
1207 e1 = new VarExp(0, argptr); | 1321 e1 = new VarExp(0, argptr); |
1208 if (parameters && parameters->dim) | 1322 if (parameters && parameters->dim) |
1209 p = (VarDeclaration *)parameters->data[parameters->dim - 1]; | 1323 p = (VarDeclaration *)parameters->data[parameters->dim - 1]; |
1210 else | 1324 else |
1211 p = v_arguments; // last parameter is _arguments[] | 1325 p = v_arguments; // last parameter is _arguments[] |
1212 offset = p->type->size(); | 1326 if (p->storage_class & STClazy) |
1327 // If the last parameter is lazy, it's the size of a delegate | |
1328 offset = PTRSIZE * 2; | |
1329 else | |
1330 offset = p->type->size(); | |
1213 offset = (offset + 3) & ~3; // assume stack aligns on 4 | 1331 offset = (offset + 3) & ~3; // assume stack aligns on 4 |
1214 e = new SymOffExp(0, p, offset); | 1332 e = new SymOffExp(0, p, offset); |
1215 e = new AssignExp(0, e1, e); | 1333 e = new AssignExp(0, e1, e); |
1216 e->type = t; | 1334 e->type = t; |
1217 a->push(new ExpStatement(0, e)); | 1335 a->push(new ExpStatement(0, e)); |
1225 */ | 1343 */ |
1226 Expression *e = new VarExp(0, v_arguments); | 1344 Expression *e = new VarExp(0, v_arguments); |
1227 e = new DotIdExp(0, e, Id::elements); | 1345 e = new DotIdExp(0, e, Id::elements); |
1228 Expression *e1 = new VarExp(0, _arguments); | 1346 Expression *e1 = new VarExp(0, _arguments); |
1229 e = new AssignExp(0, e1, e); | 1347 e = new AssignExp(0, e1, e); |
1230 e = e->semantic(sc); | 1348 e->op = TOKconstruct; |
1349 e = e->semantic(sc2); | |
1231 a->push(new ExpStatement(0, e)); | 1350 a->push(new ExpStatement(0, e)); |
1232 } | 1351 } |
1233 | 1352 |
1234 #endif // !IN_LLVM | 1353 #endif // !IN_LLVM |
1235 | 1354 |
1282 } | 1401 } |
1283 | 1402 |
1284 // LDC: check for null this | 1403 // LDC: check for null this |
1285 ThisExp* v = new ThisExp(0); | 1404 ThisExp* v = new ThisExp(0); |
1286 v->type = vthis->type; | 1405 v->type = vthis->type; |
1406 #if STRUCTTHISREF | |
1407 if (ad->isStructDeclaration()) | |
1408 v = v->addressOf(sc); | |
1409 #endif | |
1287 v->var = vthis; | 1410 v->var = vthis; |
1288 | 1411 |
1289 NullExp *nv = new NullExp(0); | 1412 NullExp *nv = new NullExp(0); |
1290 nv->type = v->type; | 1413 nv->type = v->type; |
1291 | 1414 |
1330 a->push(s); | 1453 a->push(s); |
1331 } | 1454 } |
1332 } | 1455 } |
1333 | 1456 |
1334 fbody = new CompoundStatement(0, a); | 1457 fbody = new CompoundStatement(0, a); |
1458 #if DMDV2 | |
1459 /* Append destructor calls for parameters as finally blocks. | |
1460 */ | |
1461 if (parameters) | |
1462 { for (size_t i = 0; i < parameters->dim; i++) | |
1463 { | |
1464 VarDeclaration *v = (VarDeclaration *)parameters->data[i]; | |
1465 | |
1466 if (v->storage_class & (STCref | STCout)) | |
1467 continue; | |
1468 | |
1469 /* Don't do this for static arrays, since static | |
1470 * arrays are called by reference. Remove this | |
1471 * when we change them to call by value. | |
1472 */ | |
1473 if (v->type->toBasetype()->ty == Tsarray) | |
1474 continue; | |
1475 | |
1476 Expression *e = v->callAutoDtor(sc); | |
1477 if (e) | |
1478 { Statement *s = new ExpStatement(0, e); | |
1479 s = s->semantic(sc); | |
1480 if (fbody->blockExit() == BEfallthru) | |
1481 fbody = new CompoundStatement(0, fbody, s); | |
1482 else | |
1483 fbody = new TryFinallyStatement(0, fbody, s); | |
1484 } | |
1485 } | |
1486 } | |
1487 #endif | |
1335 | 1488 |
1336 // wrap body of synchronized functions in a synchronized statement | 1489 // wrap body of synchronized functions in a synchronized statement |
1337 if (isSynchronized()) | 1490 if (isSynchronized()) |
1338 { | 1491 { |
1339 ClassDeclaration *cd = parent->isClassDeclaration(); | 1492 ClassDeclaration *cd = parent->isClassDeclaration(); |
1428 buf->writenl(); | 1581 buf->writenl(); |
1429 } | 1582 } |
1430 } | 1583 } |
1431 | 1584 |
1432 /**************************************************** | 1585 /**************************************************** |
1586 * Merge into this function the 'in' contracts of all it overrides. | |
1587 * 'in's are OR'd together, i.e. only one of them needs to pass. | |
1588 */ | |
1589 | |
1590 Statement *FuncDeclaration::mergeFrequire(Statement *sf) | |
1591 { | |
1592 /* Implementing this is done by having the overriding function call | |
1593 * nested functions (the fdrequire functions) nested inside the overridden | |
1594 * function. This requires that the stack layout of the calling function's | |
1595 * parameters and 'this' pointer be in the same place (as the nested | |
1596 * function refers to them). | |
1597 * This is easy for the parameters, as they are all on the stack in the same | |
1598 * place by definition, since it's an overriding function. The problem is | |
1599 * getting the 'this' pointer in the same place, since it is a local variable. | |
1600 * We did some hacks in the code generator to make this happen: | |
1601 * 1. always generate exception handler frame, or at least leave space for it | |
1602 * in the frame (Windows 32 SEH only) | |
1603 * 2. always generate an EBP style frame | |
1604 * 3. since 'this' is passed in a register that is subsequently copied into | |
1605 * a stack local, allocate that local immediately following the exception | |
1606 * handler block, so it is always at the same offset from EBP. | |
1607 */ | |
1608 for (int i = 0; i < foverrides.dim; i++) | |
1609 { | |
1610 FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; | |
1611 sf = fdv->mergeFrequire(sf); | |
1612 if (fdv->fdrequire) | |
1613 { | |
1614 //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); | |
1615 /* Make the call: | |
1616 * try { __require(); } | |
1617 * catch { frequire; } | |
1618 */ | |
1619 Expression *eresult = NULL; | |
1620 Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire), eresult); | |
1621 Statement *s2 = new ExpStatement(loc, e); | |
1622 | |
1623 if (sf) | |
1624 { Catch *c = new Catch(loc, NULL, NULL, sf); | |
1625 Array *catches = new Array(); | |
1626 catches->push(c); | |
1627 sf = new TryCatchStatement(loc, s2, catches); | |
1628 } | |
1629 else | |
1630 sf = s2; | |
1631 } | |
1632 } | |
1633 return sf; | |
1634 } | |
1635 | |
1636 /**************************************************** | |
1637 * Merge into this function the 'out' contracts of all it overrides. | |
1638 * 'out's are AND'd together, i.e. all of them need to pass. | |
1639 */ | |
1640 | |
1641 Statement *FuncDeclaration::mergeFensure(Statement *sf) | |
1642 { | |
1643 /* Same comments as for mergeFrequire(), except that we take care | |
1644 * of generating a consistent reference to the 'result' local by | |
1645 * explicitly passing 'result' to the nested function as a reference | |
1646 * argument. | |
1647 * This won't work for the 'this' parameter as it would require changing | |
1648 * the semantic code for the nested function so that it looks on the parameter | |
1649 * list for the 'this' pointer, something that would need an unknown amount | |
1650 * of tweaking of various parts of the compiler that I'd rather leave alone. | |
1651 */ | |
1652 for (int i = 0; i < foverrides.dim; i++) | |
1653 { | |
1654 FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; | |
1655 sf = fdv->mergeFensure(sf); | |
1656 if (fdv->fdensure) | |
1657 { | |
1658 //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); | |
1659 // Make the call: __ensure(result) | |
1660 Expression *eresult = NULL; | |
1661 if (outId) | |
1662 eresult = new IdentifierExp(loc, outId); | |
1663 Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure), eresult); | |
1664 Statement *s2 = new ExpStatement(loc, e); | |
1665 | |
1666 if (sf) | |
1667 { | |
1668 sf = new CompoundStatement(fensure->loc, s2, sf); | |
1669 } | |
1670 else | |
1671 sf = s2; | |
1672 } | |
1673 } | |
1674 return sf; | |
1675 } | |
1676 | |
1677 /**************************************************** | |
1433 * Determine if 'this' overrides fd. | 1678 * Determine if 'this' overrides fd. |
1434 * Return !=0 if it does. | 1679 * Return !=0 if it does. |
1435 */ | 1680 */ |
1436 | 1681 |
1437 int FuncDeclaration::overrides(FuncDeclaration *fd) | 1682 int FuncDeclaration::overrides(FuncDeclaration *fd) |
1602 } | 1847 } |
1603 return 0; | 1848 return 0; |
1604 } | 1849 } |
1605 | 1850 |
1606 /******************************************** | 1851 /******************************************** |
1852 * If there are no overloads of function f, return that function, | |
1853 * otherwise return NULL. | |
1854 */ | |
1855 | |
1856 static int fpunique(void *param, FuncDeclaration *f) | |
1857 { FuncDeclaration **pf = (FuncDeclaration **)param; | |
1858 | |
1859 if (*pf) | |
1860 { *pf = NULL; | |
1861 return 1; // ambiguous, done | |
1862 } | |
1863 else | |
1864 { *pf = f; | |
1865 return 0; | |
1866 } | |
1867 } | |
1868 | |
1869 FuncDeclaration *FuncDeclaration::isUnique() | |
1870 { FuncDeclaration *result = NULL; | |
1871 | |
1872 overloadApply(getModule(), this, &fpunique, &result); | |
1873 return result; | |
1874 } | |
1875 | |
1876 /******************************************** | |
1607 * Find function in overload list that exactly matches t. | 1877 * Find function in overload list that exactly matches t. |
1608 */ | 1878 */ |
1609 | 1879 |
1610 struct Param1 | 1880 struct Param1 |
1611 { | 1881 { |
1745 } | 2015 } |
1746 return 0; | 2016 return 0; |
1747 } | 2017 } |
1748 | 2018 |
1749 | 2019 |
1750 void overloadResolveX(Match *m, FuncDeclaration *fstart, Expressions *arguments, Module* from) | 2020 void overloadResolveX(Match *m, FuncDeclaration *fstart, |
2021 Expression *ethis, Expressions *arguments, Module *from) | |
1751 { | 2022 { |
1752 Param2 p; | 2023 Param2 p; |
1753 p.m = m; | 2024 p.m = m; |
1754 p.arguments = arguments; | 2025 p.arguments = arguments; |
1755 overloadApply(from, fstart, &fp2, &p); | 2026 overloadApply(from, fstart, &fp2, &p); |
1771 AliasDeclaration *a; | 2042 AliasDeclaration *a; |
1772 | 2043 |
1773 fa = d->isFuncAliasDeclaration(); | 2044 fa = d->isFuncAliasDeclaration(); |
1774 if (fa) | 2045 if (fa) |
1775 { | 2046 { |
1776 overloadResolveX(m, fa->funcalias, arguments); | 2047 overloadResolveX(m, fa->funcalias, NULL, arguments); |
1777 next = fa->overnext; | 2048 next = fa->overnext; |
1778 } | 2049 } |
1779 else if ((f = d->isFuncDeclaration()) != NULL) | 2050 else if ((f = d->isFuncDeclaration()) != NULL) |
1780 { | 2051 { |
1781 next = f->overnext; | 2052 next = f->overnext; |
1835 } | 2106 } |
1836 } | 2107 } |
1837 } | 2108 } |
1838 #endif | 2109 #endif |
1839 | 2110 |
1840 FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expressions *arguments, Module* from) | 2111 FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, Module *from, int flags) |
1841 { | 2112 { |
1842 TypeFunction *tf; | 2113 TypeFunction *tf; |
1843 Match m; | 2114 Match m; |
1844 | 2115 |
1845 #if 0 | 2116 #if 0 |
1858 } | 2129 } |
1859 #endif | 2130 #endif |
1860 | 2131 |
1861 memset(&m, 0, sizeof(m)); | 2132 memset(&m, 0, sizeof(m)); |
1862 m.last = MATCHnomatch; | 2133 m.last = MATCHnomatch; |
1863 overloadResolveX(&m, this, arguments, from); | 2134 overloadResolveX(&m, this, NULL, arguments, from); |
1864 | 2135 |
1865 if (m.count == 1) // exactly one match | 2136 if (m.count == 1) // exactly one match |
1866 { | 2137 { |
1867 return m.lastf; | 2138 return m.lastf; |
1868 } | 2139 } |
2037 } | 2308 } |
2038 cs = fbody->isCompoundStatement(); | 2309 cs = fbody->isCompoundStatement(); |
2039 cs->statements->push(s); | 2310 cs->statements->push(s); |
2040 } | 2311 } |
2041 | 2312 |
2313 const char *FuncDeclaration::toPrettyChars() | |
2314 { | |
2315 if (isMain()) | |
2316 return "D main"; | |
2317 else | |
2318 return Dsymbol::toPrettyChars(); | |
2319 } | |
2042 | 2320 |
2043 int FuncDeclaration::isMain() | 2321 int FuncDeclaration::isMain() |
2044 { | 2322 { |
2045 return ident == Id::main && | 2323 return ident == Id::main && |
2046 linkage != LINKc && !isMember() && !isNested(); | 2324 linkage != LINKc && !isMember() && !isNested(); |
2402 tret = Type::tvoid; | 2680 tret = Type::tvoid; |
2403 } | 2681 } |
2404 else | 2682 else |
2405 tret = cd->type; //->referenceTo(); | 2683 tret = cd->type; //->referenceTo(); |
2406 type = new TypeFunction(arguments, tret, varargs, LINKd); | 2684 type = new TypeFunction(arguments, tret, varargs, LINKd); |
2685 #if STRUCTTHISREF | |
2686 if (ad && ad->isStructDeclaration()) | |
2687 ((TypeFunction *)type)->isref = 1; | |
2688 #endif | |
2407 if (!originalType) | 2689 if (!originalType) |
2408 originalType = type; | 2690 originalType = type; |
2409 | 2691 |
2410 sc->flags |= SCOPEctor; | 2692 sc->flags |= SCOPEctor; |
2411 type = type->semantic(loc, sc); | 2693 type = type->semantic(loc, sc); |
2413 | 2695 |
2414 // Append: | 2696 // Append: |
2415 // return this; | 2697 // return this; |
2416 // to the function body | 2698 // to the function body |
2417 if (fbody) | 2699 if (fbody) |
2418 { Expression *e; | 2700 { |
2419 Statement *s; | 2701 Expression *e = new ThisExp(loc); |
2420 | 2702 Statement *s = new ReturnStatement(loc, e); |
2421 e = new ThisExp(0); | 2703 fbody = new CompoundStatement(loc, fbody, s); |
2422 s = new ReturnStatement(0, e); | |
2423 fbody = new CompoundStatement(0, fbody, s); | |
2424 } | 2704 } |
2425 | 2705 |
2426 FuncDeclaration::semantic(sc); | 2706 FuncDeclaration::semantic(sc); |
2427 | 2707 |
2428 sc->pop(); | 2708 sc->pop(); |
2463 buf->writestring("this"); | 2743 buf->writestring("this"); |
2464 Argument::argsToCBuffer(buf, hgs, arguments, varargs); | 2744 Argument::argsToCBuffer(buf, hgs, arguments, varargs); |
2465 bodyToCBuffer(buf, hgs); | 2745 bodyToCBuffer(buf, hgs); |
2466 } | 2746 } |
2467 | 2747 |
2748 /********************************* PostBlitDeclaration ****************************/ | |
2749 | |
2750 #if DMDV2 | |
2751 PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) | |
2752 : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) | |
2753 { | |
2754 } | |
2755 | |
2756 PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) | |
2757 : FuncDeclaration(loc, endloc, id, STCundefined, NULL) | |
2758 { | |
2759 } | |
2760 | |
2761 Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) | |
2762 { | |
2763 assert(!s); | |
2764 PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); | |
2765 return FuncDeclaration::syntaxCopy(dd); | |
2766 } | |
2767 | |
2768 | |
2769 void PostBlitDeclaration::semantic(Scope *sc) | |
2770 { | |
2771 //printf("PostBlitDeclaration::semantic() %s\n", toChars()); | |
2772 //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); | |
2773 parent = sc->parent; | |
2774 Dsymbol *parent = toParent(); | |
2775 StructDeclaration *ad = parent->isStructDeclaration(); | |
2776 if (!ad) | |
2777 { | |
2778 error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); | |
2779 } | |
2780 else if (ident == Id::_postblit) | |
2781 ad->postblits.push(this); | |
2782 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); | |
2783 | |
2784 sc = sc->push(); | |
2785 sc->stc &= ~STCstatic; // not static | |
2786 sc->linkage = LINKd; | |
2787 | |
2788 FuncDeclaration::semantic(sc); | |
2789 | |
2790 sc->pop(); | |
2791 } | |
2792 | |
2793 int PostBlitDeclaration::overloadInsert(Dsymbol *s) | |
2794 { | |
2795 return FALSE; // cannot overload postblits | |
2796 } | |
2797 | |
2798 int PostBlitDeclaration::addPreInvariant() | |
2799 { | |
2800 return FALSE; | |
2801 } | |
2802 | |
2803 int PostBlitDeclaration::addPostInvariant() | |
2804 { | |
2805 return (isThis() && vthis && global.params.useInvariants); | |
2806 } | |
2807 | |
2808 int PostBlitDeclaration::isVirtual() | |
2809 { | |
2810 return FALSE; | |
2811 } | |
2812 | |
2813 void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) | |
2814 { | |
2815 if (hgs->hdrgen) | |
2816 return; | |
2817 buf->writestring("=this()"); | |
2818 bodyToCBuffer(buf, hgs); | |
2819 } | |
2820 #endif | |
2821 | |
2468 /********************************* DtorDeclaration ****************************/ | 2822 /********************************* DtorDeclaration ****************************/ |
2469 | 2823 |
2470 DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) | 2824 DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) |
2471 : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) | 2825 : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) |
2472 { | 2826 { |
2485 } | 2839 } |
2486 | 2840 |
2487 | 2841 |
2488 void DtorDeclaration::semantic(Scope *sc) | 2842 void DtorDeclaration::semantic(Scope *sc) |
2489 { | 2843 { |
2490 ClassDeclaration *cd; | 2844 //printf("DtorDeclaration::semantic() %s\n", toChars()); |
2491 | 2845 //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); |
2492 parent = sc->parent; | 2846 parent = sc->parent; |
2493 Dsymbol *parent = toParent(); | 2847 Dsymbol *parent = toParent(); |
2494 cd = parent->isClassDeclaration(); | 2848 ClassDeclaration *cd = parent->isClassDeclaration(); |
2495 if (!cd) | 2849 if (!cd) |
2496 { | 2850 { |
2497 error("destructors only are for class definitions"); | 2851 error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); |
2498 fatal(); | 2852 fatal(); |
2499 } | 2853 } |
2500 else | 2854 else |
2501 cd->dtors.push(this); | 2855 cd->dtors.push(this); |
2502 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); | 2856 type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); |
2521 } | 2875 } |
2522 | 2876 |
2523 int DtorDeclaration::addPostInvariant() | 2877 int DtorDeclaration::addPostInvariant() |
2524 { | 2878 { |
2525 return FALSE; | 2879 return FALSE; |
2880 } | |
2881 | |
2882 const char *DtorDeclaration::kind() | |
2883 { | |
2884 return "destructor"; | |
2885 } | |
2886 | |
2887 char *DtorDeclaration::toChars() | |
2888 { | |
2889 return (char *)"~this"; | |
2526 } | 2890 } |
2527 | 2891 |
2528 int DtorDeclaration::isVirtual() | 2892 int DtorDeclaration::isVirtual() |
2529 { | 2893 { |
2530 /* This should be FALSE so that dtor's don't get put into the vtbl[], | 2894 /* This should be FALSE so that dtor's don't get put into the vtbl[], |
2861 sc2->linkage = LINKd; | 3225 sc2->linkage = LINKd; |
2862 FuncDeclaration::semantic(sc2); | 3226 FuncDeclaration::semantic(sc2); |
2863 sc2->pop(); | 3227 sc2->pop(); |
2864 } | 3228 } |
2865 | 3229 |
3230 #if 0 | |
2866 // We're going to need ModuleInfo even if the unit tests are not | 3231 // We're going to need ModuleInfo even if the unit tests are not |
2867 // compiled in, because other modules may import this module and refer | 3232 // compiled in, because other modules may import this module and refer |
2868 // to this ModuleInfo. | 3233 // to this ModuleInfo. |
3234 // (This doesn't make sense to me?) | |
2869 Module *m = getModule(); | 3235 Module *m = getModule(); |
2870 if (!m) | 3236 if (!m) |
2871 m = sc->module; | 3237 m = sc->module; |
2872 if (m) | 3238 if (m) |
3239 { | |
3240 //printf("module3 %s needs moduleinfo\n", m->toChars()); | |
2873 m->needmoduleinfo = 1; | 3241 m->needmoduleinfo = 1; |
3242 } | |
3243 #endif | |
2874 } | 3244 } |
2875 | 3245 |
2876 AggregateDeclaration *UnitTestDeclaration::isThis() | 3246 AggregateDeclaration *UnitTestDeclaration::isThis() |
2877 { | 3247 { |
2878 return NULL; | 3248 return NULL; |