@@ -440,6 +440,7 @@ void no_error_loan_from_current_iteration(bool cond) {
440440// ===----------------------------------------------------------------------===//
441441
442442View Identity (View v [[clang::lifetimebound]]);
443+ MyObj* Identity (MyObj* v [[clang::lifetimebound]]);
443444View Choose (bool cond, View a [[clang::lifetimebound]], View b [[clang::lifetimebound]]);
444445MyObj* GetPointer (const MyObj& obj [[clang::lifetimebound]]);
445446
@@ -582,3 +583,75 @@ void lifetimebound_ctor() {
582583 }
583584 (void )v;
584585}
586+
587+ // Conditional operator.
588+ void conditional_operator_one_unsafe_branch (bool cond) {
589+ MyObj safe;
590+ MyObj* p = &safe;
591+ {
592+ MyObj temp;
593+ p = cond ? &temp // expected-warning {{object whose reference is captured may not live long enough}}
594+ : &safe;
595+ } // expected-note {{destroyed here}}
596+
597+ // This is not a use-after-free for any value of `cond` but the analysis
598+ // cannot reason this and marks the above as a false positive. This
599+ // ensures safety regardless of cond's value.
600+ if (cond)
601+ p = &safe;
602+ (void )*p; // expected-note {{later used here}}
603+ }
604+
605+ void conditional_operator_two_unsafe_branches (bool cond) {
606+ MyObj* p;
607+ {
608+ MyObj a, b;
609+ p = cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}
610+ : &b; // expected-warning {{object whose reference is captured does not live long enough}}
611+ } // expected-note 2 {{destroyed here}}
612+ (void )*p; // expected-note 2 {{later used here}}
613+ }
614+
615+ void conditional_operator_nested (bool cond) {
616+ MyObj* p;
617+ {
618+ MyObj a, b, c, d;
619+ p = cond ? cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}.
620+ : &b // expected-warning {{object whose reference is captured does not live long enough}}.
621+ : cond ? &c // expected-warning {{object whose reference is captured does not live long enough}}.
622+ : &d; // expected-warning {{object whose reference is captured does not live long enough}}.
623+ } // expected-note 4 {{destroyed here}}
624+ (void )*p; // expected-note 4 {{later used here}}
625+ }
626+
627+ void conditional_operator_lifetimebound (bool cond) {
628+ MyObj* p;
629+ {
630+ MyObj a, b;
631+ p = Identity (cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}
632+ : &b); // expected-warning {{object whose reference is captured does not live long enough}}
633+ } // expected-note 2 {{destroyed here}}
634+ (void )*p; // expected-note 2 {{later used here}}
635+ }
636+
637+ void conditional_operator_lifetimebound_nested (bool cond) {
638+ MyObj* p;
639+ {
640+ MyObj a, b;
641+ p = Identity (cond ? Identity (&a) // expected-warning {{object whose reference is captured does not live long enough}}
642+ : Identity (&b)); // expected-warning {{object whose reference is captured does not live long enough}}
643+ } // expected-note 2 {{destroyed here}}
644+ (void )*p; // expected-note 2 {{later used here}}
645+ }
646+
647+ void conditional_operator_lifetimebound_nested_deep (bool cond) {
648+ MyObj* p;
649+ {
650+ MyObj a, b, c, d;
651+ p = Identity (cond ? Identity (cond ? &a // expected-warning {{object whose reference is captured does not live long enough}}
652+ : &b) // expected-warning {{object whose reference is captured does not live long enough}}
653+ : Identity (cond ? &c // expected-warning {{object whose reference is captured does not live long enough}}
654+ : &d)); // expected-warning {{object whose reference is captured does not live long enough}}
655+ } // expected-note 4 {{destroyed here}}
656+ (void )*p; // expected-note 4 {{later used here}}
657+ }
0 commit comments