[clang] 1b5404a - PR44540: Prefer an inherited default constructor over an initializer
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 14 19:31:33 PST 2020
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 {
More information about the cfe-commits
mailing list