From 86af6f5088b16c98e7033a6a5cf3c889c5d95e57 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Mon, 11 Mar 2019 22:55:21 +0000 Subject: [PATCH] Allow optional to tolerate being used with a nested class. When Clang tries to complete a type containing `std::optional` it considers the `in_place_t` constructor with no arguments which checks if the value type is default constructible. If the value type is a nested class type, then this check occurs too early and poisons the is_default_constructible trait. This patch makes optional deduce `in_place_t` so we can prevent this early SFINAE evaluation. Technically this could break people doing weird things with the in_place_t tag, but that seems less important than making the nested class case work. llvm-svn: 355877 --- libcxx/include/optional | 10 +++-- ...empty_in_place_t_does_not_clobber.pass.cpp | 41 +++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/empty_in_place_t_does_not_clobber.pass.cpp diff --git a/libcxx/include/optional b/libcxx/include/optional index be584b3cee13..7c136aec3a26 100644 --- a/libcxx/include/optional +++ b/libcxx/include/optional @@ -687,11 +687,15 @@ public: _LIBCPP_INLINE_VISIBILITY constexpr optional(optional&&) = default; _LIBCPP_INLINE_VISIBILITY constexpr optional(nullopt_t) noexcept {} - template > + template , + is_constructible + >::value + > > _LIBCPP_INLINE_VISIBILITY - constexpr explicit optional(in_place_t, _Args&&... __args) + constexpr explicit optional(_InPlaceT, _Args&&... __args) : __base(in_place, _VSTD::forward<_Args>(__args)...) {} template + +// constexpr optional(in_place_t); + +// Test that the SFINAE "is_constructible" isn't evaluated by the +// in_place_t constructor with no arguments when the Clang is trying to check +// copy constructor. + +#include +#include +#include + +#include "test_macros.h" +#include "archetypes.hpp" + +using std::optional; + +struct Wrapped { + struct Inner { + bool Dummy = true; + }; + std::optional inner; +}; + +int main(int, char**) { + static_assert(std::is_default_constructible::value, ""); + Wrapped w; + w.inner.emplace(); + assert(w.inner.has_value()); + + return 0; +}