Sirraide 12f78e740c
[Clang] [NFC] Fix unintended -Wreturn-type warnings everywhere in the test suite (#123464)
In preparation of making `-Wreturn-type` default to an error (as there
is virtually no situation where you’d *want* to fall off the end of a
function that is supposed to return a value), this patch fixes tests
that have relied on this being only a warning, of which there seem 
to be 3 kinds:

1. Tests which for no apparent reason have a function that triggers the
warning.

I suspect that a lot of these were on accident (or from before the
warning was introduced), since a lot of people will open issues w/ their
problematic code in the `main` function (which is the one case where you
don’t need to return from a non-void function, after all...), which
someone will then copy, possibly into a namespace, possibly renaming it,
the end result of that being that you end up w/ something that
definitely is not `main` anymore, but which still is declared as
returning `int`, and which still has no return statement (another reason
why I think this might apply to a lot of these is because usually the
actual return type of such problematic functions is quite literally
`int`).
  
A lot of these are really old tests that don’t use `-verify`, which is
why no-one noticed or had to care about the extra warning that was
already being emitted by them until now.

2. Tests which test either `-Wreturn-type`, `[[noreturn]]`, or what
codegen and sanitisers do whenever you do fall off the end of a
function.

3. Tests where I struggle to figure out what is even being tested
(usually because they’re Objective-C tests, and I don’t know
Objective-C), whether falling off the end of a function matters in the
first place, and tests where actually spelling out an expression to
return would be rather cumbersome (e.g. matrix types currently don’t
support list initialisation, so I can’t write e.g. `return {}`).

For tests that fall into categories 2 and 3, I just added
`-Wno-error=return-type` to the `RUN` lines and called it a day. This
was especially necessary for the former since `-Wreturn-type` is an
analysis-based warning, meaning that it is currently impossible to test
for more than one occurrence of it in the same compilation if it
defaults to an error since the analysis pass is skipped for subsequent
functions as soon as an error is emitted.

I’ve also added `-Werror=return-type` to a few tests that I had already
updated as this patch was previously already making the warning an error
by default, but we’ve decided to split that into two patches instead.
2025-01-18 19:16:33 +01:00

2948 lines
163 KiB
C++

// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -triple i386-unknown-unknown -Wno-error=return-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i386-unknown-unknown -Wno-error=return-type -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 -Wno-error=return-type -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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[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: br label [[EHCLEANUP:%.*]]
// CHECK-EH-03: lpad1:
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP5]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { ptr, i32 } [[TMP4]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP6]], 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: [[TMP7:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP7]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP8]]) #[[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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[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) [[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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[TMP0:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr @_ZTI1X
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTI1X) #[[ATTR7]]
// CHECK-EH-03-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP3]]
// 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: [[TMP4:%.*]] = 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) [[TMP4]])
// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-03: invoke.cont1:
// CHECK-EH-03-NEXT: [[TMP5:%.*]] = 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: [[TMP6:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP7]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP8]], 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: [[TMP9:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP9]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP10]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP11:%.*]] = extractvalue { ptr, i32 } [[TMP9]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP11]], 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: [[TMP12:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP13:%.*]] = extractvalue { ptr, i32 } [[TMP12]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP13]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: catch ptr @_ZTI1X
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTI1X) #[[ATTR6]]
// CHECK-EH-11-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[SEL]], [[TMP3]]
// 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: [[TMP4:%.*]] = 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) [[TMP4]])
// CHECK-EH-11-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]]
// CHECK-EH-11: invoke.cont1:
// CHECK-EH-11-NEXT: [[TMP5:%.*]] = 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: [[TMP6:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP7:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP7]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP8:%.*]] = extractvalue { ptr, i32 } [[TMP6]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP8]], 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: [[TMP9:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: catch ptr null
// CHECK-EH-11-NEXT: [[TMP10:%.*]] = extractvalue { ptr, i32 } [[TMP9]], 0
// CHECK-EH-11-NEXT: call void @__clang_call_terminate(ptr [[TMP10]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP4]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP2]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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 dead_on_unwind writable 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 dead_on_unwind writable 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 dead_on_unwind writable 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[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_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: [[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: @_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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[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: 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[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_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: [[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: @_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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[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: 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], 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: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[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_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: [[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: @_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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[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: 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[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_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: [[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: @_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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(ptr noundef nonnull align 1 dereferenceable(1) [[X]])
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[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: 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 nuw [[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 dead_on_unwind writable 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP2]], 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: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP3]], 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: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP4]], 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: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP5]], 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: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP6]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP2]], 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: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP3]], 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: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP4]], 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: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP5]], 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: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP6]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP3:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP2:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP6:%.*]] = icmp eq i32 [[TMP2]], 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: [[TMP3:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP9:%.*]] = icmp eq i32 [[TMP3]], 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: [[TMP4:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP12:%.*]] = icmp eq i32 [[TMP4]], 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: [[TMP5:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP15:%.*]] = icmp eq i32 [[TMP5]], 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: [[TMP6:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP18:%.*]] = icmp eq i32 [[TMP6]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-03-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 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: [[TMP1:%.*]] = load i32, ptr [[I_ADDR]], align 4
// CHECK-EH-11-NEXT: [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 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: [[TMP0:%.*]] = getelementptr inbounds nuw [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
// CHECK-EH-11-NEXT: store ptr [[AGG_RESULT]], ptr [[TMP0]], align 4
// CHECK-EH-11-NEXT: invoke void @"_ZZ6test19vENK3$_0clEv"(ptr dead_on_unwind writable 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: [[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) [[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 dead_on_unwind writable 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 dead_on_unwind writable 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: [[TMP0:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: cleanup
// CHECK-EH-03-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
// CHECK-EH-03-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-03-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
// CHECK-EH-03-NEXT: store i32 [[TMP2]], 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: [[TMP3:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-03-NEXT: catch ptr null
// CHECK-EH-03-NEXT: [[TMP4:%.*]] = extractvalue { ptr, i32 } [[TMP3]], 0
// CHECK-EH-03-NEXT: call void @__clang_call_terminate(ptr [[TMP4]]) #[[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: [[TMP0:%.*]] = landingpad { ptr, i32 }
// CHECK-EH-11-NEXT: cleanup
// CHECK-EH-11-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0
// CHECK-EH-11-NEXT: store ptr [[TMP1]], ptr [[EXN_SLOT]], align 4
// CHECK-EH-11-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1
// CHECK-EH-11-NEXT: store i32 [[TMP2]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-NEXT: br i1 [[LOADEDV]], 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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-03-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-03-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-03-NEXT: br i1 [[LOADEDV]], 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: [[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) [[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: [[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: @_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: [[STOREDV:%.*]] = zext i1 [[B:%.*]] to i8
// CHECK-EH-11-NEXT: store i8 [[STOREDV]], ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[TMP0:%.*]] = load i8, ptr [[B_ADDR]], align 1
// CHECK-EH-11-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP0]] to i1
// CHECK-EH-11-NEXT: br i1 [[LOADEDV]], 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: [[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) [[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 dead_on_unwind writable 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 dead_on_unwind writable 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