diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1889,15 +1889,28 @@ // Types of valid local variables should be complete, so this should succeed. if (const VarDecl *VD = dyn_cast(D)) { - // White-list anything with an __attribute__((unused)) type. + const Expr *Init = VD->getInit(); + if (const auto *Cleanups = dyn_cast_or_null(Init)) + Init = Cleanups->getSubExpr(); + const auto *Ty = VD->getType().getTypePtr(); // Only look at the outermost level of typedef. if (const TypedefType *TT = Ty->getAs()) { + // Allow anything marked with __attribute__((unused)). if (TT->getDecl()->hasAttr()) return false; } + // Warn for reference variables whose initializtion performs lifetime + // extension. + if (const auto *MTE = dyn_cast_or_null(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 @@ if (!RD->hasTrivialDestructor() && !RD->hasAttr()) return false; - if (const Expr *Init = VD->getInit()) { - if (const ExprWithCleanups *Cleanups = - dyn_cast(Init)) - Init = Cleanups->getSubExpr(); + if (Init) { const CXXConstructExpr *Construct = dyn_cast(Init); if (Construct && !Construct->isElidable()) { @@ -1931,10 +1941,16 @@ // 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(Init)) + return false; } } } diff --git a/clang/test/SemaCXX/warn-unused-variables.cpp b/clang/test/SemaCXX/warn-unused-variables.cpp --- a/clang/test/SemaCXX/warn-unused-variables.cpp +++ b/clang/test/SemaCXX/warn-unused-variables.cpp @@ -154,13 +154,13 @@ #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 @@ bar<2>(); } -} +} // namespace arrayRecords #if __cplusplus >= 201103L namespace with_constexpr { @@ -253,3 +253,44 @@ } } #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 +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