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