Author: Richard Smith Date: 2020-01-14T19:29:50-08:00 New Revision: 1b5404aff37953ce4c10191d04872ed7c2dc6548
URL: https://github.com/llvm/llvm-project/commit/1b5404aff37953ce4c10191d04872ed7c2dc6548 DIFF: https://github.com/llvm/llvm-project/commit/1b5404aff37953ce4c10191d04872ed7c2dc6548.diff LOG: 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. Added: Modified: clang/lib/AST/DeclCXX.cpp clang/lib/Sema/SemaInit.cpp clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index bc75c4e544d2..2ead1e70ea0d 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -738,49 +738,55 @@ void CXXRecordDecl::addedMember(Decl *D) { // Handle constructors. if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - if (!Constructor->isImplicit()) { - // Note that we have a user-declared constructor. - data().UserDeclaredConstructor = true; + 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. + data().PlainOldData = false; + } - // 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. - data().PlainOldData = false; - } + if (Constructor->isDefaultConstructor()) { + SMKind |= SMF_DefaultConstructor; - if (Constructor->isDefaultConstructor()) { - SMKind |= SMF_DefaultConstructor; + if (Constructor->isUserProvided()) + data().UserProvidedDefaultConstructor = true; + if (Constructor->isConstexpr()) + data().HasConstexprDefaultConstructor = true; + if (Constructor->isDefaulted()) + data().HasDefaultedDefaultConstructor = true; + } - if (Constructor->isUserProvided()) - data().UserProvidedDefaultConstructor = true; - if (Constructor->isConstexpr()) - data().HasConstexprDefaultConstructor = true; - if (Constructor->isDefaulted()) - data().HasDefaultedDefaultConstructor = true; - } + if (!FunTmpl) { + unsigned Quals; + if (Constructor->isCopyConstructor(Quals)) { + SMKind |= SMF_CopyConstructor; - if (!FunTmpl) { - unsigned Quals; - if (Constructor->isCopyConstructor(Quals)) { - SMKind |= SMF_CopyConstructor; + if (Quals & Qualifiers::Const) + data().HasDeclaredCopyConstructorWithConstParam = true; + } else if (Constructor->isMoveConstructor()) + SMKind |= SMF_MoveConstructor; + } - if (Quals & Qualifiers::Const) - data().HasDeclaredCopyConstructorWithConstParam = true; - } else if (Constructor->isMoveConstructor()) - SMKind |= SMF_MoveConstructor; + // C++11 [dcl.init.aggr]p1: DR1518 + // An aggregate is an array or a class with no user-provided [or] + // explicit [...] constructors + // C++20 [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-declared [...] + // constructors + if (getASTContext().getLangOpts().CPlusPlus2a + ? !Constructor->isImplicit() + : (Constructor->isUserProvided() || Constructor->isExplicit())) + data().Aggregate = false; } - - // C++11 [dcl.init.aggr]p1: DR1518 - // An aggregate is an array or a class with no user-provided [or] - // explicit [...] constructors - // C++20 [dcl.init.aggr]p1: - // An aggregate is an array or a class with no user-declared [...] - // constructors - if (getASTContext().getLangOpts().CPlusPlus2a - ? !Constructor->isImplicit() - : (Constructor->isUserProvided() || Constructor->isExplicit())) - data().Aggregate = false; } // Handle constructors, including those inherited from base classes. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 163ad8dc54dc..785637761e71 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -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; } diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp index ade327485773..e185e8fc1226 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3.cpp @@ -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 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits