elsteveogrande updated this revision to Diff 166148.
elsteveogrande added a comment.

Change `Optional` to `unique_ptr` instead, to at least save an allocation and 
keep the same semantics.  Reverified with `ninja check-clang`.


Repository:
  rC Clang

https://reviews.llvm.org/D50948

Files:
  include/clang/AST/DeclCXX.h
  lib/AST/DeclCXX.cpp
  lib/Serialization/ASTReaderDecl.cpp
  lib/Serialization/ASTWriter.cpp

Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -6010,7 +6010,7 @@
 
 void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
   auto &Data = D->data();
-  Record->push_back(Data.IsLambda);
+  Record->push_back(Data.hasLambdaData());  // lambda-specific data added below
   Record->push_back(Data.UserDeclaredConstructor);
   Record->push_back(Data.UserDeclaredSpecialMembers);
   Record->push_back(Data.Aggregate);
@@ -6068,8 +6068,6 @@
   if (ModulesDebugInfo)
     Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D));
 
-  // IsLambda bit is already saved.
-
   Record->push_back(Data.NumBases);
   if (Data.NumBases > 0)
     AddCXXBaseSpecifiers(Data.bases());
@@ -6085,8 +6083,8 @@
   AddDeclRef(D->getFirstFriend());
 
   // Add lambda-specific data.
