PCH support for indirect gotos and address-of-label expressions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69369 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index e73162d..8059ad2 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -1601,12 +1601,22 @@
QualType t)
: Expr(AddrLabelExprClass, t), AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {}
+ /// \brief Build an empty address of a label expression.
+ explicit AddrLabelExpr(EmptyShell Empty)
+ : Expr(AddrLabelExprClass, Empty) { }
+
+ SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; }
+ void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; }
+ SourceLocation getLabelLoc() const { return LabelLoc; }
+ void setLabelLoc(SourceLocation L) { LabelLoc = L; }
+
virtual SourceRange getSourceRange() const {
return SourceRange(AmpAmpLoc, LabelLoc);
}
LabelStmt *getLabel() const { return Label; }
-
+ void setLabel(LabelStmt *S) { Label = S; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == AddrLabelExprClass;
}
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 29e1931..d5e4abb 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -852,13 +852,18 @@
class IndirectGotoStmt : public Stmt {
Stmt *Target;
// FIXME: Add location information (e.g. SourceLocation objects).
- // When doing so, update the serialization routines.
+ // When doing so, update the PCH serialization routines.
public:
IndirectGotoStmt(Expr *target) : Stmt(IndirectGotoStmtClass),
Target((Stmt*)target){}
+
+ /// \brief Build an empty indirect goto statement.
+ explicit IndirectGotoStmt(EmptyShell Empty)
+ : Stmt(IndirectGotoStmtClass, Empty) { }
Expr *getTarget();
const Expr *getTarget() const;
+ void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); }
virtual SourceRange getSourceRange() const { return SourceRange(); }
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index fceafb0..93b78f1 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -397,6 +397,8 @@
STMT_FOR,
/// \brief A GotoStmt record.
STMT_GOTO,
+ /// \brief An IndirectGotoStmt record.
+ STMT_INDIRECT_GOTO,
/// \brief A ContinueStmt record.
STMT_CONTINUE,
/// \brief A BreakStmt record.
@@ -405,6 +407,7 @@
STMT_RETURN,
/// \brief A DeclStmt record.
STMT_DECL,
+ /// FIXME: An AsmStmt record.
/// \brief A PredefinedExpr record.
EXPR_PREDEFINED,
/// \brief A DeclRefExpr record.
@@ -453,7 +456,8 @@
EXPR_IMPLICIT_VALUE_INIT,
/// \brief A VAArgExpr record.
EXPR_VA_ARG,
- // FIXME: AddrLabelExpr
+ // An AddrLabelExpr record.
+ EXPR_ADDR_LABEL,
// FIXME: StmtExpr
/// \brief A TypesCompatibleExpr record.
EXPR_TYPES_COMPATIBLE,
diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h
index c573797..0507cfa 100644
--- a/include/clang/Frontend/PCHReader.h
+++ b/include/clang/Frontend/PCHReader.h
@@ -37,6 +37,7 @@
namespace clang {
+class AddrLabelExpr;
class ASTContext;
class Attr;
class Decl;
@@ -143,6 +144,11 @@
/// de-serialized.
std::multimap<unsigned, GotoStmt *> UnresolvedGotoStmts;
+ /// \brief Mapping from label IDs to the set of address label
+ /// expressions that point to that label before the label itself has
+ /// been de-serialized.
+ std::multimap<unsigned, AddrLabelExpr *> UnresolvedAddrLabelExprs;
+
PCHReadResult ReadPCHBlock();
bool CheckPredefinesBuffer(const char *PCHPredef,
unsigned PCHPredefLen,
@@ -278,6 +284,15 @@
/// immediately (updating the statement) or it may queue the
/// statement to be back-patched later.
void SetLabelOf(GotoStmt *S, unsigned ID);
+
+ /// \brief Set the label of the given expression 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(AddrLabelExpr *S, unsigned ID);
};
} // end namespace clang
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 9597b37..8928b06 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -256,6 +256,7 @@
unsigned VisitDoStmt(DoStmt *S);
unsigned VisitForStmt(ForStmt *S);
unsigned VisitGotoStmt(GotoStmt *S);
+ unsigned VisitIndirectGotoStmt(IndirectGotoStmt *S);
unsigned VisitContinueStmt(ContinueStmt *S);
unsigned VisitBreakStmt(BreakStmt *S);
unsigned VisitReturnStmt(ReturnStmt *S);
@@ -287,6 +288,7 @@
unsigned VisitDesignatedInitExpr(DesignatedInitExpr *E);
unsigned VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
unsigned VisitVAArgExpr(VAArgExpr *E);
+ unsigned VisitAddrLabelExpr(AddrLabelExpr *E);
unsigned VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
unsigned VisitChooseExpr(ChooseExpr *E);
unsigned VisitGNUNullExpr(GNUNullExpr *E);
@@ -407,6 +409,12 @@
return 0;
}
+unsigned PCHStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ S->setTarget(cast_or_null<Expr>(StmtStack.back()));
+ return 1;
+}
+
unsigned PCHStmtReader::VisitContinueStmt(ContinueStmt *S) {
VisitStmt(S);
S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
@@ -733,6 +741,14 @@
return 1;
}
+unsigned PCHStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ E->setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ Reader.SetLabelOf(E, Record[Idx++]);
+ return 0;
+}
+
unsigned PCHStmtReader::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
VisitExpr(E);
E->setArgType1(Reader.GetType(Record[Idx++]));
@@ -2218,6 +2234,10 @@
case pch::STMT_GOTO:
S = new (Context) GotoStmt(Empty);
break;
+
+ case pch::STMT_INDIRECT_GOTO:
+ S = new (Context) IndirectGotoStmt(Empty);
+ break;
case pch::STMT_CONTINUE:
S = new (Context) ContinueStmt(Empty);
@@ -2335,6 +2355,10 @@
S = new (Context) VAArgExpr(Empty);
break;
+ case pch::EXPR_ADDR_LABEL:
+ S = new (Context) AddrLabelExpr(Empty);
+ break;
+
case pch::EXPR_TYPES_COMPATIBLE:
S = new (Context) TypesCompatibleExpr(Empty);
break;
@@ -2418,6 +2442,16 @@
for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto)
Goto->second->setLabel(S);
UnresolvedGotoStmts.erase(Gotos.first, Gotos.second);
+
+ // If we've already seen any address-label statements that point to
+ // this label, resolve them now.
+ typedef std::multimap<unsigned, AddrLabelExpr *>::iterator AddrLabelIter;
+ std::pair<AddrLabelIter, AddrLabelIter> AddrLabels
+ = UnresolvedAddrLabelExprs.equal_range(ID);
+ for (AddrLabelIter AddrLabel = AddrLabels.first;
+ AddrLabel != AddrLabels.second; ++AddrLabel)
+ AddrLabel->second->setLabel(S);
+ UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second);
}
/// \brief Set the label of the given statement to the label
@@ -2439,3 +2473,23 @@
UnresolvedGotoStmts.insert(std::make_pair(ID, S));
}
}
+
+/// \brief Set the label of the given expression 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(AddrLabelExpr *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
+ // label-address expression and we're done.
+ S->setLabel(Label->second);
+ } else {
+ // We haven't seen this label yet, so add this label-address
+ // expression to the set of unresolved label-address expressions.
+ UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S));
+ }
+}
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index bde8596..4bbaaa0 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -458,6 +458,7 @@
void VisitDoStmt(DoStmt *S);
void VisitForStmt(ForStmt *S);
void VisitGotoStmt(GotoStmt *S);
+ void VisitIndirectGotoStmt(IndirectGotoStmt *S);
void VisitContinueStmt(ContinueStmt *S);
void VisitBreakStmt(BreakStmt *S);
void VisitReturnStmt(ReturnStmt *S);
@@ -489,6 +490,7 @@
void VisitDesignatedInitExpr(DesignatedInitExpr *E);
void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
void VisitVAArgExpr(VAArgExpr *E);
+ void VisitAddrLabelExpr(AddrLabelExpr *E);
void VisitTypesCompatibleExpr(TypesCompatibleExpr *E);
void VisitChooseExpr(ChooseExpr *E);
void VisitGNUNullExpr(GNUNullExpr *E);
@@ -601,6 +603,12 @@
Code = pch::STMT_GOTO;
}
+void PCHStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
+ VisitStmt(S);
+ Writer.WriteSubStmt(S->getTarget());
+ Code = pch::STMT_INDIRECT_GOTO;
+}
+
void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) {
VisitStmt(S);
Writer.AddSourceLocation(S->getContinueLoc(), Record);
@@ -880,6 +888,14 @@
Code = pch::EXPR_VA_ARG;
}
+void PCHStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) {
+ VisitExpr(E);
+ Writer.AddSourceLocation(E->getAmpAmpLoc(), Record);
+ Writer.AddSourceLocation(E->getLabelLoc(), Record);
+ Record.push_back(Writer.GetLabelID(E->getLabel()));
+ Code = pch::EXPR_ADDR_LABEL;
+}
+
void PCHStmtWriter::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) {
VisitExpr(E);
Writer.AddTypeRef(E->getArgType1(), Record);
diff --git a/test/PCH/stmts.c b/test/PCH/stmts.c
index a2278bf..fc6cfc2 100644
--- a/test/PCH/stmts.c
+++ b/test/PCH/stmts.c
@@ -8,3 +8,5 @@
void g0(void) { f0(5); }
int g1(int x) { return f1(x); }
const char* query_name(void) { return what_is_my_name(); }
+
+int use_computed_goto(int x) { return computed_goto(x); }
diff --git a/test/PCH/stmts.h b/test/PCH/stmts.h
index f1cd815..10842e8 100644
--- a/test/PCH/stmts.h
+++ b/test/PCH/stmts.h
@@ -68,3 +68,21 @@
}
const char* what_is_my_name(void) { return __func__; }
+
+int computed_goto(int x) {
+ start:
+ x = x << 1;
+ void *location = &&start;
+
+ if (x > 17)
+ location = &&done;
+
+ while (x > 12) {
+ --x;
+ if (x == 15)
+ goto *location;
+ }
+
+ done:
+ return 5;
+}