A test5() { // CHECK: [[AT0:%.*]] = alloca [[A]], align 8 // CHECK-NEXT: [[BT0:%.*]] = alloca [[B:%.*]], align 8 // CHECK-NEXT: [[X:%.*]] = alloca [[A]], align 8 // CHECK-NEXT: [[BT1:%.*]] = alloca [[B]], align 8 // CHECK-NEXT: [[BT2:%.*]] = alloca [[B]], align 8 // CHECK: call void @_ZN7Elision1BC1Ev([[B]]* [[BT0]]) // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], [[B]]* [[BT0]], i32 0, i32 0 // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[AT0]], [[A]]* dereferenceable({{[0-9]+}}) [[AM]]) // CHECK-NEXT: call void @_ZN7Elision5takeAENS_1AE([[A]]* [[AT0]]) // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[AT0]]) // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT0]]) takeA(B().a); // CHECK-NEXT: call void @llvm.lifetime.end // CHECK-NEXT: call void @_ZN7Elision1BC1Ev([[B]]* [[BT1]]) // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], [[B]]* [[BT1]], i32 0, i32 0 // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[X]], [[A]]* dereferenceable({{[0-9]+}}) [[AM]]) // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT1]]) A x = B().a; // CHECK-NEXT: call void @_ZN7Elision1BC1Ev([[B]]* [[BT2]]) // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]], [[B]]* [[BT2]], i32 0, i32 0 // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET:%.*]], [[A]]* dereferenceable({{[0-9]+}}) [[AM]]) // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT2]]) return B().a; // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]]) }
// We handle the case correctly where the move consists of an implicit call // to a conversion operator. void implicitConversionOperator() { struct Convertible { operator A() && { return A(); } }; void takeA(A a); Convertible convertible; takeA(std::move(convertible)); convertible; // CHECK-MESSAGES: [[@LINE-1]]:3: warning: 'convertible' used after it was moved // CHECK-MESSAGES: [[@LINE-3]]:9: note: move occurred here }