Skip to content

Commit 1872d3b

Browse files
ssbrcopybara-github
authored andcommitted
Delete redundant record ID in the IR.
A function _never_ has a record ID different from its enclosing record. And it isn't even useful in a typed way, because the record_id might not be a Item::Record! May as well always use the enclosing_record_id (and check for Namespace if you really need to). The previous CLs in the chain relied on the fact that this was redundant. Deleting it properly helps for the proof. PiperOrigin-RevId: 846446546
1 parent 53f1388 commit 1872d3b

File tree

61 files changed

+610
-680
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+610
-680
lines changed

common/code_gen_utils.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,7 @@ fn parse_any(ident: &str) -> syn::Result<Ident> {
183183
/// Formats a C++ (qualified) identifier. Returns an error when `ident` is a C++
184184
/// reserved keyword or is an invalid identifier.
185185
pub fn format_cc_ident(ident: &str) -> Result<Ident> {
186-
ensure!(!ident.is_empty(), "Empty string is not a valid C++ identifier");
187-
ensure!(
188-
!is_cpp_reserved_keyword(ident),
189-
"`{ident}` is a C++ reserved keyword and can't be used as a C++ identifier",
190-
);
186+
check_valid_cc_name(ident)?;
191187
// Explicitly mapping the error via `anyhow!`, because `LexError` is not `Sync`
192188
// (required for `anyhow::Error` to implement `From<LexError>`) and
193189
// therefore we can't just use `?`.
@@ -378,12 +374,26 @@ impl NamespaceQualifier {
378374

379375
/// Returns `foo::bar::baz::` (reporting errors for C++ keywords).
380376
pub fn format_for_cc(&self) -> Result<TokenStream> {
381-
let namespace_cc_idents = self.cc_idents()?;
382-
Ok(quote! { #(#namespace_cc_idents::)* })
377+
let mut path = quote! {};
378+
for namespace in &self.namespaces {
379+
let namespace = format_cc_ident(namespace)?;
380+
path.extend(quote! { #namespace :: });
381+
}
382+
for (rs_name, cc_name) in &self.nested_records {
383+
let cc_name = format_cc_type_name(&cc_name)?;
384+
path.extend(quote! { #cc_name ::});
385+
}
386+
Ok(path)
383387
}
384388

385-
pub fn cc_idents(&self) -> Result<Vec<Ident>> {
386-
self.parts().map(|ns| format_cc_ident(ns)).collect()
389+
/// Returns `foo::bar::baz::` (never reporting errors).
390+
pub fn format_for_cc_debug(&self) -> String {
391+
let mut path = String::new();
392+
for part in self.parts() {
393+
path.push_str(part);
394+
path.push_str("::");
395+
}
396+
path
387397
}
388398
}
389399

rs_bindings_from_cc/generate_bindings/cpp_type_name.rs

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -111,73 +111,48 @@ pub fn format_cpp_type_inner(
111111
> #ptr
112112
})
113113
}
114-
RsTypeKind::IncompleteRecord { incomplete_record, .. } => {
115-
cpp_type_name_for_item(&Item::IncompleteRecord(Rc::clone(incomplete_record)), ir)
116-
}
114+
RsTypeKind::IncompleteRecord { incomplete_record, .. } => tagless_cpp_type_name_for_item(
115+
&Item::IncompleteRecord(Rc::clone(incomplete_record)),
116+
ir,
117+
),
117118
RsTypeKind::Record { record, .. } => cpp_type_name_for_record(record, ir),
118-
RsTypeKind::Enum { enum_, .. } => cpp_type_name_for_item(&Item::Enum(Rc::clone(enum_)), ir),
119+
RsTypeKind::Enum { enum_, .. } => {
120+
tagless_cpp_type_name_for_item(&Item::Enum(Rc::clone(enum_)), ir)
121+
}
119122
RsTypeKind::TypeAlias { type_alias, .. } => {
120-
cpp_type_name_for_item(&Item::TypeAlias(Rc::clone(type_alias)), ir)
123+
tagless_cpp_type_name_for_item(&Item::TypeAlias(Rc::clone(type_alias)), ir)
121124
}
122125
RsTypeKind::Primitive(primitive) => Ok(quote! { #primitive }),
123126
RsTypeKind::BridgeType { original_type, .. } => cpp_type_name_for_record(original_type, ir),
124-
RsTypeKind::ExistingRustType(existing_rust_type) => {
125-
cpp_type_name_for_item(&Item::ExistingRustType(Rc::clone(existing_rust_type)), ir)
126-
}
127+
RsTypeKind::ExistingRustType(existing_rust_type) => tagless_cpp_type_name_for_item(
128+
&Item::ExistingRustType(Rc::clone(existing_rust_type)),
129+
ir,
130+
),
127131
RsTypeKind::C9Co { original_type, .. } => cpp_type_name_for_record(original_type, ir),
128132
}
129133
}
130134

131-
/// Returns the fully-qualified name for an item, not including the type tag.
132-
pub fn tagless_cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
133-
if let ir::Item::Record(record) = item {
134-
cpp_tagless_type_name_for_record(record, ir)
135-
} else {
136-
cpp_type_name_for_item(item, ir)
137-
}
138-
}
139-
140-
/// Returns the fully qualified name for an item.
135+
/// Returns the fully qualified name for an item (not including type tags).
141136
///
142137
/// For example, for `namespace x { struct Y { using X = int; }; }`, the name
143138
/// for `X` is `x::Y::X`.
144-
fn cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
145-
/// Returns the namespace / class qualifiers necessary to access the item.
146-
///
147-
/// For example, for `namespace x { struct Y { using X = int; }; }`, the prefix
148-
/// for `X` is `x::Y::`.
149-
fn cpp_qualified_path_prefix(item: &ir::Item, ir: &ir::IR) -> Result<TokenStream> {
150-
let Some(parent) = item.enclosing_item_id() else {
151-
return Ok(quote! {});
152-
};
153-
let parent: &ir::Item = ir.find_decl(parent)?;
154-
match parent {
155-
ir::Item::Namespace(_) => Ok(ir.namespace_qualifier(item).format_for_cc()?),
156-
ir::Item::Record(r) => {
157-
let name = cpp_tagless_type_name_for_record(r, ir)?;
158-
Ok(quote! {#name ::})
159-
}
160-
_ => bail!("Unexpected enclosing item: {item:?}"),
161-
}
162-
}
163-
139+
pub fn tagless_cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
164140
match item {
165141
Item::IncompleteRecord(incomplete_record) => {
166142
let ident = expect_format_cc_type_name(incomplete_record.cc_name.identifier.as_ref());
167143
let namespace_qualifier = ir.namespace_qualifier(incomplete_record).format_for_cc()?;
168-
let tag_kind = incomplete_record.record_type;
169-
Ok(quote! { #tag_kind #namespace_qualifier #ident })
144+
Ok(quote! { #namespace_qualifier #ident })
170145
}
171-
Item::Record(record) => cpp_type_name_for_record(record, ir),
146+
Item::Record(record) => cpp_tagless_type_name_for_record(record, ir),
172147
Item::Enum(enum_) => {
173148
let ident = expect_format_cc_type_name(&enum_.rs_name.identifier);
174-
let qualifier = cpp_qualified_path_prefix(item, ir)?;
175-
Ok(quote! { #qualifier #ident })
149+
let namespace_qualifier = ir.namespace_qualifier(item).format_for_cc()?;
150+
Ok(quote! { #namespace_qualifier #ident })
176151
}
177152
Item::TypeAlias(type_alias) => {
178153
let ident = expect_format_cc_type_name(&type_alias.cc_name.identifier);
179-
let qualifier = cpp_qualified_path_prefix(item, ir)?;
180-
Ok(quote! { #qualifier #ident })
154+
let namespace_qualifier = ir.namespace_qualifier(item).format_for_cc()?;
155+
Ok(quote! { #namespace_qualifier #ident })
181156
}
182157
Item::ExistingRustType(existing_rust_type) => existing_rust_type
183158
.cc_name

rs_bindings_from_cc/generate_bindings/generate_function.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -865,26 +865,25 @@ fn api_func_shape_for_constructor(
865865
/// become a `RvalueReference<'_, T>`.
866866
///
867867
/// Returns:
868-
///
869-
/// * `Err(_)`: something went wrong importing this function.
870-
/// * `Ok(None)`: the function imported as "nothing". (For example, a defaulted
868+
/// * `None`: the function imported as "nothing". (For example, a defaulted
871869
/// destructor might be mapped to no `Drop` impl at all.)
872-
/// * `Ok((func_name, impl_kind))`: The function name and ImplKind.
870+
/// * `(func_name, impl_kind)`: The function name and ImplKind.
873871
fn api_func_shape(
874872
db: &dyn BindingsGenerator,
875873
func: &Func,
876874
param_types: &mut [RsTypeKind],
877875
errors: &Errors,
878876
) -> Option<(Ident, ImplKind)> {
879877
let ir = db.ir();
880-
let maybe_record = match ir.record_for_member_func(func).map(<&Rc<Record>>::try_from) {
878+
let maybe_record = match func.enclosing_item_id.map(|id| ir.find_untyped_decl(id)) {
881879
None => None,
882-
Some(Ok(record)) => Some(record),
883-
// Functions whose record was replaced with some other IR Item type are ignored.
884-
// This occurs for instance if you use crubit_internal_rust_type: member functions defined
885-
// out-of-line, such as implicitly generated constructors, will still be present in the IR,
886-
// but should be ignored.
887-
Some(Err(_)) => return None,
880+
Some(ir::Item::Namespace(_)) => None,
881+
Some(ir::Item::Record(record)) => Some(record),
882+
// If the record was replaced by an existing Rust type using `crubit_internal_rust_type`,
883+
// don't generate any bindings for its functions. (That can't work!)
884+
Some(ir::Item::ExistingRustType(_)) => return None,
885+
// (This case should be impossible.)
886+
Some(_) => return None,
888887
};
889888

890889
if is_friend_of_record_not_visible_by_adl(db, func, param_types) {
@@ -2256,7 +2255,10 @@ fn has_copy_assignment_operator_from_const_reference(
22562255
if first_param_type.is_err() {
22572256
return false;
22582257
};
2259-
let Some(Item::Record(record)) = db.ir().record_for_member_func(copy_constructor) else {
2258+
let Some(parent_id) = copy_constructor.enclosing_item_id else {
2259+
return false;
2260+
};
2261+
let Ok(record) = db.ir().find_decl::<Rc<Record>>(parent_id) else {
22602262
return false;
22612263
};
22622264
record

rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs

Lines changed: 44 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,9 @@ pub fn can_skip_cc_thunk(db: &dyn BindingsGenerator, func: &Func) -> bool {
6161
// In terms of runtime performance, since this only occurs for virtual function
6262
// calls, which are already slow, it may not be such a big deal. We can
6363
// benchmark it later. :)
64-
if let Some(meta) = &func.member_func_metadata {
65-
if let Some(inst_meta) = &meta.instance_method_metadata {
66-
if inst_meta.is_virtual {
67-
return false;
68-
}
64+
if let Some(inst_meta) = &func.instance_method_metadata {
65+
if inst_meta.is_virtual {
66+
return false;
6967
}
7068
}
7169
// ## Custom calling convention requires a thunk.
@@ -260,44 +258,32 @@ fn generate_function_assertation_for_identifier(
260258
let ir = db.ir();
261259

262260
let fn_ident = expect_format_cc_ident(&id.identifier);
261+
let path_to_func = ir.namespace_qualifier(func).format_for_cc()?;
262+
let implementation_function = quote! { :: #path_to_func #fn_ident };
263263
let method_qualification;
264-
let implementation_function;
265264
let member_function_prefix;
266265
let func_params;
267-
if let Some(meta) = func.member_func_metadata.as_ref() {
268-
let record: &Rc<Record> = ir.find_decl(meta.record_id)?;
269-
let record_ident = expect_format_cc_type_name(record.cc_name.identifier.as_ref());
270-
let namespace_qualifier = ir.namespace_qualifier(record).format_for_cc()?;
271-
if let Some(instance_method_metadata) = meta.instance_method_metadata.as_ref() {
272-
let const_qualifier = if instance_method_metadata.is_const {
273-
quote! {const}
274-
} else {
275-
quote! {}
276-
};
277-
278-
method_qualification = match instance_method_metadata.reference {
279-
ir::ReferenceQualification::Unqualified => const_qualifier,
280-
ir::ReferenceQualification::LValue => {
281-
quote! { #const_qualifier & }
282-
}
283-
ir::ReferenceQualification::RValue => {
284-
quote! { #const_qualifier && }
285-
}
286-
};
287-
implementation_function = quote! { #namespace_qualifier #record_ident :: #fn_ident };
288-
member_function_prefix = quote! { :: #namespace_qualifier #record_ident :: };
289-
// The first parameter of instance methods is `this`.
290-
func_params = &func.params[1..];
266+
if let Some(instance_method_metadata) = &func.instance_method_metadata {
267+
let const_qualifier = if instance_method_metadata.is_const {
268+
quote! {const}
291269
} else {
292-
method_qualification = quote! {};
293-
implementation_function = quote! { #namespace_qualifier #record_ident :: #fn_ident };
294-
member_function_prefix = quote! {};
295-
func_params = &func.params[..];
296-
}
270+
quote! {}
271+
};
272+
273+
method_qualification = match instance_method_metadata.reference {
274+
ir::ReferenceQualification::Unqualified => const_qualifier,
275+
ir::ReferenceQualification::LValue => {
276+
quote! { #const_qualifier & }
277+
}
278+
ir::ReferenceQualification::RValue => {
279+
quote! { #const_qualifier && }
280+
}
281+
};
282+
member_function_prefix = path_to_func;
283+
// The first parameter of instance methods is `this`.
284+
func_params = &func.params[1..];
297285
} else {
298-
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
299286
method_qualification = quote! {};
300-
implementation_function = quote! { #namespace_qualifier #fn_ident };
301287
member_function_prefix = quote! {};
302288
func_params = &func.params[..];
303289
}
@@ -394,22 +380,11 @@ pub fn generate_function_thunk_impl(
394380
}
395381
UnqualifiedIdentifier::Identifier(id) => {
396382
let fn_ident = expect_format_cc_ident(&id.identifier);
397-
match func.member_func_metadata.as_ref() {
398-
Some(meta) => {
399-
if meta.instance_method_metadata.is_some() {
400-
quote! { #fn_ident }
401-
} else {
402-
let record: &Rc<Record> = ir.find_decl(meta.record_id)?;
403-
let record_name =
404-
expect_format_cc_type_name(record.cc_name.identifier.as_ref());
405-
let namespace_qualifier = ir.namespace_qualifier(record).format_for_cc()?;
406-
quote! { #namespace_qualifier #record_name :: #fn_ident }
407-
}
408-
}
409-
None => {
410-
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
411-
quote! { #namespace_qualifier #fn_ident }
412-
}
383+
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
384+
if func.instance_method_metadata.is_some() {
385+
quote! {#fn_ident}
386+
} else {
387+
quote! { #namespace_qualifier #fn_ident }
413388
}
414389
}
415390
// Use `destroy_at` to avoid needing to spell out the class name. Destructor identiifers
@@ -419,15 +394,16 @@ pub fn generate_function_thunk_impl(
419394
// using destroy_at, we avoid needing to determine or remember what the correct spelling
420395
// is. Similar arguments apply to `construct_at`.
421396
UnqualifiedIdentifier::Constructor => {
422-
if let Some(meta) = func.member_func_metadata.as_ref() {
423-
let record: &Rc<Record> = ir.find_decl(meta.record_id)?;
424-
if is_copy_constructor(func, record.id)
425-
&& record.copy_constructor == SpecialMemberFunc::Unavailable
426-
{
427-
bail!(
428-
"Would use an unavailable copy constructor for {}",
429-
record.cc_name.identifier.as_ref()
430-
);
397+
if let Some(parent_id) = func.enclosing_item_id {
398+
if let Ok(record) = ir.find_decl::<Rc<Record>>(parent_id) {
399+
if is_copy_constructor(func, record.id)
400+
&& record.copy_constructor == SpecialMemberFunc::Unavailable
401+
{
402+
bail!(
403+
"Would use an unavailable copy constructor for {}",
404+
record.cc_name.identifier.as_ref()
405+
);
406+
}
431407
}
432408
}
433409
quote! { crubit::construct_at }
@@ -565,14 +541,12 @@ pub fn generate_function_thunk_impl(
565541
return_type_cpp_spelling.clone()
566542
};
567543

568-
let mut this_ref_qualification =
569-
func.member_func_metadata.as_ref().and_then(|meta| match &func.rs_name {
570-
UnqualifiedIdentifier::Constructor | UnqualifiedIdentifier::Destructor => None,
571-
UnqualifiedIdentifier::Identifier(_) | UnqualifiedIdentifier::Operator(_) => meta
572-
.instance_method_metadata
573-
.as_ref()
574-
.map(|instance_method| instance_method.reference),
575-
});
544+
let mut this_ref_qualification = match &func.rs_name {
545+
UnqualifiedIdentifier::Constructor | UnqualifiedIdentifier::Destructor => None,
546+
UnqualifiedIdentifier::Identifier(_) | UnqualifiedIdentifier::Operator(_) => {
547+
func.instance_method_metadata.as_ref().map(|meta| meta.reference)
548+
}
549+
};
576550
if func.cc_name.is_constructor() {
577551
this_ref_qualification = None;
578552
}

rs_bindings_from_cc/importers/function.cc

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -507,33 +507,28 @@ std::optional<IR::Item> FunctionDeclImporter::Import(
507507
errors.Add(FormattedError::Static("Inline function is not defined"));
508508
}
509509

510-
std::optional<MemberFuncMetadata> member_func_metadata;
510+
std::optional<InstanceMethodMetadata> instance_metadata;
511511
if (auto* method_decl =
512512
clang::dyn_cast<clang::CXXMethodDecl>(function_decl)) {
513-
std::optional<MemberFuncMetadata::InstanceMethodMetadata> instance_metadata;
514513
if (method_decl->isInstance()) {
515-
MemberFuncMetadata::ReferenceQualification reference;
514+
InstanceMethodMetadata::ReferenceQualification reference;
516515
switch (method_decl->getRefQualifier()) {
517516
case clang::RQ_LValue:
518-
reference = MemberFuncMetadata::kLValue;
517+
reference = InstanceMethodMetadata::kLValue;
519518
break;
520519
case clang::RQ_RValue:
521-
reference = MemberFuncMetadata::kRValue;
520+
reference = InstanceMethodMetadata::kRValue;
522521
break;
523522
case clang::RQ_None:
524-
reference = MemberFuncMetadata::kUnqualified;
523+
reference = InstanceMethodMetadata::kUnqualified;
525524
break;
526525
}
527-
instance_metadata = MemberFuncMetadata::InstanceMethodMetadata{
526+
instance_metadata = InstanceMethodMetadata{
528527
.reference = reference,
529528
.is_const = method_decl->isConst(),
530529
.is_virtual = method_decl->isVirtual(),
531530
};
532531
}
533-
534-
member_func_metadata = MemberFuncMetadata{
535-
.record_id = ictx_.GenerateItemId(method_decl->getParent()),
536-
.instance_method_metadata = instance_metadata};
537532
}
538533

539534
if (!errors.error_set.empty()) {
@@ -618,7 +613,7 @@ std::optional<IR::Item> FunctionDeclImporter::Import(
618613
.params = std::move(params),
619614
.lifetime_params = std::move(lifetime_params),
620615
.is_inline = is_inline,
621-
.member_func_metadata = std::move(member_func_metadata),
616+
.instance_method_metadata = std::move(instance_metadata),
622617
.is_extern_c = function_decl->isExternC(),
623618
.is_noreturn = function_decl->isNoReturn(),
624619
.is_variadic = function_decl->isVariadic(),

0 commit comments

Comments
 (0)