PCH support for labels and goto.

llvm-svn: 69364
This commit is contained in:
Douglas Gregor 2009-04-17 18:18:49 +00:00
parent 059c6f6293
commit 6cc68a47b5
7 changed files with 152 additions and 2 deletions

View File

@ -530,13 +530,16 @@ public:
LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt)
: Stmt(LabelStmtClass), Label(label),
SubStmt(substmt), IdentLoc(IL) {}
// \brief Build an empty label statement.
explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { }
SourceLocation getIdentLoc() const { return IdentLoc; }
IdentifierInfo *getID() const { return Label; }
void setID(IdentifierInfo *II) { Label = II; }
const char *getName() const;
Stmt *getSubStmt() { return SubStmt; }
const Stmt *getSubStmt() const { return SubStmt; }
void setIdentLoc(SourceLocation L) { IdentLoc = L; }
void setSubStmt(Stmt *SS) { SubStmt = SS; }
@ -817,7 +820,16 @@ public:
GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL)
: Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {}
/// \brief Build an empty goto statement.
explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { }
LabelStmt *getLabel() const { return Label; }
void setLabel(LabelStmt *S) { Label = S; }
SourceLocation getGotoLoc() const { return GotoLoc; }
void setGotoLoc(SourceLocation L) { GotoLoc = L; }
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
virtual SourceRange getSourceRange() const {
return SourceRange(GotoLoc, LabelLoc);

View File

@ -383,6 +383,8 @@ namespace clang {
STMT_CASE,
/// \brief A DefaultStmt record.
STMT_DEFAULT,
/// \brief A LabelStmt record.
STMT_LABEL,
/// \brief An IfStmt record.
STMT_IF,
/// \brief A SwitchStmt record.
@ -393,6 +395,8 @@ namespace clang {
STMT_DO,
/// \brief A ForStmt record.
STMT_FOR,
/// \brief A GotoStmt record.
STMT_GOTO,
/// \brief A ContinueStmt record.
STMT_CONTINUE,
/// \brief A BreakStmt record.

View File

@ -41,6 +41,8 @@ class ASTContext;
class Attr;
class Decl;
class DeclContext;
class GotoStmt;
class LabelStmt;
class Preprocessor;
class SwitchCase;
@ -132,6 +134,15 @@ private:
/// switch-case statements.
std::map<unsigned, SwitchCase *> SwitchCaseStmts;
/// \brief Mapping from label statement IDs in the PCH file to label
/// statements.
std::map<unsigned, LabelStmt *> LabelStmts;
/// \brief Mapping from label IDs to the set of "goto" statements
/// that point to that label before the label itself has been
/// de-serialized.
std::multimap<unsigned, GotoStmt *> UnresolvedGotoStmts;
PCHReadResult ReadPCHBlock();
bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
@ -254,6 +265,19 @@ public:
/// \brief Retrieve the switch-case statement with the given ID.
SwitchCase *getSwitchCaseWithID(unsigned ID);
/// \brief Record that the given label statement has been
/// deserialized and has the given ID.
void RecordLabelStmt(LabelStmt *S, unsigned ID);
/// \brief Set the label of the given statement to the label
/// identified by ID.
///
/// Depending on the order in which the label and other statements
/// referencing that label occur, this operation may complete
/// immediately (updating the statement) or it may queue the
/// statement to be back-patched later.
void SetLabelOf(GotoStmt *S, unsigned ID);
};
} // end namespace clang

View File

@ -32,6 +32,7 @@ namespace llvm {
namespace clang {
class ASTContext;
class LabelStmt;
class Preprocessor;
class SourceManager;
class SwitchCase;
@ -113,6 +114,9 @@ private:
/// \brief Mapping from SwitchCase statements to IDs.
std::map<SwitchCase *, unsigned> SwitchCaseIDs;
/// \brief Mapping from LabelStmt statements to IDs.
std::map<LabelStmt *, unsigned> LabelIDs;
void WriteTargetTriple(const TargetInfo &Target);
void WriteLanguageOptions(const LangOptions &LangOpts);
void WriteSourceManagerBlock(SourceManager &SourceMgr);
@ -182,6 +186,10 @@ public:
/// \brief Retrieve the ID for the given switch-case statement.
unsigned getSwitchCaseID(SwitchCase *S);
/// \brief Retrieve the ID for the given label statement, which may
/// or may not have been emitted yet.
unsigned GetLabelID(LabelStmt *S);
};
} // end namespace clang

View File

@ -249,11 +249,13 @@ namespace {
unsigned VisitSwitchCase(SwitchCase *S);
unsigned VisitCaseStmt(CaseStmt *S);
unsigned VisitDefaultStmt(DefaultStmt *S);
unsigned VisitLabelStmt(LabelStmt *S);
unsigned VisitIfStmt(IfStmt *S);
unsigned VisitSwitchStmt(SwitchStmt *S);
unsigned VisitWhileStmt(WhileStmt *S);
unsigned VisitDoStmt(DoStmt *S);
unsigned VisitForStmt(ForStmt *S);
unsigned VisitGotoStmt(GotoStmt *S);
unsigned VisitContinueStmt(ContinueStmt *S);
unsigned VisitBreakStmt(BreakStmt *S);
unsigned VisitReturnStmt(ReturnStmt *S);
@ -336,6 +338,15 @@ unsigned PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) {
return 1;
}
unsigned PCHStmtReader::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
S->setID(Reader.GetIdentifierInfo(Record, Idx));
S->setSubStmt(StmtStack.back());
S->setIdentLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
Reader.RecordLabelStmt(S, Record[Idx++]);
return 1;
}
unsigned PCHStmtReader::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
S->setCond(cast<Expr>(StmtStack[StmtStack.size() - 3]));
@ -388,6 +399,14 @@ unsigned PCHStmtReader::VisitForStmt(ForStmt *S) {
return 4;
}
unsigned PCHStmtReader::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
Reader.SetLabelOf(S, Record[Idx++]);
S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
S->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
return 0;
}
unsigned PCHStmtReader::VisitContinueStmt(ContinueStmt *S) {
VisitStmt(S);
S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@ -2172,6 +2191,10 @@ Stmt *PCHReader::ReadStmt() {
S = new (Context) DefaultStmt(Empty);
break;
case pch::STMT_LABEL:
S = new (Context) LabelStmt(Empty);
break;
case pch::STMT_IF:
S = new (Context) IfStmt(Empty);
break;
@ -2192,6 +2215,10 @@ Stmt *PCHReader::ReadStmt() {
S = new (Context) ForStmt(Empty);
break;
case pch::STMT_GOTO:
S = new (Context) GotoStmt(Empty);
break;
case pch::STMT_CONTINUE:
S = new (Context) ContinueStmt(Empty);
break;
@ -2342,7 +2369,7 @@ Stmt *PCHReader::ReadStmt() {
}
}
assert(Idx == Record.size() && "Invalid deserialization of expression");
assert(Idx == Record.size() && "Invalid deserialization of statement");
StmtStack.push_back(S);
}
assert(StmtStack.size() == 1 && "Extra expressions on stack!");
@ -2376,3 +2403,39 @@ SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) {
assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID");
return SwitchCaseStmts[ID];
}
/// \brief Record that the given label statement has been
/// deserialized and has the given ID.
void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) {
assert(LabelStmts.find(ID) == LabelStmts.end() &&
"Deserialized label twice");
LabelStmts[ID] = S;
// If we've already seen any goto statements that point to this
// label, resolve them now.
typedef std::multimap<unsigned, GotoStmt *>::iterator GotoIter;
std::pair<GotoIter, GotoIter> Gotos = UnresolvedGotoStmts.equal_range(ID);
for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto)
Goto->second->setLabel(S);
UnresolvedGotoStmts.erase(Gotos.first, Gotos.second);
}
/// \brief Set the label of the given statement to the label
/// identified by ID.
///
/// Depending on the order in which the label and other statements
/// referencing that label occur, this operation may complete
/// immediately (updating the statement) or it may queue the
/// statement to be back-patched later.
void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) {
std::map<unsigned, LabelStmt *>::iterator Label = LabelStmts.find(ID);
if (Label != LabelStmts.end()) {
// We've already seen this label, so set the label of the goto and
// we're done.
S->setLabel(Label->second);
} else {
// We haven't seen this label yet, so add this goto to the set of
// unresolved goto statements.
UnresolvedGotoStmts.insert(std::make_pair(ID, S));
}
}

