blob: 618d3ec9a6f82321e5cc97265730bbca5328e247 [file] [log] [blame]
Googlerace85a22021-11-26 14:18:31 +00001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#include "lifetime_annotations/type_lifetimes.h"
6
7#include <algorithm>
Googlerc071e242021-12-16 15:23:41 +00008#include <memory>
9#include <optional>
Googlerace85a22021-11-26 14:18:31 +000010#include <string>
Googler705f9452021-12-16 15:30:08 +000011#include <utility>
Googlerace85a22021-11-26 14:18:31 +000012
Luca Versarid101a292022-01-27 17:28:42 +000013#include "lifetime_annotations/lifetime_symbol_table.h"
Googlerace85a22021-11-26 14:18:31 +000014#include "third_party/absl/strings/str_format.h"
15#include "third_party/absl/strings/str_join.h"
Luca Versarid101a292022-01-27 17:28:42 +000016#include "third_party/llvm/llvm-project/clang/include/clang/AST/Attr.h"
17#include "third_party/llvm/llvm-project/clang/include/clang/AST/Attrs.inc"
18#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h"
Googlerace85a22021-11-26 14:18:31 +000019#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclTemplate.h"
20#include "third_party/llvm/llvm-project/clang/include/clang/AST/TemplateBase.h"
21#include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
Luca Versarid101a292022-01-27 17:28:42 +000022#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceLocation.h"
23#include "third_party/llvm/llvm-project/clang/include/clang/Lex/Pragma.h"
24#include "third_party/llvm/llvm-project/clang/include/clang/Lex/Preprocessor.h"
Luca Versari162a4c52021-12-10 08:57:05 +000025#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/ArrayRef.h"
Luca Versarid101a292022-01-27 17:28:42 +000026#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/SmallVector.h"
27#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/StringRef.h"
28#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/ErrorHandling.h"
Googlerace85a22021-11-26 14:18:31 +000029
30namespace devtools_rust {
31
32std::string DebugString(const TypeLifetimes& lifetimes,
33 const LifetimeFormatter& formatter) {
34 std::vector<std::string> parts;
35 parts.reserve(lifetimes.size());
36
37 for (Lifetime l : lifetimes) {
38 parts.push_back(formatter(l));
39 }
40
41 if (parts.size() == 1) {
42 return parts[0];
43 }
44 return absl::StrFormat("(%s)", absl::StrJoin(parts, ", "));
45}
46
Luca Versarid101a292022-01-27 17:28:42 +000047llvm::SmallVector<std::string> GetLifetimeParameters(
48 const clang::CXXRecordDecl* cxx_record) {
49 const clang::AnnotateAttr* lifetime_params_attr = nullptr;
50 for (auto annotate : cxx_record->specific_attrs<clang::AnnotateAttr>()) {
51 if (annotate->getAnnotation().startswith("lifetime_params")) {
52 if (lifetime_params_attr) {
53 llvm::report_fatal_error("repeated lifetime annotation");
54 }
55 lifetime_params_attr = annotate;
56 }
57 }
58 if (!lifetime_params_attr) {
59 return {};
60 }
61
62 // The lexer requires a null character at the end of the string.
63 std::string annotation(lifetime_params_attr->getAnnotation().data(),
64 lifetime_params_attr->getAnnotationLength());
65
66 const char* end = annotation.data() + annotation.size();
67
68 clang::SourceLocation source_loc = lifetime_params_attr->getLoc();
69
70 clang::Lexer lexer(source_loc, clang::LangOptions(), annotation.data(),
71 annotation.data(), end);
72
73 auto tok = [&]() -> llvm::StringRef {
74 clang::Token token;
75 if (lexer.getBufferLocation() != end) {
76 lexer.LexFromRawLexer(token);
77 return llvm::StringRef(annotation.data() +
78 token.getLocation().getRawEncoding() -
79 source_loc.getRawEncoding(),
80 token.getLength());
81 }
82 return "";
83 };
84
85 // Consume the "lifetime_params =" initial part.
86 if (tok() != "lifetime_params" || tok() != "=") {
87 llvm::report_fatal_error("invalid lifetime annotation");
88 }
89
90 llvm::SmallVector<std::string> ret;
91
92 for (llvm::StringRef token; !(token = tok()).empty();) {
93 if (token == ",") {
94 continue;
95 }
96 ret.push_back(token.str());
97 }
98
99 return ret;
100}
101
Googlerace85a22021-11-26 14:18:31 +0000102TypeLifetimes CreateLifetimesForType(
103 clang::QualType type, std::function<Lifetime()> lifetime_factory) {
104 assert(!type.isNull());
105 TypeLifetimes ret;
Luca Versarid101a292022-01-27 17:28:42 +0000106 if (auto record = type->getAs<clang::RecordType>()) {
107 if (auto cxx_record = record->getAsCXXRecordDecl()) {
108 for (const auto& lftm_param : GetLifetimeParameters(cxx_record)) {
109 (void)lftm_param;
110 ret.push_back(lifetime_factory());
111 }
112 }
113 }
Googlerace85a22021-11-26 14:18:31 +0000114 // Add implicit lifetime parameters for type template parameters.
Googlerace85a22021-11-26 14:18:31 +0000115 llvm::ArrayRef<clang::TemplateArgument> template_args = GetTemplateArgs(type);
116 if (!template_args.empty()) {
117 for (const clang::TemplateArgument& arg : template_args) {
118 if (arg.getKind() == clang::TemplateArgument::Type) {
119 ret.append(CreateLifetimesForType(arg.getAsType(), lifetime_factory));
Luca Versaric0641b52022-01-21 21:04:26 +0000120 } else if (arg.getKind() == clang::TemplateArgument::Pack) {
121 for (const clang::TemplateArgument& inner_arg : arg.getPackAsArray()) {
122 if (inner_arg.getKind() == clang::TemplateArgument::Type) {
123 ret.append(CreateLifetimesForType(inner_arg.getAsType(),
124 lifetime_factory));
125 }
126 }
Googlerace85a22021-11-26 14:18:31 +0000127 }
128 }
129 return ret;
130 }
131 clang::QualType pointee = type->getPointeeType();
Luca Versarid101a292022-01-27 17:28:42 +0000132 if (pointee.isNull()) return ret;
Googlerace85a22021-11-26 14:18:31 +0000133 ret = CreateLifetimesForType(pointee, lifetime_factory);
134 ret.push_back(lifetime_factory());
135 return ret;
136}
137
Googlerc071e242021-12-16 15:23:41 +0000138ValueLifetimes& ValueLifetimes::operator=(const ValueLifetimes& other) {
Googler41f3e352021-12-16 15:24:21 +0000139 type_ = other.type_;
Googlerc071e242021-12-16 15:23:41 +0000140 template_argument_lifetimes_ = other.template_argument_lifetimes_;
Luca Versarid101a292022-01-27 17:28:42 +0000141 lifetime_parameters_by_name_ = other.lifetime_parameters_by_name_;
Googlerc071e242021-12-16 15:23:41 +0000142 pointee_lifetimes_ =
143 other.pointee_lifetimes_
144 ? std::make_unique<ObjectLifetimes>(*other.pointee_lifetimes_)
145 : nullptr;
146 return *this;
147}
148
149std::string ValueLifetimes::DebugString() const {
Luca Versarid101a292022-01-27 17:28:42 +0000150 // TODO(veluca): add lifetime parameters here.
Googlerc071e242021-12-16 15:23:41 +0000151 std::string ret;
152 if (!template_argument_lifetimes_.empty()) {
153 std::vector<std::string> tmpl_arg_strings;
154 for (const std::optional<ValueLifetimes>& tmpl_arg :
155 template_argument_lifetimes_) {
156 if (tmpl_arg) {
157 tmpl_arg_strings.push_back(tmpl_arg->DebugString());
158 } else {
159 tmpl_arg_strings.push_back("");
160 }
161 }
162 absl::StrAppend(&ret, "<", absl::StrJoin(tmpl_arg_strings, ", "), ">");
163 }
164 if (pointee_lifetimes_) {
165 absl::StrAppend(&ret, " -> ", pointee_lifetimes_->DebugString());
166 }
167 return ret;
168}
169
Luca Versaric0641b52022-01-21 21:04:26 +0000170void ValueLifetimes::ReverseVisitTemplateArgs(
171 llvm::ArrayRef<clang::TemplateArgument> template_args,
172 TypeLifetimesRef& type_lifetimes, ValueLifetimes& out) {
173 for (size_t i = template_args.size(); i-- > 0;) {
174 const clang::TemplateArgument& arg = template_args[i];
175 if (arg.getKind() == clang::TemplateArgument::Type) {
176 out.template_argument_lifetimes_.push_back(
177 FromTypeLifetimes(type_lifetimes, arg.getAsType()));
178 } else if (arg.getKind() == clang::TemplateArgument::Pack) {
179 ReverseVisitTemplateArgs(arg.getPackAsArray(), type_lifetimes, out);
180 } else {
181 out.template_argument_lifetimes_.push_back(std::nullopt);
182 }
183 }
184}
185
Googlerc071e242021-12-16 15:23:41 +0000186// Here, `type_lifetimes` are the lifetimes of a prvalue of the given `type`,
187// unlike ObjectLifetimes::FromTypeLifetimes, which assumes a glvalue.
188ValueLifetimes ValueLifetimes::FromTypeLifetimes(
189 TypeLifetimesRef& type_lifetimes, clang::QualType type) {
190 assert(!type.isNull());
191
Googler6a06dbc2021-12-16 15:25:02 +0000192 ValueLifetimes ret(type);
Googlerc071e242021-12-16 15:23:41 +0000193
Luca Versarid101a292022-01-27 17:28:42 +0000194 if (auto record = type->getAs<clang::RecordType>()) {
195 if (auto cxx_record = record->getAsCXXRecordDecl()) {
196 llvm::SmallVector<std::string> params = GetLifetimeParameters(cxx_record);
197 // Visit in reverse order, as we are doing a post-order traversal.
198 for (size_t i = params.size(); i-- > 0;) {
199 if (ret.lifetime_parameters_by_name_.LookupName(params[i])) {
200 llvm::report_fatal_error("duplicate lifetime parameter name");
201 }
202 ret.lifetime_parameters_by_name_.Add(params[i], type_lifetimes.back());
203 type_lifetimes = type_lifetimes.drop_back();
204 }
205 }
206 }
207
Googlerc071e242021-12-16 15:23:41 +0000208 llvm::ArrayRef<clang::TemplateArgument> template_args = GetTemplateArgs(type);
209 if (!template_args.empty()) {
210 // Since we are simulating reversing a post-order visit, we need to
211 // extract template arguments in reverse order.
Luca Versaric0641b52022-01-21 21:04:26 +0000212 ReverseVisitTemplateArgs(template_args, type_lifetimes, ret);
Googlerc071e242021-12-16 15:23:41 +0000213 std::reverse(ret.template_argument_lifetimes_.begin(),
214 ret.template_argument_lifetimes_.end());
215 return ret;
216 }
217
218 clang::QualType pointee_type = type->getPointeeType();
219 if (!pointee_type.isNull()) {
220 ret.pointee_lifetimes_ = std::make_unique<ObjectLifetimes>(
221 ObjectLifetimes::FromTypeLifetimes(type_lifetimes, pointee_type));
222 }
223 return ret;
224}
225
Googler705f9452021-12-16 15:30:08 +0000226ValueLifetimes ValueLifetimes::ForLifetimeLessType(clang::QualType type) {
227 assert(type->getPointeeType().isNull() && !type->isRecordType());
228 return ValueLifetimes(type);
229}
230
231ValueLifetimes ValueLifetimes::ForPointerLikeType(
232 clang::QualType type, const ObjectLifetimes& object_lifetimes) {
233 assert(!type->getPointeeType().isNull());
234 ValueLifetimes result(type);
235 result.pointee_lifetimes_ =
236 std::make_unique<ObjectLifetimes>(object_lifetimes);
237 return result;
238}
239
240ValueLifetimes ValueLifetimes::ForRecord(
241 clang::QualType type,
Luca Versarid101a292022-01-27 17:28:42 +0000242 std::vector<std::optional<ValueLifetimes>> template_argument_lifetimes,
243 LifetimeSymbolTable lifetime_parameters) {
Googler705f9452021-12-16 15:30:08 +0000244 assert(type->isRecordType());
245 assert(GetTemplateArgs(type).size() == template_argument_lifetimes.size());
246 ValueLifetimes result(type);
247 result.template_argument_lifetimes_ = std::move(template_argument_lifetimes);
Luca Versarid101a292022-01-27 17:28:42 +0000248 result.lifetime_parameters_by_name_ = lifetime_parameters;
Googler705f9452021-12-16 15:30:08 +0000249 return result;
250}
251
Googler41f3e352021-12-16 15:24:21 +0000252const ObjectLifetimes& ValueLifetimes::GetPointeeLifetimes() const {
253 assert(!type_->getPointeeType().isNull());
254 return *pointee_lifetimes_;
255}
256
Googlerace85a22021-11-26 14:18:31 +0000257ObjectLifetimes ObjectLifetimes::FromTypeLifetimes(
258 TypeLifetimesRef& type_lifetimes, clang::QualType type) {
259 assert(!type_lifetimes.empty());
260 assert(!type.isNull());
Googler6a06dbc2021-12-16 15:25:02 +0000261 Lifetime self_lifetime = type_lifetimes.back();
Googlerace85a22021-11-26 14:18:31 +0000262 type_lifetimes = type_lifetimes.drop_back();
Googler6a06dbc2021-12-16 15:25:02 +0000263 return ObjectLifetimes(
264 self_lifetime, ValueLifetimes::FromTypeLifetimes(type_lifetimes, type));
Googlerace85a22021-11-26 14:18:31 +0000265}
266
267std::string ObjectLifetimes::DebugString() const {
268 return absl::StrCat(lifetime_.DebugString(), value_lifetimes_.DebugString());
269}
270
271const llvm::ArrayRef<clang::TemplateArgument> GetTemplateArgs(
272 clang::QualType type) {
273 if (auto specialization = type->getAs<clang::TemplateSpecializationType>()) {
274 return specialization->template_arguments();
275 }
276 if (auto record = type->getAs<clang::RecordType>()) {
277 if (auto specialization_decl =
278 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
279 record->getDecl())) {
280 return specialization_decl->getTemplateArgs().asArray();
281 }
282 }
283 return {};
284}
285
Luca Versarid101a292022-01-27 17:28:42 +0000286ObjectLifetimes ObjectLifetimes::GetObjectLifetimesForTypeInContext(
287 clang::QualType type, llvm::SmallVector<std::string> type_lifetime_args,
288 llvm::StringRef object_lifetime_parameter) const {
Googler41f3e352021-12-16 15:24:21 +0000289 assert(value_lifetimes_.Type()->isRecordType());
Googlerace85a22021-11-26 14:18:31 +0000290
291 // The object of the `type` (i.e. field or a base class) basically has the
292 // same lifetime as the struct.
Googler705f9452021-12-16 15:30:08 +0000293 Lifetime ret_lifetime = lifetime_;
Luca Versarid101a292022-01-27 17:28:42 +0000294 // ... unless the field has lifetime parameters.
295 if (!object_lifetime_parameter.empty()) {
296 ret_lifetime =
297 value_lifetimes_.GetLifetimeParameter(object_lifetime_parameter);
298 }
Googlerace85a22021-11-26 14:18:31 +0000299
300 // `type` is one of a template argument, a struct, a pointer, or a type
301 // with no lifetimes (other than its own).
302
303 // First case: template argument. We just attach the
304 // template argument's lifetimes to the leaf ObjectLifetimes.
305 if (auto targ = type->getAs<clang::SubstTemplateTypeParmType>()) {
306 const std::optional<ValueLifetimes>& arg_lifetimes =
Googler705f9452021-12-16 15:30:08 +0000307 value_lifetimes_.GetTemplateArgumentLifetimes(
308 targ->getReplacedParameter()->getIndex());
Googlerace85a22021-11-26 14:18:31 +0000309 if (!arg_lifetimes) {
310 assert(false);
Googler6a06dbc2021-12-16 15:25:02 +0000311 return llvm::DenseMapInfo<ObjectLifetimes>::getEmptyKey();
Googlerace85a22021-11-26 14:18:31 +0000312 }
Googler705f9452021-12-16 15:30:08 +0000313 return ObjectLifetimes(ret_lifetime, *arg_lifetimes);
Googlerace85a22021-11-26 14:18:31 +0000314 } else if (type->isStructureOrClassType()) {
Luca Versarid101a292022-01-27 17:28:42 +0000315 // Second case: struct.
316 // Resolve lifetime parameters for the struct, if it has any.
317 LifetimeSymbolTable lifetime_params;
318 llvm::SmallVector<std::string> params = GetLifetimeParameters(
319 type->getAs<clang::RecordType>()->getAsCXXRecordDecl());
320 for (size_t i = params.size(); i-- > 0;) {
321 assert(!type_lifetime_args.empty());
322 auto lftm_arg = type_lifetime_args.back();
323 type_lifetime_args.pop_back();
324 lifetime_params.Add(params[i],
325 value_lifetimes_.GetLifetimeParameter(lftm_arg));
326 }
327
328 // We need to construct potentally reshuffled
Googlerace85a22021-11-26 14:18:31 +0000329 // template arguments, if the struct is a template.
Luca Versarid101a292022-01-27 17:28:42 +0000330
331 // TODO(veluca): mixing lifetimes and template parameters is not supported
332 // yet.
Googler705f9452021-12-16 15:30:08 +0000333 std::vector<std::optional<ValueLifetimes>> template_argument_lifetimes;
Luca Versari29c00862022-01-21 20:53:06 +0000334 size_t parameter_pack_expansion_index = 0;
Googlerace85a22021-11-26 14:18:31 +0000335 for (const clang::TemplateArgument& arg : GetTemplateArgs(type)) {
336 if (arg.getKind() == clang::TemplateArgument::Type) {
Luca Versari162a4c52021-12-10 08:57:05 +0000337 if (auto templ_arg = clang::dyn_cast<clang::SubstTemplateTypeParmType>(
338 arg.getAsType())) {
Luca Versari29c00862022-01-21 20:53:06 +0000339 // Template parameter packs get the index of the *pack*, not the index
340 // of the type inside the pack itself. As they must appear last, we
341 // can just increase the counter at every occurrence and wraparound
342 // when we run out of template arguments.
343 size_t index = templ_arg->getReplacedParameter()->getIndex();
344 if (templ_arg->getReplacedParameter()->isParameterPack()) {
345 index += parameter_pack_expansion_index++;
346 if (index + 1 >= value_lifetimes_.GetNumTemplateArguments()) {
347 parameter_pack_expansion_index = 0;
348 }
349 }
Googler705f9452021-12-16 15:30:08 +0000350 template_argument_lifetimes.push_back(
Luca Versari29c00862022-01-21 20:53:06 +0000351 value_lifetimes_.GetTemplateArgumentLifetimes(index));
Luca Versari162a4c52021-12-10 08:57:05 +0000352 } else {
353 // Create a new ValueLifetimes of the type of the template parameter,
354 // with lifetime `lifetime_`.
355 // TODO(veluca): we need to propagate lifetime parameters here.
356 TypeLifetimes type_lifetimes = CreateLifetimesForType(
357 arg.getAsType(), [this]() { return this->lifetime_; });
358 TypeLifetimesRef type_lifetimes_ref(type_lifetimes);
Googler705f9452021-12-16 15:30:08 +0000359 template_argument_lifetimes.push_back(
Luca Versari162a4c52021-12-10 08:57:05 +0000360 ValueLifetimes::FromTypeLifetimes(type_lifetimes_ref,
361 arg.getAsType()));
362 }
Googlerace85a22021-11-26 14:18:31 +0000363 } else {
Googler705f9452021-12-16 15:30:08 +0000364 template_argument_lifetimes.push_back(std::nullopt);
Googlerace85a22021-11-26 14:18:31 +0000365 }
366 }
Luca Versarid101a292022-01-27 17:28:42 +0000367
368 return ObjectLifetimes(
369 ret_lifetime,
370 ValueLifetimes::ForRecord(type, std::move(template_argument_lifetimes),
371 std::move(lifetime_params)));
Googlerace85a22021-11-26 14:18:31 +0000372 } else if (!type->getPointeeType().isNull()) {
Luca Versarid101a292022-01-27 17:28:42 +0000373 std::string object_lifetime_parameter;
374 if (!type_lifetime_args.empty()) {
375 object_lifetime_parameter = std::move(type_lifetime_args.back());
376 type_lifetime_args.pop_back();
377 }
Googlerace85a22021-11-26 14:18:31 +0000378 // Third case: pointer.
Googler705f9452021-12-16 15:30:08 +0000379 return ObjectLifetimes(
380 ret_lifetime,
381 ValueLifetimes::ForPointerLikeType(
Luca Versarid101a292022-01-27 17:28:42 +0000382 type, GetObjectLifetimesForTypeInContext(
383 type->getPointeeType(), std::move(type_lifetime_args),
384 object_lifetime_parameter)));
Googlerace85a22021-11-26 14:18:31 +0000385 }
386
Googler705f9452021-12-16 15:30:08 +0000387 return ObjectLifetimes(ret_lifetime,
388 ValueLifetimes::ForLifetimeLessType(type));
Googlerace85a22021-11-26 14:18:31 +0000389}
390
Luca Versarid101a292022-01-27 17:28:42 +0000391ObjectLifetimes ObjectLifetimes::GetFieldOrBaseLifetimes(
392 clang::QualType type,
393 llvm::SmallVector<std::string> type_lifetime_args) const {
394 return GetObjectLifetimesForTypeInContext(type, std::move(type_lifetime_args),
395 "");
396}
397
Googlerace85a22021-11-26 14:18:31 +0000398} // namespace devtools_rust
399
400namespace llvm {
401
Googler2e87fae2021-12-16 15:24:41 +0000402bool DenseMapInfo<devtools_rust::ValueLifetimes>::isEqual(
Googlerc071e242021-12-16 15:23:41 +0000403 const devtools_rust::ValueLifetimes& lhs,
404 const devtools_rust::ValueLifetimes& rhs) {
Luca Versarid101a292022-01-27 17:28:42 +0000405 // TODO(veluca): add lifetime parameters.
Googler41f3e352021-12-16 15:24:21 +0000406 if (lhs.type_ != rhs.type_) {
407 return false;
408 }
Googlerace85a22021-11-26 14:18:31 +0000409 if ((lhs.pointee_lifetimes_ == nullptr) !=
410 (rhs.pointee_lifetimes_ == nullptr)) {
411 return false;
412 }
413 if (lhs.pointee_lifetimes_ &&
Googler2e87fae2021-12-16 15:24:41 +0000414 !DenseMapInfo<devtools_rust::ObjectLifetimes>::isEqual(
415 *lhs.pointee_lifetimes_, *rhs.pointee_lifetimes_)) {
Googlerace85a22021-11-26 14:18:31 +0000416 return false;
417 }
418 if (lhs.template_argument_lifetimes_.size() !=
419 rhs.template_argument_lifetimes_.size()) {
420 return false;
421 }
422 for (size_t i = 0; i < lhs.template_argument_lifetimes_.size(); i++) {
423 const auto& alhs = lhs.template_argument_lifetimes_[i];
424 const auto& arhs = rhs.template_argument_lifetimes_[i];
425 if (alhs.has_value() != arhs.has_value()) {
426 return false;
427 }
428 if (alhs.has_value() && !isEqual(*alhs, *arhs)) {
429 return false;
430 }
431 }
432 return true;
433}
434
Googler2e87fae2021-12-16 15:24:41 +0000435unsigned DenseMapInfo<devtools_rust::ValueLifetimes>::getHashValue(
436 const devtools_rust::ValueLifetimes& value_lifetimes) {
Luca Versarid101a292022-01-27 17:28:42 +0000437 // TODO(veluca): add lifetime parameters.
Googlerace85a22021-11-26 14:18:31 +0000438 llvm::hash_code hash = 0;
Googler2e87fae2021-12-16 15:24:41 +0000439 if (value_lifetimes.pointee_lifetimes_) {
440 hash = DenseMapInfo<devtools_rust::ObjectLifetimes>::getHashValue(
441 *value_lifetimes.pointee_lifetimes_);
Googlerace85a22021-11-26 14:18:31 +0000442 }
Googler2e87fae2021-12-16 15:24:41 +0000443 for (const auto& tmpl_lifetime :
444 value_lifetimes.template_argument_lifetimes_) {
Googlerace85a22021-11-26 14:18:31 +0000445 if (tmpl_lifetime) {
446 hash = hash_combine(hash, getHashValue(*tmpl_lifetime));
447 }
448 }
Googler41f3e352021-12-16 15:24:21 +0000449 return hash_combine(
Googler2e87fae2021-12-16 15:24:41 +0000450 hash, DenseMapInfo<clang::QualType>::getHashValue(value_lifetimes.type_));
Googlerace85a22021-11-26 14:18:31 +0000451}
452
453} // namespace llvm