aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGBlocks.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CGBlocks.cpp')
-rw-r--r--lib/CodeGen/CGBlocks.cpp47
1 files changed, 42 insertions, 5 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 1a7abd242a..e78e175a5a 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -201,6 +201,42 @@ 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 =
+ type->getBaseElementTypeUnsafe()->getAs<RecordType>();
+
+ // Only records can be unsafe.
+ if (!recordType) return true;
+
+ const CXXRecordDecl *record = cast<CXXRecordDecl>(recordType->getDecl());
+
+ // Maintain semantics for classes with non-trivial dtors or copy ctors.
+ if (!record->hasTrivialDestructor()) return false;
+ if (!record->hasTrivialCopyConstructor()) return false;
+
+ // Otherwise, we just have to make sure there aren't any mutable
+ // fields that might have changed since initialization.
+ return !hasMutableField(record);
+}
+
/// It is illegal to modify a const object after initialization.
/// Therefore, if a const object has a constant initializer, we don't
/// actually need to keep storage for it in the block; we'll just
@@ -214,11 +250,12 @@ static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM,
// We can only do this if the variable is const.
if (!type.isConstQualified()) return 0;
- // Furthermore, in C++ we can't do this for classes. TODO: we might
- // actually be able to get away with it for classes with a trivial
- // destructor and a trivial copy constructor and no mutable fields.
- if (CGM.getLangOptions().CPlusPlus &&
- type->getBaseElementTypeUnsafe()->isRecordType())
+ // Furthermore, in C++ we have to worry about mutable fields:
+ // C++ [dcl.type.cv]p4:
+ // Except that any class member declared mutable can be
+ // modified, any attempt to modify a const object during its
+ // lifetime results in undefined behavior.
+ if (CGM.getLangOptions().CPlusPlus && !isSafeForCXXConstantCapture(type))
return 0;
// If the variable doesn't have any initializer (shouldn't this be