зеркало из https://github.com/microsoft/clang.git
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
This commit is contained in:
Родитель
7880bc34fd
Коммит
2bb110125e
|
@ -337,6 +337,9 @@ class CXXRecordDecl : public RecordDecl {
|
||||||
/// HasPublicFields - True when there are private non-static data members.
|
/// HasPublicFields - True when there are private non-static data members.
|
||||||
bool HasPublicFields : 1;
|
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
|
/// HasTrivialDefaultConstructor - True when, if this class has a default
|
||||||
/// constructor, this default constructor is trivial.
|
/// constructor, this default constructor is trivial.
|
||||||
///
|
///
|
||||||
|
@ -822,6 +825,10 @@ public:
|
||||||
/// (C++ [class]p7)
|
/// (C++ [class]p7)
|
||||||
bool isStandardLayout() const { return data().IsStandardLayout; }
|
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
|
// hasTrivialDefaultConstructor - Whether this class has a trivial default
|
||||||
// constructor
|
// constructor
|
||||||
// (C++0x [class.ctor]p5)
|
// (C++0x [class.ctor]p5)
|
||||||
|
|
|
@ -33,7 +33,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
||||||
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
||||||
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
|
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
|
||||||
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
|
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
|
||||||
HasTrivialDefaultConstructor(true),
|
HasMutableFields(false), HasTrivialDefaultConstructor(true),
|
||||||
HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
|
HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true),
|
||||||
HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
|
HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
|
||||||
HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
|
HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
|
||||||
|
@ -225,6 +225,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||||
// have trivial destructors.
|
// have trivial destructors.
|
||||||
if (!BaseClassDecl->hasTrivialDestructor())
|
if (!BaseClassDecl->hasTrivialDestructor())
|
||||||
data().HasTrivialDestructor = false;
|
data().HasTrivialDestructor = false;
|
||||||
|
|
||||||
|
// Keep track of the presence of mutable fields.
|
||||||
|
if (BaseClassDecl->hasMutableFields())
|
||||||
|
data().HasMutableFields = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VBases.empty())
|
if (VBases.empty())
|
||||||
|
@ -688,6 +692,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||||
data().HasPublicFields) > 1)
|
data().HasPublicFields) > 1)
|
||||||
data().IsStandardLayout = false;
|
data().IsStandardLayout = false;
|
||||||
|
|
||||||
|
// Keep track of the presence of mutable fields.
|
||||||
|
if (Field->isMutable())
|
||||||
|
data().HasMutableFields = true;
|
||||||
|
|
||||||
// C++0x [class]p9:
|
// C++0x [class]p9:
|
||||||
// A POD struct is a class that is both a trivial class and a
|
// 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
|
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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++.
|
/// Determines if the given type is safe for constant capture in C++.
|
||||||
static bool isSafeForCXXConstantCapture(QualType type) {
|
static bool isSafeForCXXConstantCapture(QualType type) {
|
||||||
const RecordType *recordType =
|
const RecordType *recordType =
|
||||||
|
@ -222,7 +205,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
|
||||||
|
|
||||||
// Otherwise, we just have to make sure there aren't any mutable
|
// Otherwise, we just have to make sure there aren't any mutable
|
||||||
// fields that might have changed since initialization.
|
// fields that might have changed since initialization.
|
||||||
return !hasMutableField(record);
|
return !record->hasMutableFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// It is illegal to modify a const object after initialization.
|
/// It is illegal to modify a const object after initialization.
|
||||||
|
|
|
@ -946,7 +946,9 @@ static bool DeclIsConstantGlobal(ASTContext &Context, const VarDecl *D,
|
||||||
if (Context.getLangOptions().CPlusPlus) {
|
if (Context.getLangOptions().CPlusPlus) {
|
||||||
if (const RecordType *Record
|
if (const RecordType *Record
|
||||||
= Context.getBaseElementType(D->getType())->getAs<RecordType>())
|
= 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;
|
return true;
|
||||||
|
|
|
@ -860,6 +860,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
|
||||||
Data.HasPrivateFields = Record[Idx++];
|
Data.HasPrivateFields = Record[Idx++];
|
||||||
Data.HasProtectedFields = Record[Idx++];
|
Data.HasProtectedFields = Record[Idx++];
|
||||||
Data.HasPublicFields = Record[Idx++];
|
Data.HasPublicFields = Record[Idx++];
|
||||||
|
Data.HasMutableFields = Record[Idx++];
|
||||||
Data.HasTrivialDefaultConstructor = Record[Idx++];
|
Data.HasTrivialDefaultConstructor = Record[Idx++];
|
||||||
Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
|
Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
|
||||||
Data.HasTrivialCopyConstructor = Record[Idx++];
|
Data.HasTrivialCopyConstructor = Record[Idx++];
|
||||||
|
|
|
@ -3818,6 +3818,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
|
||||||
Record.push_back(Data.HasPrivateFields);
|
Record.push_back(Data.HasPrivateFields);
|
||||||
Record.push_back(Data.HasProtectedFields);
|
Record.push_back(Data.HasProtectedFields);
|
||||||
Record.push_back(Data.HasPublicFields);
|
Record.push_back(Data.HasPublicFields);
|
||||||
|
Record.push_back(Data.HasMutableFields);
|
||||||
Record.push_back(Data.HasTrivialDefaultConstructor);
|
Record.push_back(Data.HasTrivialDefaultConstructor);
|
||||||
Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
|
Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
|
||||||
Record.push_back(Data.HasTrivialCopyConstructor);
|
Record.push_back(Data.HasTrivialCopyConstructor);
|
||||||
|
|
|
@ -18,3 +18,15 @@ int add(int x, int y) { return x + y; }
|
||||||
// CHECK: @x2 = constant
|
// CHECK: @x2 = constant
|
||||||
extern const X x2;
|
extern const X x2;
|
||||||
const X x2 = { &add };
|
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 } } };
|
||||||
|
|
Загрузка…
Ссылка в новой задаче