Add LifetimeConstraints to the lattice. First step of a UnifyLifetimes -> constraint system migration for inference. PiperOrigin-RevId: 465551174
diff --git a/lifetime_analysis/BUILD b/lifetime_analysis/BUILD index 6c90377..ebfdfa8 100644 --- a/lifetime_analysis/BUILD +++ b/lifetime_analysis/BUILD
@@ -83,10 +83,22 @@ ) cc_library( + name = "lifetime_constraints", + srcs = ["lifetime_constraints.cc"], + hdrs = ["lifetime_constraints.h"], + deps = [ + "//lifetime_annotations:lifetime", + "@llvm-project//clang:analysis", + "@llvm-project//llvm:Support", + ], +) + +cc_library( name = "lifetime_lattice", srcs = ["lifetime_lattice.cc"], hdrs = ["lifetime_lattice.h"], deps = [ + ":lifetime_constraints", ":points_to_map", "@llvm-project//clang:analysis", "@llvm-project//llvm:Support",
diff --git a/lifetime_analysis/lifetime_constraints.cc b/lifetime_analysis/lifetime_constraints.cc new file mode 100644 index 0000000..fe0e00e --- /dev/null +++ b/lifetime_analysis/lifetime_constraints.cc
@@ -0,0 +1,23 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "lifetime_analysis/lifetime_constraints.h" + +namespace clang { +namespace tidy { +namespace lifetimes { + +clang::dataflow::LatticeJoinEffect LifetimeConstraints::join( + const LifetimeConstraints& other) { + bool changed = false; + for (auto p : other.outlives_constraints_) { + changed |= outlives_constraints_.insert(p).second; + } + return changed ? clang::dataflow::LatticeJoinEffect::Changed + : clang::dataflow::LatticeJoinEffect::Unchanged; +} + +} // namespace lifetimes +} // namespace tidy +} // namespace clang
diff --git a/lifetime_analysis/lifetime_constraints.h b/lifetime_analysis/lifetime_constraints.h new file mode 100644 index 0000000..43bf77c --- /dev/null +++ b/lifetime_analysis/lifetime_constraints.h
@@ -0,0 +1,39 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifndef THIRD_PARTY_CRUBIT_LIFETIME_ANALYSIS_LIFETIME_CONSTRAINTS_H_ +#define THIRD_PARTY_CRUBIT_LIFETIME_ANALYSIS_LIFETIME_CONSTRAINTS_H_ + +#include "lifetime_annotations/lifetime.h" +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { +namespace tidy { +namespace lifetimes { + +class LifetimeConstraints { + public: + // Creates empty constraints. + LifetimeConstraints() {} + + // Imposes the constraint shorter <= longer. + void AddOutlivesConstraint(Lifetime shorter, Lifetime longer) { + outlives_constraints_.insert({shorter, longer}); + } + + // Merges this set of constraints with the provided constraints, returning + // the effect of the operation. + clang::dataflow::LatticeJoinEffect join(const LifetimeConstraints& other); + + private: + // Constraints of the form p.first <= p.second + llvm::DenseSet<std::pair<Lifetime, Lifetime>> outlives_constraints_; +}; + +} // namespace lifetimes +} // namespace tidy +} // namespace clang + +#endif // THIRD_PARTY_CRUBIT_LIFETIME_ANALYSIS_LIFETIME_CONSTRAINTS_H_
diff --git a/lifetime_analysis/lifetime_lattice.cc b/lifetime_analysis/lifetime_lattice.cc index 03478d0..81d85ff 100644 --- a/lifetime_analysis/lifetime_lattice.cc +++ b/lifetime_analysis/lifetime_lattice.cc
@@ -26,12 +26,22 @@ PointsToMap& LifetimeLattice::PointsTo() { assert(!IsError()); - return std::get<PointsToMap>(var_); + return std::get<0>(var_).first; } const PointsToMap& LifetimeLattice::PointsTo() const { assert(!IsError()); - return std::get<PointsToMap>(var_); + return std::get<0>(var_).first; +} + +LifetimeConstraints& LifetimeLattice::Constraints() { + assert(!IsError()); + return std::get<0>(var_).second; +} + +const LifetimeConstraints& LifetimeLattice::Constraints() const { + assert(!IsError()); + return std::get<0>(var_).second; } llvm::StringRef LifetimeLattice::Error() const { @@ -53,12 +63,15 @@ return clang::dataflow::LatticeJoinEffect::Changed; } + auto constraints_effect = Constraints().join(other.Constraints()); + PointsToMap joined_points_to_map = PointsTo().Union(other.PointsTo()); - if (PointsTo() == joined_points_to_map) { + if (PointsTo() == joined_points_to_map && + constraints_effect == clang::dataflow::LatticeJoinEffect::Unchanged) { return clang::dataflow::LatticeJoinEffect::Unchanged; } - *this = LifetimeLattice(std::move(joined_points_to_map)); + PointsTo() = std::move(joined_points_to_map); return clang::dataflow::LatticeJoinEffect::Changed; }
diff --git a/lifetime_analysis/lifetime_lattice.h b/lifetime_analysis/lifetime_lattice.h index 68e8a0e..9830d20 100644 --- a/lifetime_analysis/lifetime_lattice.h +++ b/lifetime_analysis/lifetime_lattice.h
@@ -9,6 +9,7 @@ #include <utility> #include <variant> +#include "lifetime_analysis/lifetime_constraints.h" #include "lifetime_analysis/points_to_map.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" @@ -20,7 +21,7 @@ class LifetimeLattice { public: - // Creates a lattice holding an empty points-to map. + // Creates a lattice holding an empty points-to map and empty constraints. LifetimeLattice() = default; LifetimeLattice(const LifetimeLattice&) = default; @@ -28,9 +29,9 @@ LifetimeLattice& operator=(const LifetimeLattice&) = default; LifetimeLattice& operator=(LifetimeLattice&&) = default; - // Creates a lattice containing the given points-to map. + // Creates a lattice containing the given points-to map and empty constraints. explicit LifetimeLattice(PointsToMap points_to_map) - : var_(std::move(points_to_map)) {} + : var_(std::make_pair(std::move(points_to_map), LifetimeConstraints())) {} // Creates an error state containing the error message `err`. explicit LifetimeLattice(std::string err) : var_(err) {} @@ -40,6 +41,11 @@ PointsToMap& PointsTo(); const PointsToMap& PointsTo() const; + // Returns the lifetime constraints. + // Precondition: !IsError(). + LifetimeConstraints& Constraints(); + const LifetimeConstraints& Constraints() const; + // Returns whether the lattice is in the error state. bool IsError() const { return std::holds_alternative<std::string>(var_); } @@ -64,7 +70,7 @@ } private: - std::variant<PointsToMap, std::string> var_; + std::variant<std::pair<PointsToMap, LifetimeConstraints>, std::string> var_; }; } // namespace lifetimes