llvm-project/clang/test/CodeGenCXX/nrvo.cpp

1825 lines
107 KiB
C++

// 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 -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();
};
template<typename T> struct Y {
Y();
static Y f() {
Y y;
return y;
}
};
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]+]]
// CHECK-NEXT: ret void
//
// CHECK-EH-LABEL: @_Z5test0v(
// 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 test0() { // http://wg21.link/p2025r2#ex-2
X x;
return x; // NRVO happens
}
// CHECK-LABEL: @_Z5test1b(
// 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: @_Z5test1b(
// 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 test1(bool B) {
X x;
if (B)
return (x); // NRVO happens
return x; // NRVO happens
}
// CHECK-LABEL: @_Z5test2b(
// 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: [[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: [[Y_X:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[X]]
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y_X]]) #[[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: 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: @_Z5test2b(
// 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:[0-9]+]]
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = 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 [[TMP1]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%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: [[TMP2:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[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) [[TMP2]])
// CHECK-EH-03-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD1:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]]
// CHECK-EH-03: lpad1:
// 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: cleanup:
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD]]
// CHECK-EH-03: invoke.cont4:
// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]]
// 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: ehcleanup:
// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD]] ], [ [[TMP4]], [[LPAD1]] ]
// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[TERMINATE_LPAD]]
// CHECK-EH-03: invoke.cont9:
// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN]]
// 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:[0-9]+]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z5test2b(
// 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:[0-9]+]]
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = 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 [[TMP1]]) #[[ATTR7]]
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%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: [[TMP2:%.*]] = select i1 [[B:%.*]], %class.X* [[Y]], %class.X* [[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) [[TMP2]])
// CHECK-EH-11-NEXT: to label [[CLEANUP:%.*]] unwind label [[LPAD1:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]]
// CHECK-EH-11: lpad1:
// 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: 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 [[TMP1]]) #[[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: ehcleanup:
// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD1]] ], [ [[TMP3]], [[LPAD]] ]
// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[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: resume { i8*, i32 } [[DOTPN]]
//
X test2(bool B) {
X x;
X y;
if (B)
return y; // NRVO is impossible
return x; // NRVO is impossible
}
// CHECK-LABEL: @_Z5test3b(
// 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: @_Z5test3b(
// 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: @_Z5test3b(
// 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 test3(bool B) { // http://wg21.link/p2025r2#ex-4
if (B) {
X y;
return y; // NRVO happens
}
X x;
return x; // FIXME: NRVO could happen, but doesn't
}
extern "C" void exit(int) throw();
// CHECK-LABEL: @_Z5test4b(
// 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 [[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: call void @exit(i32 noundef 1) #[[ATTR5]]
// CHECK-NEXT: unreachable
// CHECK: return:
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test4b(
// 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 [[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: call void @exit(i32 noundef 1) #[[ATTR7]]
// CHECK-EH-03-NEXT: unreachable
// CHECK-EH-03: return:
// CHECK-EH-03-NEXT: ret void
//
// CHECK-EH-11-LABEL: @_Z5test4b(
// 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 [[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: call void @exit(i32 noundef 1) #[[ATTR7]]
// CHECK-EH-11-NEXT: unreachable
// CHECK-EH-11: return:
// CHECK-EH-11-NEXT: ret void
//
X test4(bool B) {
{
X x;
if (B)
return x; // NRVO happens
}
exit(1);
}
#ifdef __EXCEPTIONS
void may_throw();
// CHECK-EH-03-LABEL: @_Z5test5v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: invoke void @_Z9may_throwv()
// CHECK-EH-03-NEXT: to label [[TRY_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-03-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 1
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)) #[[ATTR7]]
// CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[TMP2]], [[TMP3]]
// CHECK-EH-03-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]]
// CHECK-EH-03: catch:
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = 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 [[TMP4]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[TMP1]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = bitcast i8* [[TMP5]] to %class.X*
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP6]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-03: invoke.cont1:
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = call i8* @__cxa_begin_catch(i8* [[TMP1]]) #[[ATTR7]]
// 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_CONT3:%.*]] unwind label [[LPAD2:%.*]]
// CHECK-EH-03: invoke.cont3:
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD4:%.*]]
// CHECK-EH-03: lpad2:
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = 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 [[EHCLEANUP:%.*]] unwind label [[TERMINATE_LPAD]]
// CHECK-EH-03: invoke.cont5:
// CHECK-EH-03-NEXT: call void @__cxa_end_catch()
// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: lpad4:
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: br label [[EHCLEANUP]]
// CHECK-EH-03: ehcleanup:
// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP9]], [[LPAD4]] ], [ [[TMP8]], [[LPAD2]] ]
// CHECK-EH-03-NEXT: invoke void @__cxa_end_catch()
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[TERMINATE_LPAD]]
// CHECK-EH-03: invoke.cont7:
// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: br label [[EH_RESUME]]
// CHECK-EH-03: try.cont:
// CHECK-EH-03-NEXT: unreachable
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[LPAD_VAL11_MERGED:%.*]] = phi { i8*, i32 } [ [[DOTPN]], [[INVOKE_CONT7]] ], [ [[TMP0]], [[LPAD]] ]
// CHECK-EH-03-NEXT: resume { i8*, i32 } [[LPAD_VAL11_MERGED]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP10:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-03-NEXT: catch i8* null
// CHECK-EH-03-NEXT: [[TMP11:%.*]] = extractvalue { i8*, i32 } [[TMP10]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP11]]) #[[ATTR8]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z5test5v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: invoke void @_Z9may_throwv()
// CHECK-EH-11-NEXT: to label [[TRY_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-11-NEXT: catch i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 0
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { i8*, i32 } [[TMP0]], 1
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast ({ i8*, i8* }* @_ZTI1X to i8*)) #[[ATTR7]]
// CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[TMP2]], [[TMP3]]
// CHECK-EH-11-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]]
// CHECK-EH-11: catch:
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = 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 [[TMP4]]) #[[ATTR7]]
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[TMP1]]) #[[ATTR7]]
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = bitcast i8* [[TMP5]] to %class.X*
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]], %class.X* noundef nonnull align 1 dereferenceable(1) [[TMP6]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-11: invoke.cont1:
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = call i8* @__cxa_begin_catch(i8* [[TMP1]]) #[[ATTR7]]
// 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_CONT3:%.*]] unwind label [[LPAD2:%.*]]
// CHECK-EH-11: invoke.cont3:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]]
// CHECK-EH-11-NEXT: call void @__cxa_end_catch()
// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: lpad2:
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = 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: invoke void @__cxa_end_catch()
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[TERMINATE_LPAD]]
// CHECK-EH-11: invoke.cont4:
// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP4]]) #[[ATTR7]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME]]
// CHECK-EH-11: try.cont:
// CHECK-EH-11-NEXT: unreachable
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[LPAD_VAL7_MERGED:%.*]] = phi { i8*, i32 } [ [[TMP8]], [[INVOKE_CONT4]] ], [ [[TMP0]], [[LPAD]] ]
// CHECK-EH-11-NEXT: resume { i8*, i32 } [[LPAD_VAL7_MERGED]]
// CHECK-EH-11: terminate.lpad:
// CHECK-EH-11-NEXT: [[TMP9:%.*]] = landingpad { i8*, i32 }
// CHECK-EH-11-NEXT: catch i8* null
// CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { i8*, i32 } [[TMP9]], 0
// CHECK-EH-11-NEXT: call void @__clang_call_terminate(i8* [[TMP10]]) #[[ATTR8:[0-9]+]]
// CHECK-EH-11-NEXT: unreachable
//
X test5() { // http://wg21.link/p2025r2#ex-14
try {
may_throw();
} catch (X x) {
return x; // FIXME: NRVO could happen, but doesn't
}
}
#endif
// rdar://problem/10430868
// CHECK-LABEL: @_Z5test6v(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], 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) [[A]]) #[[ATTR5]]
// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]]
// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR5]]
// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test6v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], 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) [[A]])
// 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) [[A]])
// 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) [[A]])
// 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) [[A]])
// 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: @_Z5test6v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[A]], 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) [[A]])
// 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) [[A]])
// 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) [[A]]) #[[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) [[A]]) #[[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 test6() {
X a __attribute__((aligned(8)));
return a; // NRVO is impossible
}
// CHECK-LABEL: @_Z5test7b(
// 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: @_Z5test7b(
// 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 test7(bool b) {
if (b) {
X x;
return x; // NRVO happens
}
return X();
}
// CHECK-LABEL: @_Z5test8b(
// 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: @_Z5test8b(
// 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 test8(bool b) {
if (b) {
X x;
return x; // NRVO happens
} else {
X y;
return y; // NRVO happens
}
}
// CHECK-LABEL: @_Z5test9v(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_Y]], %struct.Y* [[TMP]], i32 0, i32 0
// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]]
// CHECK-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* nonnull sret([[STRUCT_Y]]) align 1 [[TMP]])
// CHECK-NEXT: unreachable
//
// CHECK-EH-LABEL: @_Z5test9v(
// CHECK-EH-NEXT: entry:
// CHECK-EH-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
// CHECK-EH-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_Y]], %struct.Y* [[TMP]], i32 0, i32 0
// CHECK-EH-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7:[0-9]+]]
// CHECK-EH-NEXT: call void @_ZN1YIiE1fEv(%struct.Y* nonnull sret([[STRUCT_Y]]) align 1 [[TMP]])
// CHECK-EH-NEXT: unreachable
//
Y<int> test9() {
Y<int>::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 i1 [[CMP1]], label [[RETURN]], label [[CLEANUP_CONT8:%.*]]
// 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: br label [[CLEANUP_CONT8]]
// CHECK-EH-03: cleanup.cont8:
// 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 i1 [[CMP1]], label [[RETURN]], label [[CLEANUP_CONT7:%.*]]
// 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: br label [[CLEANUP_CONT7]]
// CHECK-EH-11: cleanup.cont7:
// 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 <bool B>
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<true>();
test20<false>();
}
#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
#ifdef CXX11
template <bool B>
X test25() {
X x;
if constexpr (B) {
return x; // FIXME: NRVO could happen when B == true, but doesn't
} else {
return X();
}
}
// CHECK-EH-11-LABEL: @_Z17test25instantiatev(
// 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 !12
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I]]), !noalias !12
// 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 [[_Z6TEST25ILB1EE1XV_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 !12
// CHECK-EH-11-NEXT: br label [[COMMON_RESUME:%.*]]
// CHECK-EH-11: _Z6test25ILb1EE1Xv.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 !12
// 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 !15
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X_I2]]), !noalias !15
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]])
// CHECK-EH-11-NEXT: to label [[_Z6TEST25ILB0EE1XV_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 !15
// CHECK-EH-11-NEXT: br label [[COMMON_RESUME]]
// CHECK-EH-11: _Z6test25ILb0EE1Xv.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 !15
// 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 test25instantiate() {
test25<true>();
test25<false>();
}
#endif