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