LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 45158 - __is_constructible intrinsic does not SFINAE on default member initializers
Summary: __is_constructible intrinsic does not SFINAE on default member initializers
Status: RESOLVED INVALID
Alias: None
Product: clang
Classification: Unclassified
Component: C++ (show other bugs)
Version: 9.0
Hardware: PC Linux
: P normal
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-03-09 12:02 PDT by Alisdair Meredith
Modified: 2020-09-11 18:30 PDT (History)
6 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alisdair Meredith 2020-03-09 12:02:13 PDT
The various standard type traits querying whether a type is constructible are implemented (in both libc++ and libstdc++) as ultimately delegating to an intrinsic such as __is_constructible.  This trait fails to account for default member initializers, which produce a hard error rather than returning a true/false answer when evaluating the intrinsic, and hence the trait.

Example:

#include <type_traits>

template <class T>
struct Wrap {
    Wrap() = default;

    T data{};    // default member initializer
};

struct NoDefault {
    NoDefault(NoDefault const&) {}  // non-trivial, not an aggregate
};

int main() {
    using namespace std;
    static_assert(!is_default_constructible<Wrap<NoDefault>>::value, "bad");
}


Godbolt link for quick experimentation: https://godbolt.org/z/-D9mpA

This fails with both libc++ and libstdc++, for all dialects of C++11 and later, for all online compilers up to and including trunk.
Comment 1 Richard Smith 2020-03-09 16:55:16 PDT
SFINAE only applies to instantiating the declaration of a function template specialization (and a few other things not relevant here). It does not apply to triggering the implicit definition of a defaulted constructor, nor to determining whether a defaulted constructor would be implicitly deleted.

It doesn't appear to me that Clang is doing anything wrong here.


If you want this case to become valid, I think the right core issue to file would be to suggest that [class.default.ctor]/2 should say that a defaulted default constructor is defined as deleted if it's in a templated class and instantiation of any default member initializer results in an invalid type or expression in the immediate context of the instantiation. (That is, add a brand new kind of SFINAE for this case.) CWG2202 is doing something similar for default arguments, so this is not unprecedented.
Comment 2 Sergey 2020-09-11 05:37:21 PDT
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96645
Is there a same bug as in GCC?

Tried to compile this code:

template<bool B>
struct bool_constant
{
  static constexpr bool value = B;
  using type = bool_constant;
};

using true_type = bool_constant<true>;

template<typename T>
struct is_default_constructible
: bool_constant<__is_constructible(T)>
{ };

void testVarStruct()
{
    struct DataWithStruct {
        struct A {
            int number = 5; // compiles, if remove initialization
        };

        is_default_constructible<A>::type t = true_type{};
    };
}


Output:
<source>:22:47: error: no viable conversion from 'bool_constant<true>' to 'bool_constant<false>'

        is_default_constructible<A>::type t = true_type{};
Comment 3 Richard Smith 2020-09-11 18:30:08 PDT
Re comment#2, that's not the same as this issue.

Default member initializers are not parsed until the closing brace of the outermost enclosing class they're nested within -- the default member initializer for A is not parsed until we reach the end of DataWithStruct. As a consequence (in particular, because we can't compute the exception specification for the default constructor until we've parsed the default member initializers, and in general we never form a call to a function until after we know its exception specification), default construction of an `A` fails in the context of the type of DataWithStruct::t.

So that's not a bug.

Given the original problem is also not a bug, I'm going to resolve this INVALID. We can reopen it or open a new bug if the committee decides to do something SFINAE-like for default member initializers.