mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
For now, hide `override fn`s from name lookup, so that the base class version is always used, as the derived-class version does not have its own vptr entry and so would not do the right thing if a further-derived class adds a new override. This is implemented via a new access kind of `Hidden`. When checking the overriding function, pass in the expected `Self` type and check the `self` parameter against that; the signature that we generate for the thunk in the derived class is the base class signature with the `self` parameter's type changed to the derived class. When we generate a thunk for a virtual function, the thunk is assigned a `virtual_index`, and the virtual function itself is not. When the thunk makes a direct call to the virtual function, recognize this situation by checking for a `virtual_index`, and perform a non-virtual call if there isn't one. Assisted-by: Gemini via Antigravity
60 lines
2.3 KiB
C++
60 lines
2.3 KiB
C++
// 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::DeclAccessPair access_pair)
|
|
-> clang::AccessSpecifier {
|
|
// Note that we use `.getAccess()` here, not `->getAccess()`, which is
|
|
// equivalent to `.getDecl()->getAccess()`, because we want to consider the
|
|
// lookup access and not the lexical access.
|
|
switch (access_pair.getAccess()) {
|
|
// Lookup access takes precedence.
|
|
case clang::AS_public:
|
|
case clang::AS_protected:
|
|
case clang::AS_private:
|
|
return access_pair.getAccess();
|
|
case clang::AS_none:
|
|
// No access specified meaning depends on the declaration. For non class
|
|
// members, it means there's no access associated with this function so we
|
|
// treat it as public. For class members it means we lost access along the
|
|
// inheritance path, and the difference between `none` and `private` only
|
|
// matters when the access check is performed within a friend or member of
|
|
// the naming class. Because the naming class is a C++ class, and we don't
|
|
// yet have a mechanism for a C++ class to befriend a Carbon class, we can
|
|
// safely map `none` to `private` for now.
|
|
return access_pair->isCXXClassMember() ? clang::AS_private
|
|
: clang::AS_public;
|
|
}
|
|
}
|
|
|
|
auto MapCppAccess(clang::DeclAccessPair access_pair) -> SemIR::AccessKind {
|
|
switch (CalculateEffectiveAccess(access_pair)) {
|
|
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 convert access");
|
|
}
|
|
}
|
|
|
|
auto MapToCppAccess(SemIR::AccessKind access) -> clang::AccessSpecifier {
|
|
switch (access) {
|
|
case SemIR::AccessKind::Public:
|
|
return clang::AS_public;
|
|
case SemIR::AccessKind::Protected:
|
|
return clang::AS_protected;
|
|
case SemIR::AccessKind::Private:
|
|
case SemIR::AccessKind::Hidden:
|
|
return clang::AS_private;
|
|
}
|
|
}
|
|
|
|
} // namespace Carbon::Check
|