Files
clang-p2996/clang/test/CodeGenCXX/nrvo.cpp
Aaron Ballman 0f1c1be196 [clang] Remove rdar links; NFC
We have a new policy in place making links to private resources
something we try to avoid in source and test files. Normally, we'd
organically switch to the new policy rather than make a sweeping change
across a project. However, Clang is in a somewhat special circumstance
currently: recently, I've had several new contributors run into rdar
links around test code which their patch was changing the behavior of.
This turns out to be a surprisingly bad experience, especially for
newer folks, for a handful of reasons: not understanding what the link
is and feeling intimidated by it, wondering whether their changes are
actually breaking something important to a downstream in some way,
having to hunt down strangers not involved with the patch to impose on
them for help, accidental pressure from asking for potentially private
IP to be made public, etc. Because folks run into these links entirely
by chance (through fixing bugs or working on new features), there's not
really a set of problematic links to focus on -- all of the links have
basically the same potential for causing these problems. As a result,
this is an omnibus patch to remove all such links.

This was not a mechanical change; it was done by manually searching for
rdar, radar, radr, and other variants to find all the various
problematic links. From there, I tried to retain or reword the
surrounding comments so that we would lose as little context as
possible. However, because most links were just a plain link with no
supporting context, the majority of the changes are simple removals.

Differential Review: https://reviews.llvm.org/D158071
2023-08-28 12:13:42 -04:00

2948 lines
162 KiB
C++

// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -fcxx-exceptions -fexceptions -disable-llvm-passes -std=c++03 -o - %s | FileCheck --check-prefixes=CHECK-EH-03 %s
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -fcxx-exceptions -fexceptions -disable-llvm-passes -std=c++11 -DCXX11 -o - %s | FileCheck --check-prefixes=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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4:[0-9]+]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test0v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: ret void
//
// CHECK-EH-11-LABEL: @_Z5test0v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6:[0-9]+]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test1b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: ret void
//
// CHECK-EH-11-LABEL: @_Z5test1b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR4]]
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test2b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr 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: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]]
// CHECK-EH-03: lpad1:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD1]]
// CHECK-EH-03: invoke.cont3:
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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 @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: invoke.cont5:
// CHECK-EH-03-NEXT: br label [[EHCLEANUP]]
// CHECK-EH-03: ehcleanup:
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT7:%.*]] unwind label [[TERMINATE_LPAD]]
// CHECK-EH-03: invoke.cont7:
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL8:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL8]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP9]]) #[[ATTR6:[0-9]+]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z5test2b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr 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: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]]
// CHECK-EH-11: lpad1:
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP6]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP7]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EHCLEANUP]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[LPAD1]]
// CHECK-EH-11: invoke.cont3:
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: ehcleanup:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL5:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL5]]
//
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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: br label [[RETURN:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]]
// CHECK: nrvo.unused3:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR4]]
// CHECK: nrvo.skipdtor4:
// 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: br label [[RETURN:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]]
// CHECK-EH-03: nrvo.unused3:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR4]]
// CHECK-EH-03: nrvo.skipdtor4:
// CHECK-EH-03-NEXT: br label [[RETURN]]
// CHECK-EH-03: return:
// CHECK-EH-03-NEXT: ret void
//
// CHECK-EH-11-LABEL: @_Z5test3b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]]
// CHECK-EH-11: nrvo.unused3:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR4]]
// CHECK-EH-11: nrvo.skipdtor4:
// CHECK-EH-11-NEXT: br label [[RETURN]]
// 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-NEXT: ]
// CHECK: cleanup.cont:
// CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR4]]
// CHECK-NEXT: call void @llvm.trap()
// CHECK-NEXT: unreachable
// CHECK: return:
// CHECK-NEXT: ret void
// CHECK: unreachable:
// CHECK-NEXT: unreachable
//
// CHECK-EH-03-LABEL: @_Z5test4b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-EH-03-NEXT: ]
// CHECK-EH-03: cleanup.cont:
// CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR7:[0-9]+]]
// CHECK-EH-03-NEXT: call void @llvm.trap()
// CHECK-EH-03-NEXT: unreachable
// CHECK-EH-03: return:
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: unreachable:
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z5test4b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-EH-11-NEXT: ]
// CHECK-EH-11: cleanup.cont:
// CHECK-EH-11-NEXT: call void @exit(i32 noundef 1) #[[ATTR6]]
// CHECK-EH-11-NEXT: call void @llvm.trap()
// CHECK-EH-11-NEXT: unreachable
// CHECK-EH-11: return:
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: unreachable:
// CHECK-EH-11-NEXT: unreachable
//
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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: invoke void @_Z9may_throwv()
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-03: invoke.cont:
// CHECK-EH-03-NEXT: br label [[TRY_CONT:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr @_ZTI1X
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CATCH_DISPATCH:%.*]]
// CHECK-EH-03: catch.dispatch:
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTI1X) #[[ATTR7]]
// CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP4]]
// CHECK-EH-03-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]]
// CHECK-EH-03: catch:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = call ptr @__cxa_get_exception_ptr(ptr [[EXN]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[X]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP5]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-03: invoke.cont1:
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR7]]
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr 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 { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT6:%.*]] unwind label [[TERMINATE_LPAD]]
// CHECK-EH-03: invoke.cont5:
// CHECK-EH-03-NEXT: call void @__cxa_end_catch()
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: lpad4:
// CHECK-EH-03-NEXT: [[TMP11:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP12:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP12]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP13]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]]
// CHECK-EH-03: invoke.cont6:
// CHECK-EH-03-NEXT: br label [[EHCLEANUP]]
// CHECK-EH-03: ehcleanup:
// 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: br label [[EH_RESUME]]
// CHECK-EH-03: try.cont:
// CHECK-EH-03-NEXT: call void @llvm.trap()
// CHECK-EH-03-NEXT: unreachable
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN8:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL9:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN8]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL10:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL9]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL10]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP14:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP15:%.*]] = extractvalue { ptr, i32 } [[TMP14]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP15]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z5test5v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: invoke void @_Z9may_throwv()
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-11: invoke.cont:
// CHECK-EH-11-NEXT: br label [[TRY_CONT:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: catch ptr @_ZTI1X
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CATCH_DISPATCH:%.*]]
// CHECK-EH-11: catch.dispatch:
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = call i32 @llvm.eh.typeid.for(ptr @_ZTI1X) #[[ATTR6]]
// CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP4]]
// CHECK-EH-11-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]]
// CHECK-EH-11: catch:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = call ptr @__cxa_get_exception_ptr(ptr [[EXN]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[X]], ptr noundef nonnull align 1 dereferenceable(1) [[TMP5]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-11: invoke.cont1:
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = call ptr @__cxa_begin_catch(ptr [[EXN]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: call void @__cxa_end_catch()
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: lpad2:
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP9:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP9]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP8]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP10]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// 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: br label [[EH_RESUME]]
// CHECK-EH-11: try.cont:
// CHECK-EH-11-NEXT: call void @llvm.trap()
// CHECK-EH-11-NEXT: unreachable
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN5:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL6:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN5]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL7:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL6]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL7]]
// CHECK-EH-11: terminate.lpad:
// CHECK-EH-11-NEXT: [[TMP11:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: catch ptr null
// CHECK-EH-11-NEXT: [[TMP12:%.*]] = extractvalue { ptr, i32 } [[TMP11]], 0
// CHECK-EH-11-NEXT: call void @__clang_call_terminate(ptr [[TMP12]]) #[[ATTR7:[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
// CHECK-LABEL: @_Z5test6v(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]])
// CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[A]])
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR4]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test6v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]])
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[A]])
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL2]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP5]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z5test6v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[A:%.*]] = alloca [[CLASS_X:%.*]], align 8
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]])
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[A]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]]
//
X test6() {
X a __attribute__((aligned(8)));
return a; // NRVO is impossible
}
// CHECK-LABEL: @_Z5test7b(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: br label [[RETURN:%.*]]
// CHECK: if.end:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: br label [[RETURN]]
// CHECK: return:
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test7b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: br label [[RETURN:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr 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: @_Z5test7b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr 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 test7(bool b) {
if (b) {
X x;
return x; // NRVO happens
}
return X();
}
// CHECK-LABEL: @_Z5test8b(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: br label [[RETURN:%.*]]
// CHECK: if.else:
// CHECK-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]]
// CHECK: nrvo.unused3:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR4]]
// CHECK: nrvo.skipdtor4:
// CHECK-NEXT: br label [[RETURN]]
// CHECK: return:
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z5test8b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: br label [[RETURN:%.*]]
// CHECK-EH-03: if.else:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]]
// CHECK-EH-03: nrvo.unused3:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR4]]
// CHECK-EH-03: nrvo.skipdtor4:
// CHECK-EH-03-NEXT: br label [[RETURN]]
// CHECK-EH-03: return:
// CHECK-EH-03-NEXT: ret void
//
// CHECK-EH-11-LABEL: @_Z5test8b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-11: if.else:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL2:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL2]], label [[NRVO_SKIPDTOR4:%.*]], label [[NRVO_UNUSED3:%.*]]
// CHECK-EH-11: nrvo.unused3:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR4]]
// CHECK-EH-11: nrvo.skipdtor4:
// CHECK-EH-11-NEXT: br label [[RETURN]]
// CHECK-EH-11: return:
// CHECK-EH-11-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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: call void @_ZN1YIiE1fEv(ptr sret([[STRUCT_Y]]) align 1 [[TMP]])
// CHECK-NEXT: call void @llvm.trap()
// CHECK-NEXT: unreachable
//
// CHECK-EH-03-LABEL: @_Z5test9v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: call void @_ZN1YIiE1fEv(ptr sret([[STRUCT_Y]]) align 1 [[TMP]])
// CHECK-EH-03-NEXT: call void @llvm.trap()
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z5test9v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[TMP:%.*]] = alloca [[STRUCT_Y:%.*]], align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1YIiE1fEv(ptr sret([[STRUCT_Y]]) align 1 [[TMP]])
// CHECK-EH-11-NEXT: call void @llvm.trap()
// CHECK-EH-11-NEXT: unreachable
//
Y<int> test9() {
Y<int>::f();
}
// CHECK-LABEL: @_Z6test10b(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK: if.then:
// CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.else:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z6test10b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-03: invoke.cont1:
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: invoke.cont2:
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL3]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z6test10b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: if.else:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-11: invoke.cont1:
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]]
//
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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z6test11b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-03: invoke.cont:
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-03: invoke.cont1:
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: invoke.cont2:
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL3]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z6test11b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-11: invoke.cont:
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-11: invoke.cont1:
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]]
//
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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: br label [[DO_BODY:%.*]]
// CHECK: do.body:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-NEXT: i32 2, label [[DO_END:%.*]]
// CHECK-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-NEXT: ]
// CHECK: do.end:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: br label [[RETURN]]
// CHECK: return:
// CHECK-NEXT: ret void
// CHECK: unreachable:
// CHECK-NEXT: unreachable
//
// CHECK-EH-03-LABEL: @_Z6test12b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: br label [[DO_BODY:%.*]]
// CHECK-EH-03: do.body:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-03-NEXT: i32 2, label [[DO_END:%.*]]
// CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-EH-03-NEXT: ]
// CHECK-EH-03: do.end:
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr 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: @_Z6test12b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: br label [[DO_BODY:%.*]]
// CHECK-EH-11: do.body:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-11-NEXT: i32 2, label [[DO_END:%.*]]
// CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-EH-11-NEXT: ]
// CHECK-EH-11: do.end:
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr 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 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: br label [[RETURN:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: br label [[RETURN]]
// CHECK-EH-03: return:
// CHECK-EH-03-NEXT: ret void
//
// CHECK-EH-11-LABEL: @_Z6test13b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: br label [[RETURN]]
// 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z6test14b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-03: invoke.cont1:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]]
// CHECK-EH-03: invoke.cont2:
// CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-03: nrvo.skipdtor:
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: invoke.cont3:
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL4:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL4]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z6test14b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-11: invoke.cont1:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]]
//
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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: call void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z6test15b(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-03: invoke.cont1:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD]]
// CHECK-EH-03: invoke.cont2:
// CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-03: nrvo.skipdtor:
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: invoke.cont3:
// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL4:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL4]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z6test15b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[LPAD]]
// CHECK-EH-11: invoke.cont1:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL2]]
//
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: [[REF_TMP:%.*]] = alloca [[CLASS_ANON:%.*]], align 4
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 0
// CHECK-EH-11-NEXT: store ptr [[X]], ptr [[TMP0]], align 4
// CHECK-EH-11-NEXT: invoke void @"_ZZ6test16vENK3$_0clEv"(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP]], ptr noundef nonnull align 4 dereferenceable(4) [[REF_TMP]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-11: invoke.cont:
// CHECK-EH-11-NEXT: invoke void @_Z8ConsumeX1X(ptr noundef [[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(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]]
// CHECK-EH-11: lpad1:
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP5]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP6]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EHCLEANUP]]
// CHECK-EH-11: ehcleanup:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL3:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL3]]
//
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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4
// CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
// CHECK: if.then:
// CHECK-NEXT: br label [[IMPOSSIBLE:%.*]]
// CHECK: impossible:
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
// CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
// CHECK: if.then1:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: br label [[RETURN:%.*]]
// CHECK: if.end:
// CHECK-NEXT: br label [[IF_END2]]
// CHECK: if.end2:
// CHECK-NEXT: br label [[WHILE_BODY:%.*]]
// CHECK: while.body:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0
// CHECK-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]]
// CHECK: if.then4:
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end5:
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1
// CHECK-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]]
// CHECK: if.then7:
// CHECK-NEXT: store i32 4, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: if.end8:
// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2
// CHECK-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]]
// CHECK: if.then10:
// CHECK-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3:![0-9]+]]
// CHECK: if.end11:
// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3
// CHECK-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]]
// CHECK: if.then13:
// CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: if.end14:
// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4
// CHECK-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]]
// CHECK: if.then16:
// CHECK-NEXT: call void @exit(i32 noundef 1) #[[ATTR4]]
// CHECK-NEXT: br label [[IF_END17]]
// CHECK: if.end17:
// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5
// CHECK-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]]
// CHECK: if.then19:
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: if.end20:
// CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-NEXT: i32 1, label [[RETURN]]
// CHECK-NEXT: i32 4, label [[WHILE_END:%.*]]
// CHECK-NEXT: i32 3, label [[WHILE_BODY]]
// CHECK-NEXT: i32 2, label [[IMPOSSIBLE]]
// CHECK-NEXT: ]
// CHECK: cleanup.cont:
// CHECK-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3]]
// CHECK: while.end:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: br label [[IMPOSSIBLE:%.*]]
// CHECK-EH-03: impossible:
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
// CHECK-EH-03-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then1:
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: br label [[IF_END2]]
// CHECK-EH-03: if.end2:
// CHECK-EH-03-NEXT: br label [[WHILE_BODY:%.*]]
// CHECK-EH-03: while.body:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0
// CHECK-EH-03-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]]
// CHECK-EH-03: if.then4:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: if.end5:
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1
// CHECK-EH-03-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]]
// CHECK-EH-03: if.then7:
// CHECK-EH-03-NEXT: store i32 4, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: if.end8:
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2
// CHECK-EH-03-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]]
// CHECK-EH-03: if.then10:
// CHECK-EH-03-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: if.end11:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3
// CHECK-EH-03-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]]
// CHECK-EH-03: if.then13:
// CHECK-EH-03-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: if.end14:
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4
// CHECK-EH-03-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]]
// CHECK-EH-03: if.then16:
// CHECK-EH-03-NEXT: call void @exit(i32 noundef 1) #[[ATTR7]]
// CHECK-EH-03-NEXT: br label [[IF_END17]]
// CHECK-EH-03: if.end17:
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5
// CHECK-EH-03-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]]
// CHECK-EH-03: if.then19:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: if.end20:
// CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-EH-03-NEXT: i32 1, label [[RETURN]]
// CHECK-EH-03-NEXT: i32 4, label [[WHILE_END:%.*]]
// CHECK-EH-03-NEXT: i32 3, label [[WHILE_BODY]]
// CHECK-EH-03-NEXT: i32 2, label [[IMPOSSIBLE]]
// CHECK-EH-03-NEXT: ]
// CHECK-EH-03: cleanup.cont:
// CHECK-EH-03-NEXT: br label [[WHILE_BODY]]
// CHECK-EH-03: while.end:
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END2:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: br label [[IMPOSSIBLE:%.*]]
// CHECK-EH-11: impossible:
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 3
// CHECK-EH-11-NEXT: br i1 [[CMP]], label [[IF_THEN1:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then1:
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: br label [[IF_END2]]
// CHECK-EH-11: if.end2:
// CHECK-EH-11-NEXT: br label [[WHILE_BODY:%.*]]
// CHECK-EH-11: while.body:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP2]], 0
// CHECK-EH-11-NEXT: br i1 [[CMP3]], label [[IF_THEN4:%.*]], label [[IF_END5:%.*]]
// CHECK-EH-11: if.then4:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: if.end5:
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP3]], 1
// CHECK-EH-11-NEXT: br i1 [[CMP6]], label [[IF_THEN7:%.*]], label [[IF_END8:%.*]]
// CHECK-EH-11: if.then7:
// CHECK-EH-11-NEXT: store i32 4, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: if.end8:
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP4]], 2
// CHECK-EH-11-NEXT: br i1 [[CMP9]], label [[IF_THEN10:%.*]], label [[IF_END11:%.*]]
// CHECK-EH-11: if.then10:
// CHECK-EH-11-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]], !llvm.loop [[LOOP3:![0-9]+]]
// CHECK-EH-11: if.end11:
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP5]], 3
// CHECK-EH-11-NEXT: br i1 [[CMP12]], label [[IF_THEN13:%.*]], label [[IF_END14:%.*]]
// CHECK-EH-11: if.then13:
// CHECK-EH-11-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: if.end14:
// CHECK-EH-11-NEXT: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP6]], 4
// CHECK-EH-11-NEXT: br i1 [[CMP15]], label [[IF_THEN16:%.*]], label [[IF_END17:%.*]]
// CHECK-EH-11: if.then16:
// CHECK-EH-11-NEXT: call void @exit(i32 noundef 1) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[IF_END17]]
// CHECK-EH-11: if.end17:
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP7]], 5
// CHECK-EH-11-NEXT: br i1 [[CMP18]], label [[IF_THEN19:%.*]], label [[IF_END20:%.*]]
// CHECK-EH-11: if.then19:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: if.end20:
// CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-EH-11-NEXT: i32 1, label [[RETURN]]
// CHECK-EH-11-NEXT: i32 4, label [[WHILE_END:%.*]]
// CHECK-EH-11-NEXT: i32 3, label [[WHILE_BODY]]
// CHECK-EH-11-NEXT: i32 2, label [[IMPOSSIBLE]]
// CHECK-EH-11-NEXT: ]
// CHECK-EH-11: cleanup.cont:
// CHECK-EH-11-NEXT: br label [[WHILE_BODY]], !llvm.loop [[LOOP3]]
// CHECK-EH-11: while.end:
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[NRVO11:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
// CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP:%.*]]
// CHECK: if.end:
// CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP]]
// CHECK: cleanup:
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-NEXT: ]
// CHECK: cleanup.cont:
// CHECK-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP2]], 1
// CHECK-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]]
// CHECK: if.then3:
// CHECK-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP5:%.*]]
// CHECK: if.end4:
// CHECK-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: br label [[CLEANUP5]]
// CHECK: cleanup5:
// CHECK-NEXT: [[NRVO_VAL6:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL6]], label [[NRVO_SKIPDTOR8:%.*]], label [[NRVO_UNUSED7:%.*]]
// CHECK: nrvo.unused7:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR8]]
// CHECK: nrvo.skipdtor8:
// CHECK-NEXT: [[CLEANUP_DEST9:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: switch i32 [[CLEANUP_DEST9]], label [[UNREACHABLE]] [
// CHECK-NEXT: i32 0, label [[CLEANUP_CONT10:%.*]]
// CHECK-NEXT: i32 1, label [[RETURN]]
// CHECK-NEXT: ]
// CHECK: cleanup.cont10:
// CHECK-NEXT: store i1 false, ptr [[NRVO11]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO11]], align 1
// CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-NEXT: [[NRVO_VAL13:%.*]] = load i1, ptr [[NRVO11]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL13]], label [[NRVO_SKIPDTOR15:%.*]], label [[NRVO_UNUSED14:%.*]]
// CHECK: nrvo.unused14:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR15]]
// CHECK: nrvo.skipdtor15:
// CHECK-NEXT: br label [[RETURN]]
// CHECK: return:
// CHECK-NEXT: ret void
// CHECK: unreachable:
// CHECK-NEXT: unreachable
//
// CHECK-EH-03-LABEL: @_Z6test18i(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[NRVO11:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
// CHECK-EH-03-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP]]
// CHECK-EH-03: cleanup:
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-EH-03-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-EH-03-NEXT: ]
// CHECK-EH-03: cleanup.cont:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP2]], 1
// CHECK-EH-03-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]]
// CHECK-EH-03: if.then3:
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP5:%.*]]
// CHECK-EH-03: if.end4:
// CHECK-EH-03-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: br label [[CLEANUP5]]
// CHECK-EH-03: cleanup5:
// CHECK-EH-03-NEXT: [[NRVO_VAL6:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL6]], label [[NRVO_SKIPDTOR8:%.*]], label [[NRVO_UNUSED7:%.*]]
// CHECK-EH-03: nrvo.unused7:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR8]]
// CHECK-EH-03: nrvo.skipdtor8:
// CHECK-EH-03-NEXT: [[CLEANUP_DEST9:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: switch i32 [[CLEANUP_DEST9]], label [[UNREACHABLE]] [
// CHECK-EH-03-NEXT: i32 0, label [[CLEANUP_CONT10:%.*]]
// CHECK-EH-03-NEXT: i32 1, label [[RETURN]]
// CHECK-EH-03-NEXT: ]
// CHECK-EH-03: cleanup.cont10:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO11]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO11]], align 1
// CHECK-EH-03-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-03-NEXT: [[NRVO_VAL13:%.*]] = load i1, ptr [[NRVO11]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL13]], label [[NRVO_SKIPDTOR15:%.*]], label [[NRVO_UNUSED14:%.*]]
// CHECK-EH-03: nrvo.unused14:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: br label [[NRVO_SKIPDTOR15]]
// CHECK-EH-03: nrvo.skipdtor15:
// 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: @_Z6test18i(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[CLEANUP_DEST_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: [[NRVO1:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[NRVO11:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: store i32 [[I:%.*]], ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 0
// CHECK-EH-11-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP]]
// CHECK-EH-11: cleanup:
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: [[CLEANUP_DEST:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST]], label [[UNREACHABLE:%.*]] [
// CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT:%.*]]
// CHECK-EH-11-NEXT: i32 1, label [[RETURN:%.*]]
// CHECK-EH-11-NEXT: ]
// CHECK-EH-11: cleanup.cont:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP2]], 1
// CHECK-EH-11-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END4:%.*]]
// CHECK-EH-11: if.then3:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP5:%.*]]
// CHECK-EH-11: if.end4:
// CHECK-EH-11-NEXT: store i32 0, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: br label [[CLEANUP5]]
// CHECK-EH-11: cleanup5:
// CHECK-EH-11-NEXT: [[NRVO_VAL6:%.*]] = load i1, ptr [[NRVO1]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL6]], label [[NRVO_SKIPDTOR8:%.*]], label [[NRVO_UNUSED7:%.*]]
// CHECK-EH-11: nrvo.unused7:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR8]]
// CHECK-EH-11: nrvo.skipdtor8:
// CHECK-EH-11-NEXT: [[CLEANUP_DEST9:%.*]] = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: switch i32 [[CLEANUP_DEST9]], label [[UNREACHABLE]] [
// CHECK-EH-11-NEXT: i32 0, label [[CLEANUP_CONT10:%.*]]
// CHECK-EH-11-NEXT: i32 1, label [[RETURN]]
// CHECK-EH-11-NEXT: ]
// CHECK-EH-11: cleanup.cont10:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO11]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO11]], align 1
// CHECK-EH-11-NEXT: store i32 1, ptr [[CLEANUP_DEST_SLOT]], align 4
// CHECK-EH-11-NEXT: [[NRVO_VAL13:%.*]] = load i1, ptr [[NRVO11]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL13]], label [[NRVO_SKIPDTOR15:%.*]], label [[NRVO_UNUSED14:%.*]]
// CHECK-EH-11: nrvo.unused14:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR15]]
// CHECK-EH-11: nrvo.skipdtor15:
// 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 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[L:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 4
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT]], ptr [[TMP1]], align 4
// CHECK-EH-11-NEXT: invoke void @"_ZZ6test19vENK3$_0clEv"(ptr sret([[CLASS_X]]) align 1 [[L]], ptr noundef nonnull align 4 dereferenceable(4) [[REF_TMP]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]]
// CHECK-EH-11: invoke.cont:
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[L]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]]
//
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: [[AGG_TMP_ENSURED:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED1:%.*]] = alloca [[CLASS_X]], align 1
// CHECK-EH-11-NEXT: call void @_Z6test20ILb1EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED]])
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: call void @_Z6test20ILb0EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED1]])
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
//
void test20instantiate() {
test20<true>();
test20<false>();
}
#endif
// CHECK-LABEL: @_Z6test21v(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z6test21v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: ret void
//
// CHECK-EH-11-LABEL: @_Z6test21v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: call void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR4]]
// CHECK-NEXT: ret void
//
// CHECK-EH-03-LABEL: @_Z6test22v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL2]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP5]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z6test22v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP2]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP1]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP3]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]]
// CHECK-EH-11: eh.resume:
// CHECK-EH-11-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]]
//
X test22() { // http://wg21.link/p2025r2#ex-19
volatile X x;
return x; // NRVO is impossible
}
// CHECK-LABEL: @_Z6test23b(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK: if.then:
// CHECK-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK: nrvo.unused:
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR4]]
// CHECK-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK: nrvo.skipdtor:
// CHECK-NEXT: br label [[RETURN:%.*]]
// CHECK: if.end:
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-NEXT: call void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR4]]
// 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: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-03-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-03-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-03: if.then:
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: br label [[RETURN:%.*]]
// CHECK-EH-03: if.end:
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-EH-03-NEXT: br label [[RETURN]]
// CHECK-EH-03: lpad:
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(ptr 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: br label [[EH_RESUME:%.*]]
// CHECK-EH-03: return:
// CHECK-EH-03-NEXT: ret void
// CHECK-EH-03: eh.resume:
// CHECK-EH-03-NEXT: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-03-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-03-NEXT: [[LPAD_VAL2:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-03-NEXT: resume { ptr, i32 } [[LPAD_VAL2]]
// CHECK-EH-03: terminate.lpad:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP5]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP6]]) #[[ATTR6]]
// CHECK-EH-03-NEXT: unreachable
//
// CHECK-EH-11-LABEL: @_Z6test23b(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[B_ADDR:%.*]] = alloca i8, align 1
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[EXN_SLOT:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[EHSELECTOR_SLOT:%.*]] = alloca i32, align 4
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: [[FROMBOOL:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[FROMBOOL]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP1]] to i1
// CHECK-EH-11-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
// CHECK-EH-11: if.then:
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-NEXT: br label [[RETURN:%.*]]
// CHECK-EH-11: if.end:
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]])
// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERVKS_(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], ptr 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(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[RETURN]]
// CHECK-EH-11: lpad:
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP3]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP2]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP4]], ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR6]]
// 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: [[EXN:%.*]] = load ptr, ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[SEL:%.*]] = load i32, ptr [[EHSELECTOR_SLOT]], align 4
// CHECK-EH-11-NEXT: [[LPAD_VAL:%.*]] = insertvalue { ptr, i32 } poison, ptr [[EXN]], 0
// CHECK-EH-11-NEXT: [[LPAD_VAL1:%.*]] = insertvalue { ptr, i32 } [[LPAD_VAL]], i32 [[SEL]], 1
// CHECK-EH-11-NEXT: resume { ptr, i32 } [[LPAD_VAL1]]
//
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-03-LABEL: @_Z6test24v(
// CHECK-EH-03-NEXT: entry:
// CHECK-EH-03-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-03-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-03-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-03-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-03-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-03-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-03: nrvo.unused:
// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(ptr 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: ret void
//
// CHECK-EH-11-LABEL: @_Z6test24v(
// CHECK-EH-11-NEXT: entry:
// CHECK-EH-11-NEXT: [[RESULT_PTR:%.*]] = alloca ptr, align 4
// CHECK-EH-11-NEXT: [[NRVO:%.*]] = alloca i1, align 1
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT:%.*]], ptr [[RESULT_PTR]], align 4
// CHECK-EH-11-NEXT: store i1 false, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]])
// CHECK-EH-11-NEXT: store i1 true, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: [[NRVO_VAL:%.*]] = load i1, ptr [[NRVO]], align 1
// CHECK-EH-11-NEXT: br i1 [[NRVO_VAL]], label [[NRVO_SKIPDTOR:%.*]], label [[NRVO_UNUSED:%.*]]
// CHECK-EH-11: nrvo.unused:
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: br label [[NRVO_SKIPDTOR]]
// CHECK-EH-11: nrvo.skipdtor:
// CHECK-EH-11-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: [[AGG_TMP_ENSURED:%.*]] = alloca [[CLASS_X:%.*]], align 1
// CHECK-EH-11-NEXT: [[AGG_TMP_ENSURED1:%.*]] = alloca [[CLASS_X]], align 1
// CHECK-EH-11-NEXT: call void @_Z6test25ILb1EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED]])
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: call void @_Z6test25ILb0EE1Xv(ptr sret([[CLASS_X]]) align 1 [[AGG_TMP_ENSURED1]])
// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[AGG_TMP_ENSURED1]]) #[[ATTR6]]
// CHECK-EH-11-NEXT: ret void
//
void test25instantiate() {
test25<true>();
test25<false>();
}
#endif