Fix forwarding of static lifetimes in function calls.

PiperOrigin-RevId: 458157702
diff --git a/lifetime_analysis/lifetime_analysis.cc b/lifetime_analysis/lifetime_analysis.cc
index 9a9f002..af8ef2a 100644
--- a/lifetime_analysis/lifetime_analysis.cc
+++ b/lifetime_analysis/lifetime_analysis.cc
@@ -871,6 +871,20 @@
   //
   // Some additional considerations apply if the callee signature contains the
   // 'static lifetime, either in the parameters or the return value:
+  // - Any objects that are associated with the static lifetime in the callee
+  //   must be forced to have static lifetime.
+  //   We have no way of doing this directly, as we cannot mutate the lifetime
+  //   of the object (and, in any case, such a mutation would be global and not
+  //   limited to the current point in the program flow).
+  //   Instead, for each such object, we synthesize a pointer with static
+  //   lifetime and make it point at the object. Later, in
+  //   PropagateStaticToPointees(), this will cause us to assign static lifetime
+  //   to the object.
+  //   A cleaner solution to this would be to explicitly express "outlives"
+  //   constraints in the lattice. This might also help more generally to
+  //   simplify the logic associated with static lifetimes, but it would also be
+  //   a more invasive change.
+  //
   // - Any pointer or reference may point to an object of static lifetime. This
   //   has the following implications:
   //   - In step 2, when adding edges to the points-to map, we always add edges
@@ -878,6 +892,7 @@
   //     type of the pointer.
   //   - In step 3, an object of static lifetime conforms to any callee lifetime
   //     if that lifetime occurs in covariant position.
+  //
   // - The callee may have access to objects of static lifetime that are not
   //   passed as arguments, in addition to the ones that are accessible from the
   //   arguments.
@@ -909,6 +924,17 @@
                      object_repository, lifetime_points_to_set);
   }
 
+  // Force any objects associated with the static lifetime in the callee to have
+  // static lifetime (see more detailed explanation above).
+  if (auto iter = lifetime_points_to_set.find(Lifetime::Static());
+      iter != lifetime_points_to_set.end()) {
+    for (const Object& object : iter->second) {
+      Object pointer = object_repository.CreateStaticObject(
+          ast_context.getPointerType(object.Type()));
+      points_to_map.ExtendPointerPointsToSet(pointer, {object});
+    }
+  }
+
   // Step 2: Propagate points-to sets to output parameters.
   for (auto [type, param_lifetimes, arg_object] : fn_params) {
     PropagateLifetimesToPointees({arg_object}, type, param_lifetimes,
diff --git a/lifetime_analysis/test/static_lifetime.cc b/lifetime_analysis/test/static_lifetime.cc
index 243020e..e5e9d2a 100644
--- a/lifetime_analysis/test/static_lifetime.cc
+++ b/lifetime_analysis/test/static_lifetime.cc
@@ -186,9 +186,7 @@
       f1(s);
     }
   )"),
-              // TODO(b/237517535): The lifetimes deduced for `f2` are incorrect
-              // and should be static.
-              LifetimesAre({{"f1", "static"}, {"f2", "a"}}));
+              LifetimesAre({{"f1", "static"}, {"f2", "static"}}));
 }
 
 TEST_F(LifetimeAnalysisTest, ConstructorStoresThisPointerInStatic) {
@@ -220,10 +218,7 @@
       S s;
     };
   )"),
-              // TODO(b/230725905): The lifetimes for T::T should be "static:"
-              // because T contains a member variable of type S, and all
-              // instances of S need to be static.
-              LifetimesAre({{"S::S", "static:"}, {"T::T", "a:"}}));
+              LifetimesAre({{"S::S", "static:"}, {"T::T", "static:"}}));
 }
 
 TEST_F(LifetimeAnalysisTest,
@@ -240,10 +235,7 @@
       T() {}
     };
   )"),
-              // TODO(b/230725905): The lifetimes for T::T should be "static:"
-              // because T derives from S and all instances of S need to be
-              // static.
-              LifetimesAre({{"S::S", "static:"}, {"T::T", "a:"}}));
+              LifetimesAre({{"S::S", "static:"}, {"T::T", "static:"}}));
 }
 
 }  // namespace