llvm-project/clang/lib/AST/Stmt.cpp

520 lines
16 KiB
C++
Raw Normal View History

2006-10-25 12:09:21 +08:00
//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
2006-10-25 12:09:21 +08:00
//
//===----------------------------------------------------------------------===//
//
// This file implements the Stmt class and statement subclasses.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Stmt.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Type.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
2006-10-25 12:09:21 +08:00
using namespace clang;
static struct StmtClassNameTable {
const char *Name;
unsigned Counter;
unsigned Size;
2007-08-25 09:55:00 +08:00
} StmtClassInfo[Stmt::lastExprConstant+1];
static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
static bool Initialized = false;
if (Initialized)
return StmtClassInfo[E];
// Intialize the table on the first use.
Initialized = true;
#define STMT(CLASS, PARENT) \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \
StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS);
#include "clang/AST/StmtNodes.def"
return StmtClassInfo[E];
}
const char *Stmt::getStmtClassName() const {
return getStmtInfoTableEntry(sClass).Name;
}
void Stmt::DestroyChildren(ASTContext &C) {
for (child_iterator I = child_begin(), E = child_end(); I !=E; )
if (Stmt* Child = *I++) Child->Destroy(C);
}
void Stmt::Destroy(ASTContext &C) {
DestroyChildren(C);
// FIXME: Eventually all Stmts should be allocated with the allocator
// in ASTContext, just like with Decls.
this->~Stmt();
C.Deallocate((void *)this);
}
void DeclStmt::Destroy(ASTContext &C) {
this->~DeclStmt();
C.Deallocate((void *)this);
}
void Stmt::PrintStats() {
// Ensure the table is primed.
getStmtInfoTableEntry(Stmt::NullStmtClass);
unsigned sum = 0;
fprintf(stderr, "*** Stmt/Expr Stats:\n");
2007-08-25 09:55:00 +08:00
for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
if (StmtClassInfo[i].Name == 0) continue;
sum += StmtClassInfo[i].Counter;
}
fprintf(stderr, " %d stmts/exprs total.\n", sum);
sum = 0;
2007-08-25 09:55:00 +08:00
for (int i = 0; i != Stmt::lastExprConstant+1; i++) {
if (StmtClassInfo[i].Name == 0) continue;
fprintf(stderr, " %d %s, %d each (%d bytes)\n",
StmtClassInfo[i].Counter, StmtClassInfo[i].Name,
StmtClassInfo[i].Size,
StmtClassInfo[i].Counter*StmtClassInfo[i].Size);
sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size;
}
fprintf(stderr, "Total bytes = %d\n", sum);
}
void Stmt::addStmtClass(StmtClass s) {
++getStmtInfoTableEntry(s).Counter;
}
static bool StatSwitch = false;
bool Stmt::CollectingStats(bool enable) {
if (enable) StatSwitch = true;
return StatSwitch;
}
const char *LabelStmt::getName() const {
return getID()->getName();
}
// This is defined here to avoid polluting Stmt.h with importing Expr.h
SourceRange ReturnStmt::getSourceRange() const {
if (RetExpr)
return SourceRange(RetLoc, RetExpr->getLocEnd());
else
return SourceRange(RetLoc);
}
bool Stmt::hasImplicitControlFlow() const {
switch (sClass) {
default:
return false;
case CallExprClass:
case ConditionalOperatorClass:
case ChooseExprClass:
case StmtExprClass:
case DeclStmtClass:
return true;
case Stmt::BinaryOperatorClass: {
const BinaryOperator* B = cast<BinaryOperator>(this);
if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma)
return true;
else
return false;
}
}
}
Expr *AsmStmt::getOutputExpr(unsigned i) {
return cast<Expr>(Exprs[i]);
}
/// getOutputConstraint - Return the constraint string for the specified
/// output operand. All output constraints are known to be non-empty (either
/// '=' or '+').
std::string AsmStmt::getOutputConstraint(unsigned i) const {
return std::string(Constraints[i]->getStrData(),
Constraints[i]->getByteLength());
}
Expr *AsmStmt::getInputExpr(unsigned i) {
return cast<Expr>(Exprs[i + NumOutputs]);
}
/// getInputConstraint - Return the specified input constraint. Unlike output
/// constraints, these can be empty.
std::string AsmStmt::getInputConstraint(unsigned i) const {
return std::string(Constraints[i + NumOutputs]->getStrData(),
Constraints[i + NumOutputs]->getByteLength());
}
/// getNamedOperand - Given a symbolic operand reference like %[foo],
/// translate this into a numeric value needed to reference the same operand.
/// This returns -1 if the operand name is invalid.
int AsmStmt::getNamedOperand(const std::string &SymbolicName) const {
unsigned NumPlusOperands = 0;
// Check if this is an output operand.
for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) {
if (getOutputName(i) == SymbolicName)
return i;
// Keep track of the number of '+' operands.
if (isOutputPlusConstraint(i)) ++NumPlusOperands;
}
for (unsigned i = 0, e = getNumInputs(); i != e; ++i)
if (getInputName(i) == SymbolicName)
return getNumOutputs() + NumPlusOperands + i;
// Not found.
return -1;
}
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
ASTContext &C, unsigned &DiagOffs) const {
const char *StrStart = getAsmString()->getStrData();
const char *StrEnd = StrStart + getAsmString()->getByteLength();
const char *CurPtr = StrStart;
// "Simple" inline asms have no constraints or operands, just convert the asm
// string to escape $'s.
if (isSimple()) {
std::string Result;
for (; CurPtr != StrEnd; ++CurPtr) {
switch (*CurPtr) {
case '$':
Result += "$$";
break;
default:
Result += *CurPtr;
break;
}
}
Pieces.push_back(AsmStringPiece(Result));
return 0;
}
// CurStringPiece - The current string that we are building up as we scan the
// asm string.
std::string CurStringPiece;
while (1) {
// Done with the string?
if (CurPtr == StrEnd) {
if (!CurStringPiece.empty())
Pieces.push_back(AsmStringPiece(CurStringPiece));
return 0;
}
char CurChar = *CurPtr++;
if (CurChar == '$') {
CurStringPiece += "$$";
continue;
} else if (CurChar != '%') {
CurStringPiece += CurChar;
continue;
}
// Escaped "%" character in asm string.
// FIXME: This should be caught during Sema.
assert(CurPtr != StrEnd && "Trailing '%' in asm string.");
char EscapedChar = *CurPtr++;
if (EscapedChar == '%') { // %% -> %
// Escaped percentage sign.
CurStringPiece += '%';
continue;
}
if (EscapedChar == '=') { // %= -> Generate an unique ID.
CurStringPiece += "${:uid}";
continue;
}
// Otherwise, we have an operand. If we have accumulated a string so far,
// add it to the Pieces list.
if (!CurStringPiece.empty()) {
Pieces.push_back(AsmStringPiece(CurStringPiece));
CurStringPiece.clear();
}
// Handle %x4 and %x[foo] by capturing x as the modifier character.
char Modifier = '\0';
if (isalpha(EscapedChar)) {
Modifier = EscapedChar;
EscapedChar = *CurPtr++;
}
if (isdigit(EscapedChar)) {
// %n - Assembler operand n
char *End;
unsigned long N = strtoul(CurPtr-1, &End, 10);
assert(End != CurPtr-1 && "We know that EscapedChar is a digit!");
CurPtr = End;
// FIXME: This should be caught during Sema.
//unsigned NumOperands = S.getNumOutputs() + S.getNumInputs();
//assert(N < NumOperands && "Operand number out of range!");
Pieces.push_back(AsmStringPiece(N, Modifier));
continue;
}
// Handle %[foo], a symbolic operand reference.
if (EscapedChar == '[') {
const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr);
// FIXME: Should be caught by sema.
// FIXME: Does sema catch multiple operands with the same name?
assert(NameEnd != 0 && "Could not parse symbolic name");
std::string SymbolicName(CurPtr, NameEnd);
CurPtr = NameEnd+1;
int N = getNamedOperand(SymbolicName);
assert(N != -1 && "FIXME: Catch in Sema.");
Pieces.push_back(AsmStringPiece(N, Modifier));
continue;
}
DiagOffs = CurPtr-StrStart;
return diag::err_asm_invalid_escape;
}
}
//===----------------------------------------------------------------------===//
// Constructors
//===----------------------------------------------------------------------===//
AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
unsigned numoutputs, unsigned numinputs,
std::string *names, StringLiteral **constraints,
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
StringLiteral **clobbers, SourceLocation rparenloc)
: Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
, IsSimple(issimple), IsVolatile(isvolatile)
, NumOutputs(numoutputs), NumInputs(numinputs) {
for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
Names.push_back(names[i]);
Exprs.push_back(exprs[i]);
Constraints.push_back(constraints[i]);
}
for (unsigned i = 0; i != numclobbers; i++)
Clobbers.push_back(clobbers[i]);
}
ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
Stmt *Body, SourceLocation FCL,
SourceLocation RPL)
: Stmt(ObjCForCollectionStmtClass) {
SubExprs[ELEM] = Elem;
SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
SubExprs[BODY] = Body;
ForLoc = FCL;
RParenLoc = RPL;
}
ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc,
SourceLocation rparenloc,
ParmVarDecl *catchVarDecl, Stmt *atCatchStmt,
Stmt *atCatchList)
: Stmt(ObjCAtCatchStmtClass) {
ExceptionDecl = catchVarDecl;
SubExprs[BODY] = atCatchStmt;
SubExprs[NEXT_CATCH] = NULL;
// FIXME: O(N^2) in number of catch blocks.
if (atCatchList) {
ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList);
while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt())
AtCatchList = NextCatch;
AtCatchList->SubExprs[NEXT_CATCH] = this;
}
AtCatchLoc = atCatchLoc;
RParenLoc = rparenloc;
}
//===----------------------------------------------------------------------===//
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
// DeclStmt
Stmt::child_iterator DeclStmt::child_begin() {
return StmtIterator(DG.begin(), DG.end());
}
Stmt::child_iterator DeclStmt::child_end() {
return StmtIterator(DG.end(), DG.end());
}
// NullStmt
Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator NullStmt::child_end() { return child_iterator(); }
// CompoundStmt
Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+NumStmts; }
// CaseStmt
Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }
// DefaultStmt
Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }
// LabelStmt
Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }
// IfStmt
Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; }
// SwitchStmt
Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; }
// WhileStmt
Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; }
// DoStmt
Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }
// ForStmt
Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; }
// ObjCForCollectionStmt
Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
return &SubExprs[0];
}
Stmt::child_iterator ObjCForCollectionStmt::child_end() {
return &SubExprs[0]+END_EXPR;
}
// GotoStmt
Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); }
// IndirectGotoStmt
Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); }
const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); }
Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; }
Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; }
// ContinueStmt
Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); }
// BreakStmt
Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); }
Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); }
// ReturnStmt
const Expr* ReturnStmt::getRetValue() const {
return cast_or_null<Expr>(RetExpr);
}
Expr* ReturnStmt::getRetValue() {
return cast_or_null<Expr>(RetExpr);
}
Stmt::child_iterator ReturnStmt::child_begin() {
return &RetExpr;
}
Stmt::child_iterator ReturnStmt::child_end() {
return RetExpr ? &RetExpr+1 : &RetExpr;
}
// AsmStmt
Stmt::child_iterator AsmStmt::child_begin() {
return Exprs.empty() ? 0 : &Exprs[0];
}
Stmt::child_iterator AsmStmt::child_end() {
return Exprs.empty() ? 0 : &Exprs[0] + Exprs.size();
}
// ObjCAtCatchStmt
Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; }
Stmt::child_iterator ObjCAtCatchStmt::child_end() {
return &SubExprs[0]+END_EXPR;
}
// ObjCAtFinallyStmt
Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
// ObjCAtTryStmt
Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; }
Stmt::child_iterator ObjCAtTryStmt::child_end() {
return &SubStmts[0]+END_EXPR;
}
// ObjCAtThrowStmt
Stmt::child_iterator ObjCAtThrowStmt::child_begin() {
return &Throw;
}
Stmt::child_iterator ObjCAtThrowStmt::child_end() {
return &Throw+1;
}
2008-01-30 03:14:59 +08:00
// ObjCAtSynchronizedStmt
Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() {
return &SubStmts[0];
2008-01-30 03:14:59 +08:00
}
Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
return &SubStmts[0]+END_EXPR;
2008-01-30 03:14:59 +08:00
}
// CXXCatchStmt
Stmt::child_iterator CXXCatchStmt::child_begin() {
return &HandlerBlock;
}
Stmt::child_iterator CXXCatchStmt::child_end() {
return &HandlerBlock + 1;
}
QualType CXXCatchStmt::getCaughtType() {
if (ExceptionDecl)
return llvm::cast<VarDecl>(ExceptionDecl)->getType();
return QualType();
}
void CXXCatchStmt::Destroy(ASTContext& C) {
if (ExceptionDecl)
ExceptionDecl->Destroy(C);
Stmt::Destroy(C);
}
// CXXTryStmt
Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; }
Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); }
CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
Stmt **handlers, unsigned numHandlers)
: Stmt(CXXTryStmtClass), TryLoc(tryLoc) {
Stmts.push_back(tryBlock);
Stmts.insert(Stmts.end(), handlers, handlers + numHandlers);
}