diff options
| -rw-r--r-- | clang/include/clang/Basic/Attr.td | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 14 | ||||
| -rw-r--r-- | clang/test/SemaCXX/warn-unused-attribute.cpp | 20 |
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(); +} |

