if (!VD || !VD->hasLocalStorage())
return;
- if (!VD->getType()->isRecordType())
+ QualType SourceType = VD->getType();
+ if (!SourceType->isRecordType())
return;
+ if (!S.Context.hasSameUnqualifiedType(DestType, SourceType)) {
+ if (CXXRecordDecl *RD = SourceType->getAsCXXRecordDecl()) {
+ for (auto* Construct : RD->ctors()) {
+ if (Construct->isCopyConstructor() && Construct->isDeleted())
+ return;
+ }
+ }
+ }
+
// If we're returning a function parameter, copy elision
// is not possible.
if (isa<ParmVarDecl>(VD))
// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -verify %s
-// RUN: %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -fsyntax-only -Wredundant-move -std=c++11 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// definitions for std::move
namespace std {
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:10-[[@LINE-3]]:20}:""
// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:21-[[@LINE-4]]:22}:""
}
+
+// No more fix-its past here.
+// CHECK-NOT: fix-it
+
+// A deleted copy constructor will prevent moves without std::move
+struct E {
+ E(E &&e);
+ E(const E &e) = delete;
+ // expected-note@-1{{deleted here}}
+};
+
+struct F {
+ F(E);
+ // expected-note@-1{{passing argument to parameter here}}
+};
+
+F test6(E e) {
+ return e;
+ // expected-error@-1{{call to deleted constructor of 'E'}}
+ return std::move(e);
+}
+
+struct G {
+ G(G &&g);
+ // expected-note@-1{{copy constructor is implicitly deleted because 'G' has a user-declared move constructor}}
+};
+
+struct H {
+ H(G);
+ // expected-note@-1{{passing argument to parameter here}}
+};
+
+H test6(G g) {
+ return g; // expected-error{{call to implicitly-deleted copy constructor of 'G'}}
+ return std::move(g);
+}