summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/Attr.td5
-rw-r--r--clang/lib/Sema/SemaDecl.cpp4
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp14
-rw-r--r--clang/test/SemaCXX/warn-unused-attribute.cpp20
4 files changed, 41 insertions, 2 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 8c820a0cf4e..eea99eb5351 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -749,6 +749,11 @@ def VecReturn : InheritableAttr {
let Subjects = [CXXRecord];
}
+def WarnUnused : InheritableAttr {
+ let Spellings = [GNU<"warn_unused">, CXX11<"gnu", "warn_unused">];
+ let Subjects = [Record];
+}
+
def WarnUnusedResult : InheritableAttr {
let Spellings = [GNU<"warn_unused_result">,
CXX11<"clang", "warn_unused_result">,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2291fc208fb..53303e75d37 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1320,7 +1320,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
- if (!RD->hasTrivialDestructor())
+ if (!RD->hasTrivialDestructor() && !RD->hasAttr<WarnUnusedAttr>())
return false;
if (const Expr *Init = VD->getInit()) {
@@ -1330,7 +1330,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
CXXConstructorDecl *CD = Construct->getConstructor();
- if (!CD->isTrivial())
+ if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>())
return false;
}
}
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index ef401c3a4da..a3e05e69d2a 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -2668,6 +2668,17 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
+static void handleWarnUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ // Check the attribute arguments.
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
+ RD->addAttr(::new (S.Context) WarnUnusedAttr(Attr.getRange(), S.Context));
+ else
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -4892,6 +4903,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_TypeVisibility:
handleVisibilityAttr(S, D, Attr, true);
break;
+ case AttributeList::AT_WarnUnused:
+ handleWarnUnusedAttr(S, D, Attr);
+ break;
case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
break;
case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break;
diff --git a/clang/test/SemaCXX/warn-unused-attribute.cpp b/clang/test/SemaCXX/warn-unused-attribute.cpp
new file mode 100644
index 00000000000..72f96eea0b3
--- /dev/null
+++ b/clang/test/SemaCXX/warn-unused-attribute.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -verify %s
+struct __attribute__((warn_unused)) Test
+{
+ Test();
+ ~Test();
+ void use();
+};
+
+struct TestNormal
+{
+ TestNormal();
+};
+
+int main()
+{
+ Test unused; // expected-warning {{unused variable 'unused'}}
+ Test used;
+ TestNormal normal;
+ used.use();
+}
OpenPOWER on IntegriCloud