From 2bb110125e0e5adb7c1c65d12adfa34151ca1c47 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 13 May 2011 01:05:07 +0000 Subject: [PATCH] When determining whether we can make a declaration into a global 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 | 7 +++++++ lib/AST/DeclCXX.cpp | 14 +++++++++++++- lib/CodeGen/CGBlocks.cpp | 19 +------------------ lib/CodeGen/CodeGenModule.cpp | 4 +++- lib/Serialization/ASTReaderDecl.cpp | 1 + lib/Serialization/ASTWriter.cpp | 1 + test/CodeGenCXX/global-llvm-constant.cpp | 12 ++++++++++++ 7 files changed, 38 insertions(+), 20 deletions(-) diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index b193b9a18e..51fc729ea5 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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) diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index f32c85629c..63fa9a77af 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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; } } diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index f26d79c066..c6bedd2846 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -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(); - if (hasMutableField(cast(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. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index d99230b556..ea2b2d16d6 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -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()) - return ConstantInit && cast(Record->getDecl())->isPOD(); + return ConstantInit && + cast(Record->getDecl())->isPOD() && + !cast(Record->getDecl())->hasMutableFields(); } return true; diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 85c8f079c0..feafe6f89e 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -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++]; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index aae62a8ff8..9682dfda12 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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); diff --git a/test/CodeGenCXX/global-llvm-constant.cpp b/test/CodeGenCXX/global-llvm-constant.cpp index b23337d634..2bd43b99a5 100644 --- a/test/CodeGenCXX/global-llvm-constant.cpp +++ b/test/CodeGenCXX/global-llvm-constant.cpp @@ -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 } } }; -- 2.40.0