{"id":2224860,"url":"http://patchwork.ozlabs.org/api/patches/2224860/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/patch/20260418232807.3364700-1-ppalka@redhat.com/","project":{"id":17,"url":"http://patchwork.ozlabs.org/api/projects/17/?format=json","name":"GNU Compiler Collection","link_name":"gcc","list_id":"gcc-patches.gcc.gnu.org","list_email":"gcc-patches@gcc.gnu.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260418232807.3364700-1-ppalka@redhat.com>","list_archive_url":null,"date":"2026-04-18T23:28:07","name":"[committed,v2] libstdc++: Fix constantness of engaged -> disengaged std::optional [PR124910]","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"01ffe762de044e7abd06f9e34ce6bb687642d40c","submitter":{"id":78319,"url":"http://patchwork.ozlabs.org/api/people/78319/?format=json","name":"Patrick Palka","email":"ppalka@redhat.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/gcc/patch/20260418232807.3364700-1-ppalka@redhat.com/mbox/","series":[{"id":500477,"url":"http://patchwork.ozlabs.org/api/series/500477/?format=json","web_url":"http://patchwork.ozlabs.org/project/gcc/list/?series=500477","date":"2026-04-18T23:28:07","name":"[committed,v2] libstdc++: Fix constantness of engaged -> disengaged std::optional [PR124910]","version":2,"mbox":"http://patchwork.ozlabs.org/series/500477/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2224860/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2224860/checks/","tags":{},"related":[],"headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=f26mptY3;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=f26mptY3","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.133.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fynyd0M1Lz1yGs\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 19 Apr 2026 09:29:27 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id C78CB4BAD14A\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 18 Apr 2026 23:29:20 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id 5652E4BA9000\n for <gcc-patches@gcc.gnu.org>; Sat, 18 Apr 2026 23:28:15 +0000 (GMT)","from mail-qt1-f198.google.com (mail-qt1-f198.google.com\n [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS\n (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n us-mta-274-dyrv0VioOjyHtvp2gR5oAg-1; Sat, 18 Apr 2026 19:28:13 -0400","by mail-qt1-f198.google.com with SMTP id\n d75a77b69052e-50d8c183c2eso18204351cf.0\n for <gcc-patches@gcc.gnu.org>; Sat, 18 Apr 2026 16:28:13 -0700 (PDT)","from idea ([2600:4040:aa66:bf00:9e8e:99ff:fed1:71f])\n by smtp.gmail.com with ESMTPSA id\n d75a77b69052e-50e3fbc6513sm35294811cf.2.2026.04.18.16.28.09\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Sat, 18 Apr 2026 16:28:10 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org C78CB4BAD14A","OpenDKIM Filter v2.11.0 sourceware.org 5652E4BA9000"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 5652E4BA9000","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 5652E4BA9000","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776554895; cv=none;\n b=ZtH3BaNQLjyAscXis56v9/xUi0NnXDKXkYFCF2nQ1FYu3d9DYJPiXib78JOhC/6W0EYHQf5Uwy4X3MBrkJTSADC63CTbB9FjD4ArdDFI1JMTe0OAOEM2Yiyo4LBApR7hVHd1mp9kwbJnm1gQDviZa+rp/yPsBjNjeZpkZAA48Qw=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776554895; c=relaxed/simple;\n bh=cGfF6bydBZtrimpYtNU8/4WuyxAJHzMQ+kuayX+zdRo=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=ss38YbrvkPJJueiLdVwGZ0JFEe28WwjECHGf0qSA+976jzsG5oWyqRYnkz7fsPxrkleWI6uJlbj4gUyTQtsNKIfR3+v6l1Yd9smYYFwv0zBwvkoQ0q924A883iDngiQsEZ4+SeT2xhEz01BWZSMoPLvjw3stLLtW5Xq33m453Ec=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1776554895;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=41KoGOKlWK7GI93NVkH6gaWTmStb/BKNJSNUaqXDo6s=;\n b=f26mptY3knyUCqSIwjJe2+3p0Qm8u2NjfVdz1EbriIW15kdqoQG7yxmgq+CnWfwMbUXIFo\n Pg741ki4+pQTQbrR2wXYWij9QqJwbfw1LxgIYn0lCXAVvm/g/iUwbhUWDDjn4mmxl/Gkog\n enUiKPVGgMiw9iMCE4SUifmwaP393VM=","X-MC-Unique":"dyrv0VioOjyHtvp2gR5oAg-1","X-Mimecast-MFC-AGG-ID":"dyrv0VioOjyHtvp2gR5oAg_1776554893","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1776554892; x=1777159692;\n h=content-transfer-encoding:mime-version:message-id:date:subject:cc\n :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=41KoGOKlWK7GI93NVkH6gaWTmStb/BKNJSNUaqXDo6s=;\n b=ZQUWoT2xHc0bd1i/LEal28mOuHSYLzSqABBCq/fyMgbncdman8U4ox2gpjm8Mz+m3E\n +3KxR/ScVKn0zkQqrR9zs1iVLd1KaAWF+2gkPQOjbNV7Ab4YRjlt9bmWzptNZF5iIkSJ\n b8Z5dGmm1CNJI79GXVKuMU4cgEg3roZIdE3Io7Upzyf66vwzz9RVPVb640yHk1jsRvYF\n iPePVekRt8e6jPT9MMR29y86YjFubGBNREXMATzoR5jTB78pGROqaR/hpDl5j53PkOFt\n QIXG2x0FX6MupuXzeaBVHcQL4YM4nJqeCAKOIEXBYzmCNrDvEO6HYMaTrJCY02QdCxnj\n 6tuA==","X-Gm-Message-State":"AOJu0YxxjYeQ4npZDx0/ICnDZ954rBUKqWlnH8oqYr8p/WxbkmH2ysyG\n Ezf8aX+5uP013JI/gBASLRcbEI6XpOsMeiEPuRCTyb5f1kbJULW/UE6y+YQJ+7IuahZMfgSgO8Q\n yHDMLevcWMD4IfX/2QMKcURIXyhUUKo6gPpIR3qItVRmgp0YHmDeZbsdjcOKIIwsq59LjIJLDf8\n zFPJpmlbOL52+l2Dtlwep8kwdva7eFGix3b0wQcoQS","X-Gm-Gg":"AeBDieu3CqSLWrIBaPuxbL4F/X4ciAPOdUtz1OTdq9RHjwRv80zwI2Tx0BCaocs3I1L\n 7mVypTGDX4bmxxeE9pQaCFcdOZHsxnMsWBQzEIDSCZIUfQUGs392S6t6F8IoRpVuzKFYp94noVn\n xrIJZVYlSchU2kdKj85DL7yL+HWAynjrfz+mjG5O2yfRmX7XvJfk30WhkAU9TjvBfNiec92pJC8\n iGtjTHDZBcpfI4p8DqN+2twf78MpBEctKTdYT7QQVmk/aVhRAlQ2B3i11BbMSMW2TaeLbuEVOkn\n 4VKmhp2dmGfYub3TZsCyMy/GUVZAEMn+63fJh0MvFoOPP/iymLQNbLxxLNqBOty0hqKIdrvVFoZ\n 0EPn1ZcIKkIVOm5ihS7dKr2Y=","X-Received":["by 2002:a05:622a:144:b0:501:4767:a6f with SMTP id\n d75a77b69052e-50e36c08aa2mr87399761cf.3.1776554892069;\n Sat, 18 Apr 2026 16:28:12 -0700 (PDT)","by 2002:a05:622a:144:b0:501:4767:a6f with SMTP id\n d75a77b69052e-50e36c08aa2mr87399541cf.3.1776554891487;\n Sat, 18 Apr 2026 16:28:11 -0700 (PDT)"],"From":"Patrick Palka <ppalka@redhat.com>","To":"gcc-patches@gcc.gnu.org","Cc":"libstdc++@gcc.gnu.org, jason@redhat.com,\n Patrick Palka <ppalka@redhat.com>,\n Jonathan Wakely <jwakely@redhat.com>","Subject":"[committed v2] libstdc++: Fix constantness of engaged -> disengaged\n std::optional [PR124910]","Date":"Sat, 18 Apr 2026 19:28:07 -0400","Message-ID":"<20260418232807.3364700-1-ppalka@redhat.com>","X-Mailer":"git-send-email 2.54.0.rc1.54.g60f07c4f5c","MIME-Version":"1.0","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"EzwwT42VRE_akkUW3gpyFBsUfdJ9aPRfS-DmvuLuGpY_1776554893","X-Mimecast-Originator":"redhat.com","Content-Transfer-Encoding":"8bit","content-type":"text/plain; charset=\"US-ASCII\"; x-default=true","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"},"content":"Changes in v2:\n  - Added code comment\n  - Clarified commit message, removed red herring about trivial\n    destructibility.\n  - Extended test with 'x6' direct-initialization that avoids invoking\n    optional's move constructor.  This testcase, when instantiated with T=B,\n    demonstrates that non-trivially-copyable optional is also affected\n    and we must set _M_empty even in that case.\n\n-- >8 --\n\nWhen an optional that contains a value is cleared, _M_destroy invokes the\ndestructor of the contained value _Storage::_M_value, leaving the union\n_Storage without an active member.  While this is benign at runtime, a\nunion suboject with no active member violates core constant expression\nrequirements and in turn an optional in this state can't be used as a\nconstant initializer, which Clang and recent GCC (since r16-3022) correctly\ndiagnose.\n\nTo fix this, this patch makes _M_destroy activate the dummy union member\n_M_empty after destroying _M_value to ensure that the union always has\nan active member throughout its lifetime.  We use std::construct_at\ninstead of simple assignment to work around a front end bug (comment #3\nin the PR).  Doing so means we don't activate the member in C++17 mode,\nwhich should be fine; I don't think it's possible to disengage an engaged\noptional using only the C++17 constexpr optional operations.\n\n\tPR c++/124910\n\nlibstdc++-v3/ChangeLog:\n\n\t* include/std/optional (_Optional_payload_base::_M_destroy)\n\t[__cpp_lib_optional >= 202106L]: During constant evaluation,\n\tafter invoking destructor of _M_value, use construct_at to\n\tactivate _M_empty.\n\t* testsuite/20_util/optional/constexpr/124910.cc: New test.\n\nReviewed-by: Jonathan Wakely <jwakely@redhat.com>\n---\n libstdc++-v3/include/std/optional             |  6 ++\n .../20_util/optional/constexpr/124910.cc      | 74 +++++++++++++++++++\n 2 files changed, 80 insertions(+)\n create mode 100644 libstdc++-v3/testsuite/20_util/optional/constexpr/124910.cc","diff":"diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional\nindex 0f4cf0bd1ef6..49ba7b6b45dd 100644\n--- a/libstdc++-v3/include/std/optional\n+++ b/libstdc++-v3/include/std/optional\n@@ -321,6 +321,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n       {\n \t_M_engaged = false;\n \t_M_payload._M_value.~_Stored_type();\n+#if __cpp_lib_optional >= 202106L // full constexpr support\n+\tif (std::is_constant_evaluated())\n+\t  // Ensure union _M_payload always has an active member, for sake\n+\t  // of the core constant expression requirements.\n+\t  std::construct_at(std::__addressof(_M_payload._M_empty));\n+#endif\n       }\n \n #if __cplusplus >= 202002L\ndiff --git a/libstdc++-v3/testsuite/20_util/optional/constexpr/124910.cc b/libstdc++-v3/testsuite/20_util/optional/constexpr/124910.cc\nnew file mode 100644\nindex 000000000000..2f61f7e4e775\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/20_util/optional/constexpr/124910.cc\n@@ -0,0 +1,74 @@\n+// { dg-do compile { target c++20 } }\n+\n+// PR124910 - bogus 'std::optional{...}' is not a constant expression error\n+// after resetting it via '= nullopt'\n+\n+#include <optional>\n+\n+struct A\n+{\n+  constexpr A(int m) : m(m) { }\n+  int m;\n+};\n+\n+struct B\n+{\n+  constexpr B(int m) : m(m) { }\n+  constexpr ~B() { }\n+  int m;\n+};\n+\n+static_assert(   std::is_trivially_destructible_v<int> );\n+static_assert(   std::is_trivially_destructible_v<A> );\n+static_assert( ! std::is_trivially_destructible_v<B> );\n+\n+template<class T>\n+void\n+do_test()\n+{\n+  constexpr std::optional<T> x1 = [] {\n+    std::optional<T> o = 1;\n+    o = std::nullopt;\n+    return o;\n+  }();\n+\n+  constexpr std::optional<T> x2 = [] {\n+    std::optional<T> o = 1;\n+    o.reset();\n+    return o;\n+  }();\n+\n+  constexpr std::optional<T> x3 = [] {\n+    std::optional<T> o1 = 1;\n+    std::optional<long> o2;\n+    o1 = o2;\n+    return o1;\n+  }();\n+\n+  constexpr std::optional<T> x4 = [] {\n+    std::optional<T> o1 = 1;\n+    std::optional<long> o2;\n+    o1 = std::move(o2);\n+    return o1;\n+  }();\n+\n+  constexpr std::optional<T> x5 = [] {\n+    std::optional<T> o1 = 1;\n+    std::optional<T> o2;\n+    std::swap(o1, o2);\n+    return o1;\n+  }();\n+\n+  struct C : std::optional<T> {\n+    constexpr C() : std::optional<T>(1) { this->reset(); }\n+  };\n+  constexpr C x6;\n+}\n+\n+int\n+main()\n+{\n+  do_test<int>();\n+  do_test<A>();\n+  do_test<B>();\n+}\n","prefixes":["committed","v2"]}