-  if (Data.IsLambda) {
-    auto &Lambda = D->getLambdaData();
+  if (Data.hasLambdaData()) {
+    auto &Lambda = *Data.LambdaData;
     Record->push_back(Lambda.Dependent);
     Record->push_back(Lambda.IsGenericLambda);
     Record->push_back(Lambda.CaptureDefault);
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -1636,7 +1636,7 @@
 
 void ASTDeclReader::ReadCXXDefinitionData(
     struct CXXRecordDecl::DefinitionData &Data, const CXXRecordDecl *D) {
-  // Note: the caller has deserialized the IsLambda bit already.
+  // Note: the caller has deserialized the bit for `isLambda()` already.
   Data.UserDeclaredConstructor = Record.readInt();
   Data.UserDeclaredSpecialMembers = Record.readInt();
   Data.Aggregate = Record.readInt();
@@ -1703,10 +1703,10 @@
   assert(Data.Definition && "Data.Definition should be already set!");
   Data.FirstFriend = ReadDeclID();
 
-  if (Data.IsLambda) {
+  if (Data.hasLambdaData()) {
     using Capture = LambdaCapture;
 
-    auto &Lambda = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data);
+    auto &Lambda = *Data.LambdaData;
     Lambda.Dependent = Record.readInt();
     Lambda.IsGenericLambda = Record.readInt();
     Lambda.CaptureDefault = Record.readInt();
@@ -1761,7 +1761,8 @@
       PFDI->second == ASTReader::PendingFakeDefinitionKind::Fake) {
     // We faked up this definition data because we found a class for which we'd
     // not yet loaded the definition. Replace it with the real thing now.
-    assert(!DD.IsLambda && !MergeDD.IsLambda && "faked up lambda definition?");
+    assert(!DD.hasLambdaData() && !MergeDD.hasLambdaData() &&
+           "faked up lambda definition?");
     PFDI->second = ASTReader::PendingFakeDefinitionKind::FakeLoaded;
 
     // Don't change which declaration is the definition; that is required
@@ -1826,7 +1827,6 @@
   MATCH_FIELD(ImplicitCopyAssignmentHasConstParam)
   OR_FIELD(HasDeclaredCopyConstructorWithConstParam)
   OR_FIELD(HasDeclaredCopyAssignmentWithConstParam)
-  MATCH_FIELD(IsLambda)
 #undef OR_FIELD
 #undef MATCH_FIELD
 
@@ -1845,7 +1845,7 @@
   // FIXME: Issue a diagnostic if FirstFriend doesn't match when we come to
   // lazily load it.
 
-  if (DD.IsLambda) {
+  if (DD.hasLambdaData()) {
     // FIXME: ODR-checking for merging lambdas (this happens, for instance,
     // when they occur within the body of a function template specialization).
   }
@@ -1860,17 +1860,17 @@
 }
 
 void ASTDeclReader::ReadCXXRecordDefinition(CXXRecordDecl *D, bool Update) {
-  struct CXXRecordDecl::DefinitionData *DD;
   ASTContext &C = Reader.getContext();
 
+  struct CXXRecordDecl::DefinitionData *DD =
+      new (C) struct CXXRecordDecl::DefinitionData(D);
+
   // Determine whether this is a lambda closure type, so that we can
-  // allocate the appropriate DefinitionData structure.
-  bool IsLambda = Record.readInt();
-  if (IsLambda)
-    DD = new (C) CXXRecordDecl::LambdaDefinitionData(D, nullptr, false, false,
-                                                     LCD_None);
-  else
-    DD = new (C) struct CXXRecordDecl::DefinitionData(D);
+  // set the LambdaDefinitionData (into optional \c LambdaData field) as well.
+  bool isLambda = Record.readInt();
+  if (isLambda) {
+    DD->SetLambdaDefinitionData(nullptr, false, false, LCD_None);
+  }
 
   CXXRecordDecl *Canon = D->getCanonicalDecl();
   // Set decl definition data before reading it, so that during deserialization
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -102,7 +102,7 @@
       ImplicitCopyConstructorCanHaveConstParamForNonVBase(true),
       ImplicitCopyAssignmentHasConstParam(true),
       HasDeclaredCopyConstructorWithConstParam(false),
-      HasDeclaredCopyAssignmentWithConstParam(false), IsLambda(false),
+      HasDeclaredCopyAssignmentWithConstParam(false),
       IsParsingBaseSpecifiers(false), HasODRHash(false), Definition(D) {}
 
 CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -144,9 +144,9 @@
   auto *R = new (C, DC) CXXRecordDecl(CXXRecord, TTK_Class, C, DC, Loc, Loc,
                                       nullptr, nullptr);
   R->setBeingDefined(true);
-  R->DefinitionData =
-      new (C) struct LambdaDefinitionData(R, Info, Dependent, IsGeneric,
-                                          CaptureDefault);
+  R->DefinitionData = new (C) struct DefinitionData(R);
+  R->DefinitionData->SetLambdaDefinitionData(Info, Dependent, IsGeneric,
+                                             CaptureDefault);
   R->setMayHaveOutOfDateDef(false);
   R->setImplicit(true);
   C.getTypeDeclType(R, /*PrevDecl=*/nullptr);
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -321,7 +321,59 @@
     SMF_All = 0x3f
   };
 
-  struct DefinitionData {
+  /// Describes a C++ closure type (generated by a lambda expression).
+  /// Nested within the DefinitionData, see \c LambdaData.
+  struct LambdaDefinitionData {
+    using Capture = LambdaCapture;
+
+    /// Whether this lambda is known to be dependent, even if its
+    /// context isn't dependent.
+    ///
+    /// A lambda with a non-dependent context can be dependent if it occurs
+    /// within the default argument of a function template, because the
+    /// lambda will have been created with the enclosing context as its
+    /// declaration context, rather than function. This is an unfortunate
+    /// artifact of having to parse the default arguments before.
+    unsigned Dependent : 1;
+
+    /// Whether this lambda is a generic lambda.
+    unsigned IsGenericLambda : 1;
+
+    /// The Default Capture.
+    unsigned CaptureDefault : 2;
+
+    /// The number of captures in this lambda is limited 2^NumCaptures.
+    unsigned NumCaptures : 15;
+
+    /// The number of explicit captures in this lambda.
+    unsigned NumExplicitCaptures : 13;
+
+    /// The number used to indicate this lambda expression for name
+    /// mangling in the Itanium C++ ABI.
+    unsigned ManglingNumber = 0;
+
+    /// The declaration that provides context for this lambda, if the
+    /// actual DeclContext does not suffice. This is used for lambdas that
+    /// occur within default arguments of function parameters within the class
+    /// or within a data member initializer.
+    LazyDeclPtr ContextDecl;
+
+    /// The list of captures, both explicit and implicit, for this
+    /// lambda.
+    Capture *Captures = nullptr;
+
+    /// The type of the call method.
+    TypeSourceInfo *MethodTyInfo;
+
+    LambdaDefinitionData(TypeSourceInfo *Info,
+                         bool Dependent, bool IsGeneric,
+                         LambdaCaptureDefault CaptureDefault)
+      : Dependent(Dependent), IsGenericLambda(IsGeneric),
+        CaptureDefault(CaptureDefault), NumCaptures(0), NumExplicitCaptures(0),
+        MethodTyInfo(Info) {}
+  };
+
+  struct DefinitionData final {
     /// True if this class has any user-declared constructors.
     unsigned UserDeclaredConstructor : 1;
 
@@ -522,9 +574,6 @@
     /// const-qualified reference parameter or a non-reference parameter.
     unsigned HasDeclaredCopyAssignmentWithConstParam : 1;
 
-    /// Whether this class describes a C++ lambda.
-    unsigned IsLambda : 1;
-
     /// Whether we are currently parsing base specifiers.
     unsigned IsParsingBaseSpecifiers : 1;
 
@@ -569,6 +618,9 @@
     /// This is actually currently stored in reverse order.
     LazyDeclPtr FirstFriend;
 
+    /// Present if and only if this is for a lambda.
+    std::unique_ptr<LambdaDefinitionData> LambdaData;
+
     DefinitionData(CXXRecordDecl *D);
 
     /// Retrieve the set of direct base classes.
@@ -593,71 +645,35 @@
       return llvm::makeArrayRef(getVBases(), NumVBases);
     }
 
-  private:
-    CXXBaseSpecifier *getBasesSlowCase() const;
-    CXXBaseSpecifier *getVBasesSlowCase() const;
-  };
-
-  struct DefinitionData *DefinitionData;
-
-  /// Describes a C++ closure type (generated by a lambda expression).
-  struct LambdaDefinitionData : public DefinitionData {
-    using Capture = LambdaCapture;
-
-    /// Whether this lambda is known to be dependent, even if its
-    /// context isn't dependent.
-    ///
-    /// A lambda with a non-dependent context can be dependent if it occurs
-    /// within the default argument of a function template, because the
-    /// lambda will have been created with the enclosing context as its
-    /// declaration context, rather than function. This is an unfortunate
-    /// artifact of having to parse the default arguments before.
-    unsigned Dependent : 1;
-
-    /// Whether this lambda is a generic lambda.
-    unsigned IsGenericLambda : 1;
-
-    /// The Default Capture.
-    unsigned CaptureDefault : 2;
-
-    /// The number of captures in this lambda is limited 2^NumCaptures.
-    unsigned NumCaptures : 15;
-
-    /// The number of explicit captures in this lambda.
-    unsigned NumExplicitCaptures : 13;
-
-    /// The number used to indicate this lambda expression for name
-    /// mangling in the Itanium C++ ABI.
-    unsigned ManglingNumber = 0;
-
-    /// The declaration that provides context for this lambda, if the
-    /// actual DeclContext does not suffice. This is used for lambdas that
-    /// occur within default arguments of function parameters within the class
-    /// or within a data member initializer.
-    LazyDeclPtr ContextDecl;
-
-    /// The list of captures, both explicit and implicit, for this
-    /// lambda.
-    Capture *Captures = nullptr;
-
-    /// The type of the call method.
-    TypeSourceInfo *MethodTyInfo;
-
-    LambdaDefinitionData(CXXRecordDecl *D, TypeSourceInfo *Info,
+    void SetLambdaDefinitionData(TypeSourceInfo *Info,
                          bool Dependent, bool IsGeneric,
-                         LambdaCaptureDefault CaptureDefault)
-      : DefinitionData(D), Dependent(Dependent), IsGenericLambda(IsGeneric),
-        CaptureDefault(CaptureDefault), NumCaptures(0), NumExplicitCaptures(0),
-        MethodTyInfo(Info) {
-      IsLambda = true;
+                         LambdaCaptureDefault CaptureDefault) {
+      LambdaData.reset(new LambdaDefinitionData(
+          Info, Dependent, IsGeneric, CaptureDefault));
+
+      // Ensure the following members are set correctly, since we know now
+      // this is for a lambda.  These members are set to true by default.
 
       // C++1z [expr.prim.lambda]p4:
       //   This class type is not an aggregate type.
       Aggregate = false;
       PlainOldData = false;
+
+      // Not C-like.
+      HasOnlyCMembers = false;
+    }
+
+    bool hasLambdaData() const {
+      return bool(LambdaData);
     }
+
+  private:
+    CXXBaseSpecifier *getBasesSlowCase() const;
+    CXXBaseSpecifier *getVBasesSlowCase() const;
   };
 
+  struct DefinitionData *DefinitionData;
+
   struct DefinitionData *dataPtr() const {
     // Complete the redecl chain (if necessary).
     getMostRecentDecl();
@@ -674,8 +690,9 @@
     // No update required: a merged definition cannot change any lambda
     // properties.
     auto *DD = DefinitionData;
-    assert(DD && DD->IsLambda && "queried lambda property of non-lambda class");
-    return static_cast<LambdaDefinitionData&>(*DD);
+    assert(DD && DD->LambdaData.hasValue() &&
+           "queried lambda property of non-lambda class");
+    return *DD->LambdaData;
   }
 
   /// The template or declaration that this declaration
@@ -1202,7 +1219,7 @@
   bool isLambda() const {
     // An update record can't turn a non-lambda into a lambda.
     auto *DD = DefinitionData;
-    return DD && DD->IsLambda;
+    return DD && DD->hasLambdaData();
   }
 
   /// Determine whether this class describes a generic
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D50948: l... Steve O'Brien via Phabricator via cfe-commits
    • [PATCH] D509... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D509... Steve O'Brien via Phabricator via cfe-commits
    • [PATCH] D509... Steve O'Brien via Phabricator via cfe-commits
    • [PATCH] D509... Steve O'Brien via Phabricator via cfe-commits

Reply via email to