cor3ntin created this revision. Herald added a project: All. cor3ntin requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
const auto & var = ObjectWithSideEffects(); Fixes https://github.com/llvm/llvm-project/issues/54489 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D122661 Files: clang/lib/Sema/SemaDecl.cpp clang/test/SemaCXX/warn-unused-variables.cpp
Index: clang/test/SemaCXX/warn-unused-variables.cpp =================================================================== --- clang/test/SemaCXX/warn-unused-variables.cpp +++ 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 { @@ -250,6 +250,32 @@ template <typename T> void foo(T &t) { S s{t}; + const auto &extended = S{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}; +} + +} // namespace gh54489 Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -1889,15 +1889,30 @@ // 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 ExprWithCleanups *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>()) { + // White-list anything with an __attribute__((unused)) type. if (TT->getDecl()->hasAttr<UnusedAttr>()) return false; } + // Warn for reference variables whose initializtion performs lifetime + // extension. + if (const MaterializeTemporaryExpr *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 +1931,7 @@ 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 +1943,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<CXXUnresolvedConstructExpr>(Init)) + return false; } } }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits