Files
swift-mirror/test/Interop/Cxx/class/access/Inputs/using-non-public.h
John Hui 66c2e2c52b [cxx-interop] Import non-public inherited members (#79348)
This patch is follow-up work from #78942 and imports non-public members,
which were previously not being imported. Those members can be accessed
in a Swift file blessed by the SWIFT_PRIVATE_FILEID annotation.

As a consequence of this patch, we are also now importing inherited members
that are inaccessible from the derived classes, because they were declared
private, or because they were inherited via nested private inheritance. We
import them anyway but mark them unavailable, for better diagnostics and to
(somewhat) simplify the import logic for inheritance.

Because non-public base class members are now imported too, this patch
inflames an existing issue where a 'using' declaration on an inherited member
with a synthesized name (e.g., operators) produces duplicate members, leading
to miscompilation (resulting in a runtime crash). This was not previously noticed
because a 'using' declaration on a public inherited member is not usually
necessary, but is a common way to expose otherwise non-public members.
This patch puts in a workaround to prevent this from affecting the behavior
of MSVC's std::optional implementation, which uses this pattern of 'using'
a private inherited member. That will be fixed in a follow-up patch.

Follow-up work is also needed to correctly diagnose ambiguous overloads
in cases of multiple inheritance, and to account for virtual inheritance.

rdar://137764620
2025-02-25 01:03:16 -08:00

93 lines
2.3 KiB
C++

#ifndef _USING_BASE_METHODS_H
#define _USING_BASE_METHODS_H
enum class Return {
publUsingPubl,
protUsingPubl,
omitUsingPubl,
publUsingProt,
protUsingProt,
omitUsingProt,
};
class Base {
protected:
Return omitUsingProt(void) const { return Return::omitUsingProt; }
Return protUsingProt(void) const { return Return::protUsingProt; }
Return publUsingProt(void) const { return Return::publUsingProt; }
public:
Return omitUsingPubl(void) const { return Return::omitUsingPubl; }
// ^^^^ ^^^^
// | ` access level of base method
// ` access level of using statement
Return protUsingPubl(void) const { return Return::protUsingPubl; }
Return publUsingPubl(void) const { return Return::publUsingPubl; }
// N.B. private members should never be visible through inheritance, so having
// `using Base::privateMethod` in a derived class should be a C++ error.
//
// Thus we'll forgo defining any private members here and test those
// separately.
};
class PublUser : public Base {
public:
using Base::publUsingProt;
using Base::publUsingPubl;
protected:
using Base::protUsingProt;
using Base::protUsingPubl;
};
class ProtUser : protected Base {
public:
using Base::publUsingProt;
using Base::publUsingPubl;
protected:
using Base::protUsingProt;
using Base::protUsingPubl;
};
class PrivUser : private Base {
public:
using Base::publUsingProt;
using Base::publUsingPubl;
protected:
using Base::protUsingProt;
using Base::protUsingPubl;
};
class Publ : public Base {};
class Prot : protected Base {};
class Priv : private Base {};
// N.B. with another layer of inheritance, we could test *many* combinations,
// i.e.:
//
// // Classes inheriting from a class with using decls
// class _ : public/protected/private Publ/Prot/PrivUser {}
//
// // Classes with using decls that skip past an inherited class
// class _ : public/protected/private Publ/Prot/Priv {}
//
// but most combinations will lead to most/all fields being inaccessible.
//
// For now, we just spot-check two interesting cases, where publUsing*() should
// still be public in the derived class.
class PublPrivUser : public PrivUser {};
class PrivUserPubl : private Publ {
public:
using Base::publUsingProt;
using Base::publUsingPubl;
protected:
using Base::protUsingProt;
using Base::protUsingPubl;
};
#endif // _USING_BASE_METHODS_H