[gcc r17-3656] libstdc++: optional: Treat _M_engaged as being assumed to be false after the destructor [PR127005]

Andrea Pinski pinskia@gcc.gnu.org
Tue Aug 25 19:19:47 GMT 2026


https://gcc.gnu.org/g:e982f847aab9f76a35ec70ff53aca548abe2331e

commit r17-3656-ge982f847aab9f76a35ec70ff53aca548abe2331e
Author: Andrea Pinski <andrew.pinski@oss.qualcomm.com>
Date:   Sat Aug 22 22:09:20 2026 -0700

    libstdc++: optional: Treat _M_engaged as being assumed to be false after the destructor [PR127005]
    
    Sometimes the destructor will cause the optimizers not to see that
    _M_engaged has been to set to false (e.g. an external call). This
    means that we might get an uninitialized warning after the destructor
    in some cases.
    Adding `if (_M_engaged) __builtin_unreachable(); ` after the destructor
    will allow for the optimizations to know that the value of _M_engaged
    is 0 afterwards. This helps with optimizations and the uninitialized warning.
    
            PR libstdc++/127005
    
    libstdc++-v3/ChangeLog:
    
            * include/std/optional (optional::_M_destroy): Add an assumption on _M_engaged
            being false after the destructor call.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/warn/Wuninitialized-36.C: New test.
    
    Signed-off-by: Andrea Pinski <andrew.pinski@oss.qualcomm.com>

Diff:
---
 gcc/testsuite/g++.dg/warn/Wuninitialized-36.C | 26 ++++++++++++++++++++++++++
 libstdc++-v3/include/std/optional             |  3 +++
 2 files changed, 29 insertions(+)

diff --git a/gcc/testsuite/g++.dg/warn/Wuninitialized-36.C b/gcc/testsuite/g++.dg/warn/Wuninitialized-36.C
new file mode 100644
index 000000000000..aacb3f4e6a46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wuninitialized-36.C
@@ -0,0 +1,26 @@
+// PR tree-optimization/127005
+// { dg-do compile { target c++17 } }
+// { dg-options "-O2 -W -Wall" }
+
+#include <optional>
+
+void f(int *);
+struct s1
+{
+  int *a;
+  ~s1()
+  {
+     f(a); // { dg-bogus "uninitialized" }
+  }
+};
+
+struct conn {
+        void close() { guard.reset(); }
+        std::optional<s1> guard;
+};
+extern conn make_conn();
+int main()
+{
+        conn c = make_conn();
+        c.close();
+}
diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index d6fd33e8c2e1..b56a3366ab76 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -303,6 +303,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       {
 	_M_engaged = false;
 	_M_payload._M_value.~_Stored_type();
+	// After the destructor, _M_engaged should always be false, see PR 127005.
+	if (_M_engaged)
+	  __builtin_unreachable();
 #if defined(__clang__) && __cpp_lib_optional >= 202106L // full constexpr support
 	if (std::is_constant_evaluated())
 	  // Work around PR124910 for Clang.


More information about the Libstdc++-cvs mailing list