0
|
1 module dmd.TryCatchStatement;
|
|
2
|
114
|
3 import dmd.common;
|
0
|
4 import dmd.Statement;
|
|
5 import dmd.Array;
|
|
6 import dmd.Loc;
|
|
7 import dmd.Id;
|
|
8 import dmd.Identifier;
|
|
9 import dmd.Scope;
|
|
10 import dmd.InlineScanState;
|
|
11 import dmd.IRState;
|
|
12 import dmd.OutBuffer;
|
|
13 import dmd.Catch;
|
|
14 import dmd.HdrGenState;
|
|
15 import dmd.BE;
|
|
16
|
|
17 import dmd.backend.BC;
|
|
18 import dmd.codegen.Util;
|
|
19 import dmd.backend.Util;
|
|
20 import dmd.backend.Blockx;
|
|
21 import dmd.backend.block;
|
|
22 import dmd.backend.mTY;
|
|
23 import dmd.backend.TYM;
|
|
24
|
|
25 class TryCatchStatement : Statement
|
|
26 {
|
|
27 Statement body_;
|
|
28 Array catches;
|
|
29
|
|
30 this(Loc loc, Statement body_, Array catches)
|
|
31 {
|
178
|
32 register();
|
0
|
33 super(loc);
|
|
34 this.body_ = body_;
|
|
35 this.catches = catches;
|
|
36 }
|
|
37
|
72
|
38 override Statement syntaxCopy()
|
0
|
39 {
|
63
|
40 Array a = new Array();
|
|
41 a.setDim(catches.dim);
|
|
42 for (int i = 0; i < a.dim; i++)
|
|
43 {
|
|
44 Catch c;
|
|
45
|
|
46 c = cast(Catch)catches.data[i];
|
|
47 c = c.syntaxCopy();
|
|
48 a.data[i] = cast(void*)c;
|
|
49 }
|
|
50 TryCatchStatement s = new TryCatchStatement(loc, body_.syntaxCopy(), a);
|
|
51 return s;
|
0
|
52 }
|
|
53
|
72
|
54 override Statement semantic(Scope sc)
|
0
|
55 {
|
|
56 body_ = body_.semanticScope(sc, null /*this*/, null);
|
|
57
|
|
58 /* Even if body is null, still do semantic analysis on catches
|
|
59 */
|
|
60 for (size_t i = 0; i < catches.dim; i++)
|
|
61 {
|
|
62 Catch c = cast(Catch)catches.data[i];
|
|
63 c.semantic(sc);
|
|
64
|
|
65 // Determine if current catch 'hides' any previous catches
|
|
66 for (size_t j = 0; j < i; j++)
|
|
67 {
|
|
68 Catch cj = cast(Catch)catches.data[j];
|
|
69 string si = c.loc.toChars();
|
|
70 string sj = cj.loc.toChars();
|
|
71
|
|
72 if (c.type.toBasetype().implicitConvTo(cj.type.toBasetype()))
|
|
73 error("catch at %s hides catch at %s", sj, si);
|
|
74 }
|
|
75 }
|
|
76
|
|
77 if (!body_ || body_.isEmpty())
|
|
78 {
|
|
79 return null;
|
|
80 }
|
|
81 return this;
|
|
82 }
|
|
83
|
72
|
84 override bool hasBreak()
|
0
|
85 {
|
|
86 assert(false);
|
|
87 }
|
|
88
|
72
|
89 override bool usesEH()
|
0
|
90 {
|
|
91 assert(false);
|
|
92 }
|
|
93
|
72
|
94 override BE blockExit()
|
0
|
95 {
|
|
96 assert(body_);
|
|
97 BE result = body_.blockExit();
|
|
98
|
|
99 BE catchresult = BE.BEnone;
|
|
100 for (size_t i = 0; i < catches.dim; i++)
|
|
101 {
|
|
102 Catch c = cast(Catch)catches.data[i];
|
|
103 catchresult |= c.blockExit();
|
|
104
|
|
105 /* If we're catching Object, then there is no throwing
|
|
106 */
|
|
107 Identifier id = c.type.toBasetype().isClassHandle().ident;
|
|
108 if (i == 0 &&
|
|
109 (id is Id.Object_ || id is Id.Throwable || id is Id.Exception))
|
|
110 {
|
|
111 result &= ~BE.BEthrow;
|
|
112 }
|
|
113 }
|
|
114 return result | catchresult;
|
|
115 }
|
|
116
|
72
|
117 override Statement inlineScan(InlineScanState* iss)
|
0
|
118 {
|
|
119 if (body_)
|
|
120 body_ = body_.inlineScan(iss);
|
|
121 if (catches)
|
|
122 {
|
|
123 for (int i = 0; i < catches.dim; i++)
|
|
124 {
|
|
125 Catch c = cast(Catch)catches.data[i];
|
|
126
|
|
127 if (c.handler)
|
|
128 c.handler = c.handler.inlineScan(iss);
|
|
129 }
|
|
130 }
|
|
131 return this;
|
|
132 }
|
|
133
|
|
134 /***************************************
|
|
135 * Builds the following:
|
|
136 * _try
|
|
137 * block
|
|
138 * jcatch
|
|
139 * handler
|
|
140 * A try-catch statement.
|
|
141 */
|
72
|
142 override void toIR(IRState *irs)
|
0
|
143 {
|
|
144 Blockx *blx = irs.blx;
|
|
145
|
|
146 version (SEH) {
|
|
147 nteh_declarvars(blx);
|
|
148 }
|
|
149
|
|
150 IRState mystate = IRState(irs, this);
|
|
151
|
|
152 block* tryblock = block_goto(blx,BCgoto,null);
|
|
153
|
|
154 int previndex = blx.scope_index;
|
|
155 tryblock.Blast_index = previndex;
|
|
156 blx.scope_index = tryblock.Bscope_index = blx.next_index++;
|
|
157
|
|
158 // Set the current scope index
|
|
159 setScopeIndex(blx,tryblock,tryblock.Bscope_index);
|
|
160
|
|
161 // This is the catch variable
|
|
162 tryblock.jcatchvar = symbol_genauto(type_fake(mTYvolatile | TYnptr));
|
|
163
|
|
164 blx.tryblock = tryblock;
|
|
165 block *breakblock = block_calloc(blx);
|
|
166 block_goto(blx,BC_try,null);
|
|
167 if (body_)
|
|
168 {
|
|
169 body_.toIR(&mystate);
|
|
170 }
|
|
171 blx.tryblock = tryblock.Btry;
|
|
172
|
|
173 // break block goes here
|
|
174 block_goto(blx, BCgoto, breakblock);
|
|
175
|
|
176 setScopeIndex(blx,blx.curblock, previndex);
|
|
177 blx.scope_index = previndex;
|
|
178
|
|
179 // create new break block that follows all the catches
|
|
180 breakblock = block_calloc(blx);
|
|
181
|
|
182 list_append(&blx.curblock.Bsucc, breakblock);
|
|
183 block_next(blx,BCgoto,null);
|
|
184
|
|
185 assert(catches);
|
|
186 for (int i = 0 ; i < catches.dim; i++)
|
|
187 {
|
|
188 Catch cs = cast(Catch)(catches.data[i]);
|
|
189 if (cs.var)
|
|
190 cs.var.csym = tryblock.jcatchvar;
|
|
191 block* bcatch = blx.curblock;
|
|
192 if (cs.type)
|
|
193 bcatch.Bcatchtype = cs.type.toBasetype().toSymbol();
|
|
194 list_append(&tryblock.Bsucc,bcatch);
|
|
195 block_goto(blx,BCjcatch,null);
|
|
196 if (cs.handler !is null)
|
|
197 {
|
|
198 IRState catchState = IRState(irs, this);
|
|
199 cs.handler.toIR(&catchState);
|
|
200 }
|
|
201 list_append(&blx.curblock.Bsucc, breakblock);
|
|
202 block_next(blx, BCgoto, null);
|
|
203 }
|
|
204
|
|
205 block_next(blx,cast(BC)blx.curblock.BC, breakblock);
|
|
206 }
|
|
207
|
72
|
208 override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
0
|
209 {
|
174
|
210 buf.writestring("try");
|
|
211 buf.writenl();
|
|
212 if (body_)
|
|
213 body_.toCBuffer(buf, hgs);
|
|
214 for (size_t i = 0; i < catches.dim; i++)
|
|
215 {
|
|
216 Catch c = cast(Catch)catches.data[i];
|
|
217 c.toCBuffer(buf, hgs);
|
|
218 }
|
0
|
219 }
|
|
220
|
72
|
221 override TryCatchStatement isTryCatchStatement() { return this; }
|
|
222 }
|