aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Stmt.h15
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Sema/Sema.h10
-rw-r--r--lib/Parse/ParseStmt.cpp3
-rw-r--r--lib/Sema/SemaStmt.cpp27
-rw-r--r--lib/Sema/TreeTransform.h7
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp1
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp1
-rw-r--r--test/Sema/warn-unused-label.c3
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;
}