Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -186,6 +186,8 @@ the compilation of the foreign language sources (e.g. Swift). - The ``__has_attribute``, ``__has_c_attribute`` and ``__has_cpp_attribute`` preprocessor operators now return 1 also for attributes defined by plugins. +- In C++, the ``__attribute__((warn_unused))`` can now also be used on individual + constructors, Improvements to Clang's diagnostics ----------------------------------- Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -471,8 +471,12 @@ def SubRuleForCXXMethod : AttrSubjectMatcherSubRule<"is_member", [CXXMethod]> { let LangOpts = [CPlusPlus]; } +def SubRuleForCXXConstructor : + AttrSubjectMatcherSubRule<"constructor", [CXXConstructor]> { + let LangOpts = [CPlusPlus]; +} def SubjectMatcherForFunction : AttrSubjectMatcherRule<"function", [Function], [ - SubRuleForCXXMethod + SubRuleForCXXMethod, SubRuleForCXXConstructor ]>; // hasType is abstract, it should be used with one of the sub-rules. def SubjectMatcherForType : AttrSubjectMatcherRule<"hasType", [], [ @@ -2989,7 +2993,7 @@ def WarnUnused : InheritableAttr { let Spellings = [GCC<"warn_unused">]; - let Subjects = SubjectList<[Record]>; + let Subjects = SubjectList<[Record, CXXConstructor]>; let Documentation = [Undocumented]; let SimpleHandler = 1; } Index: clang/include/clang/Basic/DeclNodes.td =================================================================== --- clang/include/clang/Basic/DeclNodes.td +++ clang/include/clang/Basic/DeclNodes.td @@ -51,7 +51,7 @@ def Function : DeclNode, DeclContext; def CXXDeductionGuide : DeclNode; def CXXMethod : DeclNode; - def CXXConstructor : DeclNode; + def CXXConstructor : DeclNode; def CXXDestructor : DeclNode; def CXXConversion : DeclNode; def Var : DeclNode; Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -2769,7 +2769,8 @@ if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) { const auto *WarnURAttr = Type->getAttr(); if (Type->hasAttr() || - (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) { + (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) || + cast(this)->getConstructor()->hasAttr()) { WarnE = this; Loc = getBeginLoc(); R1 = getSourceRange(); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -2051,15 +2051,15 @@ return false; if (const CXXRecordDecl *RD = dyn_cast(Tag)) { - if (!RD->hasTrivialDestructor() && !RD->hasAttr()) - return false; - + bool ConstructorWarnUnused = false; if (Init) { const CXXConstructExpr *Construct = dyn_cast(Init); - if (Construct && !Construct->isElidable()) { + if (Construct) { CXXConstructorDecl *CD = Construct->getConstructor(); - if (!CD->isTrivial() && !RD->hasAttr() && + ConstructorWarnUnused = CD->hasAttr(); + if (!Construct->isElidable() && !CD->isTrivial() && + !RD->hasAttr() && !ConstructorWarnUnused && (VD->getInit()->isValueDependent() || !VD->evaluateValue())) return false; } @@ -2077,6 +2077,10 @@ if (isa(Init)) return false; } + + if (!RD->hasTrivialDestructor() && !RD->hasAttr() + && !ConstructorWarnUnused) + return false; } } Index: clang/test/Misc/pragma-attribute-strict-subjects.c =================================================================== --- clang/test/Misc/pragma-attribute-strict-subjects.c +++ clang/test/Misc/pragma-attribute-strict-subjects.c @@ -16,7 +16,7 @@ #pragma clang attribute pop #pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global))) -// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_global)'}} +// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_thread_local)'}} // We have just one error, don't error on 'variable(is_global)' // Ensure that we've recovered from the error: Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test =================================================================== --- clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -192,7 +192,7 @@ // CHECK-NEXT: UseHandle (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: VecReturn (SubjectMatchRule_record) // CHECK-NEXT: VecTypeHint (SubjectMatchRule_function) -// CHECK-NEXT: WarnUnused (SubjectMatchRule_record) +// CHECK-NEXT: WarnUnused (SubjectMatchRule_record, SubjectMatchRule_function_constructor) // CHECK-NEXT: WarnUnusedResult (SubjectMatchRule_objc_method, SubjectMatchRule_enum, SubjectMatchRule_record, SubjectMatchRule_hasType_functionType, SubjectMatchRule_type_alias) // CHECK-NEXT: Weak (SubjectMatchRule_variable, SubjectMatchRule_function, SubjectMatchRule_record) // CHECK-NEXT: WeakRef (SubjectMatchRule_variable, SubjectMatchRule_function) Index: clang/test/Parser/pragma-attribute.cpp =================================================================== --- clang/test/Parser/pragma-attribute.cpp +++ clang/test/Parser/pragma-attribute.cpp @@ -190,7 +190,7 @@ #pragma clang attribute pop #pragma clang attribute push([[clang::uninitialized]], apply_to = variable(is_global)) // expected-error {{attribute 'uninitialized' can't be applied to 'variable(is_global)'}} #pragma clang attribute pop -#pragma clang attribute push([[clang::uninitialized]], apply_to = any(variable(is_parameter), variable(unless(is_parameter)))) // expected-error {{attribute 'uninitialized' can't be applied to 'variable(is_parameter)', and 'variable(unless(is_parameter))'}} +#pragma clang attribute push([[clang::uninitialized]], apply_to = any(variable(is_parameter), variable(unless(is_parameter)))) // expected-error {{attribute 'uninitialized' can't be applied to 'variable(unless(is_parameter))', and 'variable(is_parameter)'}} #pragma clang attribute pop // We're allowed to apply attributes to subsets of allowed subjects. #pragma clang attribute push([[clang::no_destroy]], apply_to = variable) Index: clang/test/Sema/pragma-attribute-strict-subjects.c =================================================================== --- clang/test/Sema/pragma-attribute-strict-subjects.c +++ clang/test/Sema/pragma-attribute-strict-subjects.c @@ -28,7 +28,7 @@ #pragma clang attribute pop #pragma clang attribute push (__attribute__((annotate("negatedSubRuleContradictions2"))), apply_to = any(variable(unless(is_parameter)), variable(is_thread_local), function, variable(is_global))) -// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_global)'}} +// expected-error@-1 {{negated attribute subject matcher sub-rule 'variable(unless(is_parameter))' contradicts sub-rule 'variable(is_thread_local)'}} // We have just one error, don't error on 'variable(is_global)' #pragma clang attribute pop Index: clang/test/SemaCXX/warn-unused-attribute.cpp =================================================================== --- clang/test/SemaCXX/warn-unused-attribute.cpp +++ clang/test/SemaCXX/warn-unused-attribute.cpp @@ -9,12 +9,21 @@ TestNormal(); }; +struct TestCtor { + __attribute__((warn_unused)) TestCtor(); + TestCtor(int); + void __attribute__((warn_unused)) f(); // expected-warning {{'warn_unused' attribute only applies to structs, unions, classes, and constructors}} +}; + int main(void) { Test unused; // expected-warning {{unused variable 'unused'}} Test used; TestNormal normal; used.use(); - int i __attribute__((warn_unused)) = 12; // expected-warning {{'warn_unused' attribute only applies to structs, unions, and classes}} + TestCtor ctorUnused; // expected-warning {{unused variable 'ctorUnused'}} + TestCtor ctorUsed(0); + + int i __attribute__((warn_unused)) = 12; // expected-warning {{'warn_unused' attribute only applies to structs, unions, classes, and constructors}} return i; }