/// even if the class has a trivial default constructor.
bool HasUninitializedReferenceMember : 1;
+ /// \brief True if any non-mutable field whose type doesn't have a user-
+ /// provided default ctor also doesn't have an in-class initializer.
+ bool HasUninitializedFields : 1;
+
/// \brief These flags are \c true if a defaulted corresponding special
/// member can't be fully analyzed without performing overload resolution.
/// @{
return !(data().HasTrivialSpecialMembers & SMF_Destructor);
}
+ /// \brief Determine whether declaring a const variable with this type is ok
+ /// per core issue 253.
+ bool allowConstDefaultInit() const {
+ return !data().HasUninitializedFields ||
+ hasUserProvidedDefaultConstructor();
+ }
+
/// \brief Determine whether this class has a destructor which has no
/// semantic effect.
///
ToData.HasInClassInitializer = FromData.HasInClassInitializer;
ToData.HasUninitializedReferenceMember
= FromData.HasUninitializedReferenceMember;
+ ToData.HasUninitializedFields = FromData.HasUninitializedFields;
ToData.NeedOverloadResolutionForMoveConstructor
= FromData.NeedOverloadResolutionForMoveConstructor;
ToData.NeedOverloadResolutionForMoveAssignment
}
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
- : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
- Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
- Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
- HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
- HasMutableFields(false), HasVariantMembers(false), HasOnlyCMembers(true),
- HasInClassInitializer(false), HasUninitializedReferenceMember(false),
- NeedOverloadResolutionForMoveConstructor(false),
- NeedOverloadResolutionForMoveAssignment(false),
- NeedOverloadResolutionForDestructor(false),
- DefaultedMoveConstructorIsDeleted(false),
- DefaultedMoveAssignmentIsDeleted(false),
- DefaultedDestructorIsDeleted(false),
- HasTrivialSpecialMembers(SMF_All),
- DeclaredNonTrivialSpecialMembers(0),
- HasIrrelevantDestructor(true),
- HasConstexprNonCopyMoveConstructor(false),
- DefaultedDefaultConstructorIsConstexpr(true),
- HasConstexprDefaultConstructor(false),
- HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
- UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
- ImplicitCopyConstructorHasConstParam(true),
- ImplicitCopyAssignmentHasConstParam(true),
- HasDeclaredCopyConstructorWithConstParam(false),
- HasDeclaredCopyAssignmentWithConstParam(false),
- IsLambda(false), IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0),
- Bases(), VBases(),
- Definition(D), FirstFriend() {
-}
+ : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
+ Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
+ Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
+ HasPrivateFields(false), HasProtectedFields(false),
+ HasPublicFields(false), HasMutableFields(false), HasVariantMembers(false),
+ HasOnlyCMembers(true), HasInClassInitializer(false),
+ HasUninitializedReferenceMember(false), HasUninitializedFields(false),
+ NeedOverloadResolutionForMoveConstructor(false),
+ NeedOverloadResolutionForMoveAssignment(false),
+ NeedOverloadResolutionForDestructor(false),
+ DefaultedMoveConstructorIsDeleted(false),
+ DefaultedMoveAssignmentIsDeleted(false),
+ DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All),
+ DeclaredNonTrivialSpecialMembers(0), HasIrrelevantDestructor(true),
+ HasConstexprNonCopyMoveConstructor(false),
+ DefaultedDefaultConstructorIsConstexpr(true),
+ HasConstexprDefaultConstructor(false),
+ HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
+ UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
+ ImplicitCopyConstructorHasConstParam(true),
+ ImplicitCopyAssignmentHasConstParam(true),
+ HasDeclaredCopyConstructorWithConstParam(false),
+ HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
+ IsParsingBaseSpecifiers(false), NumBases(0), NumVBases(0), Bases(),
+ VBases(), Definition(D), FirstFriend() {}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
return Bases.get(Definition->getASTContext().getExternalSource());
if (BaseClassDecl->hasUninitializedReferenceMember())
data().HasUninitializedReferenceMember = true;
+ if (!BaseClassDecl->allowConstDefaultInit())
+ data().HasUninitializedFields = true;
+
addedClassSubobject(BaseClassDecl);
}
data().IsStandardLayout = false;
}
+ if (!Field->hasInClassInitializer() && !Field->isMutable()) {
+ if (CXXRecordDecl *FieldType = Field->getType()->getAsCXXRecordDecl()) {
+ if (!FieldType->allowConstDefaultInit())
+ data().HasUninitializedFields = true;
+ } else {
+ data().HasUninitializedFields = true;
+ }
+ }
+
// Record if this field is the first non-literal or volatile field or base.
if (!T->isLiteralType(Context) || T.isVolatileQualified())
data().HasNonLiteralTypeFieldsOrBases = true;
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
// user-provided default constructor.
+ // C++ core issue 253 proposal:
+ // If the implicit default constructor initializes all subobjects, no
+ // initializer should be required.
+ // The 253 proposal is for example needed to process libstdc++ headers in 5.x.
+ CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
if (Kind.getKind() == InitializationKind::IK_Default &&
- Entity.getType().isConstQualified() &&
- !cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) {
- if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
- Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
- return;
+ Entity.getType().isConstQualified()) {
+ if (!CtorDecl->getParent()->allowConstDefaultInit()) {
+ if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
}
// C++11 [over.match.list]p1:
// In copy-list-initialization, if an explicit constructor is chosen, the
// initializer is ill-formed.
- CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
if (IsListInit && !Kind.AllowExplicit() && CtorDecl->isExplicit()) {
Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor);
return;
Data.HasOnlyCMembers = Record[Idx++];
Data.HasInClassInitializer = Record[Idx++];
Data.HasUninitializedReferenceMember = Record[Idx++];
+ Data.HasUninitializedFields = Record[Idx++];
Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++];
Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++];
Data.NeedOverloadResolutionForDestructor = Record[Idx++];
MATCH_FIELD(HasOnlyCMembers)
MATCH_FIELD(HasInClassInitializer)
MATCH_FIELD(HasUninitializedReferenceMember)
+ MATCH_FIELD(HasUninitializedFields)
MATCH_FIELD(NeedOverloadResolutionForMoveConstructor)
MATCH_FIELD(NeedOverloadResolutionForMoveAssignment)
MATCH_FIELD(NeedOverloadResolutionForDestructor)
Record.push_back(Data.HasOnlyCMembers);
Record.push_back(Data.HasInClassInitializer);
Record.push_back(Data.HasUninitializedReferenceMember);
+ Record.push_back(Data.HasUninitializedFields);
Record.push_back(Data.NeedOverloadResolutionForMoveConstructor);
Record.push_back(Data.NeedOverloadResolutionForMoveAssignment);
Record.push_back(Data.NeedOverloadResolutionForDestructor);
namespace PR13492 {
struct B {
B() = default;
+ int field;
};
void f() {
// If a program calls for the default initialization of an object of a
// const-qualified type T, T shall be a class type with a
-// user-provided default constructor.
+// user-provided default constructor, except if T has no uninitialized fields.
struct MakeNonPOD { MakeNonPOD(); };
-struct NoUserDefault : public MakeNonPOD { };
+struct NoUserDefault : public MakeNonPOD { int field; };
struct HasUserDefault { HasUserDefault(); };
void test_const_default_init() {
}
// rdar://8501008
-struct s0 {};
+struct s0 { int field; };
struct s1 { static const s0 foo; };
const struct s0 s1::foo; // expected-error{{default initialization of an object of const type 'const struct s0' without a user-provided default constructor}}
int check6[ __is_trivially_assignable(B, const B&) ? 1 : -1];
}
-namespace dr497 { // dr497: yes
+namespace dr497 { // dr497: sup 253
void before() {
struct S {
mutable int i;
};
- const S cs; // expected-error {{default initialization}}
+ const S cs;
int S::*pm = &S::i;
cs.*pm = 88; // expected-error {{not assignable}}
}
// The D3D11 headers do something like this. MSVC doesn't error on this at
// all, even without the __declspec(selectany), in violation of the standard.
// We fall back to a warning for selectany to accept headers.
-struct SomeStruct {};
+struct SomeStruct {
+ int foo;
+};
extern const __declspec(selectany) SomeStruct some_struct; // expected-warning {{default initialization of an object of const type 'const SomeStruct' without a user-provided default constructor is a Microsoft extension}}
// It should be possible to redeclare variables that were defined
constexpr A a; // expected-error {{constant expression}} expected-note {{in call to 'A()'}}
}
-constexpr B b1; // expected-error {{without a user-provided default constructor}}
+constexpr B b1; // ok
constexpr B b2 = B(); // ok
static_assert(b2.a.a == 1, "");
static_assert(b2.a.b == 2, "");
non_const_copy& operator = (non_const_copy&) &;
non_const_copy& operator = (non_const_copy&) &&;
non_const_copy() = default; // expected-note {{not viable}}
+ int uninit_field;
};
non_const_copy::non_const_copy(non_const_copy&) = default; // expected-note {{not viable}}
non_const_copy& non_const_copy::operator = (non_const_copy&) & = default; // expected-note {{not viable}}
ncc = cncc; // expected-error {{no viable overloaded}}
};
+struct no_fields { };
+struct all_init {
+ int a = 0;
+ int b = 0;
+};
+struct some_init {
+ int a = 0;
+ int b;
+ int c = 0;
+};
+struct some_init_mutable {
+ int a = 0;
+ mutable int b;
+ int c = 0;
+};
+struct some_init_def {
+ some_init_def() = default;
+ int a = 0;
+ int b;
+ int c = 0;
+};
+struct some_init_ctor {
+ some_init_ctor();
+ int a = 0;
+ int b;
+ int c = 0;
+};
+struct sub_some_init : public some_init_def { };
+struct sub_some_init_ctor : public some_init_def {
+ sub_some_init_ctor();
+};
+struct sub_some_init_ctor2 : public some_init_ctor {
+};
+struct some_init_container {
+ some_init_def sid;
+};
+struct some_init_container_ctor {
+ some_init_container_ctor();
+ some_init_def sid;
+};
+struct no_fields_container {
+ no_fields nf;
+};
+
+void constobjs() {
+ const no_fields nf; // ok
+ const all_init ai; // ok
+ const some_init si; // expected-error {{default initialization of an object of const type 'const some_init' without a user-provided default constructor}}
+ const some_init_mutable sim; // ok
+ const some_init_def sid; // expected-error {{default initialization of an object of const type 'const some_init_def' without a user-provided default constructor}}
+ const some_init_ctor sic; // ok
+ const sub_some_init ssi; // expected-error {{default initialization of an object of const type 'const sub_some_init' without a user-provided default constructor}}
+ const sub_some_init_ctor ssic; // ok
+ const sub_some_init_ctor2 ssic2; // ok
+ const some_init_container sicon; // expected-error {{default initialization of an object of const type 'const some_init_container' without a user-provided default constructor}}
+ const some_init_container_ctor siconc; // ok
+ const no_fields_container nfc; // ok
+}
+
struct non_const_derived : non_const_copy {
non_const_derived(const non_const_derived&) = default; // expected-error {{requires it to be non-const}}
non_const_derived& operator =(non_const_derived&) = default;
};
struct B {
+ int field;
};
struct X {
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#497">497</a></td>
<td>CD1</td>
<td>Missing required initialization in example</td>
- <td class="full" align="center">Yes</td>
+ <td class="none" align="center">Superseded by <a href="#253">253</a></td>
</tr>
<tr class="open" id="498">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#498">498</a></td>