Mercurial > projects > ddmd
comparison dmd/FuncDeclaration.d @ 73:ef02e2e203c2
Updating to dmd2.033
author | korDen |
---|---|
date | Sat, 28 Aug 2010 19:42:41 +0400 |
parents | 2e2a5c3f943a |
children | 7e0d548de9e6 |
comparison
equal
deleted
inserted
replaced
72:2e2a5c3f943a | 73:ef02e2e203c2 |
---|---|
2 | 2 |
3 import dmd.Declaration; | 3 import dmd.Declaration; |
4 import dmd.DotIdExp; | 4 import dmd.DotIdExp; |
5 import dmd.AddrExp; | 5 import dmd.AddrExp; |
6 import dmd.TryFinallyStatement; | 6 import dmd.TryFinallyStatement; |
7 import dmd.TryCatchStatement; | |
8 import dmd.Catch; | |
9 import dmd.DeclarationStatement; | |
7 import dmd.StaticDtorDeclaration; | 10 import dmd.StaticDtorDeclaration; |
8 import dmd.GlobalExpressions; | 11 import dmd.GlobalExpressions; |
9 import dmd.PeelStatement; | 12 import dmd.PeelStatement; |
10 import dmd.SynchronizedStatement; | 13 import dmd.SynchronizedStatement; |
11 import dmd.TOK; | 14 import dmd.TOK; |
78 import dmd.InlineScanState; | 81 import dmd.InlineScanState; |
79 import dmd.IRState; | 82 import dmd.IRState; |
80 import dmd.Util; | 83 import dmd.Util; |
81 import dmd.BaseClass; | 84 import dmd.BaseClass; |
82 import dmd.Module; | 85 import dmd.Module; |
83 import dmd.ILS; | |
84 import dmd.InlineCostState; | 86 import dmd.InlineCostState; |
85 | 87 |
86 import dmd.expression.Util; | 88 import dmd.expression.Util; |
87 | 89 |
88 import dmd.declaration.Match; | 90 import dmd.declaration.Match; |
124 { | 126 { |
125 Array fthrows; // Array of Type's of exceptions (not used) | 127 Array fthrows; // Array of Type's of exceptions (not used) |
126 Statement frequire; | 128 Statement frequire; |
127 Statement fensure; | 129 Statement fensure; |
128 Statement fbody; | 130 Statement fbody; |
131 | |
132 FuncDeclarations foverrides; // functions this function overrides | |
133 FuncDeclaration fdrequire; // function that does the in contract | |
134 FuncDeclaration fdensure; // function that does the out contract | |
129 | 135 |
130 Identifier outId; // identifier for out statement | 136 Identifier outId; // identifier for out statement |
131 VarDeclaration vresult; // variable corresponding to outId | 137 VarDeclaration vresult; // variable corresponding to outId |
132 LabelDsymbol returnLabel; // where the return goes | 138 LabelDsymbol returnLabel; // where the return goes |
133 | 139 |
140 } | 146 } |
141 Dsymbols parameters; // Array of VarDeclaration's for parameters | 147 Dsymbols parameters; // Array of VarDeclaration's for parameters |
142 DsymbolTable labtab; // statement label symbol table | 148 DsymbolTable labtab; // statement label symbol table |
143 Declaration overnext; // next in overload list | 149 Declaration overnext; // next in overload list |
144 Loc endloc; // location of closing curly bracket | 150 Loc endloc; // location of closing curly bracket |
145 int vtblIndex = -1; // for member functions, index into vtbl[] | 151 int vtblIndex; // for member functions, index into vtbl[] |
146 int naked; // !=0 if naked | 152 int naked; // !=0 if naked |
147 int inlineAsm; // !=0 if has inline assembler | 153 int inlineAsm; // !=0 if has inline assembler |
148 ILS inlineStatus = ILS.ILSuninitialized; | 154 ILS inlineStatus; |
149 int inlineNest; // !=0 if nested inline | 155 int inlineNest; // !=0 if nested inline |
150 int cantInterpret; // !=0 if cannot interpret function | 156 int cantInterpret; // !=0 if cannot interpret function |
151 int semanticRun; // 1 semantic() run | 157 int semanticRun; // 1 semantic() run |
152 // 2 semantic2() run | 158 // 2 semantic2() run |
153 // 3 semantic3() started | 159 // 3 semantic3() started |
194 //printf("storage_class = x%x\n", storage_class); | 200 //printf("storage_class = x%x\n", storage_class); |
195 this.storage_class = storage_class; | 201 this.storage_class = storage_class; |
196 this.type = type; | 202 this.type = type; |
197 this.loc = loc; | 203 this.loc = loc; |
198 this.endloc = endloc; | 204 this.endloc = endloc; |
199 | 205 fthrows = null; |
206 frequire = null; | |
207 fdrequire = null; | |
208 fdensure = null; | |
209 outId = null; | |
210 vresult = null; | |
211 returnLabel = null; | |
212 fensure = null; | |
213 fbody = null; | |
214 localsymtab = null; | |
215 vthis = null; | |
216 v_arguments = null; | |
217 version (IN_GCC) { | |
218 v_argptr = null; | |
219 } | |
220 parameters = null; | |
221 labtab = null; | |
222 overnext = null; | |
223 vtblIndex = -1; | |
224 hasReturnExp = 0; | |
225 naked = 0; | |
226 inlineStatus = ILS.ILSuninitialized; | |
227 inlineNest = 0; | |
228 inlineAsm = 0; | |
229 cantInterpret = 0; | |
230 semanticRun = 0; | |
231 version (DMDV1) { | |
232 nestedFrameRef = 0; | |
233 } | |
234 fes = null; | |
235 introducing = 0; | |
236 tintro = null; | |
200 /* The type given for "infer the return type" is a TypeFunction with | 237 /* The type given for "infer the return type" is a TypeFunction with |
201 * null for the return type. | 238 * null for the return type. |
202 */ | 239 */ |
203 inferRetType = (type && type.nextOf() is null); | 240 inferRetType = (type && type.nextOf() is null); |
204 | 241 hasReturnExp = 0; |
242 nrvo_can = 1; | |
243 nrvo_var = null; | |
244 shidden = null; | |
245 version (DMDV2) { | |
246 builtin = BUILTINunknown; | |
247 tookAddressOf = 0; | |
248 } | |
249 foverrides = new FuncDeclarations(); | |
205 closureVars = new Dsymbols(); | 250 closureVars = new Dsymbols(); |
206 | |
207 version (DMDV2) { | |
208 builtin = BUILTIN.BUILTINunknown; | |
209 } | |
210 } | 251 } |
211 | 252 |
212 override Dsymbol syntaxCopy(Dsymbol s) | 253 override Dsymbol syntaxCopy(Dsymbol s) |
213 { | 254 { |
214 FuncDeclaration f; | 255 FuncDeclaration f; |
549 ) | 590 ) |
550 error("multiple overrides of same function"); | 591 error("multiple overrides of same function"); |
551 } | 592 } |
552 cd.vtbl.data[vi] = cast(void*)this; | 593 cd.vtbl.data[vi] = cast(void*)this; |
553 vtblIndex = vi; | 594 vtblIndex = vi; |
595 | |
596 /* Remember which functions this overrides | |
597 */ | |
598 foverrides.push(cast(void*)fdv); | |
554 | 599 |
555 /* This works by whenever this function is called, | 600 /* This works by whenever this function is called, |
556 * it actually returns tintro, which gets dynamically | 601 * it actually returns tintro, which gets dynamically |
557 * cast to type. But we know that tintro is a base | 602 * cast to type. But we know that tintro is a base |
558 * of type, so we could optimize it by not doing a | 603 * of type, so we could optimize it by not doing a |
595 return; | 640 return; |
596 | 641 |
597 default: | 642 default: |
598 { FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi]; | 643 { FuncDeclaration fdv = cast(FuncDeclaration)b.base.vtbl.data[vi]; |
599 Type ti = null; | 644 Type ti = null; |
645 | |
646 /* Remember which functions this overrides | |
647 */ | |
648 foverrides.push(cast(void*)fdv); | |
600 | 649 |
601 if (fdv.tintro) | 650 if (fdv.tintro) |
602 ti = fdv.tintro; | 651 ti = fdv.tintro; |
603 else if (!type.equals(fdv.type)) | 652 else if (!type.equals(fdv.type)) |
604 { | 653 { |
605 /* Only need to have a tintro if the vptr | 654 /* Only need to have a tintro if the vptr |
606 * offsets differ | 655 * offsets differ |
607 */ | 656 */ |
725 if (arg1.defaultArg) | 774 if (arg1.defaultArg) |
726 goto Lassignerr; | 775 goto Lassignerr; |
727 } | 776 } |
728 } | 777 } |
729 } | 778 } |
779 | |
780 if (isVirtual()) | |
781 { | |
782 /* Rewrite contracts as nested functions, then call them. | |
783 * Doing it as nested functions means that overriding functions | |
784 * can call them. | |
785 */ | |
786 if (frequire) | |
787 { | |
788 /* in { ... } | |
789 * becomes: | |
790 * void __require() { ... } | |
791 * __require(); | |
792 */ | |
793 Loc loc = frequire.loc; | |
794 TypeFunction tf = new TypeFunction(null, Type.tvoid, 0, LINKd); | |
795 FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.require, STCundefined, tf); | |
796 fd.fbody = frequire; | |
797 Statement s1 = new DeclarationStatement(loc, fd); | |
798 Expression e = new CallExp(loc, new VarExp(loc, fd, 0), cast(Expressions)null); | |
799 Statement s2 = new ExpStatement(loc, e); | |
800 frequire = new CompoundStatement(loc, s1, s2); | |
801 fdrequire = fd; | |
802 } | |
803 | |
804 if (fensure) | |
805 { /* out (result) { ... } | |
806 * becomes: | |
807 * tret __ensure(ref tret result) { ... } | |
808 * __ensure(result); | |
809 */ | |
810 if (!outId && f.nextOf().toBasetype().ty != Tvoid) | |
811 outId = Id.result; // provide a default | |
812 | |
813 Loc loc = fensure.loc; | |
814 Arguments arguments = new Arguments(); | |
815 Argument a = null; | |
816 if (outId) | |
817 { | |
818 a = new Argument(STCref, f.nextOf(), outId, null); | |
819 arguments.push(cast(void*)a); | |
820 } | |
821 TypeFunction tf = new TypeFunction(arguments, Type.tvoid, 0, LINKd); | |
822 FuncDeclaration fd = new FuncDeclaration(loc, loc, Id.ensure, STCundefined, tf); | |
823 fd.fbody = fensure; | |
824 Statement s1 = new DeclarationStatement(loc, fd); | |
825 Expression eresult = null; | |
826 if (outId) | |
827 eresult = new IdentifierExp(loc, outId); | |
828 Expression e = new CallExp(loc, new VarExp(loc, fd, 0), eresult); | |
829 Statement s2 = new ExpStatement(loc, e); | |
830 fensure = new CompoundStatement(loc, s1, s2); | |
831 fdensure = fd; | |
832 } | |
833 } | |
730 | 834 |
731 Ldone: | 835 Ldone: |
732 /* Save scope for possible later use (if we need the | 836 /* Save scope for possible later use (if we need the |
733 * function internals) | 837 * function internals) |
734 */ | 838 */ |
788 t = t.semantic(loc, sc); | 892 t = t.semantic(loc, sc); |
789 if (!t.isClassHandle()) | 893 if (!t.isClassHandle()) |
790 error("can only throw classes, not %s", t.toChars()); | 894 error("can only throw classes, not %s", t.toChars()); |
791 } | 895 } |
792 } | 896 } |
897 | |
898 frequire = mergeFrequire(frequire); | |
899 fensure = mergeFensure(fensure); | |
793 | 900 |
794 if (fbody || frequire) | 901 if (fbody || frequire) |
795 { | 902 { |
796 /* Symbol table into which we place parameters and nested functions, | 903 /* Symbol table into which we place parameters and nested functions, |
797 * solely to diagnose name collisions. | 904 * solely to diagnose name collisions. |
1326 } | 1433 } |
1327 | 1434 |
1328 if (argptr) | 1435 if (argptr) |
1329 { // Initialize _argptr to point past non-variadic arg | 1436 { // Initialize _argptr to point past non-variadic arg |
1330 version (IN_GCC) { | 1437 version (IN_GCC) { |
1331 // Handled in FuncDeclaration.toObjFile | 1438 // Handled in FuncDeclaration.toObjFile |
1332 v_argptr = argptr; | 1439 v_argptr = argptr; |
1333 v_argptr.init = new VoidInitializer(loc); | 1440 v_argptr.init = new VoidInitializer(loc); |
1334 } else { | 1441 } else { |
1335 Expression e1; | 1442 Type t = argptr.type; |
1336 Expression e; | 1443 VarDeclaration p; |
1337 Type t = argptr.type; | 1444 uint offset; |
1338 VarDeclaration p; | 1445 |
1339 uint offset; | 1446 Expression e1 = new VarExp(Loc(0), argptr); |
1340 | 1447 if (parameters && parameters.dim) |
1341 e1 = new VarExp(Loc(0), argptr); | 1448 p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; |
1342 if (parameters && parameters.dim) | 1449 else |
1343 p = cast(VarDeclaration)parameters.data[parameters.dim - 1]; | 1450 p = v_arguments; // last parameter is _arguments[] |
1344 else | 1451 if (p.storage_class & STClazy) |
1345 p = v_arguments; // last parameter is _arguments[] | 1452 // If the last parameter is lazy, it's the size of a delegate |
1346 offset = cast(uint)p.type.size(); /// | 1453 offset = PTRSIZE * 2; |
1347 offset = (offset + 3) & ~3; // assume stack aligns on 4 | 1454 else |
1348 e = new SymOffExp(Loc(0), p, offset); | 1455 offset = cast(size_t)p.type.size(); |
1349 e = new AssignExp(Loc(0), e1, e); | 1456 offset = (offset + 3) & ~3; // assume stack aligns on 4 |
1350 e.type = t; | 1457 Expression e = new SymOffExp(Loc(0), p, offset); |
1351 a.push(cast(void*)new ExpStatement(Loc(0), e)); | 1458 e = new AssignExp(Loc(0), e1, e); |
1459 e.type = t; | |
1460 a.push(cast(void*)new ExpStatement(Loc(0), e)); | |
1352 } | 1461 } |
1353 } | 1462 } |
1354 | 1463 |
1355 if (_arguments) | 1464 if (_arguments) |
1356 { | 1465 { |
2765 Lyes: | 2874 Lyes: |
2766 //printf("\tneeds closure\n"); | 2875 //printf("\tneeds closure\n"); |
2767 return true; | 2876 return true; |
2768 } | 2877 } |
2769 | 2878 |
2879 /**************************************************** | |
2880 * Merge into this function the 'in' contracts of all it overrides. | |
2881 * 'in's are OR'd together, i.e. only one of them needs to pass. | |
2882 */ | |
2883 | |
2884 Statement mergeFrequire(Statement sf) | |
2885 { | |
2886 /* Implementing this is done by having the overriding function call | |
2887 * nested functions (the fdrequire functions) nested inside the overridden | |
2888 * function. This requires that the stack layout of the calling function's | |
2889 * parameters and 'this' pointer be in the same place (as the nested | |
2890 * function refers to them). | |
2891 * This is easy for the parameters, as they are all on the stack in the same | |
2892 * place by definition, since it's an overriding function. The problem is | |
2893 * getting the 'this' pointer in the same place, since it is a local variable. | |
2894 * We did some hacks in the code generator to make this happen: | |
2895 * 1. always generate exception handler frame, or at least leave space for it | |
2896 * in the frame (Windows 32 SEH only) | |
2897 * 2. always generate an EBP style frame | |
2898 * 3. since 'this' is passed in a register that is subsequently copied into | |
2899 * a stack local, allocate that local immediately following the exception | |
2900 * handler block, so it is always at the same offset from EBP. | |
2901 */ | |
2902 for (int i = 0; i < foverrides.dim; i++) | |
2903 { | |
2904 FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i]; | |
2905 sf = fdv.mergeFrequire(sf); | |
2906 if (fdv.frequire) | |
2907 { | |
2908 //printf("fdv.frequire: %s\n", fdv.frequire.toChars()); | |
2909 /* Make the call: | |
2910 * try { __require(); } | |
2911 * catch { frequire; } | |
2912 */ | |
2913 Expression eresult = null; | |
2914 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, 0), eresult); | |
2915 Statement s2 = new ExpStatement(loc, e); | |
2916 | |
2917 if (sf) | |
2918 { | |
2919 Catch c = new Catch(loc, null, null, sf); | |
2920 Array catches = new Array(); | |
2921 catches.push(cast(void*)c); | |
2922 sf = new TryCatchStatement(loc, s2, catches); | |
2923 } | |
2924 else | |
2925 sf = s2; | |
2926 } | |
2927 } | |
2928 return sf; | |
2929 } | |
2930 | |
2931 /**************************************************** | |
2932 * Merge into this function the 'out' contracts of all it overrides. | |
2933 * 'out's are AND'd together, i.e. all of them need to pass. | |
2934 */ | |
2935 | |
2936 Statement mergeFensure(Statement sf) | |
2937 { | |
2938 /* Same comments as for mergeFrequire(), except that we take care | |
2939 * of generating a consistent reference to the 'result' local by | |
2940 * explicitly passing 'result' to the nested function as a reference | |
2941 * argument. | |
2942 * This won't work for the 'this' parameter as it would require changing | |
2943 * the semantic code for the nested function so that it looks on the parameter | |
2944 * list for the 'this' pointer, something that would need an unknown amount | |
2945 * of tweaking of various parts of the compiler that I'd rather leave alone. | |
2946 */ | |
2947 for (int i = 0; i < foverrides.dim; i++) | |
2948 { | |
2949 FuncDeclaration fdv = cast(FuncDeclaration)foverrides.data[i]; | |
2950 sf = fdv.mergeFensure(sf); | |
2951 if (fdv.fensure) | |
2952 { | |
2953 //printf("fdv.fensure: %s\n", fdv.fensure.toChars()); | |
2954 // Make the call: __ensure(result) | |
2955 Expression eresult = null; | |
2956 if (outId) | |
2957 eresult = new IdentifierExp(loc, outId); | |
2958 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, 0), eresult); | |
2959 Statement s2 = new ExpStatement(loc, e); | |
2960 | |
2961 if (sf) | |
2962 { | |
2963 sf = new CompoundStatement(fensure.loc, s2, sf); | |
2964 } | |
2965 else | |
2966 sf = s2; | |
2967 } | |
2968 } | |
2969 return sf; | |
2970 } | |
2971 | |
2770 static FuncDeclaration genCfunc(Type treturn, string name) | 2972 static FuncDeclaration genCfunc(Type treturn, string name) |
2771 { | 2973 { |
2772 return genCfunc(treturn, Lexer.idPool(name)); | 2974 return genCfunc(treturn, Lexer.idPool(name)); |
2773 } | 2975 } |
2774 | 2976 |
2989 if (global.params.verbose) | 3191 if (global.params.verbose) |
2990 writef("function %s\n",func.toChars()); | 3192 writef("function %s\n",func.toChars()); |
2991 | 3193 |
2992 s = func.toSymbol(); | 3194 s = func.toSymbol(); |
2993 f = s.Sfunc; | 3195 f = s.Sfunc; |
3196 | |
3197 version (TARGET_WINDOS) { | |
3198 /* This is done so that the 'this' pointer on the stack is the same | |
3199 * distance away from the function parameters, so that an overriding | |
3200 * function can call the nested fdensure or fdrequire of its overridden function | |
3201 * and the stack offsets are the same. | |
3202 */ | |
3203 if (isVirtual() && (fensure || frequire)) | |
3204 f.Fflags3 |= F3.Ffakeeh; | |
3205 } | |
2994 | 3206 |
2995 version (TARGET_OSX) { | 3207 version (TARGET_OSX) { |
2996 s.Sclass = SC.SCcomdat; | 3208 s.Sclass = SC.SCcomdat; |
2997 } else { | 3209 } else { |
2998 s.Sclass = SC.SCglobal; | 3210 s.Sclass = SC.SCglobal; |