thakis updated this revision to Diff 48373.
thakis marked an inline comment as done.
thakis added a comment.

address comments


http://reviews.llvm.org/D16552

Files:
  include/clang/AST/DeclCXX.h
  lib/AST/ASTImporter.cpp
  lib/AST/DeclCXX.cpp
  lib/Sema/SemaInit.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp
  test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
  test/CXX/dcl.decl/dcl.init/p6.cpp
  test/SemaCXX/attr-selectany.cpp
  test/SemaCXX/constexpr-value-init.cpp
  test/SemaCXX/cxx0x-cursory-default-delete.cpp
  test/SemaCXX/illegal-member-initialization.cpp

Index: test/SemaCXX/illegal-member-initialization.cpp
===================================================================
--- test/SemaCXX/illegal-member-initialization.cpp
+++ test/SemaCXX/illegal-member-initialization.cpp
@@ -7,6 +7,7 @@
 };
 
 struct B {
+  int field;
 };
 
 struct X {
Index: test/SemaCXX/cxx0x-cursory-default-delete.cpp
===================================================================
--- test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -11,6 +11,7 @@
   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}}
@@ -30,6 +31,65 @@
   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;
Index: test/SemaCXX/constexpr-value-init.cpp
===================================================================
--- test/SemaCXX/constexpr-value-init.cpp
+++ test/SemaCXX/constexpr-value-init.cpp
@@ -14,7 +14,7 @@
   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, "");
Index: test/SemaCXX/attr-selectany.cpp
===================================================================
--- test/SemaCXX/attr-selectany.cpp
+++ test/SemaCXX/attr-selectany.cpp
@@ -39,7 +39,9 @@
 // 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
Index: test/CXX/dcl.decl/dcl.init/p6.cpp
===================================================================
--- test/CXX/dcl.decl/dcl.init/p6.cpp
+++ test/CXX/dcl.decl/dcl.init/p6.cpp
@@ -4,9 +4,9 @@
 
 // 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() {
@@ -16,7 +16,7 @@
 }
 
 // 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}}
 
Index: test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
===================================================================
--- test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
+++ test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p2.cpp
@@ -116,6 +116,7 @@
 namespace PR13492 {
   struct B {
     B() = default;
+    int field;
   };
 
   void f() {
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -5554,6 +5554,7 @@
   Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
   Record.push_back(Data.DefaultedDestructorIsDeleted);
   Record.push_back(Data.HasTrivialSpecialMembers);
+  Record.push_back(Data.AllowConstDefaultInit);
   Record.push_back(Data.DeclaredNonTrivialSpecialMembers);
   Record.push_back(Data.HasIrrelevantDestructor);
   Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -1419,6 +1419,7 @@
   Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++];
   Data.DefaultedDestructorIsDeleted = Record[Idx++];
   Data.HasTrivialSpecialMembers = Record[Idx++];
+  Data.AllowConstDefaultInit = Record[Idx++];
   Data.DeclaredNonTrivialSpecialMembers = Record[Idx++];
   Data.HasIrrelevantDestructor = Record[Idx++];
   Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
Index: lib/Sema/SemaInit.cpp
===================================================================
--- lib/Sema/SemaInit.cpp
+++ lib/Sema/SemaInit.cpp
@@ -3515,18 +3515,23 @@
   //   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;
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -59,6 +59,7 @@
     DefaultedMoveAssignmentIsDeleted(false),
     DefaultedDestructorIsDeleted(false),
     HasTrivialSpecialMembers(SMF_All),
+    AllowConstDefaultInit(ACDI_Unknown),
     DeclaredNonTrivialSpecialMembers(0),
     HasIrrelevantDestructor(true),
     HasConstexprNonCopyMoveConstructor(false),
@@ -392,6 +393,37 @@
   return !forallBases([](const CXXRecordDecl *) { return true; });
 }
 
+bool CXXRecordDecl::allowConstDefaultInitSlow() const {
+  assert(getDefinition() && "only call this on completed records");
+  if (hasUserProvidedDefaultConstructor()) {
+    data().setAllowConstDefInitKind(DefinitionData::ACDI_Yes);
+    return true;
+  }
+  for (const auto *F : fields()) {
+    if (F->hasInClassInitializer() || F->isMutable() || F->isUnnamedBitfield())
+      continue;
+    if (CXXRecordDecl *FieldType = F->getType()->getAsCXXRecordDecl()) {
+      if (!FieldType->allowConstDefaultInit()) {
+        data().setAllowConstDefInitKind(DefinitionData::ACDI_No);
+        return false;
+      }
+    } else {
+      data().setAllowConstDefInitKind(DefinitionData::ACDI_No);
+      return false;
+    }
+  }
+  for (const auto& BI : bases()) {
+    const RecordType *RT = BI.getType()->getAs<RecordType>();
+    CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
+    if (!Base->allowConstDefaultInit()) {
+      data().setAllowConstDefInitKind(DefinitionData::ACDI_No);
+      return false;
+    }
+  }
+  data().setAllowConstDefInitKind(DefinitionData::ACDI_Yes);
+  return true;
+}
+
 bool CXXRecordDecl::isTriviallyCopyable() const {
   // C++0x [class]p5:
   //   A trivially copyable class is a class that:
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -2035,6 +2035,7 @@
       = FromData.DefaultedMoveAssignmentIsDeleted;
     ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted;
     ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers;
+    ToData.AllowConstDefaultInit = FromData.AllowConstDefaultInit;
     ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
     ToData.HasConstexprNonCopyMoveConstructor
       = FromData.HasConstexprNonCopyMoveConstructor;
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -402,6 +402,19 @@
     /// which have been declared but not yet defined.
     unsigned HasTrivialSpecialMembers : 6;
 
+    enum AllowConstDefInitKind {
+       ACDI_Unknown,
+       ACDI_Yes,
+       ACDI_No,
+    };
+    unsigned AllowConstDefaultInit : 2;
+    AllowConstDefInitKind allowConstDefInitKind() {
+      return static_cast<AllowConstDefInitKind>(AllowConstDefaultInit);
+    }
+    void setAllowConstDefInitKind(AllowConstDefInitKind Allow) {
+      AllowConstDefaultInit = Allow;
+    }
+
     /// \brief The declared special members of this class which are known to be
     /// non-trivial.
     ///
@@ -1270,6 +1283,15 @@
     return !(data().HasTrivialSpecialMembers & SMF_Destructor);
   }
 
+  /// \brief Determine whether declaring a const variable with this type is ok
+  /// per core issue 253.
+  bool allowConstDefaultInitSlow() const;
+  bool allowConstDefaultInit() const {
+    if (data().allowConstDefInitKind() != DefinitionData::ACDI_Unknown)
+      return data().allowConstDefInitKind() == DefinitionData::ACDI_Yes;
+    return allowConstDefaultInitSlow();
+  }
+
   /// \brief Determine whether this class has a destructor which has no
   /// semantic effect.
   ///
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to