-
Notifications
You must be signed in to change notification settings - Fork 1.5k
C++ Interop: Fix access calculation to handle private member of base classes correctly #6238
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
Changes from 1 commit
97eef9b
d18b5f4
c296cd8
018dca8
7bd83dc
311a45c
6fc59fb
db3e0f1
15318cb
9dad5ab
6bdde04
37ee14b
3bd7827
62d4dcb
a2a464f
7593a35
531527d
41b3742
dbb71ad
d3b0cf6
cbe8304
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| // Part of the Carbon Language 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 "toolchain/check/cpp/access.h" | ||
|
|
||
| namespace Carbon::Check { | ||
|
|
||
| static auto CalculateEffectiveAccess(clang::AccessSpecifier lookup_access, | ||
| clang::AccessSpecifier lexical_access) | ||
| -> clang::AccessSpecifier { | ||
| if (lookup_access != clang::AS_none) { | ||
| // Lookup access takes precedence. | ||
| return lookup_access; | ||
| } | ||
|
|
||
| if (lexical_access != clang::AS_none) { | ||
| // When a base class private member is accessed through a derived class, the | ||
| // lookup access would be set to `AS_none`. | ||
| CARBON_CHECK(lexical_access == clang::AS_private); | ||
| return lexical_access; | ||
| } | ||
|
|
||
| // No access specified means that this is not a record member, so we treat it | ||
| // as public. | ||
| return clang::AS_public; | ||
| } | ||
|
|
||
| auto DeduceClangAccess(clang::AccessSpecifier lookup_access, | ||
| clang::AccessSpecifier lexical_access) | ||
| -> SemIR::AccessKind { | ||
| switch (CalculateEffectiveAccess(lookup_access, lexical_access)) { | ||
| case clang::AS_public: | ||
| return SemIR::AccessKind::Public; | ||
| case clang::AS_protected: | ||
| return SemIR::AccessKind::Protected; | ||
| case clang::AS_private: | ||
| return SemIR::AccessKind::Private; | ||
| case clang::AS_none: | ||
| CARBON_FATAL("Couldn't deduce access"); | ||
| } | ||
| } | ||
|
|
||
| } // namespace Carbon::Check | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| // Part of the Carbon Language project, under the Apache License v2.0 with LLVM | ||
| // Exceptions. See /LICENSE for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef CARBON_TOOLCHAIN_CHECK_CPP_ACCESS_H_ | ||
| #define CARBON_TOOLCHAIN_CHECK_CPP_ACCESS_H_ | ||
|
|
||
| #include "toolchain/sem_ir/name_scope.h" | ||
|
|
||
| namespace Carbon::Check { | ||
|
|
||
| // Deduces the effective access kind from the given lookup and lexical access | ||
| // specifiers. | ||
| auto DeduceClangAccess(clang::AccessSpecifier lookup_access, | ||
|
||
| clang::AccessSpecifier lexical_access) | ||
|
||
| -> SemIR::AccessKind; | ||
|
|
||
| } // namespace Carbon::Check | ||
|
|
||
| #endif // CARBON_TOOLCHAIN_CHECK_CPP_ACCESS_H_ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
|
|
||
| #include "toolchain/check/cpp/import.h" | ||
|
|
||
| #include <algorithm> | ||
| #include <memory> | ||
| #include <optional> | ||
| #include <string> | ||
|
|
@@ -34,6 +35,7 @@ | |
| #include "toolchain/check/context.h" | ||
| #include "toolchain/check/control_flow.h" | ||
| #include "toolchain/check/convert.h" | ||
| #include "toolchain/check/cpp/access.h" | ||
| #include "toolchain/check/cpp/custom_type_mapping.h" | ||
| #include "toolchain/check/cpp/thunk.h" | ||
| #include "toolchain/check/diagnostic_helpers.h" | ||
|
|
@@ -2014,18 +2016,10 @@ auto ImportCppFunctionDecl(Context& context, SemIR::LocId loc_id, | |
| SemIR::ClangDeclKey::ForFunctionDecl(clang_decl, num_params)); | ||
| } | ||
|
|
||
| // Maps `clang::AccessSpecifier` to `SemIR::AccessKind`. | ||
| static auto MapAccess(clang::AccessSpecifier access_specifier) | ||
| // Deduces the access given UnresolvedSetIterator. | ||
| static auto MapAccess(clang::UnresolvedSetIterator iterator) | ||
| -> SemIR::AccessKind { | ||
| switch (access_specifier) { | ||
| case clang::AS_public: | ||
| case clang::AS_none: | ||
| return SemIR::AccessKind::Public; | ||
| case clang::AS_protected: | ||
| return SemIR::AccessKind::Protected; | ||
| case clang::AS_private: | ||
| return SemIR::AccessKind::Private; | ||
| } | ||
| return DeduceClangAccess(iterator.getAccess(), iterator->getAccess()); | ||
|
||
| } | ||
|
|
||
| // Imports a Clang declaration into Carbon and adds that name into the | ||
|
|
@@ -2034,13 +2028,12 @@ static auto ImportNameDeclIntoScope(Context& context, SemIR::LocId loc_id, | |
| SemIR::NameScopeId scope_id, | ||
| SemIR::NameId name_id, | ||
| SemIR::ClangDeclKey key, | ||
| clang::AccessSpecifier access) | ||
| SemIR::AccessKind access_kind) | ||
| -> SemIR::ScopeLookupResult { | ||
| SemIR::InstId inst_id = ImportDeclAndDependencies(context, loc_id, key); | ||
| if (!inst_id.has_value()) { | ||
| return SemIR::ScopeLookupResult::MakeNotFound(); | ||
| } | ||
| SemIR::AccessKind access_kind = MapAccess(access); | ||
| AddNameToScope(context, scope_id, name_id, access_kind, inst_id); | ||
| return SemIR::ScopeLookupResult::MakeWrappedLookupResult(inst_id, | ||
| access_kind); | ||
|
|
@@ -2130,16 +2123,13 @@ auto ImportCppOverloadSet( | |
| // after overload resolution. | ||
| static auto GetOverloadSetAccess(const clang::UnresolvedSet<4>& overload_set) | ||
| -> SemIR::AccessKind { | ||
| clang::AccessSpecifier access = overload_set.begin().getAccess(); | ||
| for (auto it = overload_set.begin() + 1; it != overload_set.end(); ++it) { | ||
| CARBON_CHECK( | ||
| (it.getAccess() == clang::AS_none) == (access == clang::AS_none), | ||
| "Unexpected mixture of members and non-members"); | ||
| if (it.getAccess() < access) { | ||
| access = it->getAccess(); | ||
| } | ||
| SemIR::AccessKind access_kind = MapAccess(overload_set.begin()); | ||
| for (auto it = overload_set.begin() + 1; | ||
|
||
| it != overload_set.end() && access_kind != SemIR::AccessKind::Public; | ||
|
||
| ++it) { | ||
| access_kind = std::min(access_kind, MapAccess(it)); | ||
| } | ||
| return MapAccess(access); | ||
| return access_kind; | ||
| } | ||
|
|
||
| // Imports an overload set from Clang to Carbon and adds the name into the | ||
|
|
@@ -2260,7 +2250,7 @@ auto ImportNameFromCpp(Context& context, SemIR::LocId loc_id, | |
| } | ||
| auto key = SemIR::ClangDeclKey::ForNonFunctionDecl(lookup->getFoundDecl()); | ||
| return ImportNameDeclIntoScope(context, loc_id, scope_id, name_id, key, | ||
| lookup->begin().getAccess()); | ||
| MapAccess(lookup->begin())); | ||
| } | ||
|
|
||
| auto ImportClassDefinitionForClangDecl(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.
Is this CHECK correct? I've suggested a test which I think may hit it.
If it's not correct, perhaps this function could be replaced with something like:
That also is pretty short, and if you're not expecting many other access functions, perhaps could be inlined into the header to remove access.cpp.
Uh oh!
There was an error while loading. Please reload this page.
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.
BTW, while equivalent [ed: for current tests, the suggested] tests might also suggest this still should have some TODOs
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.
You're right, this check was incorrect.
I've added more tests based on your suggestions and adjusted the logic to make it correct for these cases.