diff options
39 files changed, 294 insertions, 384 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index cba71ae8cd6..e0ffa627ac2 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -36,6 +36,7 @@ class FunctionTemplateSpecializationInfo; class DependentFunctionTemplateSpecializationInfo; class TypeLoc; class UnresolvedSetImpl; +class LabelStmt; /// \brief A container of type source information. /// @@ -294,6 +295,36 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 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/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 3e92c4e6511..1407dadd16c 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -324,7 +324,7 @@ public: 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/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index c09394d9c04..b5724a64754 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2641,9 +2641,9 @@ public: /// 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 @@ public: 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/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 8ddd5875ce4..667b8408892 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1088,6 +1088,11 @@ DEF_TRAVERSE_DECL(NamespaceAliasDecl, { 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/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 1254926facd..7ede9ce323f 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -130,14 +130,6 @@ protected: 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 @@ protected: StmtBitfields StmtBits; CompoundStmtBitfields CompoundStmtBits; - LabelStmtBitfields LabelStmtBits; ExprBitfields ExprBits; CastExprBitfields CastExprBits; CallExprBitfields CallExprBits; @@ -633,40 +624,31 @@ public: 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 @@ public: /// 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 @@ public: /// 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/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index f6c31f4877d..2ec7427cf75 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -15,6 +15,7 @@ def Named : Decl<1>; 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/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index eb8bf590c34..b815426f6c4 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1095,7 +1095,7 @@ def err_regparm_mismatch : Error<"function declared with with regparm(%0) " "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 @@ def warn_missing_braces : Warning< "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/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index edd1432d8e7..c9d38715ec8 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -23,7 +23,7 @@ namespace clang { class BlockDecl; class IdentifierInfo; -class LabelStmt; +class LabelDecl; class ReturnStmt; class Scope; class SwitchStmt; @@ -52,10 +52,10 @@ public: /// \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 @@ public: 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/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 391438248e5..d1998c29a3a 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -697,7 +697,9 @@ namespace clang { /// 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/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 94bfd163530..002f6be4102 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -56,7 +56,6 @@ class NestedNameSpecifier; class CXXBaseSpecifier; class CXXCtorInitializer; class GotoStmt; -class LabelStmt; class MacroDefinition; class NamedDecl; class Preprocessor; @@ -646,22 +645,6 @@ private: /// 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 @@ public: /// \brief Retrieve the switch-case statement with the given ID. SwitchCase *getSwitchCaseWithID(unsigned ID); - /// \brief Record that the given label statement has been - /// deserialized and has the given ID. - void RecordLabelStmt(LabelStmt *S, unsigned ID); - 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/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index f9a49973e14..d5f622a3405 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -44,7 +44,6 @@ class CXXBaseSpecifier; class CXXCtorInitializer; class FPOptions; class HeaderSearch; -class LabelStmt; class MacroDefinition; class MemorizeStatCalls; class OpenCLOptions; @@ -261,9 +260,6 @@ private: /// \brief Mapping from SwitchCase statements to IDs. std::map<SwitchCase *, unsigned> SwitchCaseIDs; - /// \brief Mapping from LabelStmt statements to IDs. - std::map<LabelStmt *, unsigned> LabelIDs; - /// \brief The number of statements written to the AST file. unsigned NumStatements; @@ -553,10 +549,6 @@ public: 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/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index d879ea13e71..800e63a4cde 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -331,11 +331,11 @@ public: 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/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 9c187117425..e7b39448ac5 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -238,7 +238,7 @@ public: return loc::MemRegionVal(R); } - Loc makeLoc(const AddrLabelExpr* E) { + Loc makeLoc(const AddrLabelExpr *E) { return loc::GotoLabel(E->getLabel()); } diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 1d1cd0b8f91..0d430794e76 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -432,15 +432,14 @@ enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind, ObjCPropRefKind }; 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/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index fded8ff38c1..441444da9e5 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2182,6 +2182,12 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { 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/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 110de64d8cd..dfc5a6ae5d3 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -269,7 +269,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCMethod: case ObjCProperty: return IDNS_Ordinary; - + case Label: + return IDNS_Label; case IndirectField: return IDNS_Ordinary | IDNS_Member; diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 66182957d68..7e73f02e67e 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -161,7 +161,7 @@ void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { } 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 @@ void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) { } // IndirectGotoStmt -LabelStmt *IndirectGotoStmt::getConstantTarget() { +LabelDecl *IndirectGotoStmt::getConstantTarget() { if (AddrLabelExpr *E = dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts())) return E->getLabel(); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index b96ffe8a48e..2ffb807abcd 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -101,7 +101,7 @@ void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) { void StmtProfiler::VisitLabelStmt(LabelStmt *S) { VisitStmt(S); - VisitName(S->getID()); + VisitDecl(S->getDecl()); } void StmtProfiler::VisitIfStmt(IfStmt *S) { @@ -129,7 +129,7 @@ void StmtProfiler::VisitForStmt(ForStmt *S) { 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::VisitConditionalOperator(ConditionalOperator *S) { void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) { VisitExpr(S); - VisitName(S->getLabel()->getID()); + VisitDecl(S->getLabel()); } void StmtProfiler::VisitStmtExpr(StmtExpr *S) { diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index d46b7e7830e..6da47844052 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -242,7 +242,7 @@ class CFGBuilder { 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 @@ class CFGBuilder { 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 @@ void CFGBuilder::addLocalScopeForStmt(Stmt* S) { 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 @@ void CFGBuilder::addLocalScopeForStmt(Stmt* S) { // 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 @@ CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { 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/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 129416fa07f..97dbf0ba316 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -70,7 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { 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/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index f782c8004a1..f809c009ce1 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -208,7 +208,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, // 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 @@ void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) { } 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::EmitLabel(const LabelStmt &S) { void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { - EmitLabel(S); + EmitLabel(S.getDecl()); EmitStmt(S.getSubStmt()); } @@ -327,7 +327,7 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) { 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/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ee8b98cdd49..b316fa86f1e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -668,7 +668,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { 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/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index c4971506c50..adbc223afc6 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -45,6 +45,7 @@ namespace clang { class CXXDestructorDecl; class CXXTryStmt; class Decl; + class LabelDecl; class EnumConstantDecl; class FunctionDecl; class FunctionProtoType; @@ -768,7 +769,7 @@ public: /// 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 @@ private: 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 @@ public: /// 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 @@ public: /// 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 @@ public: /// 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/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index bd6b48a30ff..b73f0e9f145 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -62,7 +62,7 @@ class JumpScopeChecker { 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 @@ 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); @@ -235,12 +235,12 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // 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 @@ void JumpScopeChecker::VerifyJumps() { // 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 @@ void JumpScopeChecker::VerifyIndirectJumps() { // 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 @@ void JumpScopeChecker::VerifyIndirectJumps() { // 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 @@ void JumpScopeChecker::VerifyIndirectJumps() { /// 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/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 8fbbeb85e3e..2e7f72f81c3 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/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 @@ void FunctionScopeInfo::Clear() { 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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2807e759b56..bcec9d48393 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5477,46 +5477,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // 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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0a956079750..94dd27d0c22 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -8321,20 +8321,19 @@ ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, } /// 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 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, 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/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index e5fd01ab707..2b323ef4b44 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -255,29 +255,31 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, 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 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, 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/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index ca5d1c1ea0f..cb0d4250fca 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -975,10 +975,9 @@ public: /// /// 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 @@ public: /// 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 @@ public: /// /// 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 @@ public: /// 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 @@ public: /// /// 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 @@ public: /// 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 @@ TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { // 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/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index fcf09b7bd56..83f8a84d664 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4814,72 +4814,6 @@ void ASTReader::ClearSwitchCaseIDs() { 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/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 279d081098f..27e771804c9 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -84,6 +84,7 @@ namespace clang { 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 @@ void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *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++]; @@ -1418,6 +1425,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { (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/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 864c04283b0..bd597378255 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -245,12 +245,11 @@ void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) { 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::VisitForStmt(ForStmt *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)); } @@ -759,7 +758,7 @@ void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { 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/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 17ee85ad279..dd43e1a05db 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -47,6 +47,7 @@ namespace clang { 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 @@ void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *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()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 8a90ef16c30..b043f2ee2c2 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -217,12 +217,9 @@ void ASTStmtWriter::VisitDefaultStmt(DefaultStmt *S) { 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::VisitForStmt(ForStmt *S) { 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 @@ void ASTStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) { 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 @@ void ASTWriter::ClearSwitchCaseIDs() { 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/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 99e120d303a..50b1e37c132 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -1344,7 +1344,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, /// 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 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder& builder) { 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/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp index cc866d0127d..4614e349dec 100644 --- a/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -350,7 +350,7 @@ void Loc::dumpToStream(llvm::raw_ostream& os) const { 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/clang/test/CXX/stmt.stmt/stmt.label/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.label/p1.cpp index f2ace35584c..90367f82956 100644 --- a/clang/test/CXX/stmt.stmt/stmt.label/p1.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.label/p1.cpp @@ -9,7 +9,7 @@ label1: // expected-note{{previous definition is here}} 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/clang/test/Sema/warn-unused-label.c b/clang/test/Sema/warn-unused-label.c index 163446002e6..03be7da2fc9 100644 --- a/clang/test/Sema/warn-unused-label.c +++ b/clang/test/Sema/warn-unused-label.c @@ -4,8 +4,8 @@ void f() { 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/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 88091006a81..bcd6397a584 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1529,14 +1529,14 @@ public: 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 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) { 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 @@ CXString clang_getCursorSpelling(CXCursor C) { 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 @@ CXString clang_getCursorSpelling(CXCursor C) { 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 @@ CXCursor clang_getCursorReferenced(CXCursor C) { 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 @@ CXCursor clang_getCursorDefinition(CXCursor C) { 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 |