Hi Jonathan, Thanks for the review.
Jonathan Wakely <[email protected]> writes: >> (if (looking-back "std::") >> (queue-replace i "addressof") >> (queue-replace i "std::addressof"))) > > Do gcc::optional and gcc::expected really need to use std::addressof? > Internal GCC types should not be overriding operator& and so just > taking the address should work fine. Overriding operator& is evil and > libstdc++ has to support it because the standard library can't impose > "stop being stupid" conditions on users, but GCC can impose that on > GCC devs. > > So you could replace std::addressof(x) with just &x and similarly for > std::__addressof. We probably don't really gain anything of significance from it but I also don't see a downside to it, especially since the existing code already uses it. This is also generic code, so I don't think such a small bit of extra internal gunk is too much of an issue. >> ((string-match-p "\\`_[A-Z].*[a-z].*" itext) >> ;; Move _Foo into the non-reserved identifier space as G_Foo, but >> ;; don't catch macro names. > > Would changing _Foo to simply Foo make it more readable? > Would there be ambiguous names that way? I haven't tried to see whether there would be conflicts, but these mechanically transformed names mostly exist in in the mechanically transformed code, so I didn't think it matters too much. For the mechanical bits of the backport, I chose to diverge as little as possible, so that it's easier to validate changes. >> (queue-replace i (concat "G" itext))) >> ((string-search "__" itext) >> ;; Turn '__' into 'g_' > > Turning __x into just x seems simpler, although that probably would > cause ambiguities, because we have e.g. value() and __value where the > latter should not shadow the former. Indeed. >>diff --git a/gcc/stdbackport/expected b/gcc/stdbackport/expected >>new file mode 100644 >>index 000000000000..b14913456390 >>--- /dev/null >>+++ b/gcc/stdbackport/expected > > Do you really want these to have no file extension? > > I would have expected them to be optional.h and expected.h, like other > internal headers. I am fine with either. I kept the C++ standard convention so that the code is as close to libstdc++ as possible. (Obviously, <expected> ended up effectively not being derived from libstdc++, so that doesn't really apply there, but still.) So, up to the maintainers I think; I'm fine with either. >>+ // true_type if T is void or Trait<T> holds. > > The comment says "T is void" but the implementation is "T is cv void". Whoops, fixed locally. > I think this could avoid instantiating std::is_same, like this: > > template<typename E, typename WantedValue> > struct is_expected_with_same_value<expected<WantedValue, E>, WantedValue> > : std::true_type {}; Ah, true! > And personally I would find the name "is_expected_with_value" to read > more naturally at the point of use, i.e. is_expected_with_value<E, V> > means "E is a std::expected with value type V" Hmm, yes, sounds good, and it's shorter. Fixed both of the above. >>+ // [expected.bad] >>+ template<typename G_Er> >>+ class bad_expected_access : public bad_expected_access<void> { >>+ public: >>+ GCC_BACKPORT_CONSTEXPR_BAD_EXPECTED_ACCESS explicit >>+ bad_expected_access (G_Er g_e) : G_M_unex(std::move(g_e)) { } > > Would it make more sense to just replace the _M_ prefixes with m_ > instead of G_M_ which is a very unconventional naming style? I could make a carve-out for that, I don't see any uses of the m_ prefix in libstdc++ (which makes sense, since that'd be a non-reserved name). Do note that this makes optional use rather strange function names, e.g: if (g_u) { if (this->m_is_engaged()) this->m_get() = std::move(g_u).m_fwd(); else this->m_construct(std::move(g_u).m_fwd()); } else { this->m_reset(); } ... but then, so did the original. /me shrugs I've made the change anyway. >>+ bool m_has_value; > > Ah, sensible names, not G_M_has_value :-) Yes, this bit was hand-written ;) >>+ // Default construction. >>+ template<typename T, typename E, >>+ bool is_deault_cons = trait_or_void< > > Typo: "deault" Fixed. >>+ // [expected.expected] >>+ template<typename T, typename E> >>+ struct [[nodiscard]] expected >>+ : private detail::exp::storage<std::remove_cv_t<T>, E> >>+ , private G_Enable_copy_move< >>+ // Copy constructor. >>+ detail::exp::trait_2<std::is_copy_constructible, T, E>::value, >>+ // Copy assignment. >>+ and_<detail::exp::trait_2<std::is_copy_assignable, T, E>, >>+ detail::exp::trait_2<std::is_copy_constructible, T, E>, >>+ or_<detail::exp::trait_or_void<std::is_nothrow_move_constructible, >>T>, >>+ std::is_nothrow_move_constructible<E>> >>+ >::value, >>+ // Move constructor. >>+ detail::exp::trait_2<std::is_move_constructible, T, E>::value, >>+ // Move assignment. >>+ and_<detail::exp::trait_2<std::is_move_assignable, T, E>, >>+ detail::exp::trait_2<std::is_move_constructible, T, E>, >>+ or_<detail::exp::trait_or_void<std::is_nothrow_move_constructible, >>T>, >>+ std::is_nothrow_move_constructible<E>>>::value >>+ > > > All the complexity above is because you can't use C++20 concepts to > constraint an expected<cv void, E> partial specialization, right? Not really, most of the complexity is there because we can't use concepts to constrain the special members, nor to make them conditionally trivial, so inheritance tricks have to be used. Even if T couldn't be void at all (let alone cv-void), most of the complexity would remain, since the same tests are required for E. > Because it seems like a lot of the traits stuff would be simpler if > you just had the primary template and a partial specialization for cv > void. I can see two ways to make that work, either: > > template<typename T, typename E, bool = std::is_void<T>::value> > struct expected > { /* primary template */ }; > > template<typename T, typename E> > struct expected<T, E, true> > { /* partial specialization for cv void */ }; > > or simply don't support gcc::expected<const void, E> and other > cv-quals, so that only cv-unqualified void is supported: > > template<typename T, typename E> > struct expected > { /* primary template */ }; > > template<typename E> > struct expected<void, E> > { /* partial specialization for void (but not cv void) */ }; > > The former (adding the extra bool template parameter) isn't possible > for std::expected because we must not change the template parameter > list, and we can't trust users not to do stupid things with the > standard library, and we don't need to because we have C++20 concepts > anyway. But for gcc::expected adding the bool seems fine. If anybody > is stupid enough to override the third argument to select the wrong > specialization, e.g. gcc::expected<int, int, true>, then they're > stupid and GCC won't build and they will stop doing it. Yes, the extra bool is fine for GCC. I had originally intended to treat expected<Void, E>, where Void is a cv-void, the exact same as an expected<void_storage, E>, but after reading the spec, I thought there's too much divergent behaviour for that. Now, looking back at it, I don't think that's the case. So, I restructured it to be a specialization. In the end, the result is ~200 lines longer, sure, but it is simpler, I think, by a significant factor, when it comes to constraining the non-special members. 'storage' kept most of its complexity, though I made it a touch simpler by never permitting T=void in 'storage' (replacing it with 'void_storage' early). > For the latter, not supporting cv void, I think that's totally fine > for gcc::expected. The use cases for std::expected<const void, E> are > extremely rare, and it mostly exists just for generic code working > with arbitrary types. Not something likely to matter for > gcc::expected. It would probably not matter, indeed, even for the Rust FE that does heavily use the monadic operations, but it is useful for running the tests. > I think if you just defined the two cases separately, the maze of > trait_or_void conditions would (mostly) vanish, and the code would be > easier to understand. We still need some way of propagating triviality, which means we'd need to have another chain of 'storage' for providing those operators. I think that's too much duplication. > That would mean some duplication, as you'd need to define > gcc::expected<void, E> separately. But actually it's not really > duplicated because the conditions for the void case are usually > different (and simpler). You've de-duplicated the code by smushing it > all together but now you need to handle all the cv void cases in the > primary template. > > In fact, is there even any need to support gcc::expected<const T, E>? > Certainly gcc::expected<volatile T, E> should be forbidden, and result > in having your git commit privs revoked :-) I'm not sure why the standard even permits qualifying the stored types, but I kept that so that I can test this implementation against existing testsuites. The qualification of the value type doesn't really add much complexity. For purposes of storage, we get rid of it immediately. >>diff --git a/gcc/stdbackport/expectedfwd b/gcc/stdbackport/expectedfwd >>new file mode 100644 >>index 000000000000..314df4846ae7 >>--- /dev/null >>+++ b/gcc/stdbackport/expectedfwd > > Shouldn't this have a .h file extension? Same as above - I don't mind either way. >>+namespace gcc >>+{ >>+/// @cond undocumented > > Is there any benefit to keeping these doxygen @cond comments? > If the GCC sources are ever processed using Doxygen, then these > details probably *do* want to be documented. For libstdc++ they're not > part of the user-facing standardized API, so we exclude them from the > user-facing docs. But for Doxygen docs of the GCC internals I think it > makes sense to include everything. No, they aren't useful, and were kept only because this header was mechanically converted (IIRC). Removed. >>+/** @file bits/exception_defines.h >>+ * This is an internal header file, included by other library headers. >>+ * Do not attempt to use it directly. @headername{exception} >>+ */ > > This comment doesn't make sense here. Yes, this file was also mechanically converted initially, but it received substantial changes after. Removed these also. >>--- /dev/null >>+++ b/gcc/stdbackport/gbits/extras.h >>@@ -0,0 +1,56 @@ >>+// A few more utilities used in the backports not corresponding to existing >>headers -*- C++ -*- >>+ >>+// Copyright (C) 2026 Free Software Foundation, Inc. >>+// Copyright The GNU Toolchain Authors. >>+// >>+// This file is part of the GNU ISO C++ Library. This library is free >>+// software; you can redistribute it and/or modify it under the >>+// terms of the GNU General Public License as published by the >>+// Free Software Foundation; either version 3, or (at your option) >>+// any later version. >>+ >>+// This library is distributed in the hope that it will be useful, >>+// but WITHOUT ANY WARRANTY; without even the implied warranty of >>+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >>+// GNU General Public License for more details. >>+ >>+// Under Section 7 of GPL version 3, you are granted additional >>+// permissions described in the GCC Runtime Library Exception, version >>+// 3.1, as published by the Free Software Foundation. >>+ >>+// You should have received a copy of the GNU General Public License and >>+// a copy of the GCC Runtime Library Exception along with this program; >>+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see >>+// <http://www.gnu.org/licenses/>. >>+ >>+#ifndef GCC_BACKPORT_BITS_CONDITIONALS_H >>+#define GCC_BACKPORT_BITS_CONDITIONALS_H 1 >>+ >>+#include <type_traits> >>+ >>+#ifndef __has_builtin >>+# define gcc_backport_has_builtin(x) 0 >>+#else >>+# define gcc_backport_has_builtin(x) __has_builtin (x) >>+#endif >>+ >>+// Helper. Expands to 'constexpr' in C++20 and an empty string otherwise. >>+#if __cplusplus >= 202002L >>+# define GCC_BACKPORT20_CONSTEXPR constexpr >>+#else >>+# define GCC_BACKPORT20_CONSTEXPR >>+#endif >>+ >>+namespace gcc >>+{ >>+ template<typename G_Tp> >>+ [[nodiscard]] >>+ constexpr std::add_const_t<G_Tp>& >>+ as_const(G_Tp& g_t) noexcept >>+ { return g_t; } >>+ >>+ template<typename G_Tp> >>+ void as_const(const G_Tp&&) = delete; > > An entire header for two macros and the as_const function which is > only used in the unused exception handling seems unnecessary. I could merge this into more_type_traits (or vice-versa). extras.h was supposed to be a catch-all for miscellany but most of the miscellany ended up in more_type_traits. FWIW, pretty much everything in this header is only present to enable running the libstdc++ testsuite on optional and expected. I think keeping the ability to do that (including the otherwise-unused exception handling) may be useful even if the tests don't run automatically, in case there's something to fix/add in the optional and expected implementation before the moment when we can drop them. > The deleted as_const overload is certainly not needed here. True, removed. >>+ // This does not match what libstdc++ does. It declares >>+ // true_type/false_type in terms of __bool_constant. But, if we're to >>+ // match the standard true_type/false_type, we have to do this. >>+ template<bool G_Bn> >>+ struct to_bool_trait_; >>+ template<> struct to_bool_trait_<true> >>+ { using type = std::true_type; }; >>+ template<> struct to_bool_trait_<false> >>+ { using type = std::false_type; }; >>+ >>+ template<bool G_Bn> >>+ using to_bool_trait = typename to_bool_trait_<G_Bn>::type; > > I think this is a pessimization compared to just: > > template<bool G_Bn> using to_bool_trait = std::integral_constant<bool, > G_Bn>; > > Your alias template forces an instantiation of the to_bool_trait_ > class template, which wouldn't be the case if you just defined the > alias template in terms of std::integral_constant. > > And since this is exactly equivalent to C++17 std::bool_constant, it > probably makes sense to name it gcc::bool_constant or > gcc::detail::bool_constant instead of the novel to_bool_trait name > > (and maybe define it in terms of std::bool_constant when the stage 1 > compiler is C++17, but that isn't really necessary as there's no > benefit to using the standard alias template instead your own > identical one ... maybe just a comment saying "this is the same as > bool_constant in C++17"). Yes, there's probably no benefit in that. Replaced with a bool_constant backport. >>+ // __invoke_result_t (std::invoke_result_t for C++11) >>+ template<typename G_Fn, typename... G_Args> >>+ using g_invoke_result_t = typename g_invoke_result<G_Fn, >>G_Args...>::type; >>+ /// @endcond > > Re-implementing all of this just for gcc::invoke is an enormous chunk > of code to maintain. Can't you just use std::result_of? > > #ifdef __cpp_lib_is_invocable // C++ >= 17 > template<typename Callable, typename... Args> > using g_invoke_result_t = std::invoke_result_t<Callable, Args...>; > #else > template<typename Callable, typename... Args> > using g_invoke_result_t = std::result_of_t<Callable, Args...>; > #endif > > There are some differences in behaviour between invoke_result and > result_of, but they're edge cases (related to decaying of the Args > types). I would think it's unlikely to matter in GCC code. I was actually hoping that the change to C++17 would come soon enough to just drop all of this code at some point in the relatively near future (that'd be earlier than the dropping of the rest of this backport code since optional features from C++>=20 were backported). result_of would /probably/ be okay, but I'm not sure if it's worth it, since the implementation of invoke_result here is just the libstdc++ one. However, switching on an FTM for the behavior of g_invoke_result_t might result in hard-to-debug situations, where a bit of code works in stage1 but breaks in bootstrap, or vice-versa. But, to make the question a bit more concrete: I'm not sure how likely that scenario is. Since invoke_result is used for the monadic operations (well, unless someone uses it elsewhere, in which case I'd rather not expose the 'invoke_result' name), Args can only be whatever can be stored in a optional or expected. Given that, do invoke_result and result_of even diverge? template<typename G_Tp> static constexpr bool g_is_valid_contained_type_for_optional = ( std::is_lvalue_reference<G_Tp>::value || (std::is_object<G_Tp>::value && std::is_destructible<G_Tp>::value && !std::is_array<G_Tp>::value) ) && !std::is_same<std::remove_cv_t<std::remove_reference_t<G_Tp>>, nullopt_t>::value && !std::is_same<std::remove_cv_t<std::remove_reference_t<G_Tp>>, in_place_t>::value; // true_type if E can be contained in an unexpected{} or !has_value // expected. template<typename E> using can_be_unexpected_val = and_< std::is_object<E>, not_<std::is_array<E>>, not_<is_unexpected<E>>, not_<is_cv_qualified<E>> >; // true_type if T can be contained in a has_value expected. template<typename T> using can_be_expected_val_2 = or_< std::is_same<T, void>, and_< std::is_object<T>, not_<std::is_array<T>>, not_<is_in_place<T>>, not_<is_unexpected<T>>, not_<std::is_same<T, unexpect_t>> > >; template<typename T> using can_be_expected_val = can_be_expected_val_2<std::remove_cv_t<T>>; ... i.e. no arrays or functions and no abstract classes (they'd fail to instantiate). I *think* it's possible to construct an example using std::expected monadic operations that has a difference in behavior, if the transforming callable had a 'const T&&' and 'T&&' overload. Granted, that is quite unlikely, but I don't like leaving even such very unlikely footguns in generic code, since they're a pain to debug. I think we're likely to get access to 'invoke' relatively soon. >>diff --git a/gcc/stdbackport/gbits/optional_ref.h >>b/gcc/stdbackport/gbits/optional_ref.h >>new file mode 100644 >>index 000000000000..b1f69d73a020 >>--- /dev/null >>+++ b/gcc/stdbackport/gbits/optional_ref.h > > Do you need a separate file for optional<T&>? > We need it in libstdc++ so that we can use it in std::exception_ptr > without including all of <optional> but you don't have that > requirement here. It could just be in the same file as the primary > template of gcc::optional. It could, but, by keeping it separate, it was much easier to make sure that I didn't make any unintended changes to the backported version. Basically, I ran the mechanical conversion on both, fixed them up to work in 14, and then ran it again and diffed it against my fixes, to verify that all the work I did was as small of a divergence as possible. >>+ // Used for constructing nullopt. >>+ enum class G_Construct { G_Token }; > > These names would certainly be better as just Construct and Token, > without the G_ prefix. Yes, the reason it's as such is what I said above: all of this code was mechanically converted and then kept as close to that as possible, to make it easier to verify no unintended changes happened. >>+/* This file provides the C++17 functions std::destroy_at, std::destroy, and >>+ * std::destroy_n, and the C++20 function std::construct_at. >>+ * It also provides std::_Construct, std::_Destroy,and std::_Destroy_n >>functions >>+ * which are defined in all standard modes and so can be used in C++98-14 >>code. >>+ * The _Destroy functions will dispatch to destroy_at during constant >>+ * evaluation, because calls to that function are intercepted by the compiler >>+ * to allow use in constant expressions. > > This comment is inaccurate as it still refers to the libstdc++ header. Ah, right. Same reasoning as above: I started with a mechanical conversion and forgot to remove this. >>+ */ >>+ >>+namespace gcc >>+{ >>+ >>+ /** >>+ * Constructs an object in existing memory by invoking an allocated >>+ * object's constructor with an initializer. >>+ */ >>+ template<typename G_Tp, typename... G_Args> >>+ GCC_BACKPORT20_CONSTEXPR >>+ inline void >>+ G_Construct(G_Tp* g_p, G_Args&&... g_args) >>+ { >>+#if __cpp_constexpr_dynamic_alloc // >= C++20 >>+ if (std::is_constant_evaluated()) >>+ { >>+ // Allow std::_Construct to be used in constant expressions. >>+ std::construct_at(g_p, std::forward<G_Args>(g_args)...); >>+ return; >>+ } >>+#endif >>+ ::new(static_cast<void*>(g_p)) G_Tp(std::forward<G_Args>(g_args)...); >>+ } >>+ >>+ /** >>+ * Destroy the object pointed to by a pointer type. >>+ */ >>+ template<typename G_Tp> >>+ constexpr inline std::enable_if_t<!std::is_array<G_Tp>::value> >>+ G_Destroy(G_Tp* g_pointer) >>+ { >>+ g_pointer->~G_Tp(); >>+ } >>+ >>+ template <typename G_Tp> >>+ inline std::enable_if_t<std::is_array<G_Tp>::value> >>+ G_Destroy(G_Tp* __location) >>+ { >>+ for (auto& __x : *__location) >>+ gcc::G_Destroy(std::addressof(__x)); >>+ } > > This should be renamed to destroy_at, not G_Destroy. Inside libstdc++ > we still need (and use) the pre-C++20 name, but you don't need that. > Use std::destroy_at instead. Ah, fair enough. Renamed. >>+ >>+#if __cplusplus < 202002L >>+ namespace detail { >>+ template<typename G_Up, typename... G_Args> >>+ static decltype (::new((void*)0) G_Up(std::declval<G_Args>()...), >>+ std::true_type {}) >>+ placement_new_test (int); >>+ >>+ template<typename G_Up, typename... G_Args> >>+ static std::false_type >>+ placement_new_test (...); >>+ } // namespace detail >>+ >>+ template<typename G_Tp, typename... G_Args> >>+ using can_placement_new >>+ = decltype(detail::placement_new_test<G_Tp, G_Args...>(0)); >>+ >>+ template<typename G_Tp, typename... G_Args> >>+ using can_use_construct_at = and_<can_placement_new<G_Tp, G_Args...>, >>+ not_<is_unbounded_array<G_Tp>>>; >>+ >>+ template<typename G_Tp, typename... G_Args> >>+ constexpr std::enable_if_t<and_<can_use_construct_at<G_Tp, G_Args...>, >>+ std::is_array<G_Tp>>::value, >>+ G_Tp*> >>+ construct_at (G_Tp* g_location, G_Args&&...) >>+ { >>+ void* g_loc = g_location; >>+ static_assert(sizeof...(G_Args) == 0, "std::construct_at for array " >>+ "types must not use any arguments to initialize the " >>+ "array"); >>+ return ::new(g_loc) G_Tp[1](); >>+ } >>+ template<typename G_Tp, typename... G_Args> >>+ constexpr std::enable_if_t<and_<can_use_construct_at<G_Tp, G_Args...>, >>+ not_<std::is_array<G_Tp>>>::value, >>+ G_Tp*> > > I don't think you need to constrain this function. It's constrained in > the standard library because it can be used directly by users, but for > the handful of uses inside gcc::optional and gcc::expected it's > irrelevant. If the value type can't be constructed, you would get > better diagnostics by just letting the compiler complain about the > placement-new expression below than by constraining std::construct_at > so that it becomes un-callable. > > And you don't need the overload for arrays, because optional and > expected do not allow array types. Yes, that's true, but the reason I kept that was just in case someone decides to use gcc::construct_at elsewhere. Though, perhaps a simpler approximation function is a good start until somebody does decide to do that. However, in that case, note that: >>+ construct_at (G_Tp* g_location, G_Args&&... g_args) >>+ { >>+ void* g_loc = g_location; >>+ return ::new(g_loc) G_Tp(std::forward<G_Args>(g_args)...); >>+ } >>+#else // C++ >= 20 >>+ // Use standard instead of our own implementation, to permit constexpr use. >>+ // Useful for running testsuites against expected. >>+ using std::construct_at; >>+#endif This '#if', which is here for sake of the testsuites, would mean that behavior can diverge between a future C++20 stage1 and a C++17 stage2, leading to a scenario similar to the one I posed above. >>+ G_M_construct(G_Args&&... g_args) >>+ noexcept(std::is_nothrow_constructible<G_Stored_type, G_Args...>::value) >>+ { >>+ gcc::G_Construct(std::addressof(this->G_M_payload.G_M_value), >>+ std::forward<G_Args>(g_args)...); > > Can't this just be gcc::construct_at, and then you don't need > G_Construct? That only exists in libstdc++ because std::optional is > C++17 so can't use std::construct_at. But your backport defines > gcc::construct_at unconditionally, so you could just use it here. > > That also avoids the name clash with the nullopt_t::G_Construct which > is a bit confusing. Yes - I did not notice this initially. Fixed. >>+namespace std { >>+ >>+ template<typename G_Tp> >>+ struct hash<gcc::optional<G_Tp>> >>+ // hash for optional<T&> is disabled because is_hash_enabled_for<T&> is >>false >>+ : public std::conditional_t< >>+ gcc::g_is_hash_enabled_for<std::remove_const_t<G_Tp>>::value, >>+ gcc::g_optional_hash<G_Tp>, >>+ gcc::g_hash_not_enabled<G_Tp>> > > Do you really need the g_hash_not_enabled stuff? > > The standard's std::hash<std::optional<T>> needs to perfectly > propagate the underlying enabled/disable property of std::hash<T>, but > you don't need that. If somebody tries to hash gcc::optional<T> for a > non-hashable type T, let them get an error. > > i.e. simplify the hash specialization above (or remove it entirely?) > and then get rid of the gcc/stdbackport/gbits/functional_hash.h > header. > > If gcc::optional really needs to be hashable, just do: > > namespace std { > template<typename T> > struct hash<gcc::optional<T>> > { > size_t operator()(const gcc::optional<T>& o) const > { > // We pick an arbitrary hash for disengaged optionals which hopefully > // usual values of _Tp won't typically hash to. > constexpr size_t g_magic_disengaged_hash = static_cast<size_t>(-3333); > return t ? std::hash<std::remove_t<T>>{}(*o) : g_magic_disengaged_hash; > } > }; > } > > No need for the deprecated result_type and argument_type typedefs, no > need for noexcept, no need for the separate g_optional_hash class, and > no need for the base class of std::hash to make it conditionally > disabled. This was also kept for the testsuite. Indeed, I initially just discarded hashability, but adding it back helped with testing (similar to exceptions). We can probably get rid of it in GCC proper, at expense of making the testsuite results noisier in case somebody re-runs them. I don't think it's that significant of a removal. Here's a new version per the above. Arsen Arsenović (2): gcc: backport std::{optional,expected} from libstdc++ into C++14 gcc: stop using 'int' to represent sets of qualifiers gcc/ada/gcc-interface/decl.cc | 15 +- gcc/ada/gcc-interface/gigi.h | 14 +- gcc/ada/gcc-interface/utils.cc | 3 +- gcc/attribs.cc | 7 +- gcc/attribs.h | 2 +- gcc/c-family/c-ada-spec.cc | 6 +- gcc/c-family/c-common.cc | 20 +- gcc/c-family/c-common.h | 8 +- gcc/c-family/c-format.cc | 2 +- gcc/c-family/c-pretty-print.cc | 9 +- gcc/c-family/c-pretty-print.h | 2 +- gcc/c/c-decl.cc | 90 +- gcc/c/c-objc-common.cc | 4 +- gcc/c/c-parser.cc | 8 +- gcc/c/c-tree.h | 6 +- gcc/c/c-typeck.cc | 84 +- gcc/config/aarch64/aarch64-acle-builtins.cc | 2 +- gcc/config/arm/arm-c.cc | 3 +- gcc/config/arm/arm-mve-builtins.cc | 2 +- gcc/config/avr/avr.cc | 8 +- gcc/config/gcn/gcn-tree.cc | 11 +- gcc/config/i386/i386-builtins.cc | 2 +- gcc/config/i386/i386.cc | 2 +- gcc/config/rl78/rl78.cc | 2 +- gcc/config/rs6000/rs6000-c.cc | 6 +- gcc/config/s390/s390-c.cc | 6 +- gcc/coretypes.h | 2 +- gcc/cp/call.cc | 4 +- gcc/cp/class.cc | 2 +- gcc/cp/cp-objcp-common.cc | 7 + gcc/cp/cp-objcp-common.h | 3 +- gcc/cp/cp-tree.h | 12 +- gcc/cp/decl.cc | 12 +- gcc/cp/error.cc | 2 +- gcc/cp/mangle.cc | 7 +- gcc/cp/method.cc | 32 +- gcc/cp/module.cc | 3 +- gcc/cp/pt.cc | 11 +- gcc/cp/reflect.cc | 12 +- gcc/cp/semantics.cc | 4 +- gcc/cp/tree.cc | 34 +- gcc/cp/typeck.cc | 42 +- gcc/d/d-codegen.cc | 2 +- gcc/d/types.cc | 2 +- gcc/doc/generic.texi | 460 ++- gcc/dwarf2out.cc | 46 +- gcc/fortran/trans-openmp.cc | 2 +- gcc/fortran/trans-types.cc | 3 +- gcc/gimple-lower-bitint.cc | 21 +- gcc/gimplify.cc | 13 +- gcc/ipa-free-lang-data.cc | 5 +- gcc/jit/dummy-frontend.cc | 2 +- gcc/langhooks-def.h | 2 +- gcc/langhooks.cc | 2 +- gcc/langhooks.h | 5 +- gcc/objc/objc-act.cc | 6 +- gcc/omp-low.cc | 4 +- gcc/omp-oacc-neuter-broadcast.cc | 4 +- gcc/omp-offload.cc | 15 +- gcc/rust/backend/rust-tree.cc | 35 +- gcc/rust/backend/rust-tree.h | 10 +- gcc/stdbackport/expected | 2544 +++++++++++++++++ gcc/stdbackport/expectedfwd | 35 + gcc/stdbackport/gbits/assert.h | 29 + gcc/stdbackport/gbits/check_system_h.h | 31 + .../gbits/enable_special_members.h | 302 ++ gcc/stdbackport/gbits/exception_defines.h | 48 + gcc/stdbackport/gbits/extras.h | 622 ++++ gcc/stdbackport/gbits/functional_hash.h | 54 + gcc/stdbackport/gbits/inplace_tags.h | 50 + gcc/stdbackport/gbits/invoke.h | 83 + gcc/stdbackport/gbits/optional_ref.h | 544 ++++ gcc/stdbackport/gbits/stl_construct.h | 126 + gcc/stdbackport/optional | 1783 ++++++++++++ gcc/stdbackport/optionalfwd | 36 + gcc/tree-core.h | 74 +- gcc/tree-dump.cc | 7 +- gcc/tree-pretty-print.cc | 14 +- gcc/tree-profile.cc | 2 +- gcc/tree-sra.cc | 3 +- gcc/tree-ssa-address.cc | 3 +- gcc/tree-switch-conversion.cc | 3 +- gcc/tree-vect-stmts.cc | 3 +- gcc/tree.cc | 180 +- gcc/tree.h | 282 +- gcc/ubsan.cc | 4 +- gcc/vtable-verify.cc | 6 +- libcc1/libcc1plugin.cc | 2 +- libcc1/libcp1plugin.cc | 4 +- 89 files changed, 7630 insertions(+), 396 deletions(-) create mode 100644 gcc/stdbackport/expected create mode 100644 gcc/stdbackport/expectedfwd create mode 100644 gcc/stdbackport/gbits/assert.h create mode 100644 gcc/stdbackport/gbits/check_system_h.h create mode 100644 gcc/stdbackport/gbits/enable_special_members.h create mode 100644 gcc/stdbackport/gbits/exception_defines.h create mode 100644 gcc/stdbackport/gbits/extras.h create mode 100644 gcc/stdbackport/gbits/functional_hash.h create mode 100644 gcc/stdbackport/gbits/inplace_tags.h create mode 100644 gcc/stdbackport/gbits/invoke.h create mode 100644 gcc/stdbackport/gbits/optional_ref.h create mode 100644 gcc/stdbackport/gbits/stl_construct.h create mode 100644 gcc/stdbackport/optional create mode 100644 gcc/stdbackport/optionalfwd -- 2.56.0