View File

@ -451,11 +451,13 @@ namespace {
void VisitSwitchCase(SwitchCase *S);
void VisitCaseStmt(CaseStmt *S);
void VisitDefaultStmt(DefaultStmt *S);
void VisitLabelStmt(LabelStmt *S);
void VisitIfStmt(IfStmt *S);
void VisitSwitchStmt(SwitchStmt *S);
void VisitWhileStmt(WhileStmt *S);
void VisitDoStmt(DoStmt *S);
void VisitForStmt(ForStmt *S);
void VisitGotoStmt(GotoStmt *S);
void VisitContinueStmt(ContinueStmt *S);
void VisitBreakStmt(BreakStmt *S);
void VisitReturnStmt(ReturnStmt *S);
@ -536,6 +538,15 @@ void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
Code = pch::STMT_DEFAULT;
}
void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
Writer.AddIdentifierRef(S->getID(), Record);
Writer.WriteSubStmt(S->getSubStmt());
Writer.AddSourceLocation(S->getIdentLoc(), Record);
Record.push_back(Writer.GetLabelID(S));
Code = pch::STMT_LABEL;
}
void PCHStmtWriter::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
Writer.WriteSubStmt(S->getCond());
@ -582,6 +593,14 @@ void PCHStmtWriter::VisitForStmt(ForStmt *S) {
Code = pch::STMT_FOR;
}
void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
Record.push_back(Writer.GetLabelID(S->getLabel()));
Writer.AddSourceLocation(S->getGotoLoc(), Record);
Writer.AddSourceLocation(S->getLabelLoc(), Record);
Code = pch::STMT_GOTO;
}
void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getContinueLoc(), Record);
@ -1857,3 +1876,15 @@ unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) {
"SwitchCase hasn't been seen yet");
return SwitchCaseIDs[S];
}
/// \brief Retrieve the ID for the given label statement, which may
/// or may not have been emitted yet.
unsigned PCHWriter::GetLabelID(LabelStmt *S) {
std::map<LabelStmt *, unsigned>::iterator Pos = LabelIDs.find(S);
if (Pos != LabelIDs.end())
return Pos->second;
unsigned NextID = LabelIDs.size();
LabelIDs[S] = NextID;
return NextID;
}

View File

@ -33,17 +33,25 @@ void f0(int x) {
continue;
} else if (x < 5)
break;
else
goto done;
}
do {
x++;
} while (x < 10);
almost_done:
for (int y = x; y < 20; ++y) {
if (x + y == 12)
return;
else if (x - y == 7)
goto almost_done;
}
done:
x = x + 2;
int z = x, *y, j = 5;
}