Step #1/N of implementing support for __label__: split labels into
LabelDecl and LabelStmt. There is a 1-1 correspondence between the
two, but this simplifies a bunch of code by itself. This is because
labels are the only place where we previously had references to random
other statements, causing grief for AST serialization and other stuff.
This does cause one regression (attr(unused) doesn't silence unused
label warnings) which I'll address next.
This does fix some minor bugs:
1. "The only valid attribute " diagnostic was capitalized.
2. Various diagnostics printed as ''labelname'' instead of 'labelname'
3. This reduces duplication of label checking between functions and blocks.
Review appreciated, particularly for the cindex and template bits.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125733 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index cba71ae..e0ffa62 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -36,6 +36,7 @@
class DependentFunctionTemplateSpecializationInfo;
class TypeLoc;
class UnresolvedSetImpl;
+class LabelStmt;
/// \brief A container of type source information.
///
@@ -294,6 +295,36 @@
return OS;
}
+/// LabelDecl - Represents the declaration of a label. Labels also have a
+/// corresponding LabelStmt, which indicates the position that the label was
+/// defined at. For normal labels, the location of the decl is the same as the
+/// location of the statement. For GNU local labels (__label__), the decl
+/// location is where the __label__ is.
+class LabelDecl : public NamedDecl {
+ /// HasUnusedAttr - True if the label has __attribute__((unused)) on it.
+ /// FIXME: Just use attributes!
+ unsigned HasUnusedAttr : 1;
+
+ LabelStmt *TheStmt;
+ LabelDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *II, LabelStmt *S)
+ : NamedDecl(Label, DC, L, II), TheStmt(S) {}
+
+public:
+ static LabelDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *II);
+
+ LabelStmt *getStmt() const { return TheStmt; }
+ void setStmt(LabelStmt *T) { TheStmt = T; }
+
+ bool hasUnusedAttribute() const { return HasUnusedAttr; }
+ void setHasUnusedAttribute() { HasUnusedAttr = true; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classof(const LabelDecl *D) { return true; }
+ static bool classofKind(Kind K) { return K == Label; }
+};
+
/// NamespaceDecl - Represent a C++ namespace.
class NamespaceDecl : public NamedDecl, public DeclContext {
bool IsInline : 1;
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 3e92c4e..1407dad 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -324,7 +324,7 @@
bool hasAttrs() const { return HasAttrs; }
void setAttrs(const AttrVec& Attrs);
- AttrVec& getAttrs() {
+ AttrVec &getAttrs() {
return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs());
}
const AttrVec &getAttrs() const;
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index c09394d..b5724a6 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -2641,9 +2641,9 @@
/// AddrLabelExpr - The GNU address of label extension, representing &&label.
class AddrLabelExpr : public Expr {
SourceLocation AmpAmpLoc, LabelLoc;
- LabelStmt *Label;
+ LabelDecl *Label;
public:
- AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelStmt *L,
+ AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelDecl *L,
QualType t)
: Expr(AddrLabelExprClass, t, VK_RValue, OK_Ordinary, false, false, false),
AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {}
@@ -2661,8 +2661,8 @@
return SourceRange(AmpAmpLoc, LabelLoc);
}
- LabelStmt *getLabel() const { return Label; }
- void setLabel(LabelStmt *S) { Label = S; }
+ LabelDecl *getLabel() const { return Label; }
+ void setLabel(LabelDecl *L) { Label = L; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == AddrLabelExprClass;
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 8ddd587..667b840 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1088,6 +1088,11 @@
return true;
})
+DEF_TRAVERSE_DECL(LabelDecl, {
+ // There is no code in a LabelDecl.
+})
+
+
DEF_TRAVERSE_DECL(NamespaceDecl, {
// Code in an unnamed namespace shows up automatically in
// decls_begin()/decls_end(). Thus we don't need to recurse on
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index 1254926..7ede9ce 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -130,14 +130,6 @@
unsigned NumStmts : 32 - NumStmtBits;
};
- class LabelStmtBitfields {
- friend class LabelStmt;
- unsigned : NumStmtBits;
-
- unsigned Used : 1;
- unsigned HasUnusedAttr : 1;
- };
-
class ExprBitfields {
friend class Expr;
friend class DeclRefExpr; // computeDependence
@@ -187,7 +179,6 @@
StmtBitfields StmtBits;
CompoundStmtBitfields CompoundStmtBits;
- LabelStmtBitfields LabelStmtBits;
ExprBitfields ExprBits;
CastExprBitfields CastExprBits;
CallExprBitfields CallExprBits;
@@ -633,40 +624,31 @@
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
};
+
+/// LabelStmt - Represents a label, which has a substatement. For example:
+/// foo: return;
+///
class LabelStmt : public Stmt {
- IdentifierInfo *Label;
+ LabelDecl *TheDecl;
Stmt *SubStmt;
SourceLocation IdentLoc;
public:
- LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt,
- bool hasUnusedAttr = false)
- : Stmt(LabelStmtClass), Label(label), SubStmt(substmt), IdentLoc(IL) {
- LabelStmtBits.Used = false;
- LabelStmtBits.HasUnusedAttr = hasUnusedAttr;
+ LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt)
+ : Stmt(LabelStmtClass), TheDecl(D), 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; }
+ LabelDecl *getDecl() const { return TheDecl; }
+ void setDecl(LabelDecl *D) { TheDecl = D; }
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; }
- /// \brief Whether this label was used.
- bool isUsed(bool CheckUnusedAttr = true) const {
- return LabelStmtBits.Used ||
- (CheckUnusedAttr && LabelStmtBits.HasUnusedAttr);
- }
- void setUsed(bool U = true) { LabelStmtBits.Used = U; }
-
- bool HasUnusedAttribute() const { return LabelStmtBits.HasUnusedAttr; }
- void setUnusedAttribute(bool U) { LabelStmtBits.HasUnusedAttr = U; }
-
SourceRange getSourceRange() const {
return SourceRange(IdentLoc, SubStmt->getLocEnd());
}
@@ -995,18 +977,18 @@
/// GotoStmt - This represents a direct goto.
///
class GotoStmt : public Stmt {
- LabelStmt *Label;
+ LabelDecl *Label;
SourceLocation GotoLoc;
SourceLocation LabelLoc;
public:
- GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL)
+ GotoStmt(LabelDecl *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; }
+ LabelDecl *getLabel() const { return Label; }
+ void setLabel(LabelDecl *D) { Label = D; }
SourceLocation getGotoLoc() const { return GotoLoc; }
void setGotoLoc(SourceLocation L) { GotoLoc = L; }
@@ -1052,8 +1034,8 @@
/// getConstantTarget - Returns the fixed target of this indirect
/// goto, if one exists.
- LabelStmt *getConstantTarget();
- const LabelStmt *getConstantTarget() const {
+ LabelDecl *getConstantTarget();
+ const LabelDecl *getConstantTarget() const {
return const_cast<IndirectGotoStmt*>(this)->getConstantTarget();
}
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index f6c31f4..2ec7427 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -15,6 +15,7 @@
def Namespace : DDecl<Named>, DeclContext;
def UsingDirective : DDecl<Named>;
def NamespaceAlias : DDecl<Named>;
+ def Label : DDecl<Named>;
def Type : DDecl<Named, 1>;
def Typedef : DDecl<Type>;
def UnresolvedUsingTypename : DDecl<Type>;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index eb8bf59..b815426 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1095,7 +1095,7 @@
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
def warn_label_attribute_not_unused : Warning<
- "The only valid attribute for labels is 'unused'">;
+ "the only valid attribute for labels is 'unused'">;
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
@@ -2157,9 +2157,9 @@
"suggest braces around initialization of subobject">,
InGroup<DiagGroup<"missing-braces">>, DefaultIgnore;
-def err_redefinition_of_label : Error<"redefinition of label '%0'">;
-def err_undeclared_label_use : Error<"use of undeclared label '%0'">;
-def warn_unused_label : Warning<"unused label '%0'">,
+def err_redefinition_of_label : Error<"redefinition of label %0">;
+def err_undeclared_label_use : Error<"use of undeclared label %0">;
+def warn_unused_label : Warning<"unused label %0">,
InGroup<UnusedLabel>, DefaultIgnore;
def err_goto_into_protected_scope : Error<"goto into protected scope">;
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index edd1432..c9d3871 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -23,7 +23,7 @@
class BlockDecl;
class IdentifierInfo;
-class LabelStmt;
+class LabelDecl;
class ReturnStmt;
class Scope;
class SwitchStmt;
@@ -52,10 +52,10 @@
/// \brief Used to determine if errors occurred in this function or block.
DiagnosticErrorTrap ErrorTrap;
- /// LabelMap - This is a mapping from label identifiers to the LabelStmt for
- /// it (which acts like the label decl in some ways). Forward referenced
- /// labels have a LabelStmt created for them with a null location & SubStmt.
- llvm::DenseMap<IdentifierInfo*, LabelStmt*> LabelMap;
+ /// LabelMap - This is a mapping from label identifiers to the LabelDecl for
+ /// it. Forward referenced labels have a LabelDecl created for them with a
+ /// null statement.
+ llvm::DenseMap<IdentifierInfo*, LabelDecl*> LabelMap;
/// SwitchStack - This is the current set of active switch statements in the
/// block.
@@ -92,6 +92,11 @@
virtual ~FunctionScopeInfo();
+ /// checkLabelUse - This checks to see if any labels are used without being
+ /// defined, emiting errors and returning true if any are found. This also
+ /// warns about unused labels.
+ bool checkLabelUse(Stmt *Body, Sema &S);
+
/// \brief Clear out the information in this function scope, making it
/// suitable for reuse.
void Clear();
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 3914382..d1998c2 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -697,7 +697,9 @@
/// IDs. This data is used when performing qualified name lookup
/// into a DeclContext via DeclContext::lookup.
DECL_CONTEXT_VISIBLE,
- /// \brief A NamespaceDecl rcord.
+ /// \brief A LabelDecl record.
+ DECL_LABEL,
+ /// \brief A NamespaceDecl record.
DECL_NAMESPACE,
/// \brief A NamespaceAliasDecl record.
DECL_NAMESPACE_ALIAS,
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 94bfd16..002f6be 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -56,7 +56,6 @@
class CXXBaseSpecifier;
class CXXCtorInitializer;
class GotoStmt;
-class LabelStmt;
class MacroDefinition;
class NamedDecl;
class Preprocessor;
@@ -646,22 +645,6 @@
/// switch statement can refer to them.
std::map<unsigned, SwitchCase *> SwitchCaseStmts;
- /// \brief Mapping from label statement IDs in the chain to label statements.
- ///
- /// Statements usually don't have IDs, but labeled statements need them, so
- /// that goto statements and address-of-label expressions can refer to them.
- 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;
-
- /// \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;
-
/// \brief The number of stat() calls that hit/missed the stat
/// cache.
unsigned NumStatHits, NumStatMisses;
@@ -1278,29 +1261,7 @@
/// \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);
-
void ClearSwitchCaseIDs();
-
- /// \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);
-
- /// \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);
};
/// \brief Helper class that saves the current stream position and
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index f9a4997..d5f622a 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -44,7 +44,6 @@
class CXXCtorInitializer;
class FPOptions;
class HeaderSearch;
-class LabelStmt;
class MacroDefinition;
class MemorizeStatCalls;
class OpenCLOptions;
@@ -261,9 +260,6 @@
/// \brief Mapping from SwitchCase statements to IDs.
std::map<SwitchCase *, unsigned> SwitchCaseIDs;
- /// \brief Mapping from LabelStmt statements to IDs.
- std::map<LabelStmt *, unsigned> LabelIDs;
-
/// \brief The number of statements written to the AST file.
unsigned NumStatements;
@@ -553,10 +549,6 @@
void ClearSwitchCaseIDs();
- /// \brief Retrieve the ID for the given label statement, which may
- /// or may not have been emitted yet.
- unsigned GetLabelID(LabelStmt *S);
-
unsigned getParmVarDeclAbbrev() const { return ParmVarDeclAbbrev; }
bool hasChain() const { return Chain; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index d879ea1..800e63a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -331,11 +331,11 @@
iterator& operator++() { ++I; return *this; }
bool operator!=(const iterator& X) const { return I != X.I; }
- const LabelStmt* getLabel() const {
- return llvm::cast<LabelStmt>((*I)->getLabel());
+ const LabelDecl *getLabel() const {
+ return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
}
- const CFGBlock* getBlock() const {
+ const CFGBlock *getBlock() const {
return *I;
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 9c18711..e7b3944 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -238,7 +238,7 @@
return loc::MemRegionVal(R);
}
- Loc makeLoc(const AddrLabelExpr* E) {
+ Loc makeLoc(const AddrLabelExpr *E) {
return loc::GotoLabel(E->getLabel());
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index 1d1cd0b..0d43079 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -432,15 +432,14 @@
class GotoLabel : public Loc {
public:
- explicit GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {}
+ explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {}
- const LabelStmt* getLabel() const {
- return static_cast<const LabelStmt*>(Data);
+ const LabelDecl *getLabel() const {
+ return static_cast<const LabelDecl*>(Data);
}
static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind &&
- V->getSubKind() == GotoLabelKind;
+ return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind;
}
static inline bool classof(const Loc* V) {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index fded8ff..441444d 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2182,6 +2182,12 @@
return new (C) TranslationUnitDecl(C);
}
+LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *II) {
+ return new (C) LabelDecl(DC, L, II, 0);
+}
+
+
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id) {
return new (C) NamespaceDecl(DC, L, Id);
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 110de64..dfc5a6a 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -269,7 +269,8 @@
case ObjCMethod:
case ObjCProperty:
return IDNS_Ordinary;
-
+ case Label:
+ return IDNS_Label;
case IndirectField:
return IDNS_Ordinary | IDNS_Member;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 6618295..7e73f02 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -161,7 +161,7 @@
}
const char *LabelStmt::getName() const {
- return getID()->getNameStart();
+ return getDecl()->getIdentifier()->getNameStart();
}
// This is defined here to avoid polluting Stmt.h with importing Expr.h
@@ -658,7 +658,7 @@
}
// IndirectGotoStmt
-LabelStmt *IndirectGotoStmt::getConstantTarget() {
+LabelDecl *IndirectGotoStmt::getConstantTarget() {
if (AddrLabelExpr *E =
dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts()))
return E->getLabel();
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index b96ffe8..2ffb807 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -101,7 +101,7 @@
void StmtProfiler::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
- VisitName(S->getID());
+ VisitDecl(S->getDecl());
}
void StmtProfiler::VisitIfStmt(IfStmt *S) {
@@ -129,7 +129,7 @@
void StmtProfiler::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
- VisitName(S->getLabel()->getID());
+ VisitDecl(S->getLabel());
}
void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
@@ -351,7 +351,7 @@
void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
VisitExpr(S);
- VisitName(S->getLabel()->getID());
+ VisitDecl(S->getLabel());
}
void StmtProfiler::VisitStmtExpr(StmtExpr *S) {
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index d46b7e7..6da4784 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -242,7 +242,7 @@
LocalScope::const_iterator ScopePos;
// LabelMap records the mapping from Label expressions to their jump targets.
- typedef llvm::DenseMap<LabelStmt*, JumpTarget> LabelMapTy;
+ typedef llvm::DenseMap<LabelDecl*, JumpTarget> LabelMapTy;
LabelMapTy LabelMap;
// A list of blocks that end with a "goto" that must be backpatched to their
@@ -251,7 +251,7 @@
BackpatchBlocksTy BackpatchBlocks;
// A list of labels whose address has been taken (for indirect gotos).
- typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy;
+ typedef llvm::SmallPtrSet<LabelDecl*, 5> LabelSetTy;
LabelSetTy AddressTakenLabels;
bool badCFG;
@@ -648,13 +648,13 @@
LocalScope *Scope = 0;
// For compound statement we will be creating explicit scope.
- if (CompoundStmt* CS = dyn_cast<CompoundStmt>(S)) {
+ if (CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) {
for (CompoundStmt::body_iterator BI = CS->body_begin(), BE = CS->body_end()
; BI != BE; ++BI) {
- Stmt* SI = *BI;
- if (LabelStmt* LS = dyn_cast<LabelStmt>(SI))
+ Stmt *SI = *BI;
+ if (LabelStmt *LS = dyn_cast<LabelStmt>(SI))
SI = LS->getSubStmt();
- if (DeclStmt* DS = dyn_cast<DeclStmt>(SI))
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(SI))
Scope = addLocalScopeForDeclStmt(DS, Scope);
}
return;
@@ -662,9 +662,9 @@
// For any other statement scope will be implicit and as such will be
// interesting only for DeclStmt.
- if (LabelStmt* LS = dyn_cast<LabelStmt>(S))
+ if (LabelStmt *LS = dyn_cast<LabelStmt>(S))
S = LS->getSubStmt();
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S))
addLocalScopeForDeclStmt(DS);
}
@@ -1454,16 +1454,17 @@
return VisitStmt(R, AddStmtChoice::AlwaysAdd);
}
-CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
+CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt *L) {
// Get the block of the labeled statement. Add it to our map.
addStmt(L->getSubStmt());
- CFGBlock* LabelBlock = Block;
+ CFGBlock *LabelBlock = Block;
if (!LabelBlock) // This can happen when the body is empty, i.e.
LabelBlock = createBlock(); // scopes that only contains NullStmts.
- assert(LabelMap.find(L) == LabelMap.end() && "label already in map");
- LabelMap[ L ] = JumpTarget(LabelBlock, ScopePos);
+ assert(LabelMap.find(L->getDecl()) == LabelMap.end() &&
+ "label already in map");
+ LabelMap[L->getDecl()] = JumpTarget(LabelBlock, ScopePos);
// Labels partition blocks, so this is the end of the basic block we were
// processing (L is the block's label). Because this is label (and we have
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 129416f..97dbf0b 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -70,7 +70,7 @@
case Decl::Friend:
case Decl::FriendTemplate:
case Decl::Block:
-
+ case Decl::Label:
assert(0 && "Declaration not should not be in declstmts!");
case Decl::Function: // void X();
case Decl::Record: // struct/union/class X;
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index f782c80..f809c00 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -208,7 +208,7 @@
// emitting them before we evaluate the subexpr.
const Stmt *LastStmt = S.body_back();
while (const LabelStmt *LS = dyn_cast<LabelStmt>(LastStmt)) {
- EmitLabel(*LS);
+ EmitLabel(LS->getDecl());
LastStmt = LS->getSubStmt();
}
@@ -276,24 +276,24 @@
}
CodeGenFunction::JumpDest
-CodeGenFunction::getJumpDestForLabel(const LabelStmt *S) {
- JumpDest &Dest = LabelMap[S];
+CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) {
+ JumpDest &Dest = LabelMap[D];
if (Dest.isValid()) return Dest;
// Create, but don't insert, the new block.
- Dest = JumpDest(createBasicBlock(S->getName()),
+ Dest = JumpDest(createBasicBlock(D->getName()),
EHScopeStack::stable_iterator::invalid(),
NextCleanupDestIndex++);
return Dest;
}
-void CodeGenFunction::EmitLabel(const LabelStmt &S) {
- JumpDest &Dest = LabelMap[&S];
+void CodeGenFunction::EmitLabel(const LabelDecl *D) {
+ JumpDest &Dest = LabelMap[D];
// If we didn't need a forward reference to this label, just go
// ahead and create a destination at the current scope.
if (!Dest.isValid()) {
- Dest = getJumpDestInCurrentScope(S.getName());
+ Dest = getJumpDestInCurrentScope(D->getName());
// Otherwise, we need to give this label a target depth and remove
// it from the branch-fixups list.
@@ -311,7 +311,7 @@
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
- EmitLabel(S);
+ EmitLabel(S.getDecl());
EmitStmt(S.getSubStmt());
}
@@ -327,7 +327,7 @@
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
- if (const LabelStmt *Target = S.getConstantTarget()) {
+ if (const LabelDecl *Target = S.getConstantTarget()) {
EmitBranchThroughCleanup(getJumpDestForLabel(Target));
return;
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index ee8b98c..b316fa8 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -668,7 +668,7 @@
Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, Align, false);
}
-llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) {
+llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
// Make sure that there is a block for the indirect goto.
if (IndirectBranch == 0)
GetIndirectGotoBlock();
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index c497150..adbc223 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -45,6 +45,7 @@
class CXXDestructorDecl;
class CXXTryStmt;
class Decl;
+ class LabelDecl;
class EnumConstantDecl;
class FunctionDecl;
class FunctionProtoType;
@@ -768,7 +769,7 @@
/// The given basic block lies in the current EH scope, but may be a
/// target of a potentially scope-crossing jump; get a stable handle
/// to which we can perform this jump later.
- JumpDest getJumpDestInCurrentScope(const char *Name = 0) {
+ JumpDest getJumpDestInCurrentScope(llvm::StringRef Name = llvm::StringRef()) {
return getJumpDestInCurrentScope(createBasicBlock(Name));
}
@@ -887,7 +888,7 @@
DeclMapTy LocalDeclMap;
/// LabelMap - This keeps track of the LLVM basic block for each C label.
- llvm::DenseMap<const LabelStmt*, JumpDest> LabelMap;
+ llvm::DenseMap<const LabelDecl*, JumpDest> LabelMap;
// BreakContinueStack - This keeps track of where break and continue
// statements should jump to.
@@ -1168,7 +1169,7 @@
/// getBasicBlockForLabel - Return the LLVM basicblock that the specified
/// label maps to.
- JumpDest getJumpDestForLabel(const LabelStmt *S);
+ JumpDest getJumpDestForLabel(const LabelDecl *S);
/// SimplifyForwardingBlocks - If the given basic block is only a branch to
/// another basic block, simplify it. This assumes that no other code could
@@ -1321,7 +1322,7 @@
/// the input field number being accessed.
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
- llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L);
+ llvm::BlockAddress *GetAddrOfLabel(const LabelDecl *L);
llvm::BasicBlock *GetIndirectGotoBlock();
/// EmitNullInitialization - Generate code to set a value of the given type to
@@ -1504,7 +1505,7 @@
/// EmitLabel - Emit the block for the given label. It is legal to call this
/// function even if there is no current insertion point.
- void EmitLabel(const LabelStmt &S); // helper for EmitLabelStmt.
+ void EmitLabel(const LabelDecl *D); // helper for EmitLabelStmt.
void EmitLabelStmt(const LabelStmt &S);
void EmitGotoStmt(const GotoStmt &S);
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index bd6b48a..b73f0e9 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -62,7 +62,7 @@
llvm::SmallVector<Stmt*, 16> Jumps;
llvm::SmallVector<IndirectGotoStmt*, 4> IndirectJumps;
- llvm::SmallVector<LabelStmt*, 4> IndirectJumpTargets;
+ llvm::SmallVector<LabelDecl*, 4> IndirectJumpTargets;
public:
JumpScopeChecker(Stmt *Body, Sema &S);
private:
@@ -71,7 +71,7 @@
void VerifyJumps();
void VerifyIndirectJumps();
void DiagnoseIndirectJump(IndirectGotoStmt *IG, unsigned IGScope,
- LabelStmt *Target, unsigned TargetScope);
+ LabelDecl *Target, unsigned TargetScope);
void CheckJump(Stmt *From, Stmt *To,
SourceLocation DiagLoc, unsigned JumpDiag);
@@ -235,12 +235,12 @@
// order to avoid blowing out the stack.
while (true) {
Stmt *Next;
- if (isa<CaseStmt>(SubStmt))
- Next = cast<CaseStmt>(SubStmt)->getSubStmt();
- else if (isa<DefaultStmt>(SubStmt))
- Next = cast<DefaultStmt>(SubStmt)->getSubStmt();
- else if (isa<LabelStmt>(SubStmt))
- Next = cast<LabelStmt>(SubStmt)->getSubStmt();
+ if (CaseStmt *CS = dyn_cast<CaseStmt>(SubStmt))
+ Next = CS->getSubStmt();
+ else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SubStmt))
+ Next = DS->getSubStmt();
+ else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
+ Next = LS->getSubStmt();
else
break;
@@ -346,15 +346,15 @@
// With a goto,
if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) {
- CheckJump(GS, GS->getLabel(), GS->getGotoLoc(),
+ CheckJump(GS, GS->getLabel()->getStmt(), GS->getGotoLoc(),
diag::err_goto_into_protected_scope);
continue;
}
// We only get indirect gotos here when they have a constant target.
if (IndirectGotoStmt *IGS = dyn_cast<IndirectGotoStmt>(Jump)) {
- LabelStmt *Target = IGS->getConstantTarget();
- CheckJump(IGS, Target, IGS->getGotoLoc(),
+ LabelDecl *Target = IGS->getConstantTarget();
+ CheckJump(IGS, Target->getStmt(), IGS->getGotoLoc(),
diag::err_goto_into_protected_scope);
continue;
}
@@ -424,15 +424,15 @@
// Collect a single representative of every scope containing a
// label whose address was taken somewhere in the function.
// For most code bases, there will be only one such scope.
- llvm::DenseMap<unsigned, LabelStmt*> TargetScopes;
- for (llvm::SmallVectorImpl<LabelStmt*>::iterator
+ llvm::DenseMap<unsigned, LabelDecl*> TargetScopes;
+ for (llvm::SmallVectorImpl<LabelDecl*>::iterator
I = IndirectJumpTargets.begin(), E = IndirectJumpTargets.end();
I != E; ++I) {
- LabelStmt *TheLabel = *I;
- assert(LabelAndGotoScopes.count(TheLabel) &&
+ LabelDecl *TheLabel = *I;
+ assert(LabelAndGotoScopes.count(TheLabel->getStmt()) &&
"Referenced label didn't get added to scopes?");
- unsigned LabelScope = LabelAndGotoScopes[TheLabel];
- LabelStmt *&Target = TargetScopes[LabelScope];
+ unsigned LabelScope = LabelAndGotoScopes[TheLabel->getStmt()];
+ LabelDecl *&Target = TargetScopes[LabelScope];
if (!Target) Target = TheLabel;
}
@@ -445,10 +445,10 @@
// entered, then verify that every jump scope can be trivially
// exitted to reach a scope in S.
llvm::BitVector Reachable(Scopes.size(), false);
- for (llvm::DenseMap<unsigned,LabelStmt*>::iterator
+ for (llvm::DenseMap<unsigned,LabelDecl*>::iterator
TI = TargetScopes.begin(), TE = TargetScopes.end(); TI != TE; ++TI) {
unsigned TargetScope = TI->first;
- LabelStmt *TargetLabel = TI->second;
+ LabelDecl *TargetLabel = TI->second;
Reachable.reset();
@@ -511,12 +511,12 @@
/// Diagnose an indirect jump which is known to cross scopes.
void JumpScopeChecker::DiagnoseIndirectJump(IndirectGotoStmt *Jump,
unsigned JumpScope,
- LabelStmt *Target,
+ LabelDecl *Target,
unsigned TargetScope) {
assert(JumpScope != TargetScope);
S.Diag(Jump->getGotoLoc(), diag::err_indirect_goto_in_protected_scope);
- S.Diag(Target->getIdentLoc(), diag::note_indirect_goto_target);
+ S.Diag(Target->getStmt()->getIdentLoc(), diag::note_indirect_goto_target);
unsigned Common = GetDeepestCommonScope(JumpScope, TargetScope);
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 8fbbeb8..2e7f72f 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -31,6 +31,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/StmtCXX.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
@@ -50,6 +51,53 @@
ErrorTrap.reset();
}
+bool FunctionScopeInfo::checkLabelUse(Stmt *Body, Sema &S) {
+ bool AnyErrors = false;
+ for (llvm::DenseMap<IdentifierInfo*, LabelDecl*>::iterator
+ I = LabelMap.begin(), E = LabelMap.end(); I != E; ++I) {
+ LabelDecl *L = I->second;
+
+ // Verify that we have no forward references left. If so, there was a goto
+ // or address of a label taken, but no definition of it. Label fwd
+ // definitions are indicated with a null substmt.
+ if (L->getStmt() != 0) {
+ if (!L->isUsed())
+ S.Diag(L->getLocation(), diag::warn_unused_label) << L->getDeclName();
+ continue;
+ }
+
+ AnyErrors = true;
+
+ // Emit error.
+ S.Diag(L->getLocation(), diag::err_undeclared_label_use) << L->getDeclName();
+
+ // At this point, we have gotos that use the bogus label. Stitch it into
+ // the function body so that the AST is well formed.
+ if (Body == 0) {
+ // The whole function wasn't parsed correctly.
+ continue;
+ }
+
+ // Otherwise, the body is valid: we want to stitch the label decl into the
+ // function somewhere so that it is properly owned and so that the goto
+ // has a valid target. Do this by creating LabelStmt and adding it to the
+ // end of the outer CompoundStmt.
+ LabelStmt *LS = new (S.Context) LabelStmt(L->getLocation(), L,
+ new (S.Context) NullStmt(L->getLocation()));
+
+ CompoundStmt *Compound = isa<CXXTryStmt>(Body) ?
+ cast<CXXTryStmt>(Body)->getTryBlock() :
+ cast<CompoundStmt>(Body);
+ llvm::SmallVector<Stmt*, 64> Elements(Compound->body_begin(),
+ Compound->body_end());
+ Elements.push_back(LS);
+ Compound->setStmts(S.Context, Elements.data(), Elements.size());
+ }
+ return AnyErrors;
+}
+
+
+
BlockScopeInfo::~BlockScopeInfo() { }
void Sema::ActOnTranslationUnitScope(Scope *S) {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2807e75..bcec9d4 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -5477,46 +5477,7 @@
// Check goto/label use.
FunctionScopeInfo *CurFn = getCurFunction();
- for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
- I = CurFn->LabelMap.begin(), E = CurFn->LabelMap.end(); I != E; ++I) {
- LabelStmt *L = I->second;
-
- // Verify that we have no forward references left. If so, there was a goto
- // or address of a label taken, but no definition of it. Label fwd
- // definitions are indicated with a null substmt.
- if (L->getSubStmt() != 0) {
- if (!L->isUsed())
- Diag(L->getIdentLoc(), diag::warn_unused_label) << L->getName();
- continue;
- }
-
- // Emit error.
- Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
-
- // At this point, we have gotos that use the bogus label. Stitch it into
- // the function body so that they aren't leaked and that the AST is well
- // formed.
- if (Body == 0) {
- // The whole function wasn't parsed correctly.
- continue;
- }
-
- // Otherwise, the body is valid: we want to stitch the label decl into the
- // function somewhere so that it is properly owned and so that the goto
- // has a valid target. Do this by creating a new compound stmt with the
- // label in it.
-
- // Give the label a sub-statement.
- L->setSubStmt(new (Context) NullStmt(L->getIdentLoc()));
-
- CompoundStmt *Compound = isa<CXXTryStmt>(Body) ?
- cast<CXXTryStmt>(Body)->getTryBlock() :
- cast<CompoundStmt>(Body);
- llvm::SmallVector<Stmt*, 64> Elements(Compound->body_begin(),
- Compound->body_end());
- Elements.push_back(L);
- Compound->setStmts(Context, Elements.data(), Elements.size());
- }
+ CurFn->checkLabelUse(Body, *this);
if (Body) {
// C++ constructors that have function-try-blocks can't have return
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0a95607..94dd27d 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -8321,20 +8321,19 @@
}
/// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo".
-ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
- SourceLocation LabLoc,
- IdentifierInfo *LabelII) {
+ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc,
+ IdentifierInfo *LabelII) {
// Look up the record for this label identifier.
- LabelStmt *&LabelDecl = getCurFunction()->LabelMap[LabelII];
+ LabelDecl *&TheDecl = getCurFunction()->LabelMap[LabelII];
// If we haven't seen this label yet, create a forward reference. It
// will be validated and/or cleaned up in ActOnFinishFunctionBody.
- if (LabelDecl == 0)
- LabelDecl = new (Context) LabelStmt(LabLoc, LabelII, 0);
+ if (TheDecl == 0)
+ TheDecl = LabelDecl::Create(Context, CurContext, LabLoc, LabelII);
- LabelDecl->setUsed();
+ TheDecl->setUsed();
// Create the AST node. The address of a label always has type 'void*'.
- return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, LabelDecl,
+ return Owned(new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl,
Context.getPointerType(Context.VoidTy)));
}
@@ -8833,25 +8832,8 @@
BSI->TheDecl->setBody(cast<CompoundStmt>(Body));
- bool Good = true;
// Check goto/label use.
- for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
- I = BSI->LabelMap.begin(), E = BSI->LabelMap.end(); I != E; ++I) {
- LabelStmt *L = I->second;
-
- // Verify that we have no forward references left. If so, there was a goto
- // or address of a label taken, but no definition of it.
- if (L->getSubStmt() != 0) {
- if (!L->isUsed())
- Diag(L->getIdentLoc(), diag::warn_unused_label) << L->getName();
- continue;
- }
-
- // Emit error.
- Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
- Good = false;
- }
- if (!Good) {
+ if (BSI->checkLabelUse(0, *this)) {
PopFunctionOrBlockScope();
return ExprError();
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index e5fd01a..2b323ef 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -255,29 +255,31 @@
SourceLocation ColonLoc, Stmt *SubStmt,
bool HasUnusedAttr) {
// Look up the record for this label identifier.
- LabelStmt *&LabelDecl = getCurFunction()->LabelMap[II];
+ LabelDecl *&TheDecl = getCurFunction()->LabelMap[II];
- // If not forward referenced or defined already, just create a new LabelStmt.
- if (LabelDecl == 0)
- return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt,
- HasUnusedAttr));
+ // If not forward referenced or defined already, create the backing decl.
+ if (TheDecl == 0)
+ TheDecl = LabelDecl::Create(Context, CurContext, IdentLoc, II);
- assert(LabelDecl->getID() == II && "Label mismatch!");
+ assert(TheDecl->getIdentifier() == II && "Label mismatch!");
- // Otherwise, this label was either forward reference or multiply defined. If
- // multiply defined, reject it now.
- if (LabelDecl->getSubStmt()) {
- Diag(IdentLoc, diag::err_redefinition_of_label) << LabelDecl->getID();
- Diag(LabelDecl->getIdentLoc(), diag::note_previous_definition);
+ // If the label was multiply defined, reject it now.
+ if (TheDecl->getStmt()) {
+ Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName();
+ Diag(TheDecl->getLocation(), diag::note_previous_definition);
return Owned(SubStmt);
}
- // Otherwise, this label was forward declared, and we just found its real
- // definition. Fill in the forward definition and return it.
- LabelDecl->setIdentLoc(IdentLoc);
- LabelDecl->setSubStmt(SubStmt);
- LabelDecl->setUnusedAttribute(HasUnusedAttr);
- return Owned(LabelDecl);
+ // Otherwise, things are good. Fill in the declaration and return it.
+ TheDecl->setLocation(IdentLoc);
+
+ // FIXME: Just use Decl ATTRIBUTES!
+ if (HasUnusedAttr)
+ TheDecl->setHasUnusedAttribute();
+ LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt);
+ TheDecl->setStmt(LS);
+ TheDecl->setLocation(IdentLoc);
+ return Owned(LS);
}
StmtResult
@@ -1036,17 +1038,17 @@
StmtResult
Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
IdentifierInfo *LabelII) {
- // Look up the record for this label identifier.
- LabelStmt *&LabelDecl = getCurFunction()->LabelMap[LabelII];
-
getCurFunction()->setHasBranchIntoScope();
+
+ // Look up the record for this label identifier.
+ LabelDecl *&TheDecl = getCurFunction()->LabelMap[LabelII];
// If we haven't seen this label yet, create a forward reference.
- if (LabelDecl == 0)
- LabelDecl = new (Context) LabelStmt(LabelLoc, LabelII, 0);
+ if (TheDecl == 0)
+ TheDecl = LabelDecl::Create(Context, CurContext, LabelLoc, LabelII);
- LabelDecl->setUsed();
- return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc));
+ TheDecl->setUsed();
+ return Owned(new (Context) GotoStmt(TheDecl, GotoLoc, LabelLoc));
}
StmtResult
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index ca5d1c1..cb0d425 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -975,10 +975,9 @@
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildLabelStmt(SourceLocation IdentLoc,
- IdentifierInfo *Id,
- SourceLocation ColonLoc,
- Stmt *SubStmt, bool HasUnusedAttr) {
+ StmtResult RebuildLabelStmt(SourceLocation IdentLoc, IdentifierInfo *Id,
+ SourceLocation ColonLoc, Stmt *SubStmt,
+ bool HasUnusedAttr) {
return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, SubStmt,
HasUnusedAttr);
}
@@ -1028,10 +1027,8 @@
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildDoStmt(SourceLocation DoLoc, Stmt *Body,
- SourceLocation WhileLoc,
- SourceLocation LParenLoc,
- Expr *Cond,
- SourceLocation RParenLoc) {
+ SourceLocation WhileLoc, SourceLocation LParenLoc,
+ Expr *Cond, SourceLocation RParenLoc) {
return getSema().ActOnDoStmt(DoLoc, Body, WhileLoc, LParenLoc,
Cond, RParenLoc);
}
@@ -1040,24 +1037,21 @@
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildForStmt(SourceLocation ForLoc,
- SourceLocation LParenLoc,
- Stmt *Init, Sema::FullExprArg Cond,
- VarDecl *CondVar, Sema::FullExprArg Inc,
- SourceLocation RParenLoc, Stmt *Body) {
+ StmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
+ Stmt *Init, Sema::FullExprArg Cond,
+ VarDecl *CondVar, Sema::FullExprArg Inc,
+ SourceLocation RParenLoc, Stmt *Body) {
return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond,
- CondVar,
- Inc, RParenLoc, Body);
+ CondVar, Inc, RParenLoc, Body);
}
/// \brief Build a new goto statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildGotoStmt(SourceLocation GotoLoc,
- SourceLocation LabelLoc,
- LabelStmt *Label) {
- return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getID());
+ StmtResult RebuildGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
+ LabelDecl *Label) {
+ return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getIdentifier());
}
/// \brief Build a new indirect goto statement.
@@ -1065,8 +1059,8 @@
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc,
- SourceLocation StarLoc,
- Expr *Target) {
+ SourceLocation StarLoc,
+ Expr *Target) {
return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, Target);
}
@@ -1074,9 +1068,7 @@
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildReturnStmt(SourceLocation ReturnLoc,
- Expr *Result) {
-
+ StmtResult RebuildReturnStmt(SourceLocation ReturnLoc, Expr *Result) {
return getSema().ActOnReturnStmt(ReturnLoc, Result);
}
@@ -1550,9 +1542,8 @@
/// rather than attempting to map the label statement itself.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildAddrLabelExpr(SourceLocation AmpAmpLoc,
- SourceLocation LabelLoc,
- LabelStmt *Label) {
- return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc, Label->getID());
+ SourceLocation LabelLoc, LabelDecl *Label) {
+ return getSema().ActOnAddrLabel(AmpAmpLoc, LabelLoc,Label->getIdentifier());
}
/// \brief Build a new GNU statement expression.
@@ -4522,8 +4513,10 @@
// FIXME: Pass the real colon location in.
SourceLocation ColonLoc = SemaRef.PP.getLocForEndOfToken(S->getIdentLoc());
- return getDerived().RebuildLabelStmt(S->getIdentLoc(), S->getID(), ColonLoc,
- SubStmt.get(), S->HasUnusedAttribute());
+ return getDerived().RebuildLabelStmt(S->getIdentLoc(),
+ S->getDecl()->getIdentifier(), ColonLoc,
+ SubStmt.get(),
+ S->getDecl()->hasUnusedAttribute());
}
template<typename Derived>
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index fcf09b7..83f8a84 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -4814,72 +4814,6 @@
SwitchCaseStmts.clear();
}
-/// \brief Record that the given label statement has been
-/// deserialized and has the given ID.
-void ASTReader::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);
-
- // 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
-/// 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 ASTReader::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));
- }
-}
-
-/// \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 ASTReader::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));
- }
-}
-
void ASTReader::FinishedDeserializing() {
assert(NumCurrentElementsDeserializing &&
"FinishedDeserializing not paired with StartedDeserializing");
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 279d081..27e7718 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -84,6 +84,7 @@
void VisitDecl(Decl *D);
void VisitTranslationUnitDecl(TranslationUnitDecl *TU);
void VisitNamedDecl(NamedDecl *ND);
+ void VisitLabelDecl(LabelDecl *LD);
void VisitNamespaceDecl(NamespaceDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
@@ -722,6 +723,12 @@
D->setHasBraces(Record[Idx++]);
}
+void ASTDeclReader::VisitLabelDecl(LabelDecl *D) {
+ VisitNamedDecl(D);
+ if (Record[Idx++]) D->setHasUnusedAttribute();
+}
+
+
void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
VisitNamedDecl(D);
D->IsInline = Record[Idx++];
@@ -1418,6 +1425,9 @@
(LinkageSpecDecl::LanguageIDs)0,
false);
break;
+ case DECL_LABEL:
+ D = LabelDecl::Create(*Context, 0, SourceLocation(), 0);
+ break;
case DECL_NAMESPACE:
D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0);
break;
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 864c042..bd59737 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -245,12 +245,11 @@
void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
- S->setID(Reader.GetIdentifierInfo(Record, Idx));
+ LabelDecl *LD = cast<LabelDecl>(Reader.GetDecl(Record[Idx++]));
+ LD->setStmt(S);
+ S->setDecl(LD);
S->setSubStmt(Reader.ReadSubStmt());
S->setIdentLoc(ReadSourceLocation(Record, Idx));
- S->setUsed(Record[Idx++]);
- S->setUnusedAttribute(Record[Idx++]);
- Reader.RecordLabelStmt(S, Record[Idx++]);
}
void ASTStmtReader::VisitIfStmt(IfStmt *S) {
@@ -319,7 +318,7 @@
void ASTStmtReader::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
- Reader.SetLabelOf(S, Record[Idx++]);
+ S->setLabel(cast<LabelDecl>(Reader.GetDecl(Record[Idx++])));
S->setGotoLoc(ReadSourceLocation(Record, Idx));
S->setLabelLoc(ReadSourceLocation(Record, Idx));
}
@@ -759,7 +758,7 @@
VisitExpr(E);
E->setAmpAmpLoc(ReadSourceLocation(Record, Idx));
E->setLabelLoc(ReadSourceLocation(Record, Idx));
- Reader.SetLabelOf(E, Record[Idx++]);
+ E->setLabel(cast<LabelDecl>(Reader.GetDecl(Record[Idx++])));
}
void ASTStmtReader::VisitStmtExpr(StmtExpr *E) {
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 17ee85a..dd43e1a 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -47,6 +47,7 @@
void VisitDecl(Decl *D);
void VisitTranslationUnitDecl(TranslationUnitDecl *D);
void VisitNamedDecl(NamedDecl *D);
+ void VisitLabelDecl(LabelDecl *LD);
void VisitNamespaceDecl(NamespaceDecl *D);
void VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
@@ -651,6 +652,13 @@
Code = serialization::DECL_LINKAGE_SPEC;
}
+void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) {
+ VisitNamedDecl(D);
+ Record.push_back(D->hasUnusedAttribute());
+ Code = serialization::DECL_LABEL;
+}
+
+
void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
VisitNamedDecl(D);
Record.push_back(D->isInline());
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 8a90ef1..b043f2e 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -217,12 +217,9 @@
void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
- Writer.AddIdentifierRef(S->getID(), Record);
+ Writer.AddDeclRef(S->getDecl(), Record);
Writer.AddStmt(S->getSubStmt());
Writer.AddSourceLocation(S->getIdentLoc(), Record);
- Record.push_back(S->isUsed());
- Record.push_back(S->HasUnusedAttribute());
- Record.push_back(Writer.GetLabelID(S));
Code = serialization::STMT_LABEL;
}
@@ -284,7 +281,7 @@
void ASTStmtWriter::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
- Record.push_back(Writer.GetLabelID(S->getLabel()));
+ Writer.AddDeclRef(S->getLabel(), Record);
Writer.AddSourceLocation(S->getGotoLoc(), Record);
Writer.AddSourceLocation(S->getLabelLoc(), Record);
Code = serialization::STMT_GOTO;
@@ -722,7 +719,7 @@
VisitExpr(E);
Writer.AddSourceLocation(E->getAmpAmpLoc(), Record);
Writer.AddSourceLocation(E->getLabelLoc(), Record);
- Record.push_back(Writer.GetLabelID(E->getLabel()));
+ Writer.AddDeclRef(E->getLabel(), Record);
Code = serialization::EXPR_ADDR_LABEL;
}
@@ -1359,18 +1356,6 @@
SwitchCaseIDs.clear();
}
-/// \brief Retrieve the ID for the given label statement, which may
-/// or may not have been emitted yet.
-unsigned ASTWriter::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;
-}
-
/// \brief Write the given substatement or subexpression to the
/// bitstream.
void ASTWriter::WriteSubStmt(Stmt *S) {
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index 99e120d..50b1e37 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -1344,7 +1344,7 @@
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
-void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder& builder) {
+void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
const GRState *state = builder.getState();
SVal V = state->getSVal(builder.getTarget());
@@ -1359,16 +1359,16 @@
typedef IndirectGotoNodeBuilder::iterator iterator;
if (isa<loc::GotoLabel>(V)) {
- const LabelStmt* L = cast<loc::GotoLabel>(V).getLabel();
+ const LabelDecl *L = cast<loc::GotoLabel>(V).getLabel();
- for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) {
+ for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) {
if (I.getLabel() == L) {
builder.generateNode(I, state);
return;
}
}
- assert (false && "No block with label.");
+ assert(false && "No block with label.");
return;
}
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index cc866d0..4614e34 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -350,7 +350,7 @@
os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
break;
case loc::GotoLabelKind:
- os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getID()->getName();
+ os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName();
break;
case loc::MemRegionKind:
os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
diff --git a/test/CXX/stmt.stmt/stmt.label/p1.cpp b/test/CXX/stmt.stmt/stmt.label/p1.cpp
index f2ace35..90367f8 100644
--- a/test/CXX/stmt.stmt/stmt.label/p1.cpp
+++ b/test/CXX/stmt.stmt/stmt.label/p1.cpp
@@ -9,7 +9,7 @@
x = 1;
goto label2; // expected-error{{use of undeclared label 'label2'}}
-label1: // expected-error{{redefinition of label ''label1''}}
+label1: // expected-error{{redefinition of label 'label1'}}
x = 2;
}
diff --git a/test/Sema/warn-unused-label.c b/test/Sema/warn-unused-label.c
index 1634460..03be7da 100644
--- a/test/Sema/warn-unused-label.c
+++ b/test/Sema/warn-unused-label.c
@@ -4,8 +4,8 @@
a:
goto a;
b: // expected-warning{{unused}}
- c: __attribute__((unused));
- d: __attribute__((noreturn)); // expected-warning {{The only valid attribute for labels is 'unused'}}
+ c: __attribute__((unused)); // expected-warning {{unused label 'c'}}
+ d: __attribute__((noreturn)); // expected-warning {{the only valid attribute for labels is 'unused'}}
goto d;
return;
}
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 8809100..bcd6397 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -1529,14 +1529,14 @@
class LabelRefVisit : public VisitorJob {
public:
- LabelRefVisit(LabelStmt *LS, SourceLocation labelLoc, CXCursor parent)
- : VisitorJob(parent, VisitorJob::LabelRefVisitKind, LS,
+ LabelRefVisit(LabelDecl *LD, SourceLocation labelLoc, CXCursor parent)
+ : VisitorJob(parent, VisitorJob::LabelRefVisitKind, LD,
labelLoc.getPtrEncoding()) {}
static bool classof(const VisitorJob *VJ) {
return VJ->getKind() == VisitorJob::LabelRefVisitKind;
}
- LabelStmt *get() const { return static_cast<LabelStmt*>(data[0]); }
+ LabelDecl *get() const { return static_cast<LabelDecl*>(data[0]); }
SourceLocation getLoc() const {
return SourceLocation::getFromPtrEncoding(data[1]); }
};
@@ -1985,8 +1985,8 @@
continue;
}
case VisitorJob::LabelRefVisitKind: {
- LabelStmt *LS = cast<LabelRefVisit>(&LI)->get();
- if (Visit(MakeCursorLabelRef(LS,
+ LabelDecl *LS = cast<LabelRefVisit>(&LI)->get();
+ if (Visit(MakeCursorLabelRef(LS->getStmt(),
cast<LabelRefVisit>(&LI)->getLoc(),
TU)))
return true;
@@ -2851,7 +2851,7 @@
LabelStmt *Label = getCursorLabelRef(C).first;
assert(Label && "Missing label");
- return createCXString(Label->getID()->getName());
+ return createCXString(Label->getName());
}
case CXCursor_OverloadedDeclRef: {
@@ -2885,7 +2885,7 @@
if (clang_isStatement(C.kind)) {
Stmt *S = getCursorStmt(C);
if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
- return createCXString(Label->getID()->getName());
+ return createCXString(Label->getName());
return createCXString("");
}
@@ -3569,7 +3569,7 @@
if (clang_isStatement(C.kind)) {
Stmt *S = getCursorStmt(C);
if (GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S))
- return MakeCXCursor(Goto->getLabel(), getCursorDecl(C), tu);
+ return MakeCXCursor(Goto->getLabel()->getStmt(), getCursorDecl(C), tu);
return clang_getNullCursor();
}
@@ -3676,6 +3676,7 @@
case Decl::FileScopeAsm:
case Decl::StaticAssert:
case Decl::Block:
+ case Decl::Label: // FIXME: Is this right??
return C;
// Declaration kinds that don't make any sense here, but are