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

Reply via email to