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;