]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/AST/Stmt.cpp
Upgrade our copy of llvm/clang to r126079, from upstream's trunk.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / AST / Stmt.cpp
1 //===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the Stmt class and statement subclasses.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/AST/Stmt.h"
15 #include "clang/AST/ExprCXX.h"
16 #include "clang/AST/ExprObjC.h"
17 #include "clang/AST/StmtCXX.h"
18 #include "clang/AST/StmtObjC.h"
19 #include "clang/AST/Type.h"
20 #include "clang/AST/ASTContext.h"
21 #include "clang/AST/ASTDiagnostic.h"
22 #include "clang/Basic/TargetInfo.h"
23 #include <cstdio>
24 using namespace clang;
25
26 static struct StmtClassNameTable {
27   const char *Name;
28   unsigned Counter;
29   unsigned Size;
30 } StmtClassInfo[Stmt::lastStmtConstant+1];
31
32 static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
33   static bool Initialized = false;
34   if (Initialized)
35     return StmtClassInfo[E];
36
37   // Intialize the table on the first use.
38   Initialized = true;
39 #define ABSTRACT_STMT(STMT)
40 #define STMT(CLASS, PARENT) \
41   StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS;    \
42   StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
43 #include "clang/AST/StmtNodes.inc"
44
45   return StmtClassInfo[E];
46 }
47
48 const char *Stmt::getStmtClassName() const {
49   return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
50 }
51
52 void Stmt::PrintStats() {
53   // Ensure the table is primed.
54   getStmtInfoTableEntry(Stmt::NullStmtClass);
55
56   unsigned sum = 0;
57   fprintf(stderr, "*** Stmt/Expr Stats:\n");
58   for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
59     if (StmtClassInfo[i].Name == 0) continue;
60     sum += StmtClassInfo[i].Counter;
61   }
62   fprintf(stderr, "  %d stmts/exprs total.\n", sum);
63   sum = 0;
64   for (int i = 0; i != Stmt::lastStmtConstant+1; i++) {
65     if (StmtClassInfo[i].Name == 0) continue;
66     if (StmtClassInfo[i].Counter == 0) continue;
67     fprintf(stderr, "    %d %s, %d each (%d bytes)\n",
68             StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
69             StmtClassInfo[i].Size,
70             StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
71     sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
72   }
73   fprintf(stderr, "Total bytes = %d\n", sum);
74 }
75
76 void Stmt::addStmtClass(StmtClass s) {
77   ++getStmtInfoTableEntry(s).Counter;
78 }
79
80 static bool StatSwitch = false;
81
82 bool Stmt::CollectingStats(bool Enable) {
83   if (Enable) StatSwitch = true;
84   return StatSwitch;
85 }
86
87 namespace {
88   struct good {};
89   struct bad {};
90
91   // These silly little functions have to be static inline to suppress
92   // unused warnings, and they have to be defined to suppress other
93   // warnings.
94   static inline good is_good(good) { return good(); }
95
96   typedef Stmt::child_range children_t();
97   template <class T> good implements_children(children_t T::*) {
98     return good();
99   }
100   static inline bad implements_children(children_t Stmt::*) {
101     return bad();
102   }
103
104   typedef SourceRange getSourceRange_t() const;
105   template <class T> good implements_getSourceRange(getSourceRange_t T::*) {
106     return good();
107   }
108   static inline bad implements_getSourceRange(getSourceRange_t Stmt::*) {
109     return bad();
110   }
111
112 #define ASSERT_IMPLEMENTS_children(type) \
113   (void) sizeof(is_good(implements_children(&type::children)))
114 #define ASSERT_IMPLEMENTS_getSourceRange(type) \
115   (void) sizeof(is_good(implements_getSourceRange(&type::getSourceRange)))
116 }
117
118 /// Check whether the various Stmt classes implement their member
119 /// functions.
120 static inline void check_implementations() {
121 #define ABSTRACT_STMT(type)
122 #define STMT(type, base) \
123   ASSERT_IMPLEMENTS_children(type); \
124   ASSERT_IMPLEMENTS_getSourceRange(type);
125 #include "clang/AST/StmtNodes.inc"
126 }
127
128 Stmt::child_range Stmt::children() {
129   switch (getStmtClass()) {
130   case Stmt::NoStmtClass: llvm_unreachable("statement without class");
131 #define ABSTRACT_STMT(type)
132 #define STMT(type, base) \
133   case Stmt::type##Class: \
134     return static_cast<type*>(this)->children();
135 #include "clang/AST/StmtNodes.inc"
136   }
137   llvm_unreachable("unknown statement kind!");
138   return child_range();
139 }
140
141 SourceRange Stmt::getSourceRange() const {
142   switch (getStmtClass()) {
143   case Stmt::NoStmtClass: llvm_unreachable("statement without class");
144 #define ABSTRACT_STMT(type)
145 #define STMT(type, base) \
146   case Stmt::type##Class: \
147     return static_cast<const type*>(this)->getSourceRange();
148 #include "clang/AST/StmtNodes.inc"
149   }
150   llvm_unreachable("unknown statement kind!");
151   return SourceRange();
152 }
153
154 void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
155   if (this->Body)
156     C.Deallocate(Body);
157   this->CompoundStmtBits.NumStmts = NumStmts;
158
159   Body = new (C) Stmt*[NumStmts];
160   memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts);
161 }
162
163 const char *LabelStmt::getName() const {
164   return getDecl()->getIdentifier()->getNameStart();
165 }
166
167 // This is defined here to avoid polluting Stmt.h with importing Expr.h
168 SourceRange ReturnStmt::getSourceRange() const {
169   if (RetExpr)
170     return SourceRange(RetLoc, RetExpr->getLocEnd());
171   else
172     return SourceRange(RetLoc);
173 }
174
175 bool Stmt::hasImplicitControlFlow() const {
176   switch (StmtBits.sClass) {
177     default:
178       return false;
179
180     case CallExprClass:
181     case ConditionalOperatorClass:
182     case ChooseExprClass:
183     case StmtExprClass:
184     case DeclStmtClass:
185       return true;
186
187     case Stmt::BinaryOperatorClass: {
188       const BinaryOperator* B = cast<BinaryOperator>(this);
189       if (B->isLogicalOp() || B->getOpcode() == BO_Comma)
190         return true;
191       else
192         return false;
193     }
194   }
195 }
196
197 Expr *AsmStmt::getOutputExpr(unsigned i) {
198   return cast<Expr>(Exprs[i]);
199 }
200
201 /// getOutputConstraint - Return the constraint string for the specified
202 /// output operand.  All output constraints are known to be non-empty (either
203 /// '=' or '+').
204 llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const {
205   return getOutputConstraintLiteral(i)->getString();
206 }
207
208 /// getNumPlusOperands - Return the number of output operands that have a "+"
209 /// constraint.
210 unsigned AsmStmt::getNumPlusOperands() const {
211   unsigned Res = 0;
212   for (unsigned i = 0, e = getNumOutputs(); i != e; ++i)
213     if (isOutputPlusConstraint(i))
214       ++Res;
215   return Res;
216 }
217
218 Expr *AsmStmt::getInputExpr(unsigned i) {
219   return cast<Expr>(Exprs[i + NumOutputs]);
220 }
221
222 /// getInputConstraint - Return the specified input constraint.  Unlike output
223 /// constraints, these can be empty.
224 llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const {
225   return getInputConstraintLiteral(i)->getString();
226 }
227
228
229 void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
230                                              IdentifierInfo **Names,
231                                              StringLiteral **Constraints,
232                                              Stmt **Exprs,
233                                              unsigned NumOutputs,
234                                              unsigned NumInputs,                                      
235                                              StringLiteral **Clobbers,
236                                              unsigned NumClobbers) {
237   this->NumOutputs = NumOutputs;
238   this->NumInputs = NumInputs;
239   this->NumClobbers = NumClobbers;
240
241   unsigned NumExprs = NumOutputs + NumInputs;
242   
243   C.Deallocate(this->Names);
244   this->Names = new (C) IdentifierInfo*[NumExprs];
245   std::copy(Names, Names + NumExprs, this->Names);
246   
247   C.Deallocate(this->Exprs);
248   this->Exprs = new (C) Stmt*[NumExprs];
249   std::copy(Exprs, Exprs + NumExprs, this->Exprs);
250   
251   C.Deallocate(this->Constraints);
252   this->Constraints = new (C) StringLiteral*[NumExprs];
253   std::copy(Constraints, Constraints + NumExprs, this->Constraints);
254   
255   C.Deallocate(this->Clobbers);
256   this->Clobbers = new (C) StringLiteral*[NumClobbers];
257   std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers);
258 }
259
260 /// getNamedOperand - Given a symbolic operand reference like %[foo],
261 /// translate this into a numeric value needed to reference the same operand.
262 /// This returns -1 if the operand name is invalid.
263 int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const {
264   unsigned NumPlusOperands = 0;
265
266   // Check if this is an output operand.
267   for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) {
268     if (getOutputName(i) == SymbolicName)
269       return i;
270   }
271
272   for (unsigned i = 0, e = getNumInputs(); i != e; ++i)
273     if (getInputName(i) == SymbolicName)
274       return getNumOutputs() + NumPlusOperands + i;
275
276   // Not found.
277   return -1;
278 }
279
280 /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
281 /// it into pieces.  If the asm string is erroneous, emit errors and return
282 /// true, otherwise return false.
283 unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
284                                    ASTContext &C, unsigned &DiagOffs) const {
285   llvm::StringRef Str = getAsmString()->getString();
286   const char *StrStart = Str.begin();
287   const char *StrEnd = Str.end();
288   const char *CurPtr = StrStart;
289
290   // "Simple" inline asms have no constraints or operands, just convert the asm
291   // string to escape $'s.
292   if (isSimple()) {
293     std::string Result;
294     for (; CurPtr != StrEnd; ++CurPtr) {
295       switch (*CurPtr) {
296       case '$':
297         Result += "$$";
298         break;
299       default:
300         Result += *CurPtr;
301         break;
302       }
303     }
304     Pieces.push_back(AsmStringPiece(Result));
305     return 0;
306   }
307
308   // CurStringPiece - The current string that we are building up as we scan the
309   // asm string.
310   std::string CurStringPiece;
311
312   bool HasVariants = !C.Target.hasNoAsmVariants();
313   
314   while (1) {
315     // Done with the string?
316     if (CurPtr == StrEnd) {
317       if (!CurStringPiece.empty())
318         Pieces.push_back(AsmStringPiece(CurStringPiece));
319       return 0;
320     }
321
322     char CurChar = *CurPtr++;
323     switch (CurChar) {
324     case '$': CurStringPiece += "$$"; continue;
325     case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
326     case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
327     case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
328     case '%':
329       break;
330     default:
331       CurStringPiece += CurChar;
332       continue;
333     }
334     
335     // Escaped "%" character in asm string.
336     if (CurPtr == StrEnd) {
337       // % at end of string is invalid (no escape).
338       DiagOffs = CurPtr-StrStart-1;
339       return diag::err_asm_invalid_escape;
340     }
341
342     char EscapedChar = *CurPtr++;
343     if (EscapedChar == '%') {  // %% -> %
344       // Escaped percentage sign.
345       CurStringPiece += '%';
346       continue;
347     }
348
349     if (EscapedChar == '=') {  // %= -> Generate an unique ID.
350       CurStringPiece += "${:uid}";
351       continue;
352     }
353
354     // Otherwise, we have an operand.  If we have accumulated a string so far,
355     // add it to the Pieces list.
356     if (!CurStringPiece.empty()) {
357       Pieces.push_back(AsmStringPiece(CurStringPiece));
358       CurStringPiece.clear();
359     }
360
361     // Handle %x4 and %x[foo] by capturing x as the modifier character.
362     char Modifier = '\0';
363     if (isalpha(EscapedChar)) {
364       Modifier = EscapedChar;
365       EscapedChar = *CurPtr++;
366     }
367
368     if (isdigit(EscapedChar)) {
369       // %n - Assembler operand n
370       unsigned N = 0;
371
372       --CurPtr;
373       while (CurPtr != StrEnd && isdigit(*CurPtr))
374         N = N*10 + ((*CurPtr++)-'0');
375
376       unsigned NumOperands =
377         getNumOutputs() + getNumPlusOperands() + getNumInputs();
378       if (N >= NumOperands) {
379         DiagOffs = CurPtr-StrStart-1;
380         return diag::err_asm_invalid_operand_number;
381       }
382
383       Pieces.push_back(AsmStringPiece(N, Modifier));
384       continue;
385     }
386
387     // Handle %[foo], a symbolic operand reference.
388     if (EscapedChar == '[') {
389       DiagOffs = CurPtr-StrStart-1;
390
391       // Find the ']'.
392       const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr);
393       if (NameEnd == 0)
394         return diag::err_asm_unterminated_symbolic_operand_name;
395       if (NameEnd == CurPtr)
396         return diag::err_asm_empty_symbolic_operand_name;
397
398       llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr);
399
400       int N = getNamedOperand(SymbolicName);
401       if (N == -1) {
402         // Verify that an operand with that name exists.
403         DiagOffs = CurPtr-StrStart;
404         return diag::err_asm_unknown_symbolic_operand_name;
405       }
406       Pieces.push_back(AsmStringPiece(N, Modifier));
407
408       CurPtr = NameEnd+1;
409       continue;
410     }
411
412     DiagOffs = CurPtr-StrStart-1;
413     return diag::err_asm_invalid_escape;
414   }
415 }
416
417 QualType CXXCatchStmt::getCaughtType() const {
418   if (ExceptionDecl)
419     return ExceptionDecl->getType();
420   return QualType();
421 }
422
423 //===----------------------------------------------------------------------===//
424 // Constructors
425 //===----------------------------------------------------------------------===//
426
427 AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, 
428                  bool isvolatile, bool msasm, 
429                  unsigned numoutputs, unsigned numinputs,
430                  IdentifierInfo **names, StringLiteral **constraints,
431                  Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
432                  StringLiteral **clobbers, SourceLocation rparenloc)
433   : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
434   , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
435   , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) {
436
437   unsigned NumExprs = NumOutputs +NumInputs;
438     
439   Names = new (C) IdentifierInfo*[NumExprs];
440   std::copy(names, names + NumExprs, Names);
441
442   Exprs = new (C) Stmt*[NumExprs];
443   std::copy(exprs, exprs + NumExprs, Exprs);
444
445   Constraints = new (C) StringLiteral*[NumExprs];
446   std::copy(constraints, constraints + NumExprs, Constraints);
447
448   Clobbers = new (C) StringLiteral*[NumClobbers];
449   std::copy(clobbers, clobbers + NumClobbers, Clobbers);
450 }
451
452 ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
453                                              Stmt *Body,  SourceLocation FCL,
454                                              SourceLocation RPL)
455 : Stmt(ObjCForCollectionStmtClass) {
456   SubExprs[ELEM] = Elem;
457   SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
458   SubExprs[BODY] = Body;
459   ForLoc = FCL;
460   RParenLoc = RPL;
461 }
462
463 ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
464                              Stmt **CatchStmts, unsigned NumCatchStmts,
465                              Stmt *atFinallyStmt)
466   : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc),
467     NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0)
468 {
469   Stmt **Stmts = getStmts();
470   Stmts[0] = atTryStmt;
471   for (unsigned I = 0; I != NumCatchStmts; ++I)
472     Stmts[I + 1] = CatchStmts[I];
473   
474   if (HasFinally)
475     Stmts[NumCatchStmts + 1] = atFinallyStmt;
476 }
477
478 ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, 
479                                      SourceLocation atTryLoc, 
480                                      Stmt *atTryStmt,
481                                      Stmt **CatchStmts, 
482                                      unsigned NumCatchStmts,
483                                      Stmt *atFinallyStmt) {
484   unsigned Size = sizeof(ObjCAtTryStmt) + 
485     (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
486   void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>());
487   return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
488                                  atFinallyStmt);
489 }
490
491 ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, 
492                                                  unsigned NumCatchStmts,
493                                                  bool HasFinally) {
494   unsigned Size = sizeof(ObjCAtTryStmt) + 
495     (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
496   void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>());
497   return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);  
498 }
499
500 SourceRange ObjCAtTryStmt::getSourceRange() const {
501   SourceLocation EndLoc;
502   if (HasFinally)
503     EndLoc = getFinallyStmt()->getLocEnd();
504   else if (NumCatchStmts)
505     EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
506   else
507     EndLoc = getTryBody()->getLocEnd();
508   
509   return SourceRange(AtTryLoc, EndLoc);
510 }
511
512 CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
513                                Stmt *tryBlock, Stmt **handlers, 
514                                unsigned numHandlers) {
515   std::size_t Size = sizeof(CXXTryStmt);
516   Size += ((numHandlers + 1) * sizeof(Stmt));
517
518   void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>());
519   return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
520 }
521
522 CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
523                                unsigned numHandlers) {
524   std::size_t Size = sizeof(CXXTryStmt);
525   Size += ((numHandlers + 1) * sizeof(Stmt));
526
527   void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>());
528   return new (Mem) CXXTryStmt(Empty, numHandlers);
529 }
530
531 CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
532                        Stmt **handlers, unsigned numHandlers)
533   : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) {
534   Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
535   Stmts[0] = tryBlock;
536   std::copy(handlers, handlers + NumHandlers, Stmts + 1);
537 }
538
539 IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, 
540                Stmt *then, SourceLocation EL, Stmt *elsev)
541   : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
542 {
543   setConditionVariable(C, var);
544   SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
545   SubExprs[THEN] = then;
546   SubExprs[ELSE] = elsev;  
547 }
548
549 VarDecl *IfStmt::getConditionVariable() const {
550   if (!SubExprs[VAR])
551     return 0;
552   
553   DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
554   return cast<VarDecl>(DS->getSingleDecl());
555 }
556
557 void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
558   if (!V) {
559     SubExprs[VAR] = 0;
560     return;
561   }
562   
563   SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), 
564                                    V->getSourceRange().getBegin(),
565                                    V->getSourceRange().getEnd());
566 }
567
568 ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, 
569                  Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, 
570                  SourceLocation RP)
571   : Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP) 
572 {
573   SubExprs[INIT] = Init;
574   setConditionVariable(C, condVar);
575   SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
576   SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
577   SubExprs[BODY] = Body;
578 }
579
580 VarDecl *ForStmt::getConditionVariable() const {
581   if (!SubExprs[CONDVAR])
582     return 0;
583   
584   DeclStmt *DS = cast<DeclStmt>(SubExprs[CONDVAR]);
585   return cast<VarDecl>(DS->getSingleDecl());
586 }
587
588 void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
589   if (!V) {
590     SubExprs[CONDVAR] = 0;
591     return;
592   }
593   
594   SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), 
595                                        V->getSourceRange().getBegin(),
596                                        V->getSourceRange().getEnd());
597 }
598
599 SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond) 
600   : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0) 
601 {
602   setConditionVariable(C, Var);
603   SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
604   SubExprs[BODY] = NULL;
605 }
606
607 VarDecl *SwitchStmt::getConditionVariable() const {
608   if (!SubExprs[VAR])
609     return 0;
610   
611   DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
612   return cast<VarDecl>(DS->getSingleDecl());
613 }
614
615 void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
616   if (!V) {
617     SubExprs[VAR] = 0;
618     return;
619   }
620   
621   SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), 
622                                    V->getSourceRange().getBegin(),
623                                    V->getSourceRange().getEnd());
624 }
625
626 Stmt *SwitchCase::getSubStmt() {
627   if (isa<CaseStmt>(this)) return cast<CaseStmt>(this)->getSubStmt();
628   return cast<DefaultStmt>(this)->getSubStmt();
629 }
630
631 WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, 
632                      SourceLocation WL)
633 : Stmt(WhileStmtClass)
634 {
635   setConditionVariable(C, Var);
636   SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
637   SubExprs[BODY] = body;
638   WhileLoc = WL;
639 }
640
641 VarDecl *WhileStmt::getConditionVariable() const {
642   if (!SubExprs[VAR])
643     return 0;
644   
645   DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]);
646   return cast<VarDecl>(DS->getSingleDecl());
647 }
648
649 void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
650   if (!V) {
651     SubExprs[VAR] = 0;
652     return;
653   }
654   
655   SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), 
656                                    V->getSourceRange().getBegin(),
657                                    V->getSourceRange().getEnd());
658 }
659
660 // IndirectGotoStmt
661 LabelDecl *IndirectGotoStmt::getConstantTarget() {
662   if (AddrLabelExpr *E =
663         dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts()))
664     return E->getLabel();
665   return 0;
666 }
667
668 // ReturnStmt
669 const Expr* ReturnStmt::getRetValue() const {
670   return cast_or_null<Expr>(RetExpr);
671 }
672 Expr* ReturnStmt::getRetValue() {
673   return cast_or_null<Expr>(RetExpr);
674 }