Skip to content

Commit 56f9570

Browse files
Googlercopybara-github
authored andcommitted
Introduce OWNED_PTR and OWNED_PTR_TYPE and generate IR for them
The documentation in annotations.h explains the purpose of the annotations. The generation code is not complete, this milestone CL only handles the IR-generation portion of the task. PiperOrigin-RevId: 817125324
1 parent 39ff4ea commit 56f9570

File tree

14 files changed

+218
-35
lines changed

14 files changed

+218
-35
lines changed

common/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ cc_library(
3636
":status_macros",
3737
":string_view_conversion",
3838
"@abseil-cpp//absl/base:core_headers",
39+
"@abseil-cpp//absl/base:nullability",
3940
"@abseil-cpp//absl/status",
4041
"@abseil-cpp//absl/status:statusor",
4142
"@abseil-cpp//absl/strings",

common/annotation_reader.cc

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <string>
1010

1111
#include "absl/base/attributes.h"
12+
#include "absl/base/nullability.h"
1213
#include "absl/status/status.h"
1314
#include "absl/status/statusor.h"
1415
#include "absl/strings/str_cat.h"
@@ -23,6 +24,8 @@
2324
#include "clang/AST/DeclBase.h"
2425
#include "clang/AST/DeclTemplate.h"
2526
#include "clang/AST/Expr.h"
27+
#include "clang/AST/TypeBase.h"
28+
#include "clang/Basic/AttrKinds.h"
2629
#include "clang/Basic/LLVM.h"
2730
#include "llvm/ADT/APSInt.h"
2831
#include "llvm/ADT/StringRef.h"
@@ -167,9 +170,10 @@ static absl::Status CheckAnnotationsConsistent(
167170

168171
// Returns the `clang::Decl` that should be used for reading annotations.
169172
//
170-
// Template declarations technically do not have annotations-- the *templated*
171-
// decl has annotations. So, if we're searching for annotations on a template
172-
// decl, we should search for annotations on the templated decl instead.
173+
// Template declarations technically do not have annotations-- the
174+
// *templated* decl has annotations. So, if we're searching for annotations
175+
// on a template decl, we should search for annotations on the templated
176+
// decl instead.
173177
static const clang::Decl& DeclForAnnotations(const clang::Decl& decl) {
174178
auto* template_decl = clang::dyn_cast<clang::TemplateDecl>(&decl);
175179
if (template_decl == nullptr) {
@@ -290,4 +294,29 @@ absl::StatusOr<std::optional<std::string>> GetAnnotationWithStringArg(
290294
return std::string(*arg);
291295
}
292296

297+
absl::StatusOr<const clang::AnnotateTypeAttr* absl_nullable>
298+
GetTypeAnnotationSingleDecl(const clang::Type* absl_nonnull type
299+
ABSL_ATTRIBUTE_LIFETIME_BOUND,
300+
absl::string_view annotation_name) {
301+
const clang::Type* current_type = type;
302+
const clang::AnnotateTypeAttr* found_attr = nullptr;
303+
while (const auto* attributed_type =
304+
current_type->getAs<clang::AttributedType>()) {
305+
if (attributed_type->getAttrKind() == clang::attr::AnnotateType) {
306+
const clang::AnnotateTypeAttr* annotateAttr =
307+
clang::cast<clang::AnnotateTypeAttr>(attributed_type->getAttr());
308+
if (annotateAttr->getAnnotation() == llvm::StringRef(annotation_name)) {
309+
if (found_attr != nullptr) {
310+
return absl::InvalidArgumentError(
311+
absl::StrCat("Only one `", annotation_name,
312+
"` annotation may be placed on a type."));
313+
}
314+
found_attr = annotateAttr;
315+
}
316+
}
317+
current_type = attributed_type->getEquivalentType().getTypePtr();
318+
}
319+
return found_attr;
320+
}
321+
293322
} // namespace crubit

common/annotation_reader.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <optional>
99
#include <string>
1010

11+
#include "absl/base/attributes.h"
12+
#include "absl/base/nullability.h"
1113
#include "absl/status/status.h"
1214
#include "absl/status/statusor.h"
1315
#include "absl/strings/string_view.h"
@@ -16,6 +18,7 @@
1618
#include "clang/AST/Decl.h"
1719
#include "clang/AST/DeclBase.h"
1820
#include "clang/AST/Expr.h"
21+
#include "clang/AST/TypeBase.h"
1922

2023
namespace crubit {
2124

@@ -83,6 +86,13 @@ absl::StatusOr<std::optional<std::string>> GetAnnotationWithStringArg(
8386
absl::StatusOr<bool> HasAnnotationWithoutArgs(
8487
const clang::Decl& decl, absl::string_view annotation_name);
8588

89+
// Returns the `AnnotateTypeAttr` with the given `annotation_name` if it exists.
90+
// If there are multiple annotations with the given name, returns an error.
91+
absl::StatusOr<const clang::AnnotateTypeAttr* absl_nullable>
92+
GetTypeAnnotationSingleDecl(const clang::Type* absl_nonnull type
93+
ABSL_ATTRIBUTE_LIFETIME_BOUND,
94+
absl::string_view annotation_name);
95+
8696
} // namespace crubit
8797

8898
#endif // THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_IMPORTERS_ANNOTATION_READER_H_

rs_bindings_from_cc/generate_bindings/generate_function.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,6 +1362,7 @@ fn rs_type_kinds_for_func(
13621362
PointerTypeKind::Nullable | PointerTypeKind::NonNull => {
13631363
*kind = PointerTypeKind::LValueRef;
13641364
}
1365+
PointerTypeKind::Owned => panic!("owned `this` pointers are not supported"),
13651366
}
13661367
}
13671368
}

rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,9 @@ pub fn generate_function_thunk_impl(
492492
CcTypeVariant::Pointer(pointer) => match pointer.kind {
493493
PointerTypeKind::RValueRef => Ok(quote! { std::move(*#ident) }),
494494
PointerTypeKind::LValueRef => Ok(quote! { *#ident }),
495-
PointerTypeKind::Nullable | PointerTypeKind::NonNull => Ok(quote! { #ident }),
495+
PointerTypeKind::Nullable
496+
| PointerTypeKind::NonNull
497+
| PointerTypeKind::Owned => Ok(quote! { #ident }),
496498
},
497499
CcTypeVariant::FuncPointer { non_null, .. } => {
498500
if *non_null {

rs_bindings_from_cc/generate_bindings/rs_type_kind.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,13 @@ pub fn rs_type_kind_with_lifetime_elision(
7878
// of the pointer. In the future, we may wish to consume this information along
7979
// with a user-provided annotation in order to convert some pointers into either
8080
// references or optional references.
81-
PointerTypeKind::NonNull | PointerTypeKind::Nullable => RsTypeKind::Pointer {
82-
pointee,
83-
kind: RustPtrKind::CcPtr(pointer.kind),
84-
mutability,
85-
},
81+
PointerTypeKind::NonNull | PointerTypeKind::Nullable | PointerTypeKind::Owned => {
82+
RsTypeKind::Pointer {
83+
pointee,
84+
kind: RustPtrKind::CcPtr(pointer.kind),
85+
mutability,
86+
}
87+
}
8688
})
8789
}
8890
CcTypeVariant::FuncPointer { non_null, call_conv, param_and_return_types } => {

rs_bindings_from_cc/importer.cc

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "rs_bindings_from_cc/recording_diagnostic_consumer.h"
4242
#include "rs_bindings_from_cc/type_map.h"
4343
#include "clang/AST/ASTContext.h"
44+
#include "clang/AST/Attrs.inc"
4445
#include "clang/AST/Decl.h"
4546
#include "clang/AST/DeclBase.h"
4647
#include "clang/AST/DeclCXX.h"
@@ -1149,6 +1150,17 @@ absl::StatusOr<CcType> Importer::ConvertUnattributedType(
11491150
// Qualifiers are handled separately in ConvertQualType().
11501151
std::string type_string = clang::QualType(type, 0).getAsString();
11511152

1153+
CRUBIT_ASSIGN_OR_RETURN(
1154+
const clang::AnnotateTypeAttr* crubit_owned_ptr_attr,
1155+
GetTypeAnnotationSingleDecl(type, "crubit_owned_ptr"));
1156+
1157+
if (crubit_owned_ptr_attr != nullptr && !type->isPointerType()) {
1158+
return absl::InvalidArgumentError(
1159+
"CRUBIT_OWNED_PTR can only be applied to pointer types.");
1160+
}
1161+
1162+
bool is_owned_ptr = crubit_owned_ptr_attr != nullptr;
1163+
11521164
assert(!lifetimes || IsSameCanonicalUnqualifiedType(
11531165
lifetimes->Type(), clang::QualType(type, 0)));
11541166

@@ -1214,7 +1226,12 @@ absl::StatusOr<CcType> Importer::ConvertUnattributedType(
12141226
// IR consumer to error if a lifetime is required. This allows the IR
12151227
// consumer to infer a lifetime where-appropriate (e.g. constructors).
12161228
if (type->isPointerType()) {
1217-
return CcType::PointerTo(std::move(cpp_pointee_type), lifetime, nullable);
1229+
if (is_owned_ptr) {
1230+
return CcType::OwnedPointerTo(std::move(cpp_pointee_type), lifetime);
1231+
} else {
1232+
return CcType::PointerTo(std::move(cpp_pointee_type), lifetime,
1233+
nullable);
1234+
}
12181235
} else if (type->isLValueReferenceType()) {
12191236
return CcType::LValueReferenceTo(std::move(cpp_pointee_type), lifetime);
12201237
} else {

rs_bindings_from_cc/importers/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ cc_library(
9696
hdrs = ["function.h"],
9797
deps = [
9898
"//common:annotation_reader",
99+
"//common:status_macros",
99100
"//lifetime_annotations",
100101
"//lifetime_annotations:lifetime",
101102
"//lifetime_annotations:lifetime_error",

rs_bindings_from_cc/importers/cxx_record.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,15 @@ std::optional<IR::Item> CXXRecordDeclImporter::Import(
437437
bool is_explicit_class_template_instantiation_definition = false;
438438
std::optional<TemplateSpecialization> template_specialization;
439439
std::optional<BridgeType> bridge_type = GetBridgeTypeAnnotation(*record_decl);
440+
441+
absl::StatusOr<std::optional<std::string>> owned_ptr_type =
442+
GetAnnotationWithStringArg(*record_decl, "crubit_owned_ptr_type");
443+
if (!owned_ptr_type.ok()) {
444+
return ictx_.ImportUnsupportedItem(
445+
*record_decl, std::nullopt,
446+
FormattedError::FromStatus(owned_ptr_type.status()));
447+
}
448+
440449
BazelLabel owning_target = ictx_.GetOwningTarget(record_decl);
441450
if (auto* specialization_decl =
442451
clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
@@ -650,6 +659,7 @@ std::optional<IR::Item> CXXRecordDeclImporter::Import(
650659
.unknown_attr = std::move(*unknown_attr),
651660
.doc_comment = std::move(doc_comment),
652661
.bridge_type = std::move(bridge_type),
662+
.owned_ptr_type = std::move(*owned_ptr_type),
653663
.source_loc = ictx_.ConvertSourceLocation(source_loc),
654664
.unambiguous_public_bases = GetUnambiguousPublicBases(*record_decl),
655665
.fields = ImportFields(record_decl),

rs_bindings_from_cc/ir.cc

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -76,25 +76,25 @@ llvm::json::Value CcType::ToJson() const {
7676
[&](CcType::PointerType pointer) {
7777
return llvm::json::Object{
7878
{"Pointer",
79-
llvm::json::Object{
80-
{
81-
"kind",
82-
[&]() -> llvm::json::Value {
83-
switch (pointer.kind) {
84-
case PointerTypeKind::kLValueRef:
85-
return "LValueRef";
86-
case PointerTypeKind::kRValueRef:
87-
return "RValueRef";
88-
case PointerTypeKind::kNullable:
89-
return "Nullable";
90-
case PointerTypeKind::kNonNull:
91-
return "NonNull";
92-
}
93-
}(),
94-
},
95-
{"lifetime", pointer.lifetime},
96-
{"pointee_type", *pointer.pointee_type},
97-
}},
79+
llvm::json::Object{{
80+
"kind",
81+
[&]() -> llvm::json::Value {
82+
switch (pointer.kind) {
83+
case PointerTypeKind::kLValueRef:
84+
return "LValueRef";
85+
case PointerTypeKind::kRValueRef:
86+
return "RValueRef";
87+
case PointerTypeKind::kNullable:
88+
return "Nullable";
89+
case PointerTypeKind::kNonNull:
90+
return "NonNull";
91+
case PointerTypeKind::kOwned:
92+
return "Owned";
93+
}
94+
}(),
95+
},
96+
{"lifetime", pointer.lifetime},
97+
{"pointee_type", *pointer.pointee_type}}},
9898
};
9999
},
100100
[&](const CcType::FuncPointer& func_value) {
@@ -160,6 +160,12 @@ CcType CcType::PointerTo(CcType pointee_type,
160160
lifetime);
161161
}
162162

163+
CcType CcType::OwnedPointerTo(CcType pointee_type,
164+
std::optional<LifetimeId> lifetime) {
165+
return PointerOrReferenceTo(std::move(pointee_type), PointerTypeKind::kOwned,
166+
lifetime);
167+
}
168+
163169
CcType CcType::LValueReferenceTo(CcType pointee_type,
164170
std::optional<LifetimeId> lifetime) {
165171
return PointerOrReferenceTo(std::move(pointee_type),
@@ -554,6 +560,7 @@ llvm::json::Value Record::ToJson() const {
554560
{"unknown_attr", unknown_attr},
555561
{"doc_comment", doc_comment},
556562
{"bridge_type", bridge_type},
563+
{"owned_ptr_type", owned_ptr_type},
557564
{"source_loc", source_loc},
558565
{"unambiguous_public_bases", unambiguous_public_bases},
559566
{"fields", fields},

0 commit comments

Comments
 (0)