]> granicus.if.org Git - clang/commitdiff
When determining whether we can make a declaration into a global
authorDouglas Gregor <dgregor@apple.com>
Fri, 13 May 2011 01:05:07 +0000 (01:05 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 13 May 2011 01:05:07 +0000 (01:05 +0000)
constant, also consider whether it's a class type that has any mutable
fields. If so, it can't be a global constant.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131276 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclCXX.h
lib/AST/DeclCXX.cpp
lib/CodeGen/CGBlocks.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
test/CodeGenCXX/global-llvm-constant.cpp

index b193b9a18ee4047f412dc6c0de075d94042b5939..51fc729ea565f541d56a6f92fc5968e4d8311379 100644 (file)
@@ -337,6 +337,9 @@ class CXXRecordDecl : public RecordDecl {
     /// HasPublicFields - True when there are private non-static data members.
     bool HasPublicFields : 1;
 
+    /// \brief True if this class (or any subobject) has mutable fields.
+    bool HasMutableFields : 1;
+    
     /// HasTrivialDefaultConstructor - True when, if this class has a default
     /// constructor, this default constructor is trivial.
     ///
@@ -822,6 +825,10 @@ public:
   /// (C++ [class]p7)
   bool isStandardLayout() const { return data().IsStandardLayout; }
 
+  /// \brief Whether this class, or any of its class subobjects, contains a
+  /// mutable field.
+  bool hasMutableFields() const { return data().HasMutableFields; }
+  
   // hasTrivialDefaultConstructor - Whether this class has a trivial default
   // constructor
   // (C++0x [class.ctor]p5)
index f32c85629c5a4f0f78d1ed0b7f050015038d965e..63fa9a77af0c63bb36b78aae700a58d441e04a9b 100644 (file)
@@ -33,7 +33,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
     Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
     Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
     HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
-    HasTrivialDefaultConstructor(true),
+    HasMutableFields(false), HasTrivialDefaultConstructor(true),
     HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
     HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
     HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
@@ -225,6 +225,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
     //   have trivial destructors.
     if (!BaseClassDecl->hasTrivialDestructor())
       data().HasTrivialDestructor = false;
+    
+    // Keep track of the presence of mutable fields.
+    if (BaseClassDecl->hasMutableFields())
+      data().HasMutableFields = true;
   }
   
   if (VBases.empty())
@@ -688,6 +692,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
          data().HasPublicFields) > 1)
       data().IsStandardLayout = false;
 
+    // Keep track of the presence of mutable fields.
+    if (Field->isMutable())
+      data().HasMutableFields = true;
+    
     // C++0x [class]p9:
     //   A POD struct is a class that is both a trivial class and a 
     //   standard-layout class, and has no non-static data members of type 
@@ -779,6 +787,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
             }
           }
         }
+        
+        // Keep track of the presence of mutable fields.
+        if (FieldRec->hasMutableFields())
+          data().HasMutableFields = true;
       }
     }
 
index f26d79c0667dd266a0cb68ca2a59bfbf39a31bce..c6bedd28460140a9f4737f45fbc48c6a4789d180 100644 (file)
@@ -189,23 +189,6 @@ namespace {
   }
 }
 
-/// Determines if the given record type has a mutable field.
-static bool hasMutableField(const CXXRecordDecl *record) {
-  for (CXXRecordDecl::field_iterator
-         i = record->field_begin(), e = record->field_end(); i != e; ++i)
-    if ((*i)->isMutable())
-      return true;
-
-  for (CXXRecordDecl::base_class_const_iterator
-         i = record->bases_begin(), e = record->bases_end(); i != e; ++i) {
-    const RecordType *record = i->getType()->castAs<RecordType>();
-    if (hasMutableField(cast<CXXRecordDecl>(record->getDecl())))
-      return true;
-  }
-
-  return false;
-}
-
 /// Determines if the given type is safe for constant capture in C++.
 static bool isSafeForCXXConstantCapture(QualType type) {
   const RecordType *recordType =
@@ -222,7 +205,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
 
   // Otherwise, we just have to make sure there aren't any mutable
   // fields that might have changed since initialization.
-  return !hasMutableField(record);
+  return !record->hasMutableFields();
 }
 
 /// It is illegal to modify a const object after initialization.
index d99230b556ec76cf0b4a0b4ed3fade8a379bbcc2..ea2b2d16d614fd05193dad6c48ad500604d26f53 100644 (file)
@@ -946,7 +946,9 @@ static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
   if (Context.getLangOptions().CPlusPlus) {
     if (const RecordType *Record 
           = Context.getBaseElementType(D->getType())->getAs<RecordType>())
-      return ConstantInit && cast<CXXRecordDecl>(Record->getDecl())->isPOD();
+      return ConstantInit && 
+             cast<CXXRecordDecl>(Record->getDecl())->isPOD() &&
+             !cast<CXXRecordDecl>(Record->getDecl())->hasMutableFields();
   }
   
   return true;
index 85c8f079c006fd17659b5b4a10bda77106f0f2bf..feafe6f89e1cd87699dc4322e7f282034ab04d19 100644 (file)
@@ -860,6 +860,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
   Data.HasPrivateFields = Record[Idx++];
   Data.HasProtectedFields = Record[Idx++];
   Data.HasPublicFields = Record[Idx++];
+  Data.HasMutableFields = Record[Idx++];
   Data.HasTrivialDefaultConstructor = Record[Idx++];
   Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
   Data.HasTrivialCopyConstructor = Record[Idx++];
index aae62a8ff869ed0d9d154632e98a73dc91d15218..9682dfda12119f375649987c7cafb4a8d02a09fb 100644 (file)
@@ -3818,6 +3818,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
   Record.push_back(Data.HasPrivateFields);
   Record.push_back(Data.HasProtectedFields);
   Record.push_back(Data.HasPublicFields);
+  Record.push_back(Data.HasMutableFields);
   Record.push_back(Data.HasTrivialDefaultConstructor);
   Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
   Record.push_back(Data.HasTrivialCopyConstructor);
index b23337d634cbe8ff3f6699b664ebc2b4fe6ca60a..2bd43b99a5d94880faa242a0f09994e64ff61cbb 100644 (file)
@@ -18,3 +18,15 @@ int add(int x, int y) { return x + y; }
 // CHECK: @x2 = constant
 extern const X x2;
 const X x2 = { &add };
+
+struct X1 {
+  mutable int i;
+};
+
+struct X2 {
+  X1 array[3];
+};
+
+// CHECK: @x2b = global
+extern const X2 x2b;
+const X2 x2b = { { { 1 }, { 2 }, { 3 } } };