Commit 1b5404af authored by Richard Smith's avatar Richard Smith
Browse files

PR44540: Prefer an inherited default constructor over an initializer

list constructor when initializing from {}.

We would previously pick between calling an initializer list constructor
and calling a default constructor unstably in this situation, depending
on whether the inherited default constructor had already been used
elsewhere in the program.
parent c6e69880
Loading
Loading
Loading
Loading
+43 −37
Original line number Diff line number Diff line
@@ -738,14 +738,19 @@ void CXXRecordDecl::addedMember(Decl *D) {

  // Handle constructors.
  if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
    if (Constructor->isInheritingConstructor()) {
      // Ignore constructor shadow declarations. They are lazily created and
      // so shouldn't affect any properties of the class.
    } else {
      if (!Constructor->isImplicit()) {
        // Note that we have a user-declared constructor.
        data().UserDeclaredConstructor = true;

        // C++ [class]p4:
        //   A POD-struct is an aggregate class [...]
      // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
      // type is technically an aggregate in C++0x since it wouldn't be in 03.
        // Since the POD bit is meant to be C++03 POD-ness, clear it even if
        // the type is technically an aggregate in C++0x since it wouldn't be
        // in 03.
        data().PlainOldData = false;
      }

@@ -782,6 +787,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
              : (Constructor->isUserProvided() || Constructor->isExplicit()))
        data().Aggregate = false;
    }
  }

  // Handle constructors, including those inherited from base classes.
  if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(DUnderlying)) {
+2 −2
Original line number Diff line number Diff line
@@ -4059,7 +4059,7 @@ static void TryConstructorInitialization(Sema &S,

    // If the initializer list has no elements and T has a default constructor,
    // the first phase is omitted.
    if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor()))
    if (!(UnwrappedArgs.empty() && S.LookupDefaultConstructor(DestRecordDecl)))
      Result = ResolveConstructorOverload(S, Kind.getLocation(), Args,
                                          CandidateSet, DestType, Ctors, Best,
                                          CopyInitialization, AllowExplicit,
@@ -4343,7 +4343,7 @@ static void TryListInitialization(Sema &S,
      //     value-initialized.
      if (InitList->getNumInits() == 0) {
        CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
        if (RD->hasDefaultConstructor()) {
        if (S.LookupDefaultConstructor(RD)) {
          TryValueInitialization(S, Entity, Kind, Sequence, InitList);
          return;
        }
+14 −0
Original line number Diff line number Diff line
@@ -86,6 +86,20 @@ namespace bullet6 {
  const int& i1 = { 1 };
  const int& i2 = { 1.1 };  // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{silence}} expected-warning {{implicit conversion}}
  const int (&iar)[2] = { 1, 2 };

  // We interpret "class type with a default constructor" as including the case
  // where a default constructor is inherited.
  struct X {
    X();
    X(std::initializer_list<int>) = delete;
  };
  struct Y : X {
    using X::X;
    Y(int);
  };
  Y y1{};
  void use() { Y y; }
  Y y2{};
}

namespace bullet7 {