class DependentFunctionTemplateSpecializationInfo;
class TypeLoc;
class UnresolvedSetImpl;
+class LabelStmt;
/// \brief A container of type source information.
///
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;
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;
/// 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) {}
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;
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
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
StmtBitfields StmtBits;
CompoundStmtBitfields CompoundStmtBits;
- LabelStmtBitfields LabelStmtBits;
ExprBitfields ExprBits;
CastExprBitfields CastExprBits;
CallExprBitfields CallExprBits;
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());
}
/// 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; }
/// 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();
}
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>;
"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">,
"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">;
class BlockDecl;
class IdentifierInfo;
-class LabelStmt;
+class LabelDecl;
class ReturnStmt;
class Scope;
class SwitchStmt;
/// \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.
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();
/// 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,
class CXXBaseSpecifier;
class CXXCtorInitializer;
class GotoStmt;
-class LabelStmt;
class MacroDefinition;
class NamedDecl;
class Preprocessor;
/// 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;
/// \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
class CXXCtorInitializer;
class FPOptions;
class HeaderSearch;
-class LabelStmt;
class MacroDefinition;
class MemorizeStatCalls;
class OpenCLOptions;
/// \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;
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; }
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;
}
};
return loc::MemRegionVal(R);
}
- Loc makeLoc(const AddrLabelExpr* E) {
+ Loc makeLoc(const AddrLabelExpr *E) {
return loc::GotoLabel(E->getLabel());
}
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) {
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);
case ObjCMethod:
case ObjCProperty:
return IDNS_Ordinary;
-
+ case Label:
+ return IDNS_Label;
case IndirectField:
return IDNS_Ordinary | IDNS_Member;
}
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
}
// IndirectGotoStmt
-LabelStmt *IndirectGotoStmt::getConstantTarget() {
+LabelDecl *IndirectGotoStmt::getConstantTarget() {
if (AddrLabelExpr *E =
dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts()))
return E->getLabel();
void StmtProfiler::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
- VisitName(S->getID());
+ VisitDecl(S->getDecl());
}
void StmtProfiler::VisitIfStmt(IfStmt *S) {
void StmtProfiler::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
- VisitName(S->getLabel()->getID());
+ VisitDecl(S->getLabel());
}
void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
VisitExpr(S);
- VisitName(S->getLabel()->getID());
+ VisitDecl(S->getLabel());
}
void StmtProfiler::VisitStmtExpr(StmtExpr *S) {
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
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;
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;
// 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);
}
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
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;
// 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();
}
}
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.
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
- EmitLabel(S);
+ EmitLabel(S.getDecl());
EmitStmt(S.getSubStmt());
}
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
- if (const LabelStmt *Target = S.getConstantTarget()) {
+ if (const LabelDecl *Target = S.getConstantTarget()) {
EmitBranchThroughCleanup(getJumpDestForLabel(Target));
return;
}
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();
class CXXDestructorDecl;
class CXXTryStmt;
class Decl;
+ class LabelDecl;
class EnumConstantDecl;
class FunctionDecl;
class FunctionProtoType;
/// 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));
}
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.
/// 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
/// 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
/// 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);
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:
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);
// 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;
// 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;
}
// 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;
}
// 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();
/// 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);
#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"
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) {
// 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
}
/// 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)));
}
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();
}
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
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
///
/// 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);
}
/// 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);
}
///
/// 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.
/// 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);
}
///
/// 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);
}
/// 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.
// 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>
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");
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);
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++];
(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;
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) {
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));
}
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) {
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);
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());
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;
}
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;
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;
}
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) {
/// 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());
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;
}
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();
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;
}
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;
}
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]); }
};
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;
LabelStmt *Label = getCursorLabelRef(C).first;
assert(Label && "Missing label");
- return createCXString(Label->getID()->getName());
+ return createCXString(Label->getName());
}
case CXCursor_OverloadedDeclRef: {
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("");
}
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();
}
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