diff options
-rw-r--r-- | include/clang/AST/Stmt.h | 15 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 10 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 7 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 1 | ||||
-rw-r--r-- | test/Sema/warn-unused-label.c | 3 |
9 files changed, 54 insertions, 15 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 0bb257b2e0..508bedacd7 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -562,10 +562,13 @@ class LabelStmt : public Stmt { Stmt *SubStmt; SourceLocation IdentLoc; bool Used : 1; + bool HasUnusedAttr : 1; public: - LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt) + LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt, + bool hasUnusedAttr = false) : Stmt(LabelStmtClass), Label(label), - SubStmt(substmt), IdentLoc(IL), Used(false) {} + SubStmt(substmt), IdentLoc(IL), Used(false), + HasUnusedAttr(hasUnusedAttr) {} // \brief Build an empty label statement. explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } @@ -580,10 +583,14 @@ public: void setSubStmt(Stmt *SS) { SubStmt = SS; } /// \brief Whether this label was used. - /// FIXME: Check "used" attribute (requires storing label attributes). - bool isUsed() const { return Used; } + bool isUsed(bool CheckUnusedAttr = true) const { + return Used || (CheckUnusedAttr && HasUnusedAttr); + } void setUsed(bool U = true) { Used = U; } + bool HasUnusedAttribute() const { return HasUnusedAttr; } + void setUnusedAttribute(bool U) { HasUnusedAttr = U; } + virtual SourceRange getSourceRange() const { return SourceRange(IdentLoc, SubStmt->getLocEnd()); } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 92a2c1c859..9a2576208f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -962,6 +962,8 @@ def err_regparm_mismatch : Error<"function declared with with regparm(%0) " "attribute was previously declared %plural{0:without the regparm|1:" "with the regparm(1)|2:with the regparm(2)|3:with the regparm(3)|:with the" "regparm}1 attribute">; +def warn_label_attribute_not_unused : Warning< + "The only valid attribute for labels is 'unused'">; def warn_impcast_vector_scalar : Warning< "implicit conversion turns vector to scalar: %0 to %1">, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 5d8ead37dc..dcbf3dc2ca 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1540,10 +1540,12 @@ public: StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope); - StmtResult ActOnLabelStmt(SourceLocation IdentLoc, - IdentifierInfo *II, - SourceLocation ColonLoc, - Stmt *SubStmt); + StmtResult ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, + SourceLocation ColonLoc, Stmt *SubStmt, + const AttributeList *Attr); + StmtResult ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, + SourceLocation ColonLoc, Stmt *SubStmt, + bool HasUnusedAttr); StmtResult ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, Stmt *ThenVal, diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 5ebee67b7a..d4523d226a 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -241,10 +241,9 @@ StmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { if (SubStmt.isInvalid()) SubStmt = Actions.ActOnNullStmt(ColonLoc); - // FIXME: use attributes? return Actions.ActOnLabelStmt(IdentTok.getLocation(), IdentTok.getIdentifierInfo(), - ColonLoc, SubStmt.get()); + ColonLoc, SubStmt.get(), AttrList.take()); } /// ParseCaseStatement diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 24489544e0..7acadc541c 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -227,13 +227,35 @@ Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, StmtResult Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, - SourceLocation ColonLoc, Stmt *SubStmt) { + SourceLocation ColonLoc, Stmt *SubStmt, + const AttributeList *Attr) { + // According to GCC docs, "the only attribute that makes sense after a label + // is 'unused'". + bool HasUnusedAttr = false; + llvm::OwningPtr<const AttributeList> AttrList(Attr); + for (const AttributeList* a = AttrList.get(); a; a = a->getNext()) { + if (a->getKind() == AttributeList::AT_unused) { + HasUnusedAttr = true; + } else { + Diag(a->getLoc(), diag::warn_label_attribute_not_unused); + a->setInvalid(true); + } + } + + return ActOnLabelStmt(IdentLoc, II, ColonLoc, SubStmt, HasUnusedAttr); +} + +StmtResult +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]; // If not forward referenced or defined already, just create a new LabelStmt. if (LabelDecl == 0) - return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt)); + return Owned(LabelDecl = new (Context) LabelStmt(IdentLoc, II, SubStmt, + HasUnusedAttr)); assert(LabelDecl->getID() == II && "Label mismatch!"); @@ -249,6 +271,7 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, // definition. Fill in the forward definition and return it. LabelDecl->setIdentLoc(IdentLoc); LabelDecl->setSubStmt(SubStmt); + LabelDecl->setUnusedAttribute(HasUnusedAttr); return Owned(LabelDecl); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index a865348e49..71492254c6 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -758,8 +758,9 @@ public: StmtResult RebuildLabelStmt(SourceLocation IdentLoc, IdentifierInfo *Id, SourceLocation ColonLoc, - Stmt *SubStmt) { - return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, SubStmt); + Stmt *SubStmt, bool HasUnusedAttr) { + return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, SubStmt, + HasUnusedAttr); } /// \brief Build a new "if" statement. @@ -3562,7 +3563,7 @@ 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()); + SubStmt.get(), S->HasUnusedAttribute()); } template<typename Derived> diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 7b0845d5e7..ab2bba7283 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -220,6 +220,7 @@ void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { S->setSubStmt(Reader.ReadSubStmt()); S->setIdentLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); S->setUsed(Record[Idx++]); + S->setUnusedAttribute(Record[Idx++]); Reader.RecordLabelStmt(S, Record[Idx++]); } diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index edd8002d47..3905ad6896 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -214,6 +214,7 @@ void ASTStmtWriter::VisitLabelStmt(LabelStmt *S) { 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; } diff --git a/test/Sema/warn-unused-label.c b/test/Sema/warn-unused-label.c index b5979be264..163446002e 100644 --- a/test/Sema/warn-unused-label.c +++ b/test/Sema/warn-unused-label.c @@ -4,5 +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'}} + goto d; return; } |