/// HasObjectMember - This is true if this struct has at least one member
/// containing an Objective-C object pointer type.
bool HasObjectMember : 1;
+
+ /// HasVolatileMember - This is true if struct has at least one member of
+ /// 'volatile' type.
+ bool HasVolatileMember : 1;
/// \brief Whether the field declarations of this record have been loaded
/// from external storage. To avoid unnecessary deserialization of
bool hasObjectMember() const { return HasObjectMember; }
void setHasObjectMember (bool val) { HasObjectMember = val; }
+ bool hasVolatileMember() const { return HasVolatileMember; }
+ void setHasVolatileMember (bool val) { HasVolatileMember = val; }
+
/// \brief Determines whether this declaration represents the
/// injected class name.
///
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
+ HasVolatileMember = false;
LoadedFieldsFromExternalStorage = false;
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
}
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
setHasObjectMember(true);
+
+ if (BaseClassDecl->hasVolatileMember())
+ setHasVolatileMember(true);
// Keep track of the presence of mutable fields.
if (BaseClassDecl->hasMutableFields())
data().HasIrrelevantDestructor = false;
if (FieldRec->hasObjectMember())
setHasObjectMember(true);
+ if (FieldRec->hasVolatileMember())
+ setHasVolatileMember(true);
// C++0x [class]p7:
// A standard-layout class is a class that:
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased);
+ // A non-volatile aggregate destination might have volatile member.
+ if (!LHSSlot.isVolatile() &&
+ CGF.hasVolatileMember(E->getLHS()->getType()))
+ LHSSlot.setVolatile(true);
+
CGF.EmitAggExpr(E->getRHS(), LHSSlot);
// Copy into the destination if the assignment isn't ignored.
return Quals.hasVolatile();
}
+ void setVolatile(bool flag) {
+ Quals.setVolatile(flag);
+ }
+
Qualifiers::ObjCLifetime getObjCLifetime() const {
return Quals.getObjCLifetime();
}
void EmitExprAsInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit);
+ /// hasVolatileMember - returns true if aggregate type has a volatile
+ /// member.
+ bool hasVolatileMember(QualType T) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+ return RD->hasVolatileMember();
+ }
+ return false;
+ }
/// EmitAggregateCopy - Emit an aggrate assignment.
///
/// The difference to EmitAggregateCopy is that tail padding is not copied.
/// This is required for correctness when assigning non-POD structures in C++.
void EmitAggregateAssign(llvm::Value *DestPtr, llvm::Value *SrcPtr,
- QualType EltTy, bool isVolatile=false,
- CharUnits Alignment = CharUnits::Zero()) {
- EmitAggregateCopy(DestPtr, SrcPtr, EltTy, isVolatile, Alignment, true);
+ QualType EltTy) {
+ bool IsVolatile = hasVolatileMember(EltTy);
+ EmitAggregateCopy(DestPtr, SrcPtr, EltTy, IsVolatile, CharUnits::Zero(),
+ true);
}
/// EmitAggregateCopy - Emit an aggrate copy.
}
if (Record && FDTTy->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
+ if (Record && FDTTy->getDecl()->hasVolatileMember())
+ Record->setHasVolatileMember(true);
} else if (FDTy->isObjCObjectType()) {
/// A field cannot be an Objective-c object
Diag(FD->getLocation(), diag::err_statically_allocated_object)
}
}
}
+ if (Record && FD->getType().isVolatileQualified())
+ Record->setHasVolatileMember(true);
// Keep track of the number of named members.
if (FD->getIdentifier())
++NumNamedMembers;
RD->setHasFlexibleArrayMember(Record[Idx++]);
RD->setAnonymousStructOrUnion(Record[Idx++]);
RD->setHasObjectMember(Record[Idx++]);
+ RD->setHasVolatileMember(Record[Idx++]);
}
void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
Record.push_back(D->hasFlexibleArrayMember());
Record.push_back(D->isAnonymousStructOrUnion());
Record.push_back(D->hasObjectMember());
+ Record.push_back(D->hasVolatileMember());
if (!D->hasAttrs() &&
!D->isImplicit() &&
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasVolatileMember
// DC
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
--- /dev/null
+// RUN: %clang_cc1 -O0 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// rdar://11861085
+
+struct s {
+ char filler [128];
+ volatile int x;
+};
+
+struct s gs;
+
+void foo (void) {
+ struct s ls;
+ ls = ls;
+ gs = gs;
+ ls = gs;
+}
+// CHECK: define void @foo()
+// CHECK: %[[LS:.*]] = alloca %struct.s, align 4
+// CHECK-NEXT: %[[ZERO:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: %[[ONE:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* %[[ZERO]], i8* %[[ONE]], i64 132, i32 4, i1 true)
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+// CHECK-NEXT: %[[TWO:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* %[[TWO]], i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+
+
+struct s1 {
+ struct s y;
+};
+
+struct s1 s;
+
+void fee (void) {
+ s = s;
+ s.y = gs;
+}
+// CHECK: define void @fee()
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+
--- /dev/null
+// RUN: %clang_cc1 -O -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// rdar://11861085
+
+struct s {
+ char filler [128];
+ volatile int x;
+};
+
+struct s gs;
+
+void foo (void) {
+ struct s ls;
+ ls = ls;
+ gs = gs;
+ ls = gs;
+}
+// CHECK: call void @llvm.memcpy
+// CHECK: call void @llvm.memcpy
+// CHECK: call void @llvm.memcpy
+
+struct s1 {
+ struct s y;
+};
+
+struct s1 s;
+
+void fee (void) {
+ s = s;
+ s.y = gs;
+}
+// CHECK: call void @llvm.memcpy
+// CHECK: call void @llvm.memcpy
+
+
+struct d : s1 {
+};
+
+d gd;
+
+void gorf(void) {
+ gd = gd;
+}
+// CHECK: call void @llvm.memcpy
+