diff --git a/clang/test/CodeGenCXX/nrvo.cpp b/clang/test/CodeGenCXX/nrvo.cpp --- a/clang/test/CodeGenCXX/nrvo.cpp +++ b/clang/test/CodeGenCXX/nrvo.cpp @@ -1,13 +1,14 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o - %s | FileCheck %s // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-03 %s -// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -fcxx-exceptions -fexceptions -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=CHECK-EH,CHECK-EH-11 %s // Test code generation for the named return value optimization. class X { public: X(); X(const X&); + X(const volatile X &); ~X(); }; @@ -19,6 +20,9 @@ } }; +void ConsumeX(X x); +extern X OuterX; + // CHECK-LABEL: @_Z5test0v( // CHECK-NEXT: entry: // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5:[0-9]+]] @@ -29,10 +33,9 @@ // CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) // CHECK-EH-NEXT: ret void // -X test0() { +X test0() { // http://wg21.link/p2025r2#ex-2 X x; - - return x; + return x; // NRVO happens } // CHECK-LABEL: @_Z5test1b( @@ -48,8 +51,8 @@ X test1(bool B) { X x; if (B) - return (x); - return x; + return (x); // NRVO happens + return x; // NRVO happens } // CHECK-LABEL: @_Z5test2b( @@ -155,13 +158,11 @@ // CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] // X test2(bool B) { - // No NRVO. - X x; X y; if (B) - return y; - return x; + return y; // NRVO is impossible + return x; // NRVO is impossible } // CHECK-LABEL: @_Z5test3b( @@ -242,14 +243,13 @@ // CHECK-EH-11: return: // CHECK-EH-11-NEXT: ret void // -X test3(bool B) { +X test3(bool B) { // http://wg21.link/p2025r2#ex-4 if (B) { X y; - return y; + return y; // NRVO happens } - // FIXME: we should NRVO this variable too. X x; - return x; + return x; // FIXME: NRVO could happen, but doesn't } extern "C" void exit(int) throw(); @@ -291,7 +291,7 @@ { X x; if (B) - return x; + return x; // NRVO happens } exit(1); } @@ -407,11 +407,11 @@ // CHECK-EH-11-NEXT: call void @__clang_call_terminate(i8* [[TMP10]]) #[[ATTR8:[0-9]+]] // CHECK-EH-11-NEXT: unreachable // -X test5() { +X test5() { // http://wg21.link/p2025r2#ex-14 try { may_throw(); } catch (X x) { - return x; + return x; // FIXME: NRVO could happen, but doesn't } } #endif @@ -476,7 +476,7 @@ // X test6() { X a __attribute__((aligned(8))); - return a; + return a; // NRVO is impossible } // CHECK-LABEL: @_Z5test7b( @@ -492,7 +492,7 @@ X test7(bool b) { if (b) { X x; - return x; + return x; // NRVO happens } return X(); } @@ -510,10 +510,10 @@ X test8(bool b) { if (b) { X x; - return x; + return x; // NRVO happens } else { X y; - return y; + return y; // NRVO happens } } @@ -536,3 +536,1227 @@ Y test9() { Y::f(); } + +// CHECK-LABEL: @_Z6test10b( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK: if.then: +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP:%.*]] +// CHECK: if.else: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP]] +// CHECK: cleanup: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test10b( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK-EH-03: if.then: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: if.else: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] +// CHECK-EH-03: cleanup: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: invoke.cont2: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test10b( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] +// CHECK-EH-11: if.then: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11: if.else: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] +// CHECK-EH-11: cleanup: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// +X test10(bool b) { // http://wg21.link/p2025r2#ex-3 + X x; + if (b) + return x; // NRVO is impossible + else + return X(); +} + +// CHECK-LABEL: @_Z6test11b( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK: if.then: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP:%.*]] +// CHECK: if.end: +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP]] +// CHECK: cleanup: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test11b( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03: if.then: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: if.end: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] +// CHECK-EH-03: cleanup: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: invoke.cont2: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test11b( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11: if.then: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11: if.end: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] +// CHECK-EH-11: cleanup: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// +X test11(bool b) { // http://wg21.link/p2025r2#ex-5 + X x; + if (b) + return X(); + return x; // NRVO is impossible +} + +// CHECK-LABEL: @_Z6test12b( +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// CHECK-NEXT: br i1 [[B:%.*]], label [[NRVO_UNUSED:%.*]], label [[RETURN:%.*]] +// CHECK: nrvo.unused: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN]] +// CHECK: return: +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test12b( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[NRVO_UNUSED:%.*]], label [[RETURN:%.*]] +// CHECK-EH-03: nrvo.unused: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: br label [[RETURN]] +// CHECK-EH-03: return: +// CHECK-EH-03-NEXT: ret void +// +// CHECK-EH-11-LABEL: @_Z6test12b( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[NRVO_UNUSED:%.*]], label [[RETURN:%.*]] +// CHECK-EH-11: nrvo.unused: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-11-NEXT: br label [[RETURN]] +// CHECK-EH-11: return: +// CHECK-EH-11-NEXT: ret void +// +X test12(bool b) { // http://wg21.link/p2025r2#ex-6 + do { + X x; + if (b) + break; + return x; // NRVO happens + } while (false); + return X(); +} + +// CHECK-LABEL: @_Z6test13b( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK: if.then: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN:%.*]] +// CHECK: if.end: +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN]] +// CHECK: return: +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test13b( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03: if.then: +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-03-NEXT: br label [[RETURN:%.*]] +// CHECK-EH-03: if.end: +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: invoke.cont: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[RETURN]] +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: invoke.cont1: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03: return: +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test13b( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11: if.then: +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-11-NEXT: br label [[RETURN:%.*]] +// CHECK-EH-11: if.end: +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: invoke.cont: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[RETURN]] +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11: return: +// CHECK-EH-11-NEXT: ret void +// +X test13(bool b) { // http://wg21.link/p2025r2#ex-7 + if (b) + return X(); + X x; + return x; // FIXME: NRVO could happen, but doesn't +} + +// CHECK-LABEL: @_Z6test14b( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK: if.then: +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP:%.*]] +// CHECK: if.end: +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP]] +// CHECK: cleanup: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test14b( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03: if.then: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: br label [[EHCLEANUP7:%.*]] +// CHECK-EH-03: if.end: +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] +// CHECK-EH-03: invoke.cont2: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] +// CHECK-EH-03: invoke.cont4: +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD1]] +// CHECK-EH-03: lpad1: +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] +// CHECK-EH-03: lpad3: +// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: invoke.cont5: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[CLEANUP]] +// CHECK-EH-03: ehcleanup: +// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD1]] ], [ [[TMP4]], [[LPAD3]] ] +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[EHCLEANUP7]] +// CHECK-EH-03: cleanup: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: ehcleanup7: +// CHECK-EH-03-NEXT: [[DOTPN13:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-EH-03: invoke.cont8: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN13]] +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test14b( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11: if.then: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: br label [[EHCLEANUP5:%.*]] +// CHECK-EH-11: if.end: +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] +// CHECK-EH-11: invoke.cont2: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] +// CHECK-EH-11: invoke.cont4: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[CLEANUP]] +// CHECK-EH-11: lpad1: +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] +// CHECK-EH-11: lpad3: +// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[EHCLEANUP]] +// CHECK-EH-11: ehcleanup: +// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD3]] ], [ [[TMP3]], [[LPAD1]] ] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[EHCLEANUP5]] +// CHECK-EH-11: cleanup: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11: ehcleanup5: +// CHECK-EH-11-NEXT: [[DOTPN10:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN10]] +// +X test14(bool b) { // http://wg21.link/p2025r2#ex-8 + X x; + if (b) + return x; + X y; + return y; // FIXME: NRVO could happen, but doesn't +} + +// CHECK-LABEL: @_Z6test15b( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK: if.then: +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP:%.*]] +// CHECK: if.end: +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: br label [[CLEANUP]] +// CHECK: cleanup: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test15b( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03: if.then: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: br label [[EHCLEANUP7:%.*]] +// CHECK-EH-03: if.end: +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] +// CHECK-EH-03: invoke.cont2: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] +// CHECK-EH-03: invoke.cont4: +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD1]] +// CHECK-EH-03: lpad1: +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] +// CHECK-EH-03: lpad3: +// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: invoke.cont5: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[CLEANUP]] +// CHECK-EH-03: ehcleanup: +// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD1]] ], [ [[TMP4]], [[LPAD3]] ] +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[EHCLEANUP7]] +// CHECK-EH-03: cleanup: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: ehcleanup7: +// CHECK-EH-03-NEXT: [[DOTPN13:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-EH-03: invoke.cont8: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN13]] +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test15b( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11: if.then: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: br label [[EHCLEANUP5:%.*]] +// CHECK-EH-11: if.end: +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] +// CHECK-EH-11: invoke.cont2: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] +// CHECK-EH-11: invoke.cont4: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[CLEANUP]] +// CHECK-EH-11: lpad1: +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] +// CHECK-EH-11: lpad3: +// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[EHCLEANUP]] +// CHECK-EH-11: ehcleanup: +// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD3]] ], [ [[TMP3]], [[LPAD1]] ] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[EHCLEANUP5]] +// CHECK-EH-11: cleanup: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11: ehcleanup5: +// CHECK-EH-11-NEXT: [[DOTPN10:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN10]] +// +X test15(bool b) { // http://wg21.link/p2025r2#ex-15 + X x; + if (b) + return (x); + X y; + return ((y)); // FIXME: NRVO could happen, but doesn't +} + +#ifdef CXX11 +// CHECK-EH-11-LABEL: @_Z6test16v( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[AGG_TMP:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: invoke.cont: +// CHECK-EH-11-NEXT: invoke void @_Z8ConsumeX1X(%class.X* noundef nonnull [[AGG_TMP]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] +// CHECK-EH-11: invoke.cont2: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] +// CHECK-EH-11: lpad1: +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[EHCLEANUP]] +// CHECK-EH-11: ehcleanup: +// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP2]], [[LPAD1]] ], [ [[TMP1]], [[LPAD]] ] +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] +// +void test16() { // http://wg21.link/p2025r2#ex-9 + X x; + ConsumeX([&] { + X y(x); + return y; // NRVO happens + }()); +} +#endif + +// CHECK-LABEL: @_Z6test17i( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 3 +// CHECK-NEXT: br label [[WHILE_BODY:%.*]] +// CHECK: impossible: +// CHECK-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[WHILE_BODY_BACKEDGE:%.*]] +// CHECK: while.body.backedge: +// CHECK-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3:![0-9]+]] +// CHECK: while.body: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// CHECK-NEXT: switch i32 [[I]], label [[IF_END20:%.*]] [ +// CHECK-NEXT: i32 0, label [[CLEANUP:%.*]] +// CHECK-NEXT: i32 1, label [[IF_THEN7:%.*]] +// CHECK-NEXT: i32 2, label [[IF_THEN10:%.*]] +// CHECK-NEXT: i32 3, label [[IF_THEN13:%.*]] +// CHECK-NEXT: i32 4, label [[IF_THEN16:%.*]] +// CHECK-NEXT: i32 5, label [[CLEANUP]] +// CHECK-NEXT: ] +// CHECK: if.then7: +// CHECK-NEXT: br label [[CLEANUP]] +// CHECK: if.then10: +// CHECK-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3]] +// CHECK: if.then13: +// CHECK-NEXT: br label [[CLEANUP]] +// CHECK: if.then16: +// CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR5]] +// CHECK-NEXT: br label [[IF_END20]] +// CHECK: if.end20: +// CHECK-NEXT: br label [[CLEANUP]] +// CHECK: cleanup: +// CHECK-NEXT: [[NRVO_0:%.*]] = phi i1 [ false, [[IF_THEN7]] ], [ false, [[IF_THEN10]] ], [ false, [[IF_THEN13]] ], [ false, [[IF_END20]] ], [ true, [[WHILE_BODY]] ], [ true, [[WHILE_BODY]] ] +// CHECK-NEXT: [[CLEANUP_DEST_SLOT_0:%.*]] = phi i32 [ 4, [[IF_THEN7]] ], [ 3, [[IF_THEN10]] ], [ 2, [[IF_THEN13]] ], [ 0, [[IF_END20]] ], [ 1, [[WHILE_BODY]] ], [ 1, [[WHILE_BODY]] ] +// CHECK-NEXT: br i1 [[NRVO_0]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK: nrvo.unused: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK: nrvo.skipdtor: +// CHECK-NEXT: switch i32 [[CLEANUP_DEST_SLOT_0]], label [[UNREACHABLE:%.*]] [ +// CHECK-NEXT: i32 0, label [[WHILE_BODY_BACKEDGE]] +// CHECK-NEXT: i32 1, label [[RETURN:%.*]] +// CHECK-NEXT: i32 4, label [[RETURN_SINK_SPLIT]] +// CHECK-NEXT: i32 3, label [[WHILE_BODY_BACKEDGE]] +// CHECK-NEXT: i32 2, label [[IMPOSSIBLE:%.*]] +// CHECK-NEXT: ] +// CHECK: return.sink.split: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN]] +// CHECK: return: +// CHECK-NEXT: ret void +// CHECK: unreachable: +// CHECK-NEXT: unreachable +// +// CHECK-EH-03-LABEL: @_Z6test17i( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 3 +// CHECK-EH-03-NEXT: br label [[WHILE_BODY:%.*]] +// CHECK-EH-03: impossible: +// CHECK-EH-03-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[WHILE_BODY_BACKEDGE:%.*]] +// CHECK-EH-03: while.body.backedge: +// CHECK-EH-03-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3:![0-9]+]] +// CHECK-EH-03: while.body: +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-03-NEXT: switch i32 [[I]], label [[IF_END20:%.*]] [ +// CHECK-EH-03-NEXT: i32 0, label [[CLEANUP:%.*]] +// CHECK-EH-03-NEXT: i32 1, label [[IF_THEN7:%.*]] +// CHECK-EH-03-NEXT: i32 2, label [[IF_THEN10:%.*]] +// CHECK-EH-03-NEXT: i32 3, label [[IF_THEN13:%.*]] +// CHECK-EH-03-NEXT: i32 4, label [[IF_THEN16:%.*]] +// CHECK-EH-03-NEXT: i32 5, label [[CLEANUP]] +// CHECK-EH-03-NEXT: ] +// CHECK-EH-03: if.then7: +// CHECK-EH-03-NEXT: br label [[CLEANUP]] +// CHECK-EH-03: if.then10: +// CHECK-EH-03-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3]] +// CHECK-EH-03: if.then13: +// CHECK-EH-03-NEXT: br label [[CLEANUP]] +// CHECK-EH-03: if.then16: +// CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[IF_END20]] +// CHECK-EH-03: if.end20: +// CHECK-EH-03-NEXT: br label [[CLEANUP]] +// CHECK-EH-03: cleanup: +// CHECK-EH-03-NEXT: [[NRVO_0:%.*]] = phi i1 [ false, [[IF_THEN7]] ], [ false, [[IF_THEN10]] ], [ false, [[IF_THEN13]] ], [ false, [[IF_END20]] ], [ true, [[WHILE_BODY]] ], [ true, [[WHILE_BODY]] ] +// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT_0:%.*]] = phi i32 [ 4, [[IF_THEN7]] ], [ 3, [[IF_THEN10]] ], [ 2, [[IF_THEN13]] ], [ 0, [[IF_END20]] ], [ 1, [[WHILE_BODY]] ], [ 1, [[WHILE_BODY]] ] +// CHECK-EH-03-NEXT: br i1 [[NRVO_0]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK-EH-03: nrvo.unused: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK-EH-03: nrvo.skipdtor: +// CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST_SLOT_0]], label [[UNREACHABLE:%.*]] [ +// CHECK-EH-03-NEXT: i32 0, label [[WHILE_BODY_BACKEDGE]] +// CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]] +// CHECK-EH-03-NEXT: i32 4, label [[RETURN_SINK_SPLIT]] +// CHECK-EH-03-NEXT: i32 3, label [[WHILE_BODY_BACKEDGE]] +// CHECK-EH-03-NEXT: i32 2, label [[IMPOSSIBLE:%.*]] +// CHECK-EH-03-NEXT: ] +// CHECK-EH-03: return.sink.split: +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: br label [[RETURN]] +// CHECK-EH-03: return: +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: unreachable: +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test17i( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 3 +// CHECK-EH-11-NEXT: br label [[WHILE_BODY:%.*]] +// CHECK-EH-11: impossible: +// CHECK-EH-11-NEXT: br i1 [[CMP]], label [[RETURN_SINK_SPLIT:%.*]], label [[WHILE_BODY_BACKEDGE:%.*]] +// CHECK-EH-11: while.body.backedge: +// CHECK-EH-11-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3:![0-9]+]] +// CHECK-EH-11: while.body: +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-11-NEXT: switch i32 [[I]], label [[IF_END20:%.*]] [ +// CHECK-EH-11-NEXT: i32 0, label [[CLEANUP:%.*]] +// CHECK-EH-11-NEXT: i32 1, label [[IF_THEN7:%.*]] +// CHECK-EH-11-NEXT: i32 2, label [[IF_THEN10:%.*]] +// CHECK-EH-11-NEXT: i32 3, label [[IF_THEN13:%.*]] +// CHECK-EH-11-NEXT: i32 4, label [[IF_THEN16:%.*]] +// CHECK-EH-11-NEXT: i32 5, label [[CLEANUP]] +// CHECK-EH-11-NEXT: ] +// CHECK-EH-11: if.then7: +// CHECK-EH-11-NEXT: br label [[CLEANUP]] +// CHECK-EH-11: if.then10: +// CHECK-EH-11-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3]] +// CHECK-EH-11: if.then13: +// CHECK-EH-11-NEXT: br label [[CLEANUP]] +// CHECK-EH-11: if.then16: +// CHECK-EH-11-NEXT: call void @exit(i32 noundef 1) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[IF_END20]] +// CHECK-EH-11: if.end20: +// CHECK-EH-11-NEXT: br label [[CLEANUP]] +// CHECK-EH-11: cleanup: +// CHECK-EH-11-NEXT: [[NRVO_0:%.*]] = phi i1 [ false, [[IF_THEN7]] ], [ false, [[IF_THEN10]] ], [ false, [[IF_THEN13]] ], [ false, [[IF_END20]] ], [ true, [[WHILE_BODY]] ], [ true, [[WHILE_BODY]] ] +// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT_0:%.*]] = phi i32 [ 4, [[IF_THEN7]] ], [ 3, [[IF_THEN10]] ], [ 2, [[IF_THEN13]] ], [ 0, [[IF_END20]] ], [ 1, [[WHILE_BODY]] ], [ 1, [[WHILE_BODY]] ] +// CHECK-EH-11-NEXT: br i1 [[NRVO_0]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK-EH-11: nrvo.unused: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]] +// CHECK-EH-11: nrvo.skipdtor: +// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST_SLOT_0]], label [[UNREACHABLE:%.*]] [ +// CHECK-EH-11-NEXT: i32 0, label [[WHILE_BODY_BACKEDGE]] +// CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]] +// CHECK-EH-11-NEXT: i32 4, label [[RETURN_SINK_SPLIT]] +// CHECK-EH-11-NEXT: i32 3, label [[WHILE_BODY_BACKEDGE]] +// CHECK-EH-11-NEXT: i32 2, label [[IMPOSSIBLE:%.*]] +// CHECK-EH-11-NEXT: ] +// CHECK-EH-11: return.sink.split: +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-11-NEXT: br label [[RETURN]] +// CHECK-EH-11: return: +// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11: unreachable: +// CHECK-EH-11-NEXT: unreachable +// +X test17(int i) { // http://wg21.link/p2025r2#ex-10 + if (false) { + impossible: + if (i == 3) + return X(); + } + + while (true) { + X x; + if (i == 0) + return x; // NRVO happens + if (i == 1) + break; + if (i == 2) + continue; + if (i == 3) + goto impossible; + if (i == 4) + exit(1); + if (i == 5) + return x; // NRVO happens + } + return X(); +} + +// CHECK-LABEL: @_Z6test18i( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 +// CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK: nrvo.unused: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 +// CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT7_CRITEDGE:%.*]] +// CHECK: if.then2: +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN]] +// CHECK: cleanup.cont7.critedge: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN]] +// CHECK: return: +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test18i( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 +// CHECK-EH-03-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK-EH-03: nrvo.unused: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 +// CHECK-EH-03-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT8_CRITEDGE:%.*]] +// CHECK-EH-03: if.then2: +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP4:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: cleanup4: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[RETURN]] +// CHECK-EH-03: cleanup.cont8.critedge: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT10:%.*]] unwind label [[LPAD9:%.*]] +// CHECK-EH-03: invoke.cont10: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[RETURN]] +// CHECK-EH-03: invoke.cont5: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] +// CHECK-EH-03: lpad9: +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT12:%.*]] unwind label [[TERMINATE_LPAD]] +// CHECK-EH-03: invoke.cont12: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[EH_RESUME]] +// CHECK-EH-03: return: +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: eh.resume: +// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[INVOKE_CONT12]] ], [ [[TMP1]], [[INVOKE_CONT5]] ] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN]] +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP5]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test18i( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 +// CHECK-EH-11-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] +// CHECK-EH-11: nrvo.unused: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 +// CHECK-EH-11-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT7_CRITEDGE:%.*]] +// CHECK-EH-11: if.then2: +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP4:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] +// CHECK-EH-11: cleanup4: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[RETURN]] +// CHECK-EH-11: cleanup.cont7.critedge: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[LPAD8:%.*]] +// CHECK-EH-11: invoke.cont9: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[RETURN]] +// CHECK-EH-11: lpad8: +// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[EH_RESUME]] +// CHECK-EH-11: return: +// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11: eh.resume: +// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD8]] ], [ [[TMP1]], [[LPAD]] ] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] +// +X test18(int i) { // http://wg21.link/p2025r2#ex-11 + { + { + X x; + if (i == 0) + return x; // NRVO happens + } + X y; + if (i == 1) + return y; // FIXME: NRVO could happen, but doesn't + } + X z; + return z; // FIXME: NRVO could happen, but doesn't +} + +#ifdef CXX11 +// CHECK-EH-11-LABEL: @_Z6test19v( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[L:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[L]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[L]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: invoke.cont: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[L]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// +X test19() { // http://wg21.link/p2025r2#ex-12 + X x; + struct S { + X f() { return X(); } + }; + auto L = [&x]() { return X(); }(); + if constexpr (false) { + return X(); + } + return x; // NRVO happens +} + +template +X test20() { // http://wg21.link/p2025r2#ex-18 + X x; + if constexpr (B) { + if (false) + return X(); + } + return x; // FIXME: NRVO could happen when B == false, but doesn't +} + +// CHECK-EH-11-LABEL: @_Z17test20instantiatev( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X_I2:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[X_I:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED1:%.*]] = alloca [[CLASS_X]], align 1 +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X_I]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !6 +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]), !noalias !6 +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) +// CHECK-EH-11-NEXT: to label [[_Z6TEST20ILB1EE1XV_EXIT:%.*]] unwind label [[LPAD_I:%.*]] +// CHECK-EH-11: common.resume: +// CHECK-EH-11-NEXT: [[COMMON_RESUME_OP:%.*]] = phi { i8*, i32 } [ [[TMP1:%.*]], [[LPAD_I]] ], [ [[TMP3:%.*]], [[LPAD_I3:%.*]] ] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[COMMON_RESUME_OP]] +// CHECK-EH-11: lpad.i: +// CHECK-EH-11-NEXT: [[TMP1]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !6 +// CHECK-EH-11-NEXT: br label [[COMMON_RESUME:%.*]] +// CHECK-EH-11: _Z6test20ILb1EE1Xv.exit: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]], !noalias !6 +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X_I2]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !9 +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]), !noalias !9 +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) +// CHECK-EH-11-NEXT: to label [[_Z6TEST20ILB0EE1XV_EXIT:%.*]] unwind label [[LPAD_I3]] +// CHECK-EH-11: lpad.i3: +// CHECK-EH-11-NEXT: [[TMP3]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !9 +// CHECK-EH-11-NEXT: br label [[COMMON_RESUME]] +// CHECK-EH-11: _Z6test20ILb0EE1Xv.exit: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]], !noalias !9 +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// +void test20instantiate() { + test20(); + test20(); +} +#endif + +// CHECK-LABEL: @_Z6test21v( +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// CHECK-NEXT: ret void +// +// CHECK-EH-LABEL: @_Z6test21v( +// CHECK-EH-NEXT: entry: +// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-NEXT: ret void +// +const volatile X test21() { // http://wg21.link/p2025r2#ex-19 + X x; + return x; // NRVO happens +} + +// CHECK-LABEL: @_Z6test22v( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test22v( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: invoke.cont: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: invoke.cont1: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test22v( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: invoke.cont: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: ret void +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// +X test22() { // http://wg21.link/p2025r2#ex-19 + volatile X x; + return x; // NRVO is impossible +} + +// CHECK-LABEL: @_Z6test23b( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK: if.then: +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN:%.*]] +// CHECK: if.end: +// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] +// CHECK-NEXT: br label [[RETURN]] +// CHECK: return: +// CHECK-NEXT: ret void +// +// CHECK-EH-03-LABEL: @_Z6test23b( +// CHECK-EH-03-NEXT: entry: +// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-03: if.then: +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-03-NEXT: br label [[RETURN:%.*]] +// CHECK-EH-03: if.end: +// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-03: invoke.cont: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: br label [[RETURN]] +// CHECK-EH-03: lpad: +// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: cleanup +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] +// CHECK-EH-03: invoke.cont1: +// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-03: return: +// CHECK-EH-03-NEXT: ret void +// CHECK-EH-03: terminate.lpad: +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: catch i8* null +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: unreachable +// +// CHECK-EH-11-LABEL: @_Z6test23b( +// CHECK-EH-11-NEXT: entry: +// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 +// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +// CHECK-EH-11: if.then: +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-11-NEXT: br label [[RETURN:%.*]] +// CHECK-EH-11: if.end: +// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 +// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) +// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] +// CHECK-EH-11: invoke.cont: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: br label [[RETURN]] +// CHECK-EH-11: lpad: +// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-11-NEXT: cleanup +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] +// CHECK-EH-11: return: +// CHECK-EH-11-NEXT: ret void +// +X test23(bool b) { // http://wg21.link/p2025r2#ex-19 + if (b) { + const X x; + return x; // NRVO happens + } + volatile X y; + return y; // NRVO is impossible +} + +#ifdef __EXCEPTIONS +// CHECK-EH-LABEL: @_Z6test24v( +// CHECK-EH-NEXT: entry: +// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-NEXT: ret void +// +X test24() { // http://wg21.link/p2025r2#ex-20 + X x; + if (&x == &OuterX) + throw 0; + return x; // NRVO happens +} +#endif