-
Notifications
You must be signed in to change notification settings - Fork 1.5k
When using a C++ struct as a parameter, map its type to a Carbon class type #5538
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Conversation
|
||
struct S {}; | ||
|
||
auto foo(S) -> void; | ||
|
||
// --- fail_todo_import_struct_param_type.carbon | ||
// --- todo_import_struct_definition_param_type.carbon |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove todo_
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -347,11 +345,60 @@ static auto MapType(Context& context, clang::QualType type) -> TypeExpr { | |||
.type_id = SemIR::ErrorInst::TypeId}; | |||
} | |||
|
|||
// Maps a C++ record type to a Carbon type. | |||
// TODO: Support more record types. | |||
static auto MapRecordType(Context& context, SemIR::LocId loc_id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a test for the scope? (e.g. the name not found in the scope)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer do name lookup.
`ClangDeclId` value is `ClangDecl` which includes the mapped Carbon instruction in addition to the Clang declaration. This allows finding the Carbon instruction for a given Clang declaration, which is necessary for mapping a Clang struct parameter type to the Carbon class without doing name lookup. To map the type, we also need to map namespaces. To avoid recursion for inner namespaces, we use a vector.
toolchain/sem_ir/clang_decl.h
Outdated
}; | ||
|
||
// Hashing for ClangDecl. See common/hashing.h. | ||
inline auto CarbonHashValue(const ClangDecl& value, uint64_t seed) -> HashCode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be a "hidden friend", like CarbonHashtableEq
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
FWIW, I was following the example of EntityName
.
https://github.com/carbon-language/carbon-lang/blob/trunk/toolchain/sem_ir/entity_name.h#L22-L50
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's just a historical accident -- equality and hashing were added in separate PRs by separate authors.
struct ClangDecl : public Printable<ClangDecl> { | ||
auto Print(llvm::raw_ostream& out) const -> void; | ||
|
||
friend auto CarbonHashtableEq(const ClangDecl& lhs, const ClangDecl& rhs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hashing and equality comparison should operate on the full logical state of the object, and inst_id
really seems like it's part of the logical state of ClangDecl
. See also style guide, which says:
... don't define operator overloads just because other libraries expect them. For example, if your type doesn't have a natural ordering, but you want to store it in a
std::set
, use a custom comparator rather than overloading<
."
I think the more general principle it's getting at is that fundamental operations like equality and hashing should be defined based on the meaning of the type as a whole, and not contorted to fit one particular use case. Excluding inst_id
from hashing and equality feels like such a contortion to me.
Would it work to have a separate Map<clang::Decl*, ClangDeclId>
for performing the lookup that you're trying to support here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The general principal makes sense to me, even though I'm not sure the style guide for operator overloads applies here.
I'm fine with a separate mapping, using a custom hashing was proposed here, which also makes sense to me if it's considered an ok practice in Carbon toolchain. Sorry for not providing this context before. Feel free to continue the discussion in Discord or here. I'm fine with both approaches.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The general principal makes sense to me, even though I'm not sure the style guide for operator overloads applies here.
I agree that the style rule doesn't directly apply here; I was just citing it for the general principle.
I'm fine with a separate mapping, using a custom hashing was proposed here, which also makes sense to me if it's considered an ok practice in Carbon toolchain. Sorry for not providing this context before. Feel free to continue the discussion in Discord or here. I'm fine with both approaches.
As far as I know, this way of using a custom hash isn't an established practice in our codebase (at least, I can't find any existing examples of it). I've moved the discussion to Discord.
…XRecordDecl()` does that on success
…lIntoScope()` and use it by both `ImportNameFromCpp()` and `MapRecordType()`. This way that logic is deduplicated. However, this adds recursive call: `ImportNameFromCpp()` -> `ImportNameDeclIntoScope()` -> `ImportNameDecl()` -> `ImportFunctionDecl()` -> ... -> `MapType()` -> `MapRecordType()` -> `ImportNameDeclIntoScope()` -> `ImportNameDecl()` -> `ImportCXXRecordDecl()`. Also take out static function from anonymous namespace.
This doesn't support actually passing the value of the struct, which is planned to be implemented using thunks.
ClangDeclId
value is nowClangDecl
which includes the mapped Carbon instruction in addition to the Clang declaration. This allows finding the Carbon instruction for a given Clang declaration, which is necessary for mapping a Clang struct parameter type to the Carbon class without doing name lookup. We don't take the instruction as part of the hash key, as discussed in Discord.To map the type, we also need to map namespaces. To avoid recursion for inner namespaces, we use a vector.
Moved the logic that adds the name to the name scope into
ImportNameDeclIntoScope()
so it can be used both when importing by name and by decl. However, this technically creates a recursive call since when we import a function, we import its parameter and return types, so while importing the function named declaration we could also call back to import the types named declaration.Note that the first commit just changes the order of functions in the file to make review easier.
C++ Interop Demo (that shows missing behavior):
Part of #5533.