[clang] 3587b15 - [Clang] [P2025] More exhaustive tests for NRVO

Evgeny Shulgin via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 16 17:58:52 PDT 2022


Author: Evgeny Shulgin
Date: 2022-03-17T03:58:40+03:00
New Revision: 3587b15abe683f164093f8d057e921f913572007

URL: https://github.com/llvm/llvm-project/commit/3587b15abe683f164093f8d057e921f913572007
DIFF: https://github.com/llvm/llvm-project/commit/3587b15abe683f164093f8d057e921f913572007.diff

LOG: [Clang] [P2025] More exhaustive tests for NRVO

This is a preliminary patch ahead of D119792 (I'll rebase that one on top of this).
This shows what Clang's _current_ behaviour is for calculating NRVO in various
common cases. Then, in D119792 (and future patches), I'll be able to demostrate
exactly how LLVM IR for each of these cases changes.

Reviewed By: Quuxplusone

Differential Revision: https://reviews.llvm.org/D119927

Added: 
    

Modified: 
    clang/test/CodeGenCXX/nrvo.cpp

Removed: 
    


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


        


More information about the cfe-commits mailing list