]> granicus.if.org Git - clang/commitdiff
PR14279: Work around this major miscompilation by treating move operations as
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Nov 2012 07:36:28 +0000 (07:36 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Nov 2012 07:36:28 +0000 (07:36 +0000)
non-trivial if they would not call a move operation, even if they would in fact
call a trivial copy operation. A proper fix is to follow, but this small
directed fix is intended for porting to the 3.2 release branch.

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

lib/AST/DeclCXX.cpp
test/CodeGenCXX/cxx11-special-members.cpp [new file with mode: 0644]

index 9db33357a6099f33af030af82ccb3a9f0faae3ed..82e630acefba85553087c7d62b5d411dfe4aeed2 100644 (file)
@@ -240,10 +240,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
       //    -- the constructor selected to copy/move each direct base class
       //       subobject is trivial, and
       // FIXME: C++0x: We need to only consider the selected constructor
-      // instead of all of them.
+      // instead of all of them. For now, we treat a move constructor as being
+      // non-trivial if it calls anything other than a trivial move constructor.
       if (!BaseClassDecl->hasTrivialCopyConstructor())
         data().HasTrivialCopyConstructor = false;
-      if (!BaseClassDecl->hasTrivialMoveConstructor())
+      if (!BaseClassDecl->hasTrivialMoveConstructor() ||
+          !(BaseClassDecl->hasDeclaredMoveConstructor() ||
+            BaseClassDecl->needsImplicitMoveConstructor()))
         data().HasTrivialMoveConstructor = false;
 
       // C++0x [class.copy]p27:
@@ -255,7 +258,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
       // of all of them.
       if (!BaseClassDecl->hasTrivialCopyAssignment())
         data().HasTrivialCopyAssignment = false;
-      if (!BaseClassDecl->hasTrivialMoveAssignment())
+      if (!BaseClassDecl->hasTrivialMoveAssignment() ||
+          !(BaseClassDecl->hasDeclaredMoveAssignment() ||
+            BaseClassDecl->needsImplicitMoveAssignment()))
         data().HasTrivialMoveAssignment = false;
 
       // C++11 [class.ctor]p6:
@@ -830,7 +835,9 @@ NotASpecialMember:;
         // FIXME: C++0x: We don't correctly model 'selected' constructors.
         if (!FieldRec->hasTrivialCopyConstructor())
           data().HasTrivialCopyConstructor = false;
-        if (!FieldRec->hasTrivialMoveConstructor())
+        if (!FieldRec->hasTrivialMoveConstructor() ||
+            !(FieldRec->hasDeclaredMoveConstructor() ||
+              FieldRec->needsImplicitMoveConstructor()))
           data().HasTrivialMoveConstructor = false;
 
         // C++0x [class.copy]p27:
@@ -842,7 +849,9 @@ NotASpecialMember:;
         // FIXME: C++0x: We don't correctly model 'selected' operators.
         if (!FieldRec->hasTrivialCopyAssignment())
           data().HasTrivialCopyAssignment = false;
-        if (!FieldRec->hasTrivialMoveAssignment())
+        if (!FieldRec->hasTrivialMoveAssignment() ||
+            !(FieldRec->hasDeclaredMoveAssignment() ||
+              FieldRec->needsImplicitMoveAssignment()))
           data().HasTrivialMoveAssignment = false;
 
         if (!FieldRec->hasTrivialDestructor())
diff --git a/test/CodeGenCXX/cxx11-special-members.cpp b/test/CodeGenCXX/cxx11-special-members.cpp
new file mode 100644 (file)
index 0000000..59461f9
--- /dev/null
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - -triple=i686-linux-gnu | FileCheck %s
+
+struct A {
+  A(const A&);
+  A &operator=(const A&);
+};
+
+struct B {
+  A a;
+  B(B&&) = default;
+  B &operator=(B&&) = default;
+};
+
+// CHECK: define {{.*}} @_Z2f1
+void f1(B &x) {
+  // CHECK-NOT: memcpy
+  // CHECK: call {{.*}} @_ZN1BC1EOS_(
+  B b(static_cast<B&&>(x));
+}
+
+// CHECK: define {{.*}} @_Z2f2
+void f2(B &x, B &y) {
+  // CHECK-NOT: memcpy
+  // CHECK: call {{.*}} @_ZN1BaSEOS_(
+  x = static_cast<B&&>(y);
+}
+
+// CHECK: define {{.*}} @_ZN1BaSEOS_(
+// CHECK: call {{.*}} @_ZN1AaSERKS_(
+
+// CHECK: define {{.*}} @_ZN1BC2EOS_(
+// CHECK: call {{.*}} @_ZN1AC1ERKS_(