Author: Corentin Jabot Date: 2022-04-05T21:03:02+02:00 New Revision: 84f0a36b14bbd464d65cb1a6135134072b828447
URL: https://github.com/llvm/llvm-project/commit/84f0a36b14bbd464d65cb1a6135134072b828447 DIFF: https://github.com/llvm/llvm-project/commit/84f0a36b14bbd464d65cb1a6135134072b828447.diff LOG: [Clang] Do not warn on unused lifetime-extending vars with side effects... const auto & var = ObjectWithSideEffects(); Fixes https://github.com/llvm/llvm-project/issues/54489 Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D122661 Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaDecl.cpp clang/test/SemaCXX/warn-unused-variables.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index acc433f2bc86b..86d0a3e7303f1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -110,6 +110,9 @@ Improvements to Clang's diagnostics <https://github.com/llvm/llvm-project/issues/50794>`_. - ``-Wunused-but-set-variable`` now also warns if the variable is only used by unary operators. +- ``-Wunused-variable`` no longer warn for references extending the lifetime + of temporaries with side effects. This fixes `Issue 54489 + <https://github.com/llvm/llvm-project/issues/54489>`_. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0b5b530bc756c..a2d3722f2efb8 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1889,15 +1889,28 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { // Types of valid local variables should be complete, so this should succeed. if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - // White-list anything with an __attribute__((unused)) type. + const Expr *Init = VD->getInit(); + if (const auto *Cleanups = dyn_cast_or_null<ExprWithCleanups>(Init)) + Init = Cleanups->getSubExpr(); + const auto *Ty = VD->getType().getTypePtr(); // Only look at the outermost level of typedef. if (const TypedefType *TT = Ty->getAs<TypedefType>()) { + // Allow anything marked with __attribute__((unused)). if (TT->getDecl()->hasAttr<UnusedAttr>()) return false; } + // Warn for reference variables whose initializtion performs lifetime + // extension. + if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(Init)) { + if (MTE->getExtendingDecl()) { + Ty = VD->getType().getNonReferenceType().getTypePtr(); + Init = MTE->getSubExpr()->IgnoreImplicitAsWritten(); + } + } + // If we failed to complete the type for some reason, or if the type is // dependent, don't diagnose the variable. if (Ty->isIncompleteType() || Ty->isDependentType()) @@ -1916,10 +1929,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (!RD->hasTrivialDestructor() && !RD->hasAttr<WarnUnusedAttr>()) return false; - if (const Expr *Init = VD->getInit()) { - if (const ExprWithCleanups *Cleanups = - dyn_cast<ExprWithCleanups>(Init)) - Init = Cleanups->getSubExpr(); + if (Init) { const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init); if (Construct && !Construct->isElidable()) { @@ -1931,10 +1941,16 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { // Suppress the warning if we don't know how this is constructed, and // it could possibly be non-trivial constructor. - if (Init->isTypeDependent()) + if (Init->isTypeDependent()) { for (const CXXConstructorDecl *Ctor : RD->ctors()) if (!Ctor->isTrivial()) return false; + } + + // Suppress the warning if the constructor is unresolved because + // its arguments are dependent. + if (isa<CXXUnresolvedConstructExpr>(Init)) + return false; } } } diff --git a/clang/test/SemaCXX/warn-unused-variables.cpp b/clang/test/SemaCXX/warn-unused-variables.cpp index 2634fb1ec0f7f..4db8bdf12e5de 100644 --- a/clang/test/SemaCXX/warn-unused-variables.cpp +++ b/clang/test/SemaCXX/warn-unused-variables.cpp @@ -154,13 +154,13 @@ namespace ctor_with_cleanups { #include "Inputs/warn-unused-variables.h" -namespace arrayRecords { - class NonTriviallyDestructible { public: ~NonTriviallyDestructible() {} }; +namespace arrayRecords { + struct Foo { int x; Foo(int x) : x(x) {} @@ -196,7 +196,7 @@ void test() { bar<2>(); } -} +} // namespace arrayRecords #if __cplusplus >= 201103L namespace with_constexpr { @@ -253,3 +253,44 @@ void foo(T &t) { } } #endif + +// Ensure we do not warn on lifetime extension +namespace gh54489 { + +void f() { + const auto &a = NonTriviallyDestructible(); + const auto &b = a; // expected-warning {{unused variable 'b'}} +#if __cplusplus >= 201103L + const auto &&c = NonTriviallyDestructible(); + auto &&d = c; // expected-warning {{unused variable 'd'}} +#endif +} + +struct S { + S() = default; + S(const S &) = default; + S(int); +}; + +template <typename T> +void foo(T &t) { + const auto &extended = S{t}; +} + +void test_foo() { + int i; + foo(i); +} + +struct RAIIWrapper { + RAIIWrapper(); + ~RAIIWrapper(); +}; + +void RAIIWrapperTest() { + auto const guard = RAIIWrapper(); + auto const &guard2 = RAIIWrapper(); + auto &&guard3 = RAIIWrapper(); +} + +} // namespace gh54489 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits