blob: 060709985a2027fc8938be1a4ea899bd89380941 [file] [log] [blame]
// 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/builtin_lifetimes.h"
#include <cassert>
#include <optional>
#include <string>
#include "lifetime_annotations/function_lifetimes.h"
#include "lifetime_annotations/lifetime.h"
#include "lifetime_annotations/lifetime_annotations.h"
#include "lifetime_annotations/type_lifetimes.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
namespace clang {
namespace tidy {
namespace lifetimes {
namespace {
class ForwardAndMoveFactory : public FunctionLifetimeFactory {
llvm::Expected<ValueLifetimes> CreateThisLifetimes(
clang::QualType type, const clang::Expr*) const override {
return CreateParamLifetimes(type, clang::TypeLoc());
}
llvm::Expected<ValueLifetimes> CreateParamLifetimes(
clang::QualType type, clang::TypeLoc) const override {
return ValueLifetimes::Create(
type, [](const clang::Expr*) { return Lifetime::CreateVariable(); });
}
llvm::Expected<ValueLifetimes> CreateReturnLifetimes(
clang::QualType type, clang::TypeLoc,
const llvm::SmallVector<ValueLifetimes>& param_lifetimes,
const std::optional<ValueLifetimes>& /*this_lifetimes*/) const override {
assert(param_lifetimes.size() == 1);
// `forward` and `move` convert from one type of reference to the other; the
// lifetimes in the pointees of these references are the same.
return ValueLifetimes::ForPointerLikeType(
type, param_lifetimes[0].GetPointeeLifetimes());
}
};
} // namespace
FunctionLifetimesOrError GetBuiltinLifetimes(const clang::FunctionDecl* decl) {
unsigned builtin_id = decl->getBuiltinID();
const auto& builtin_info = decl->getASTContext().BuiltinInfo;
assert(builtin_id != 0);
if (!builtin_info.hasPtrArgsOrResult(builtin_id) &&
!builtin_info.hasReferenceArgsOrResult(builtin_id)) {
return FunctionLifetimes::CreateForDecl(
decl,
FunctionLifetimeFactorySingleCallback([](const clang::Expr*) {
assert(false);
return Lifetime();
}))
.get();
}
switch (builtin_id) {
case clang::Builtin::BI__builtin_addressof:
return ParseLifetimeAnnotations(decl, "a -> a").get();
case clang::Builtin::BIstrtod:
case clang::Builtin::BIstrtof:
return ParseLifetimeAnnotations(decl, "a, (a, b)").get();
case clang::Builtin::BIstrtoll:
case clang::Builtin::BIstrtol:
return ParseLifetimeAnnotations(decl, "a, (a, b), ()").get();
case clang::Builtin::BI__builtin_memchr:
return ParseLifetimeAnnotations(decl, "a, (), () -> a").get();
case clang::Builtin::BI__builtin_strchr:
case clang::Builtin::BI__builtin_strrchr:
return ParseLifetimeAnnotations(decl, "a, () -> a").get();
case clang::Builtin::BI__builtin_strstr:
case clang::Builtin::BI__builtin_strpbrk:
return ParseLifetimeAnnotations(decl, "a, b -> a").get();
case clang::Builtin::BIforward:
case clang::Builtin::BImove: {
FunctionLifetimes result;
return FunctionLifetimes::CreateForDecl(decl, ForwardAndMoveFactory())
.get();
}
// TODO(veluca): figure out variadic functions.
default:
return FunctionAnalysisError(
("Unknown builtin: '" + builtin_info.getName(builtin_id) + "'")
.str());
}
}
} // namespace lifetimes
} // namespace tidy
} // namespace clang