brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.5 KiB · 4eafa72 Raw
521 lines · cpp
1// RUN: %clang_cc1 --std=c++20 -fexceptions -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=EH %s2// RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefixes=NOEH,CHECK %s3 4struct Printy {5  Printy(const char *name) : name(name) {}6  ~Printy() {}7  const char *name;8};9 10int foo() { return 2; }11 12struct Printies {13  Printy a;14  Printy b;15  Printy c;16};17 18void ParenInit() {19  // CHECK-LABEL: define dso_local void @_Z9ParenInitv()20  // CHECK: [[CLEANUP_DEST:%.+]] = alloca i32, align 421  Printies ps(Printy("a"), 22              // CHECK: call void @_ZN6PrintyC1EPKc23              ({24                if (foo()) return;25                // CHECK:     if.then:26                // CHECK-NEXT:   store i32 1, ptr [[CLEANUP_DEST]], align 427                // CHECK-NEXT:   br label %cleanup28                Printy("b");29                // CHECK:     if.end:30                // CHECK-NEXT:  call void @_ZN6PrintyC1EPKc31              }),32              ({33                if (foo()) return;34                // CHECK:     if.then{{.*}}:35                // CHECK-NEXT:  store i32 1, ptr [[CLEANUP_DEST]], align 436                // CHECK-NEXT:  call void @_ZN6PrintyD1Ev37                // CHECK-NEXT:  br label %cleanup38                Printy("c");39                // CHECK:     if.end{{.*}}:40                // CHECK-NEXT:  call void @_ZN6PrintyC1EPKc41                // CHECK-NEXT:  call void @_ZN8PrintiesD1Ev42                // CHECK-NEXT:  br label %return43              }));44  // CHECK:     cleanup:45  // CHECK-NEXT:  call void @_ZN6PrintyD1Ev46  // CHECK-NEXT:  br label %return47}48 49void break_in_stmt_expr() {50  // Verify that the "break" in "if.then".calls dtor before jumping to "for.end".51 52  // CHECK-LABEL: define dso_local void @_Z18break_in_stmt_exprv()53  Printies p{Printy("a"), 54            // CHECK: call void @_ZN6PrintyC1EPKc55            ({56                for (;;) {57                    Printies ps{58                      Printy("b"), 59                      // CHECK: for.cond:60                      // CHECK:   call void @_ZN6PrintyC1EPKc61                      ({62                        if (foo()) {63                          break;64                          // CHECK:       if.then:65                          // CHECK-NEXT:    call void @_ZN6PrintyD1Ev66                          // CHECK-NEXT:    br label %for.end67                        }68                        Printy("c");69                        // CHECK:       if.end:70                        // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc71                      }),72                      Printy("d")};73                      // CHECK:           call void @_ZN6PrintyC1EPKc74                      // CHECK-NEXT:      call void @_ZN8PrintiesD1Ev75                      // CHECK-NEXT:      br label %for.cond76                }77                Printy("e");78  // CHECK:       for.end:79  // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc80              }),81              Printy("f")};82  // CHECK:         call void @_ZN6PrintyC1EPKc83  // CHECK-NEXT:    call void @_ZN8PrintiesD1Ev84}85 86void goto_in_stmt_expr() {87  // Verify that:88  //  - correct branch fixups for deactivated normal cleanups are generated correctly.89 90  // CHECK-LABEL: define dso_local void @_Z17goto_in_stmt_exprv()91  // CHECK: [[CLEANUP_DEST_SLOT:%cleanup.dest.slot.*]] = alloca i32, align 492  {93    Printies p1{Printy("a"), // CHECK: call void @_ZN6PrintyC1EPKc94                ({95                  {96                    Printies p2{Printy("b"),97                                // CHECK: call void @_ZN6PrintyC1EPKc98                                ({99                                  if (foo() == 1) {100                                    goto in;101                                    // CHECK:       if.then:102                                    // CHECK-NEXT:    store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4103                                    // CHECK-NEXT:    br label %[[CLEANUP1:.+]]104                                  }105                                  if (foo() == 2) {106                                    goto out;107                                    // CHECK:       if.then{{.*}}:108                                    // CHECK-NEXT:    store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4109                                    // CHECK-NEXT:    br label %[[CLEANUP1]]110                                  }111                                  Printy("c");112                                  // CHECK:       if.end{{.*}}:113                                  // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc114                                }),115                                Printy("d")};116                                // CHECK:           call void @_ZN6PrintyC1EPKc117                                // CHECK-NEXT:      call void @_ZN8PrintiesD1Ev118                                // CHECK-NEXT:      br label %in119 120                  }121                in:122                  Printy("e");123                // CHECK:       in:                                               ; preds = %if.end{{.*}}, %[[CLEANUP1]]124                // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc125                }),126                Printy("f")};127                // CHECK:         call void @_ZN6PrintyC1EPKc128                // CHECK-NEXT:    call void @_ZN8PrintiesD1Ev129                // CHECK-NEXT:    br label %out130  }131out:132  return;133  // CHECK:       out:134  // CHECK-NEXT:    ret void135 136  // CHECK:       [[CLEANUP1]]:                                          ; preds = %if.then{{.*}}, %if.then137  // CHECK-NEXT:    call void @_ZN6PrintyD1Ev138  // CHECK-NEXT:    %cleanup.dest = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4139  // CHECK-NEXT:    switch i32 %cleanup.dest, label %[[CLEANUP2:.+]] [140  // CHECK-NEXT:      i32 2, label %in141  // CHECK-NEXT:    ]142 143  // CHECK:       [[CLEANUP2]]:                                         ; preds = %[[CLEANUP1]]144  // CHECK-NEXT:    call void @_ZN6PrintyD1Ev145  // CHECK-NEXT:    %cleanup.dest{{.*}} = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4146  // CHECK-NEXT:    switch i32 %cleanup.dest{{.*}}, label %unreachable [147  // CHECK-NEXT:      i32 3, label %out148  // CHECK-NEXT:    ]149}150 151void ArrayInit() {152  // Printy arr[4] = {ctorA, ctorB, stmt-exprC, stmt-exprD};153  // Verify that:154  //  - We do the necessary stores for array cleanups (endOfInit and last constructed element).155  //  - We update the array init element correctly for ctorA, ctorB and stmt-exprC.156  //  - stmt-exprC and stmt-exprD share the array body dtor code (see %cleanup).157 158  // CHECK-LABEL: define dso_local void @_Z9ArrayInitv()159  // CHECK: %arrayinit.endOfInit = alloca ptr, align 8160  // CHECK: %cleanup.dest.slot = alloca i32, align 4161  // CHECK: store ptr %arr, ptr %arrayinit.endOfInit, align 8162  Printy arr[4] = {163    Printy("a"),164    // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) %arr, ptr noundef @.str)165    // CHECK: [[ARRAYINIT_ELEMENT1:%.+]] = getelementptr inbounds %struct.Printy, ptr %arr, i64 1166    // CHECK: store ptr [[ARRAYINIT_ELEMENT1]], ptr %arrayinit.endOfInit, align 8167    Printy("b"),168    // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) [[ARRAYINIT_ELEMENT1]], ptr noundef @.str.1)169    // CHECK: [[ARRAYINIT_ELEMENT2:%.+]] = getelementptr inbounds %struct.Printy, ptr %arr, i64 2170    // CHECK: store ptr [[ARRAYINIT_ELEMENT2]], ptr %arrayinit.endOfInit, align 8171    ({172    // CHECK: br i1 {{.*}}, label %if.then, label %if.end173      if (foo()) {174        return;175      // CHECK:       if.then:176      // CHECK-NEXT:    store i32 1, ptr %cleanup.dest.slot, align 4177      // CHECK-NEXT:    br label %cleanup178      }179      // CHECK:       if.end:180      Printy("c");181      // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc182      // CHECK-NEXT:    %arrayinit.element2 = getelementptr inbounds %struct.Printy, ptr %arr, i64 3183      // CHECK-NEXT:    store ptr %arrayinit.element2, ptr %arrayinit.endOfInit, align 8184    }),185    ({186    // CHECK: br i1 {{%.+}} label %[[IF_THEN2:.+]], label %[[IF_END2:.+]]187      if (foo()) {188        return;189      // CHECK:       [[IF_THEN2]]:190      // CHECK-NEXT:    store i32 1, ptr %cleanup.dest.slot, align 4191      // CHECK-NEXT:    br label %cleanup192      }193      // CHECK:       [[IF_END2]]:194      Printy("d");195      // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc196      // CHECK-NEXT:    %array.begin = getelementptr inbounds [4 x %struct.Printy], ptr %arr, i32 0, i32 0197      // CHECK-NEXT:    %0 = getelementptr inbounds %struct.Printy, ptr %array.begin, i64 4198      // CHECK-NEXT:    br label %[[ARRAY_DESTROY_BODY1:.+]]199  }),200  };201 202  // CHECK:       [[ARRAY_DESTROY_BODY1]]:203  // CHECK-NEXT:    %arraydestroy.elementPast{{.*}} = phi ptr [ %0, %[[IF_END2]] ], [ %arraydestroy.element{{.*}}, %[[ARRAY_DESTROY_BODY1]] ]204  // CHECK-NEXT:    %arraydestroy.element{{.*}} = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast{{.*}}, i64 -1205  // CHECK-NEXT:    call void @_ZN6PrintyD1Ev206  // CHECK-NEXT:    %arraydestroy.done{{.*}} = icmp eq ptr %arraydestroy.element{{.*}}, %array.begin207  // CHECK-NEXT:    br i1 %arraydestroy.done{{.*}}, label %[[ARRAY_DESTROY_DONE1:.+]], label %[[ARRAY_DESTROY_BODY1]]208 209  // CHECK:       [[ARRAY_DESTROY_DONE1]]:210  // CHECK-NEXT:    ret void211 212  // CHECK:       cleanup:213  // CHECK-NEXT:    %1 = load ptr, ptr %arrayinit.endOfInit, align 8214  // CHECK-NEXT:    %arraydestroy.isempty = icmp eq ptr %arr, %1215  // CHECK-NEXT:    br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2:.+]]216 217  // CHECK:       [[ARRAY_DESTROY_BODY2]]:218  // CHECK-NEXT:    %arraydestroy.elementPast = phi ptr [ %1, %cleanup ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY2]] ]219  // CHECK-NEXT:    %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1220  // CHECK-NEXT:    call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)221  // CHECK-NEXT:    %arraydestroy.done = icmp eq ptr %arraydestroy.element, %arr222  // CHECK-NEXT:    br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE2]], label %[[ARRAY_DESTROY_BODY2]]223 224  // CHECK:       [[ARRAY_DESTROY_DONE2]]:225  // CHECK-NEXT:    br label %[[ARRAY_DESTROY_DONE1]]226}227 228void ArraySubobjects() {229  struct S {230    Printy arr1[2];231    Printy arr2[2];232    Printy p;233  };234  // CHECK-LABEL: define dso_local void @_Z15ArraySubobjectsv()235  // CHECK: %arrayinit.endOfInit = alloca ptr, align 8236  S s{{Printy("a"), Printy("b")},237      // CHECK: call void @_ZN6PrintyC1EPKc238      // CHECK: call void @_ZN6PrintyC1EPKc239      {Printy("a"),240      // CHECK: store ptr %arr2, ptr %arrayinit.endOfInit, align 8241      // CHECK: call void @_ZN6PrintyC1EPKc242      // CHECK: [[ARRAYINIT_ELEMENT:%.+]] = getelementptr inbounds %struct.Printy243      // CHECK: store ptr [[ARRAYINIT_ELEMENT]], ptr %arrayinit.endOfInit, align 8244      ({245         if (foo()) {246           return;247           // CHECK:      if.then:248           // CHECK-NEXT:   [[V0:%.+]] = load ptr, ptr %arrayinit.endOfInit, align 8249           // CHECK-NEXT:   %arraydestroy.isempty = icmp eq ptr %arr2, [[V0]]250           // CHECK-NEXT:   br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE:.+]], label %[[ARRAY_DESTROY_BODY:.+]]251         }252         Printy("b");253       })254      },255      Printy("c")256      // CHECK:       if.end:257      // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc258      // CHECK:         call void @_ZN6PrintyC1EPKc259      // CHECK-NEXT:    call void @_ZZ15ArraySubobjectsvEN1SD1Ev260      // CHECK-NEXT:    br label %return261    };262    // CHECK:       return:263    // CHECK-NEXT:    ret void264 265    // CHECK:       [[ARRAY_DESTROY_BODY]]:266    // CHECK-NEXT:    %arraydestroy.elementPast = phi ptr [ %0, %if.then ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY]] ]267    // CHECK-NEXT:    %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1268    // CHECK-NEXT:    call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)269    // CHECK-NEXT:    %arraydestroy.done = icmp eq ptr %arraydestroy.element, %arr2270    // CHECK-NEXT:    br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE]], label %[[ARRAY_DESTROY_BODY]]271 272    // CHECK:       [[ARRAY_DESTROY_DONE]]273    // CHECK-NEXT:    [[ARRAY_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.Printy], ptr %arr1, i32 0, i32 0274    // CHECK-NEXT:    [[V1:%.+]] = getelementptr inbounds %struct.Printy, ptr [[ARRAY_BEGIN]], i64 2275    // CHECK-NEXT:    br label %[[ARRAY_DESTROY_BODY2:.+]]276 277    // CHECK:       [[ARRAY_DESTROY_BODY2]]:278    // CHECK-NEXT:    %arraydestroy.elementPast4 = phi ptr [ %1, %[[ARRAY_DESTROY_DONE]] ], [ %arraydestroy.element5, %[[ARRAY_DESTROY_BODY2]] ]279    // CHECK-NEXT:    %arraydestroy.element5 = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast4, i64 -1280    // CHECK-NEXT:    call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element5)281    // CHECK-NEXT:    %arraydestroy.done6 = icmp eq ptr %arraydestroy.element5, [[ARRAY_BEGIN]]282    // CHECK-NEXT:    br i1 %arraydestroy.done6, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2]]283 284 285    // CHECK:     [[ARRAY_DESTROY_DONE2]]:286    // CHECK-NEXT:  br label %return287}288 289void LambdaInit() {290  // CHECK-LABEL: define dso_local void @_Z10LambdaInitv()291  auto S = [a = Printy("a"), b = ({292                               if (foo()) {293                                 return;294                                 // CHECK:       if.then:295                                 // CHECK-NEXT:    call void @_ZN6PrintyD1Ev296                                 // CHECK-NEXT:    br label %return297                               }298                               Printy("b");299                             })]() { return a; };300}301 302struct PrintyRefBind {303  const Printy &a;304  const Printy &b;305};306 307struct Temp {308  Temp();309  ~Temp();310};311Temp CreateTemp();312Printy CreatePrinty();313Printy CreatePrinty(const Temp&);314 315void LifetimeExtended() {316  // CHECK-LABEL: define dso_local void @_Z16LifetimeExtendedv317  PrintyRefBind ps = {Printy("a"), ({318                        if (foo()) {319                          return;320                          // CHECK: if.then:321                          // CHECK-NEXT: call void @_ZN6PrintyD1Ev322                          // CHECK-NEXT: br label %return323                        }324                        Printy("b");325                      })};326}327 328void ConditionalLifetimeExtended() {329  // CHECK-LABEL: @_Z27ConditionalLifetimeExtendedv()330 331  // Verify that we create two cleanup flags.332  //  1. First for the cleanup which is deactivated after full expression.333  //  2. Second for the life-ext cleanup which is activated if the branch is taken.334 335  // Note: We use `CreateTemp()` to ensure that life-ext destroy cleanup is not at336  // the top of EHStack on deactivation. This ensures using active flags.337 338  Printy* p1 = nullptr;339  // CHECK:       store i1 false, ptr [[BRANCH1_DEFERRED:%cleanup.cond]], align 1340  // CHECK-NEXT:  store i1 false, ptr [[BRANCH1_LIFEEXT:%cleanup.cond.*]], align 1341  PrintyRefBind ps = {342      p1 != nullptr ? static_cast<const Printy&>(CreatePrinty())343      // CHECK:       cond.true:344      // CHECK-NEXT:    call void @_Z12CreatePrintyv345      // CHECK-NEXT:    store i1 true, ptr [[BRANCH1_DEFERRED]], align 1346      // CHECK-NEXT:    store i1 true, ptr [[BRANCH1_LIFEEXT]], align 1347      // CHECK-NEXT:    br label %{{.*}}348      : foo() ? static_cast<const Printy&>(CreatePrinty(CreateTemp()))349              : *p1,350      ({351        if (foo()) return;352        Printy("c");353        // CHECK:       if.end:354        // CHECK-NEXT:    call void @_ZN6PrintyC1EPKc355        // CHECK-NEXT:    store ptr356      })};357      // CHECK-NEXT:      store i1 false, ptr [[BRANCH1_DEFERRED]], align 1358      // CHECK-NEXT:      store i32 0, ptr %cleanup.dest.slot, align 4359      // CHECK-NEXT:      br label %cleanup360 361}362 363void NewArrayInit() {364  // CHECK-LABEL: define dso_local void @_Z12NewArrayInitv()365  // CHECK: %array.init.end = alloca ptr, align 8366  // CHECK: store ptr %0, ptr %array.init.end, align 8367  Printy *array = new Printy[3]{368    "a",369    // CHECK: call void @_ZN6PrintyC1EPKc370    // CHECK: store ptr %array.exp.next, ptr %array.init.end, align 8371    "b", 372    // CHECK: call void @_ZN6PrintyC1EPKc373    // CHECK: store ptr %array.exp.next1, ptr %array.init.end, align 8374    ({375        if (foo()) {376          return;377          // CHECK: if.then:378          // CHECK:   br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body379        }380        "b";381        // CHECK: if.end:382        // CHECK:   call void @_ZN6PrintyC1EPKc383    })};384  // CHECK:       arraydestroy.body:385  // CHECK-NEXT:    %arraydestroy.elementPast = phi ptr [ %{{.*}}, %if.then ], [ %arraydestroy.element, %arraydestroy.body ]386  // CHECK-NEXT:    %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1387  // CHECK-NEXT:    call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)388  // CHECK-NEXT:    %arraydestroy.done = icmp eq ptr %arraydestroy.element, %0389  // CHECK-NEXT:    br i1 %arraydestroy.done, label %arraydestroy.done{{.*}}, label %arraydestroy.body390 391  // CHECK:       arraydestroy.done{{.*}}:                               ; preds = %arraydestroy.body, %if.then392  // CHECK-NEXT:    br label %return393}394 395void DestroyInConditionalCleanup() {396  // EH-LABEL: DestroyInConditionalCleanupv()397  // NOEH-LABEL: DestroyInConditionalCleanupv()398  struct A {399    A() {}400    ~A() {}401  };402 403  struct Value {404    Value(A) {}405    ~Value() {}406  };407 408  struct V2 {409    Value K;410    Value V;411  };412  // Verify we use conditional cleanups.413  (void)(foo() ? V2{A(), A()} : V2{A(), A()});414  // NOEH:   cond.true:415  // NOEH:      call void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev416  // NOEH:      store ptr %{{.*}}, ptr %cond-cleanup.save417 418  // EH:   cond.true:419  // EH:        invoke void @_ZZ27DestroyInConditionalCleanupvEN1AC1Ev420  // EH:        store ptr %{{.*}}, ptr %cond-cleanup.save421}422 423void ArrayInitWithContinue() {424  // CHECK-LABEL: @_Z21ArrayInitWithContinuev425  // Verify that we start to emit the array destructor.426  // CHECK: %arrayinit.endOfInit = alloca ptr, align 8427  for (int i = 0; i < 1; ++i) {428    Printy arr[2] = {"a", ({429                       if (foo()) {430                         continue;431                       }432                       "b";433                     })};434  }435}436 437struct [[clang::trivial_abi]] HasTrivialABI {438  HasTrivialABI();439  ~HasTrivialABI();440};441void AcceptTrivialABI(HasTrivialABI, int);442void TrivialABI() {443  // CHECK-LABEL: define dso_local void @_Z10TrivialABIv()444  AcceptTrivialABI(HasTrivialABI(), ({445                     if (foo()) return;446                     // CHECK:      if.then:447                     // CHECK-NEXT:   call void @_ZN13HasTrivialABID1Ev448                     // CHECK-NEXT:   br label %return449                     0;450                   }));451}452 453namespace CleanupFlag {454struct A {455  A() {}456  ~A() {}457};458 459struct B {460  B(const A&) {}461  B() {}462  ~B() {}463};464 465struct S {466  A a;467  B b;468};469 470int AcceptS(S s);471 472void Accept2(int x, int y);473 474void InactiveNormalCleanup() {475  // CHECK-LABEL: define {{.*}}InactiveNormalCleanupEv()476  477  // The first A{} below is an inactive normal cleanup which478  // is not popped from EHStack on deactivation. This needs an479  // "active" cleanup flag.480 481  // CHECK: [[ACTIVE:%cleanup.isactive.*]] = alloca i1, align 1482  // CHECK: call void [[A_CTOR:@.*AC1Ev]]483  // CHECK: store i1 true, ptr [[ACTIVE]], align 1484  // CHECK: call void [[A_CTOR]]485  // CHECK: call void [[B_CTOR:@.*BC1ERKNS_1AE]]486  // CHECK: store i1 false, ptr [[ACTIVE]], align 1487  // CHECK: call noundef i32 [[ACCEPTS:@.*AcceptSENS_1SE]]488  Accept2(AcceptS({.a = A{}, .b = A{}}), ({489            if (foo()) return;490            // CHECK: if.then:491            // CHECK:   br label %cleanup492            0;493            // CHECK: if.end:494            // CHECK:   call void [[ACCEPT2:@.*Accept2Eii]]495            // CHECK:   br label %cleanup496          }));497  // CHECK: cleanup:498  // CHECK:   call void [[S_DTOR:@.*SD1Ev]]499  // CHECK:   call void [[A_DTOR:@.*AD1Ev]]500  // CHECK:   %cleanup.is_active = load i1, ptr [[ACTIVE]]501  // CHECK:   br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done502 503  // CHECK: cleanup.action:504  // CHECK:   call void [[A_DTOR]]505 506  // The "active" cleanup flag is not required for unused cleanups.507  Accept2(AcceptS({.a = A{}, .b = A{}}), 0);508  // CHECK: cleanup.cont:509  // CHECK:   call void [[A_CTOR]]510  // CHECK-NOT: store i1 true511  // CHECK:   call void [[A_CTOR]]512  // CHECK:   call void [[B_CTOR]]513  // CHECK-NOT: store i1 false514  // CHECK:   call noundef i32 [[ACCEPTS]]515  // CHECK:   call void [[ACCEPT2]]516  // CHECK:   call void [[S_DTOR]]517  // CHECK:   call void [[A_DTOR]]518  // CHECK:   br label %return519}520}  // namespace CleanupFlag521