Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 1 | // 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_analysis/builtin_lifetimes.h" |
| 6 | |
| 7 | #include <optional> |
| 8 | #include <string> |
| 9 | |
| 10 | #include "absl/strings/str_cat.h" |
| 11 | #include "lifetime_annotations/function_lifetimes.h" |
| 12 | #include "lifetime_annotations/lifetime.h" |
| 13 | #include "lifetime_annotations/lifetime_annotations.h" |
| 14 | #include "lifetime_annotations/type_lifetimes.h" |
| 15 | #include "clang/AST/ASTContext.h" |
| 16 | #include "clang/AST/Decl.h" |
| 17 | #include "clang/AST/Type.h" |
| 18 | #include "clang/Basic/Builtins.h" |
| 19 | #include "llvm/ADT/StringRef.h" |
| 20 | |
| 21 | namespace clang { |
| 22 | namespace tidy { |
| 23 | namespace lifetimes { |
| 24 | |
| 25 | namespace { |
| 26 | |
| 27 | class ForwardAndMoveFactory : public FunctionLifetimeFactory { |
Martin Brænne | 1c097f2 | 2022-06-23 01:14:09 -0700 | [diff] [blame] | 28 | llvm::Expected<ValueLifetimes> CreateThisLifetimes( |
| 29 | clang::QualType type, const clang::Expr*) const override { |
| 30 | return CreateParamLifetimes(type, clang::TypeLoc()); |
| 31 | } |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 32 | llvm::Expected<ValueLifetimes> CreateParamLifetimes( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 33 | clang::QualType type, clang::TypeLoc) const override { |
Martin Brænne | 03d9330 | 2022-06-23 00:23:38 -0700 | [diff] [blame] | 34 | return ValueLifetimes::Create( |
| 35 | type, [](const clang::Expr*) { return Lifetime::CreateVariable(); }); |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 36 | } |
| 37 | |
| 38 | llvm::Expected<ValueLifetimes> CreateReturnLifetimes( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 39 | clang::QualType type, clang::TypeLoc, |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 40 | const llvm::SmallVector<ValueLifetimes>& param_lifetimes, |
| 41 | const std::optional<ValueLifetimes>& /*this_lifetimes*/) const override { |
| 42 | assert(param_lifetimes.size() == 1); |
| 43 | // `forward` and `move` convert from one type of reference to the other; the |
| 44 | // lifetimes in the pointees of these references are the same. |
| 45 | return ValueLifetimes::ForPointerLikeType( |
| 46 | type, param_lifetimes[0].GetPointeeLifetimes()); |
| 47 | } |
| 48 | }; |
| 49 | |
| 50 | } // namespace |
| 51 | |
| 52 | FunctionLifetimesOrError GetBuiltinLifetimes(const clang::FunctionDecl* decl) { |
| 53 | unsigned builtin_id = decl->getBuiltinID(); |
| 54 | const auto& builtin_info = decl->getASTContext().BuiltinInfo; |
| 55 | assert(builtin_id != 0); |
| 56 | |
| 57 | if (!builtin_info.hasPtrArgsOrResult(builtin_id) && |
| 58 | !builtin_info.hasReferenceArgsOrResult(builtin_id)) { |
| 59 | return FunctionLifetimes::CreateForDecl( |
Martin Brænne | 03d9330 | 2022-06-23 00:23:38 -0700 | [diff] [blame] | 60 | decl, |
| 61 | FunctionLifetimeFactorySingleCallback([](const clang::Expr*) { |
Martin Brænne | bcdfe32 | 2022-06-23 00:13:55 -0700 | [diff] [blame] | 62 | assert(false); |
| 63 | return Lifetime(); |
| 64 | })) |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 65 | .get(); |
| 66 | } |
| 67 | switch (builtin_id) { |
| 68 | case clang::Builtin::BI__builtin_addressof: |
| 69 | return ParseLifetimeAnnotations(decl, "a -> a").get(); |
| 70 | case clang::Builtin::BIstrtod: |
| 71 | case clang::Builtin::BIstrtof: |
| 72 | return ParseLifetimeAnnotations(decl, "a, (a, b)").get(); |
| 73 | case clang::Builtin::BIstrtoll: |
| 74 | case clang::Builtin::BIstrtol: |
| 75 | return ParseLifetimeAnnotations(decl, "a, (a, b), ()").get(); |
| 76 | case clang::Builtin::BI__builtin_memchr: |
| 77 | return ParseLifetimeAnnotations(decl, "a, (), () -> a").get(); |
| 78 | case clang::Builtin::BI__builtin_strchr: |
| 79 | case clang::Builtin::BI__builtin_strrchr: |
| 80 | return ParseLifetimeAnnotations(decl, "a, () -> a").get(); |
| 81 | case clang::Builtin::BI__builtin_strstr: |
| 82 | case clang::Builtin::BI__builtin_strpbrk: |
| 83 | return ParseLifetimeAnnotations(decl, "a, b -> a").get(); |
| 84 | case clang::Builtin::BIforward: |
| 85 | case clang::Builtin::BImove: { |
| 86 | FunctionLifetimes result; |
| 87 | return FunctionLifetimes::CreateForDecl(decl, ForwardAndMoveFactory()) |
| 88 | .get(); |
| 89 | } |
| 90 | // TODO(veluca): figure out variadic functions. |
| 91 | default: |
Googler | 4273a7b | 2022-12-27 20:29:27 -0800 | [diff] [blame] | 92 | return FunctionAnalysisError( |
| 93 | ("Unknown builtin: '" + builtin_info.getName(builtin_id) + "'") |
| 94 | .str()); |
Luca Versari | 99fddff | 2022-05-25 10:22:32 -0700 | [diff] [blame] | 95 | } |
| 96 | } |
| 97 | |
| 98 | } // namespace lifetimes |
| 99 | } // namespace tidy |
| 100 | } // namespace clang |