diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 4dfd949529bc8..07a264819e9bf 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -16,7 +16,9 @@ #ifndef SWIFT_CLANG_IMPORTER_H #define SWIFT_CLANG_IMPORTER_H +#include "swift/AST/AttrKind.h" #include "swift/AST/ClangModuleLoader.h" +#include "clang/Basic/Specifiers.h" #include "llvm/Support/VirtualFileSystem.h" /// The maximum number of SIMD vector elements we currently try to import. @@ -728,7 +730,11 @@ llvm::StringRef getCFTypeName(const clang::TypedefNameDecl *decl); ValueDecl *getImportedMemberOperator(const DeclBaseName &name, NominalTypeDecl *selfType, std::optional parameterType); - +/// Map the access specifier of a Clang record member to a Swift access level. +/// +/// This mapping is conservative: the resulting Swift access should be at _most_ +/// as permissive as the input C++ access. +AccessLevel convertClangAccess(clang::AccessSpecifier access); } // namespace importer struct ClangInvocationFileMapping { diff --git a/include/swift/ClangImporter/ClangModule.h b/include/swift/ClangImporter/ClangModule.h index 29cf61c9b64c9..a31545408a348 100644 --- a/include/swift/ClangImporter/ClangModule.h +++ b/include/swift/ClangImporter/ClangModule.h @@ -108,7 +108,7 @@ class ClangModuleUnit final : public LoadedFile { Identifier getDiscriminatorForPrivateDecl(const Decl *D) const override { - llvm_unreachable("no private decls in Clang modules"); + llvm_unreachable("Clang modules do not need discriminators"); } virtual version::Version getLanguageVersionBuiltWith() const override { diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index b84873948e6b7..52b60286ec682 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -41,6 +41,7 @@ #include "swift/Basic/Defer.h" #include "swift/Basic/SourceManager.h" #include "swift/ClangImporter/ClangImporter.h" +#include "swift/ClangImporter/ClangModule.h" #include "swift/Demangling/Demangler.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Demangling/ManglingUtils.h" @@ -53,8 +54,8 @@ #include "clang/AST/Mangle.h" #include "clang/Basic/CharInfo.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" @@ -1092,6 +1093,11 @@ static StringRef getPrivateDiscriminatorIfNecessary(const Decl *decl) { auto topLevelSubcontext = decl->getDeclContext()->getModuleScopeContext(); auto fileUnit = cast(topLevelSubcontext); + // Clang modules do not provide a namespace, so no discriminator is needed + // here, even for non-public declarations. + if (isa(fileUnit)) + return StringRef(); + Identifier discriminator = fileUnit->getDiscriminatorForPrivateDecl(decl); assert(!discriminator.empty()); diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 0be0903587fd6..ec77b2dc87616 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -6152,6 +6152,8 @@ TinyPtrVector ClangRecordMemberLookup::evaluate( NominalTypeDecl *inheritingDecl = desc.inheritingDecl; DeclName name = desc.name; + bool inheritedLookup = recordDecl != inheritingDecl; + auto &ctx = recordDecl->getASTContext(); auto directResults = evaluateOrDefault( ctx.evaluator, @@ -6177,7 +6179,7 @@ TinyPtrVector ClangRecordMemberLookup::evaluate( // If this member is found due to inheritance, clone it from the base class // by synthesizing getters and setters. - if (inheritingDecl != recordDecl) { + if (inheritedLookup) { imported = clangModuleLoader->importBaseMemberDecl( cast(imported), inheritingDecl); if (!imported) @@ -6186,8 +6188,8 @@ TinyPtrVector ClangRecordMemberLookup::evaluate( result.push_back(cast(imported)); } - if (inheritingDecl != recordDecl) { - // For inheritied members, add members that are synthesized eagerly, such as + if (inheritedLookup) { + // For inherited members, add members that are synthesized eagerly, such as // subscripts. This is not necessary for non-inherited members because those // should already be in the lookup table. for (auto member : @@ -8275,3 +8277,34 @@ bool importer::isCxxConstReferenceType(const clang::Type *type) { auto pointeeType = getCxxReferencePointeeTypeOrNone(type); return pointeeType && pointeeType->isConstQualified(); } + +AccessLevel importer::convertClangAccess(clang::AccessSpecifier access) { + switch (access) { + case clang::AS_public: + // C++ 'public' is actually closer to Swift 'open' than Swift 'public', + // since C++ 'public' does not prevent users from subclassing a type or + // overriding a method. However, subclassing and overriding are currently + // unsupported across the interop boundary, so we conservatively map C++ + // 'public' to Swift 'public' in case there are other C++ subtleties that + // are being missed at this time (e.g., C++ 'final' vs Swift 'final'). + return AccessLevel::Public; + + case clang::AS_protected: + // Swift does not have a notion of protected fields, so map C++ 'protected' + // to Swift 'private'. + return AccessLevel::Private; + + case clang::AS_private: + // N.B. Swift 'private' is more restrictive than C++ 'private' because it + // also cares about what source file the member is accessed. + return AccessLevel::Private; + + case clang::AS_none: + // The fictional 'none' specifier is given to top-level C++ declarations, + // for which C++ lacks the syntax to give an access specifier. (It may also + // be used in other cases I'm not aware of.) Those declarations are globally + // visible and thus correspond to Swift 'public' (with the same caveats + // about Swift 'public' vs 'open'; see above). + return AccessLevel::Public; + } +} diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 2ed671347aea1..c03cdada92241 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -467,7 +467,7 @@ void ClangImporter::Implementation::addSynthesizedTypealias( auto typealias = new (ctx) TypeAliasDecl(SourceLoc(), SourceLoc(), name, SourceLoc(), nullptr, nominal); typealias->setUnderlyingType(underlyingType); - typealias->setAccess(AccessLevel::Public); + typealias->setAccess(nominal->getFormalAccess()); typealias->setImplicit(); nominal->addMember(typealias); @@ -1426,11 +1426,10 @@ namespace { // Create a typealias for this CF typedef. TypeAliasDecl *typealias = nullptr; typealias = Impl.createDeclWithClangNode( - Decl, AccessLevel::Public, - Impl.importSourceLoc(Decl->getBeginLoc()), - SourceLoc(), Name, - Impl.importSourceLoc(Decl->getLocation()), - /*genericparams*/nullptr, DC); + Decl, importer::convertClangAccess(Decl->getAccess()), + Impl.importSourceLoc(Decl->getBeginLoc()), SourceLoc(), Name, + Impl.importSourceLoc(Decl->getLocation()), + /*genericparams*/ nullptr, DC); typealias->setUnderlyingType( underlying->getDeclaredInterfaceType()); @@ -1445,11 +1444,10 @@ namespace { // Create a typealias for this CF typedef. TypeAliasDecl *typealias = nullptr; typealias = Impl.createDeclWithClangNode( - Decl, AccessLevel::Public, - Impl.importSourceLoc(Decl->getBeginLoc()), - SourceLoc(), Name, - Impl.importSourceLoc(Decl->getLocation()), - /*genericparams*/nullptr, DC); + Decl, importer::convertClangAccess(Decl->getAccess()), + Impl.importSourceLoc(Decl->getBeginLoc()), SourceLoc(), Name, + Impl.importSourceLoc(Decl->getLocation()), + /*genericparams*/ nullptr, DC); typealias->setUnderlyingType( Impl.SwiftContext.getAnyObjectType()); @@ -1514,12 +1512,10 @@ namespace { return nullptr; auto Loc = Impl.importSourceLoc(Decl->getLocation()); - auto Result = Impl.createDeclWithClangNode(Decl, - AccessLevel::Public, - Impl.importSourceLoc(Decl->getBeginLoc()), - SourceLoc(), Name, - Loc, - /*genericparams*/nullptr, DC); + auto Result = Impl.createDeclWithClangNode( + Decl, importer::convertClangAccess(Decl->getAccess()), + Impl.importSourceLoc(Decl->getBeginLoc()), SourceLoc(), Name, Loc, + /*genericparams*/ nullptr, DC); Result->setUnderlyingType(SwiftType); if (SwiftType->isUnsafe()) @@ -1623,21 +1619,21 @@ namespace { if (!underlyingType) return nullptr; + auto access = importer::convertClangAccess(decl->getAccess()); auto Loc = Impl.importSourceLoc(decl->getLocation()); auto structDecl = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, Loc, name, Loc, std::nullopt, nullptr, - dc); + decl, access, Loc, name, Loc, std::nullopt, nullptr, dc); auto options = getDefaultMakeStructRawValuedOptions(); options |= MakeStructRawValuedFlags::MakeUnlabeledValueInit; options -= MakeStructRawValuedFlags::IsLet; options -= MakeStructRawValuedFlags::IsImplicit; - synthesizer.makeStructRawValued( - structDecl, underlyingType, - {KnownProtocolKind::RawRepresentable, KnownProtocolKind::Equatable, - KnownProtocolKind::Hashable}, - options, /*setterAccess=*/AccessLevel::Public); + synthesizer.makeStructRawValued(structDecl, underlyingType, + {KnownProtocolKind::RawRepresentable, + KnownProtocolKind::Equatable, + KnownProtocolKind::Hashable}, + options, /*setterAccess=*/access); result = structDecl; break; @@ -1674,6 +1670,10 @@ namespace { (nsErrorDecl = C.getNSErrorDecl()) && (errorCodeProto = C.getProtocol(KnownProtocolKind::ErrorCodeProtocol))) { + assert( + decl->getAccess() != clang::AS_private && + decl->getAccess() != clang::AS_protected && + "NSError enums shouldn't be defined as non-public C++ members"); // Create the wrapper struct. errorWrapper = new (C) StructDecl(loc, name, loc, std::nullopt, nullptr, dc); @@ -1745,9 +1745,9 @@ namespace { // Create the enumeration. auto enumDecl = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, loc, enumName, - Impl.importSourceLoc(decl->getLocation()), std::nullopt, nullptr, - enumDC); + decl, importer::convertClangAccess(decl->getAccess()), loc, + enumName, Impl.importSourceLoc(decl->getLocation()), std::nullopt, + nullptr, enumDC); enumDecl->setHasFixedRawValues(); // Annotate as 'frozen' if appropriate. @@ -1789,7 +1789,7 @@ namespace { SourceLoc(), varName, enumDecl); rawValue->setImplicit(); - rawValue->setAccess(AccessLevel::Public); + rawValue->copyFormalAccessFrom(enumDecl); rawValue->setSetterAccess(AccessLevel::Private); rawValue->setInterfaceType(underlyingType); @@ -1812,6 +1812,10 @@ namespace { // If we have an error wrapper, finish it up now that its // nested enum has been constructed. if (errorWrapper) { + assert( + decl->getAccess() != clang::AS_private && + decl->getAccess() != clang::AS_protected && + "NSError enums shouldn't be defined as non-public C++ members"); // Add the ErrorType alias: // public typealias ErrorType auto alias = Impl.createDeclWithClangNode( @@ -2186,12 +2190,12 @@ namespace { auto loc = Impl.importSourceLoc(decl->getLocation()); if (recordHasReferenceSemantics(decl)) result = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, loc, name, loc, - ArrayRef{}, nullptr, dc, false); + decl, importer::convertClangAccess(decl->getAccess()), loc, name, + loc, ArrayRef{}, nullptr, dc, false); else result = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, loc, name, loc, std::nullopt, nullptr, - dc); + decl, importer::convertClangAccess(decl->getAccess()), loc, name, + loc, std::nullopt, nullptr, dc); Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; // We have to do this after populating ImportedDecls to avoid importing @@ -3195,7 +3199,8 @@ namespace { name, dc, type, clang::APValue(decl->getInitVal()), enumKind == EnumKind::Unknown ? ConstantConvertKind::Construction : ConstantConvertKind::None, - isStatic, decl); + isStatic, decl, + importer::convertClangAccess(clangEnum->getAccess())); Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result; // If this is a compatibility stub, mark it as such. @@ -3264,12 +3269,10 @@ namespace { auto type = importedType.getType(); // Map this indirect field to a Swift variable. - auto result = Impl.createDeclWithClangNode(decl, - AccessLevel::Public, - /*IsStatic*/false, - VarDecl::Introducer::Var, - Impl.importSourceLoc(decl->getBeginLoc()), - name, dc); + auto result = Impl.createDeclWithClangNode( + decl, importer::convertClangAccess(decl->getAccess()), + /*IsStatic*/ false, VarDecl::Introducer::Var, + Impl.importSourceLoc(decl->getBeginLoc()), name, dc); result->setInterfaceType(type); result->setIsObjC(false); result->setIsDynamic(false); @@ -3897,7 +3900,8 @@ namespace { DeclName ctorName(Impl.SwiftContext, DeclBaseName::createConstructor(), bodyParams); result = Impl.createDeclWithClangNode( - clangNode, AccessLevel::Public, ctorName, loc, + clangNode, importer::convertClangAccess(ctordecl->getAccess()), + ctorName, loc, /*failable=*/false, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), @@ -3930,8 +3934,7 @@ namespace { func->setImportAsStaticMember(); } } - // Someday, maybe this will need to be 'open' for C++ virtual methods. - func->setAccess(AccessLevel::Public); + func->setAccess(importer::convertClangAccess(decl->getAccess())); if (!importFuncWithoutSignature) { bool success = processSpecialImportedFunc( @@ -4297,21 +4300,10 @@ namespace { auto type = importedType.getType(); - // Private C++ fields should also be private in Swift. Since Swift does - // not have a notion of protected field, map protected C++ fields to - // private Swift fields. - AccessLevel accessLevel = - (decl->getAccess() == clang::AccessSpecifier::AS_private || - decl->getAccess() == clang::AccessSpecifier::AS_protected) - ? AccessLevel::Private - : AccessLevel::Public; - - auto result = - Impl.createDeclWithClangNode(decl, accessLevel, - /*IsStatic*/ false, - VarDecl::Introducer::Var, - Impl.importSourceLoc(decl->getLocation()), - name, dc); + auto result = Impl.createDeclWithClangNode( + decl, importer::convertClangAccess(decl->getAccess()), + /*IsStatic*/ false, VarDecl::Introducer::Var, + Impl.importSourceLoc(decl->getLocation()), name, dc); if (decl->getType().isConstQualified()) { // Note that in C++ there are ways to change the values of const // members, so we don't use WriteImplKind::Immutable storage. @@ -4374,11 +4366,10 @@ namespace { auto introducer = Impl.shouldImportGlobalAsLet(decl->getType()) ? VarDecl::Introducer::Let : VarDecl::Introducer::Var; - auto result = Impl.createDeclWithClangNode(decl, - AccessLevel::Public, - /*IsStatic*/isStatic, introducer, - Impl.importSourceLoc(decl->getLocation()), - name, dc); + auto result = Impl.createDeclWithClangNode( + decl, importer::convertClangAccess(decl->getAccess()), + /*IsStatic*/ isStatic, introducer, + Impl.importSourceLoc(decl->getLocation()), name, dc); result->setIsObjC(false); result->setIsDynamic(false); @@ -4462,8 +4453,8 @@ namespace { Impl.SwiftContext, loc, genericParams, loc); auto structDecl = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, loc, name, loc, std::nullopt, - genericParamList, dc); + decl, importer::convertClangAccess(decl->getAccess()), loc, name, loc, + std::nullopt, genericParamList, dc); auto attr = AvailableAttr::createUniversallyUnavailable( Impl.SwiftContext, "Un-specialized class templates are not currently " @@ -4530,12 +4521,9 @@ namespace { auto Loc = Impl.importSourceLoc(decl->getLocation()); auto Result = Impl.createDeclWithClangNode( - decl, - AccessLevel::Public, - Impl.importSourceLoc(decl->getBeginLoc()), - SourceLoc(), Name, - Loc, - /*genericparams*/nullptr, importedDC); + decl, importer::convertClangAccess(decl->getAccess()), + Impl.importSourceLoc(decl->getBeginLoc()), SourceLoc(), Name, Loc, + /*genericparams*/ nullptr, importedDC); Result->setUnderlyingType(SwiftTypeDecl->getDeclaredInterfaceType()); return Result; @@ -6218,9 +6206,11 @@ Decl *SwiftDeclConverter::importCompatibilityTypeAlias( // Create the type alias. auto alias = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, Impl.importSourceLoc(decl->getBeginLoc()), - SourceLoc(), compatibilityName.getBaseIdentifier(Impl.SwiftContext), - Impl.importSourceLoc(decl->getLocation()), /*generic params*/nullptr, dc); + decl, importer::convertClangAccess(decl->getAccess()), + Impl.importSourceLoc(decl->getBeginLoc()), SourceLoc(), + compatibilityName.getBaseIdentifier(Impl.SwiftContext), + Impl.importSourceLoc(decl->getLocation()), /*generic params*/ nullptr, + dc); auto *GTD = dyn_cast(typeDecl); if (GTD && !isa(GTD)) { @@ -6315,7 +6305,8 @@ SwiftDeclConverter::importSwiftNewtype(const clang::TypedefNameDecl *decl, auto Loc = Impl.importSourceLoc(decl->getLocation()); auto structDecl = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, Loc, name, Loc, std::nullopt, nullptr, dc); + decl, importer::convertClangAccess(decl->getAccess()), Loc, name, Loc, + std::nullopt, nullptr, dc); // Import the type of the underlying storage ImportDiagnosticAdder addImportDiag(Impl, decl, decl->getLocation()); @@ -6515,8 +6506,8 @@ Decl *SwiftDeclConverter::importEnumCase(const clang::EnumConstantDecl *decl, rawValueExpr->setNegative(SourceLoc()); auto element = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, SourceLoc(), name, nullptr, - SourceLoc(), rawValueExpr, theEnum); + decl, importer::convertClangAccess(clangEnum->getAccess()), SourceLoc(), + name, nullptr, SourceLoc(), rawValueExpr, theEnum); Impl.importAttributes(decl, element); @@ -6540,7 +6531,8 @@ SwiftDeclConverter::importOptionConstant(const clang::EnumConstantDecl *decl, convertKind = ConstantConvertKind::ConstructionWithUnwrap; Decl *CD = synthesizer.createConstant( name, theStruct, theStruct->getDeclaredInterfaceType(), - clang::APValue(decl->getInitVal()), convertKind, /*isStatic*/ true, decl); + clang::APValue(decl->getInitVal()), convertKind, /*isStatic*/ true, decl, + importer::convertClangAccess(clangEnum->getAccess())); Impl.importAttributes(decl, CD); // NS_OPTIONS members that have a value of 0 (typically named "None") do @@ -6604,9 +6596,10 @@ Decl *SwiftDeclConverter::importEnumCaseAlias( result->setType(original->getInterfaceType()); } - Decl *CD = synthesizer.createConstant(name, importIntoDC, importedEnumTy, - result, ConstantConvertKind::None, - /*isStatic*/ true, alias); + Decl *CD = synthesizer.createConstant( + name, importIntoDC, importedEnumTy, result, ConstantConvertKind::None, + /*isStatic*/ true, alias, + importer::convertClangAccess(clangEnum->getAccess())); Impl.importAttributes(alias, CD); return CD; } @@ -6620,7 +6613,8 @@ SwiftDeclConverter::importAsOptionSetType(DeclContext *dc, Identifier name, // Create a struct with the underlying type as a field. auto structDecl = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, Loc, name, Loc, std::nullopt, nullptr, dc); + decl, importer::convertClangAccess(decl->getAccess()), Loc, name, Loc, + std::nullopt, nullptr, dc); Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = structDecl; // Compute the underlying type. @@ -6696,7 +6690,7 @@ Decl *SwiftDeclConverter::importGlobalAsInitializer( } auto result = Impl.createDeclWithClangNode( - decl, AccessLevel::Public, name, + decl, importer::convertClangAccess(decl->getAccess()), name, Impl.importSourceLoc(decl->getLocation()), failable, /*FailabilityLoc=*/SourceLoc(), /*Async=*/false, /*AsyncLoc=*/SourceLoc(), @@ -6877,8 +6871,8 @@ SwiftDeclConverter::getImplicitProperty(ImportedName importedName, Type swiftPropertyType = importedType.getType(); auto property = Impl.createDeclWithClangNode( - getter, AccessLevel::Public, /*IsStatic*/isStatic, - VarDecl::Introducer::Var, SourceLoc(), + getter, importer::convertClangAccess(getter->getAccess()), + /*IsStatic*/ isStatic, VarDecl::Introducer::Var, SourceLoc(), propertyName, dc); property->setInterfaceType(swiftPropertyType); property->setIsObjC(false); @@ -9234,17 +9228,6 @@ ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl, if (ClangDecl->isInvalidDecl()) return nullptr; - // Private and protected C++ class members should never be used from Swift, - // however, parts of the Swift typechecker rely on being able to iterate over - // all of the stored fields of a particular struct. This means we still need - // to add private fields to the Swift AST. - // - // Other kinds of private and protected C++ decls are not relevant for Swift. - clang::AccessSpecifier access = ClangDecl->getAccess(); - if ((access == clang::AS_protected || access == clang::AS_private) && - !isa(ClangDecl)) - return nullptr; - bool SkippedOverTypedef = false; Decl *Result = nullptr; if (auto *UnderlyingDecl = canSkipOverTypedef(*this, ClangDecl, @@ -9872,16 +9855,14 @@ markUnavailable(ValueDecl *decl, StringRef unavailabilityMsgRef) { /// Create a decl with error type and an "unavailable" attribute on it /// with the specified message. -ValueDecl *ClangImporter::Implementation:: -createUnavailableDecl(Identifier name, DeclContext *dc, Type type, - StringRef UnavailableMessage, bool isStatic, - ClangNode ClangN) { +ValueDecl *ClangImporter::Implementation::createUnavailableDecl( + Identifier name, DeclContext *dc, Type type, StringRef UnavailableMessage, + bool isStatic, ClangNode ClangN, AccessLevel access) { // Create a new VarDecl with dummy type. - auto var = createDeclWithClangNode(ClangN, AccessLevel::Public, - /*IsStatic*/isStatic, - VarDecl::Introducer::Var, - SourceLoc(), name, dc); + auto var = createDeclWithClangNode( + ClangN, access, + /*IsStatic*/ isStatic, VarDecl::Introducer::Var, SourceLoc(), name, dc); var->setIsObjC(false); var->setIsDynamic(false); var->setInterfaceType(type); diff --git a/lib/ClangImporter/ImportMacro.cpp b/lib/ClangImporter/ImportMacro.cpp index 0c51ae9e3eabb..c44e929802082 100644 --- a/lib/ClangImporter/ImportMacro.cpp +++ b/lib/ClangImporter/ImportMacro.cpp @@ -75,8 +75,9 @@ createMacroConstant(ClangImporter::Implementation &Impl, bool isStatic, ClangNode ClangN) { Impl.ImportedMacroConstants[macro] = {value, type}; - return SwiftDeclSynthesizer(Impl).createConstant( - name, dc, type, value, convertKind, isStatic, ClangN); + return SwiftDeclSynthesizer(Impl).createConstant(name, dc, type, value, + convertKind, isStatic, + ClangN, AccessLevel::Public); } static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl, @@ -203,9 +204,9 @@ static ValueDecl *importStringLiteral(ClangImporter::Implementation &Impl, if (!unicode::isWellFormedUTF8(text)) return nullptr; - return SwiftDeclSynthesizer(Impl).createConstant(name, DC, importTy, text, - ConstantConvertKind::None, - /*static*/ false, ClangN); + return SwiftDeclSynthesizer(Impl).createConstant( + name, DC, importTy, text, ConstantConvertKind::None, + /*static*/ false, ClangN, AccessLevel::Public); } static ValueDecl *importLiteral(ClangImporter::Implementation &Impl, @@ -262,9 +263,9 @@ static ValueDecl *importNil(ClangImporter::Implementation &Impl, // We use a dummy type since we don't have a convenient type for 'nil'. Any // use of this will be an error anyway. auto type = TupleType::getEmpty(Impl.SwiftContext); - return Impl.createUnavailableDecl(name, DC, type, - "use 'nil' instead of this imported macro", - /*isStatic=*/false, clangN); + return Impl.createUnavailableDecl( + name, DC, type, "use 'nil' instead of this imported macro", + /*isStatic=*/false, clangN, AccessLevel::Public); } static bool isSignToken(const clang::Token &tok) { diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 20f615d37ef4e..609992020e3e5 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -1203,9 +1203,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation /// Create a decl with error type and an "unavailable" attribute on it /// with the specified message. - ValueDecl *createUnavailableDecl(Identifier name, DeclContext *dc, - Type type, StringRef UnavailableMessage, - bool isStatic, ClangNode ClangN); + ValueDecl *createUnavailableDecl(Identifier name, DeclContext *dc, Type type, + StringRef UnavailableMessage, bool isStatic, + ClangNode ClangN, AccessLevel access); /// Add a synthesized typealias to the given nominal type. void addSynthesizedTypealias(NominalTypeDecl *nominal, Identifier name, diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.cpp b/lib/ClangImporter/SwiftDeclSynthesizer.cpp index a86608755aae1..1bae0f8d38a81 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.cpp +++ b/lib/ClangImporter/SwiftDeclSynthesizer.cpp @@ -12,6 +12,7 @@ #include "SwiftDeclSynthesizer.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/AttrKind.h" #include "swift/AST/Builtins.h" #include "swift/AST/Expr.h" #include "swift/AST/ParameterList.h" @@ -192,9 +193,12 @@ Type SwiftDeclSynthesizer::getConstantLiteralType( } } -ValueDecl *SwiftDeclSynthesizer::createConstant( - Identifier name, DeclContext *dc, Type type, const clang::APValue &value, - ConstantConvertKind convertKind, bool isStatic, ClangNode ClangN) { +ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name, + DeclContext *dc, Type type, + const clang::APValue &value, + ConstantConvertKind convertKind, + bool isStatic, ClangNode ClangN, + AccessLevel access) { auto &context = ImporterImpl.SwiftContext; // Create the integer literal value. @@ -289,12 +293,16 @@ ValueDecl *SwiftDeclSynthesizer::createConstant( } assert(expr); - return createConstant(name, dc, type, expr, convertKind, isStatic, ClangN); + return createConstant(name, dc, type, expr, convertKind, isStatic, ClangN, + access); } -ValueDecl *SwiftDeclSynthesizer::createConstant( - Identifier name, DeclContext *dc, Type type, StringRef value, - ConstantConvertKind convertKind, bool isStatic, ClangNode ClangN) { +ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name, + DeclContext *dc, Type type, + StringRef value, + ConstantConvertKind convertKind, + bool isStatic, ClangNode ClangN, + AccessLevel access) { ASTContext &ctx = ImporterImpl.SwiftContext; auto expr = new (ctx) StringLiteralExpr(value, SourceRange()); @@ -304,7 +312,8 @@ ValueDecl *SwiftDeclSynthesizer::createConstant( expr->setBuiltinInitializer(ctx.getStringBuiltinInitDecl(stringDecl)); expr->setType(literalType); - return createConstant(name, dc, type, expr, convertKind, isStatic, ClangN); + return createConstant(name, dc, type, expr, convertKind, isStatic, ClangN, + access); } /// Synthesizer callback to synthesize the getter for a constant value. @@ -381,15 +390,18 @@ synthesizeConstantGetterBody(AbstractFunctionDecl *afd, void *voidContext) { /*isTypeChecked=*/true}; } -ValueDecl *SwiftDeclSynthesizer::createConstant( - Identifier name, DeclContext *dc, Type type, Expr *valueExpr, - ConstantConvertKind convertKind, bool isStatic, ClangNode ClangN) { +ValueDecl *SwiftDeclSynthesizer::createConstant(Identifier name, + DeclContext *dc, Type type, + Expr *valueExpr, + ConstantConvertKind convertKind, + bool isStatic, ClangNode ClangN, + AccessLevel access) { auto &C = ImporterImpl.SwiftContext; VarDecl *var = nullptr; if (ClangN) { var = ImporterImpl.createDeclWithClangNode( - ClangN, AccessLevel::Public, + ClangN, access, /*IsStatic*/ isStatic, VarDecl::Introducer::Var, SourceLoc(), name, dc); } else { var = new (C) VarDecl( @@ -497,7 +509,7 @@ SwiftDeclSynthesizer::createDefaultConstructor(NominalTypeDecl *structDecl) { /*GenericParams=*/nullptr, structDecl, /*LifetimeDependentTypeRepr*/ nullptr); - constructor->setAccess(AccessLevel::Public); + constructor->copyFormalAccessFrom(structDecl); // Mark the constructor transparent so that we inline it away completely. constructor->getAttrs().add(new (context) TransparentAttr(/*implicit*/ true)); @@ -628,7 +640,7 @@ ConstructorDecl *SwiftDeclSynthesizer::createValueConstructor( /*GenericParams=*/nullptr, structDecl, /*LifetimeDependentTypeRepr*/ nullptr); - constructor->setAccess(AccessLevel::Public); + constructor->copyFormalAccessFrom(structDecl); // Make the constructor transparent so we inline it away completely. constructor->getAttrs().add(new (context) TransparentAttr(/*implicit*/ true)); @@ -738,7 +750,7 @@ void SwiftDeclSynthesizer::makeStructRawValuedWithBridge( computedVarName, structDecl); computedVar->setInterfaceType(bridgedType); computedVar->setImplicit(); - computedVar->setAccess(AccessLevel::Public); + computedVar->copyFormalAccessFrom(structDecl); computedVar->setSetterAccess(AccessLevel::Private); // Create the getter for the computed value variable. @@ -794,7 +806,7 @@ void SwiftDeclSynthesizer::makeStructRawValued( std::tie(var, patternBinding) = createVarWithPattern( structDecl, ctx.Id_rawValue, underlyingType, introducer, options.contains(MakeStructRawValuedFlags::IsImplicit), - AccessLevel::Public, setterAccess); + structDecl->getFormalAccess(), setterAccess); assert(var->hasStorage()); @@ -1276,7 +1288,7 @@ SwiftDeclSynthesizer::makeEnumRawValueConstructor(EnumDecl *enumDecl) { /*GenericParams=*/nullptr, enumDecl, /*LifetimeDependentTypeRepr*/ nullptr); ctorDecl->setImplicit(); - ctorDecl->setAccess(AccessLevel::Public); + ctorDecl->copyFormalAccessFrom(enumDecl); ctorDecl->setBodySynthesizer(synthesizeEnumRawValueConstructorBody, enumDecl); return ctorDecl; } @@ -1352,7 +1364,7 @@ void SwiftDeclSynthesizer::makeEnumRawValueGetter(EnumDecl *enumDecl, getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(false); - getterDecl->setAccess(AccessLevel::Public); + getterDecl->copyFormalAccessFrom(enumDecl); getterDecl->setBodySynthesizer(synthesizeEnumRawValueGetterBody, enumDecl); ImporterImpl.makeComputed(rawValueDecl, getterDecl, nullptr); } @@ -1416,7 +1428,7 @@ AccessorDecl *SwiftDeclSynthesizer::makeStructRawValueGetter( getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(false); - getterDecl->setAccess(AccessLevel::Public); + getterDecl->copyFormalAccessFrom(structDecl); getterDecl->setBodySynthesizer(synthesizeStructRawValueGetterBody, storedVar); return getterDecl; } @@ -1696,7 +1708,7 @@ SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter, ctx, name, getterImpl->getLoc(), bodyParams, getterImpl->getLoc(), elementTy, dc, getterImpl->getGenericParams(), getterImpl->getClangNode()); - subscript->setAccess(AccessLevel::Public); + subscript->copyFormalAccessFrom(getterImpl); AccessorDecl *getterDecl = AccessorDecl::create(ctx, getterImpl->getLoc(), getterImpl->getLoc(), @@ -1704,7 +1716,7 @@ SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), bodyParams, elementTy, dc); - getterDecl->setAccess(AccessLevel::Public); + getterDecl->copyFormalAccessFrom(subscript); getterDecl->setImplicit(); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(true); @@ -1732,7 +1744,7 @@ SubscriptDecl *SwiftDeclSynthesizer::makeSubscript(FuncDecl *getter, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), setterParamList, TupleType::getEmpty(ctx), dc); - setterDecl->setAccess(AccessLevel::Public); + setterDecl->copyFormalAccessFrom(subscript); setterDecl->setImplicit(); setterDecl->setIsDynamic(false); setterDecl->setIsTransparent(true); @@ -1782,7 +1794,7 @@ SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter, VarDecl(/*isStatic*/ false, VarDecl::Introducer::Var, getterImpl->getStartLoc(), ctx.getIdentifier("pointee"), dc); result->setInterfaceType(elementTy); - result->setAccess(AccessLevel::Public); + result->copyFormalAccessFrom(getterImpl); AccessorDecl *getterDecl = AccessorDecl::create( ctx, getterImpl->getLoc(), getterImpl->getLoc(), @@ -1791,7 +1803,7 @@ SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter, /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), ParameterList::createEmpty(ctx), useAddress ? elementTy->wrapInPointer(PTK_UnsafePointer) : elementTy, dc); - getterDecl->setAccess(AccessLevel::Public); + getterDecl->copyFormalAccessFrom(getterImpl); if (isImplicit) getterDecl->setImplicit(); getterDecl->setIsDynamic(false); @@ -1830,7 +1842,7 @@ SwiftDeclSynthesizer::makeDereferencedPointeeProperty(FuncDecl *getter, useAddress ? elementTy->wrapInPointer(PTK_UnsafeMutablePointer) : TupleType::getEmpty(ctx), dc); - setterDecl->setAccess(AccessLevel::Public); + setterDecl->copyFormalAccessFrom(setterImpl); if (isImplicit) setterDecl->setImplicit(); setterDecl->setIsDynamic(false); @@ -1883,7 +1895,8 @@ synthesizeSuccessorFuncBody(AbstractFunctionDecl *afd, void *context) { std::tie(copyDecl, patternDecl) = SwiftDeclSynthesizer::createVarWithPattern( successorDecl, ctx.getIdentifier("__copy"), returnTy, VarDecl::Introducer::Var, - /*isImplicit*/ true, AccessLevel::Public, AccessLevel::Public); + /*isImplicit*/ true, successorDecl->getFormalAccess(), + successorDecl->getFormalAccess()); auto copyRefLValueExpr = new (ctx) DeclRefExpr(copyDecl, DeclNameLoc(), /*implicit*/ true); @@ -1931,7 +1944,7 @@ FuncDecl *SwiftDeclSynthesizer::makeSuccessorFunc(FuncDecl *incrementFunc) { /*Async*/ false, /*Throws*/ false, /*ThrownType=*/Type(), /*GenericParams*/ nullptr, params, returnTy, dc); - result->setAccess(AccessLevel::Public); + result->copyFormalAccessFrom(incrementFunc); result->setIsDynamic(false); result->setBodySynthesizer(synthesizeSuccessorFuncBody, incrementFunc); @@ -2234,7 +2247,7 @@ SwiftDeclSynthesizer::makeOperator(FuncDecl *operatorMethod, genericParamList, ParameterList::create(ctx, newParams), operatorMethod->getResultInterfaceType(), parentCtx); - topLevelStaticFuncDecl->setAccess(AccessLevel::Public); + topLevelStaticFuncDecl->copyFormalAccessFrom(operatorMethod); topLevelStaticFuncDecl->setIsDynamic(false); topLevelStaticFuncDecl->setStatic(); topLevelStaticFuncDecl->setBodySynthesizer(synthesizeOperatorMethodBody, @@ -2344,7 +2357,7 @@ SwiftDeclSynthesizer::makeComputedPropertyFromCXXMethods(FuncDecl *getter, new (ctx) VarDecl(false, VarDecl::Introducer::Var, getter->getStartLoc(), ctx.getIdentifier(importedName), dc); result->setInterfaceType(getter->getResultInterfaceType()); - result->setAccess(AccessLevel::Public); + result->copyFormalAccessFrom(getter); result->setImplInfo(StorageImplInfo::getMutableComputed()); AccessorDecl *getterDecl = AccessorDecl::create( @@ -2353,7 +2366,7 @@ SwiftDeclSynthesizer::makeComputedPropertyFromCXXMethods(FuncDecl *getter, /*throws*/ false, SourceLoc(), /*ThrownType=*/TypeLoc(), ParameterList::createEmpty(ctx), getter->getResultInterfaceType(), dc); - getterDecl->setAccess(AccessLevel::Public); + getterDecl->copyFormalAccessFrom(getter); getterDecl->setImplicit(); getterDecl->setIsDynamic(false); getterDecl->setIsTransparent(true); @@ -2378,7 +2391,7 @@ SwiftDeclSynthesizer::makeComputedPropertyFromCXXMethods(FuncDecl *getter, /*async*/ false, SourceLoc(), /*throws*/ false, SourceLoc(), /*thrownType*/ TypeLoc(), setterParamList, setter->getResultInterfaceType(), dc); - setterDecl->setAccess(AccessLevel::Public); + setterDecl->copyFormalAccessFrom(setter); setterDecl->setImplicit(); setterDecl->setIsDynamic(false); setterDecl->setIsTransparent(true); diff --git a/lib/ClangImporter/SwiftDeclSynthesizer.h b/lib/ClangImporter/SwiftDeclSynthesizer.h index e7ab62a46e7ab..1cd13732189b8 100644 --- a/lib/ClangImporter/SwiftDeclSynthesizer.h +++ b/lib/ClangImporter/SwiftDeclSynthesizer.h @@ -84,10 +84,11 @@ class SwiftDeclSynthesizer { /// \param value The value of the named constant. /// \param convertKind How to convert the constant to the given type. /// \param isStatic Whether the constant should be a static member of \p dc. + /// \param access What access level should be given to the constant. ValueDecl *createConstant(Identifier name, DeclContext *dc, Type type, const clang::APValue &value, ConstantConvertKind convertKind, bool isStatic, - ClangNode ClangN); + ClangNode ClangN, AccessLevel access); /// Create a new named constant with the given value. /// @@ -97,9 +98,11 @@ class SwiftDeclSynthesizer { /// \param value The value of the named constant. /// \param convertKind How to convert the constant to the given type. /// \param isStatic Whether the constant should be a static member of \p dc. + /// \param access What access level should be given to the constant. ValueDecl *createConstant(Identifier name, DeclContext *dc, Type type, StringRef value, ConstantConvertKind convertKind, - bool isStatic, ClangNode ClangN); + bool isStatic, ClangNode ClangN, + AccessLevel access); /// Create a new named constant using the given expression. /// @@ -109,9 +112,11 @@ class SwiftDeclSynthesizer { /// \param valueExpr An expression to use as the value of the constant. /// \param convertKind How to convert the constant to the given type. /// \param isStatic Whether the constant should be a static member of \p dc. + /// \param access What access level should be given to the constant. ValueDecl *createConstant(Identifier name, DeclContext *dc, Type type, Expr *valueExpr, ConstantConvertKind convertKind, - bool isStatic, ClangNode ClangN); + bool isStatic, ClangNode ClangN, + AccessLevel access); /// Create a default constructor that initializes a struct to zero. ConstructorDecl *createDefaultConstructor(NominalTypeDecl *structDecl); diff --git a/test/Interop/Cxx/class/Inputs/access-inversion.h b/test/Interop/Cxx/class/Inputs/access-inversion.h new file mode 100644 index 0000000000000..65fbc96d83228 --- /dev/null +++ b/test/Interop/Cxx/class/Inputs/access-inversion.h @@ -0,0 +1,86 @@ +#ifndef TEST_INTEROP_CXX_CLASS_INPUTS_ACCESS_INVERSION_H +#define TEST_INTEROP_CXX_CLASS_INPUTS_ACCESS_INVERSION_H + +/// A record whose public members expose private members +struct Leaky { +public: + Leaky() { + } // Apparently necessary to ensure constructor is unambiguous in Swift + +private: + typedef bool PrivateAlias; + + struct PrivateRec { + public: + void privateRecMethod() const {} + static const bool PRIVATE_REC_CONST = true; + }; + + enum PrivateEnum { privateEnumMember }; + + enum class PrivateEnumClass { privateEnumClassMember }; + + static const bool PRIVATE_CONST = true; + + // These are used as return values in functions that return private types + static PrivateAlias privateAliasVal; + static PrivateRec privateRecVal; + static PrivateEnum privateEnumVal; + static PrivateEnumClass privateEnumClassVal; + +public: + typedef PrivateAlias AliasToPrivateAlias; + typedef PrivateRec AliasToPrivateRec; + typedef PrivateEnum AliasToPrivateEnum; + typedef PrivateEnumClass AliasToPrivateEnumClass; + + struct RecWithPrivateAlias { + PrivateAlias mem; + }; + struct RecWithPrivateRec { + PrivateRec mem; + }; + struct RecWithPrivateEnum { + PrivateEnum mem; + }; + struct RecWithPrivateEnumClass { + PrivateEnumClass mem; + }; + struct RecWithPrivateConst { + const bool mem = PRIVATE_CONST; + }; + + static PrivateAlias staticReturningPrivateAlias() { return privateAliasVal; } + static PrivateRec staticReturningPrivateRec() { return privateRecVal; } + static PrivateEnum staticReturningPrivateEnum() { return privateEnumVal; } + static PrivateEnumClass staticReturningPrivateEnumClass() { + return privateEnumClassVal; + } + + static void staticTakingPrivateAlias(PrivateAlias p) {} + static void staticTakingPrivateRec(PrivateRec p) {} + static void staticTakingPrivateEnum(PrivateEnum p) {} + static void staticTakingPrivateEnumClass(PrivateEnumClass p) {} + + PrivateAlias methodReturningPrivateAlias() const { return privateAliasVal; } + PrivateRec methodReturningPrivateRec() const { return privateRecVal; } + PrivateEnum methodReturningPrivateEnum() const { return privateEnumVal; } + PrivateEnumClass methodReturningPrivateEnumClass() const { + return privateEnumClassVal; + } + + void methodTakingPrivateAlias(PrivateAlias p) const {} + void methodTakingPrivateRec(PrivateRec p) const {} + void methodTakingPrivateEnum(PrivateEnum p) const {} + void methodTakingPrivateEnumClass(PrivateEnumClass p) const {} + + void defaultArgOfPrivateRec(PrivateRec a = privateRecVal) const {} + void defaultArgOfPrivateEnum(PrivateEnum a = privateEnumMember) const {} + void defaultArgOfPrivateEnumClass( + PrivateEnumClass a = PrivateEnumClass::privateEnumClassMember) const {} + void defaultArgOfPrivateConst(bool a = PRIVATE_CONST) const {} + void + defaultArgOfPrivateRecConst(bool a = PrivateRec::PRIVATE_REC_CONST) const {} +}; + +#endif diff --git a/test/Interop/Cxx/class/Inputs/access-specifiers.h b/test/Interop/Cxx/class/Inputs/access-specifiers.h index fc2c1ecdaf0fd..f2e1623f09f66 100644 --- a/test/Interop/Cxx/class/Inputs/access-specifiers.h +++ b/test/Interop/Cxx/class/Inputs/access-specifiers.h @@ -10,7 +10,7 @@ class PublicPrivate { typedef int PublicTypedef; struct PublicStruct {}; enum PublicEnum { PublicEnumValue1 }; - enum { PublicAnonymousEnumValue }; + enum { PublicAnonymousEnumValue1 }; enum PublicClosedEnum { PublicClosedEnumValue1 } __attribute__((enum_extensibility(closed))); diff --git a/test/Interop/Cxx/class/Inputs/module.modulemap b/test/Interop/Cxx/class/Inputs/module.modulemap index adf85a1b7be88..40db420bb2a7d 100644 --- a/test/Interop/Cxx/class/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/Inputs/module.modulemap @@ -1,3 +1,8 @@ +module AccessInversion { + header "access-inversion.h" + requires cplusplus +} + module AccessSpecifiers { header "access-specifiers.h" requires cplusplus diff --git a/test/Interop/Cxx/class/access-inversion-executable.swift b/test/Interop/Cxx/class/access-inversion-executable.swift new file mode 100644 index 0000000000000..175afde0997bc --- /dev/null +++ b/test/Interop/Cxx/class/access-inversion-executable.swift @@ -0,0 +1,54 @@ +// Testing a C++ type whose public members expose private members. +// +// The typechecker test covers most of the interesting cases, which all happen +// during semantic checking and shouldn't really affect execution. This +// executable test only exists to make sure we don't hit any unexpected +// assertions about access level invariants during latter stages of compilation, +// and does not exhaustively test runtime behavior (which is not very interesting). + +// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=default) +// +// REQUIRES: executable_test + +import StdlibUnittest +import AccessInversion + +var AccessInversionTestSuite = TestSuite("AccessInversion") + +AccessInversionTestSuite.test("usePrivateAlias") { + let a: Leaky.AliasToPrivateAlias = true + expectEqual(a, true) +} + +AccessInversionTestSuite.test("usePrivateRec") { + let p = Leaky.staticReturningPrivateRec() + // p.privateRecMethod() + var r = Leaky.RecWithPrivateRec() + r.mem = p +} + +AccessInversionTestSuite.test("usePrivateEnum") { + let e = Leaky.AliasToPrivateEnum(rawValue: 0)! + expectEqual(e.rawValue, 0) +} + +AccessInversionTestSuite.test("usePrivateEnumClass") { + let e = Leaky.AliasToPrivateEnumClass(rawValue: 0)! + + switch e { + default: + // There is not much to test since we can't access private enums' variants + expectEqual(e.rawValue, 0) + } +} + +AccessInversionTestSuite.test("usePrivateDefaultArgs") { + let leaky = Leaky() + leaky.defaultArgOfPrivateRec() + leaky.defaultArgOfPrivateEnum() + leaky.defaultArgOfPrivateEnumClass() + leaky.defaultArgOfPrivateConst() + leaky.defaultArgOfPrivateRecConst() +} + +runAllTests() diff --git a/test/Interop/Cxx/class/access-inversion-module-interface.swift b/test/Interop/Cxx/class/access-inversion-module-interface.swift new file mode 100644 index 0000000000000..3d91c42f894b3 --- /dev/null +++ b/test/Interop/Cxx/class/access-inversion-module-interface.swift @@ -0,0 +1,96 @@ +// RUN: %target-swift-ide-test -print-module -print-access -module-to-print=AccessInversion -I %S/Inputs -source-filename=x -cxx-interoperability-mode=default | %FileCheck %s + +// CHECK: public struct Leaky { + +// CHECK: private typealias PrivateAlias = Bool + +// CHECK: private struct PrivateRec { +// CHECK: public init() +// CHECK: private init() +// CHECK: public func privateRecMethod() +// CHECK: public static let PRIVATE_REC_CONST: Bool +// CHECK: } + +// CHECK: private struct PrivateEnum : Hashable, Equatable, RawRepresentable { +// CHECK: private init(_ rawValue: [[ENUM_RV_T:.*]]) +// CHECK: private init(rawValue: [[ENUM_RV_T]]) +// CHECK: private var rawValue: [[ENUM_RV_T]] +// CHECK: private typealias RawValue = [[ENUM_RV_T]] +// CHECK: } + +// CHECK: private enum PrivateEnumClass : [[ENUM_CLASS_RV_T:.*]] { +// CHECK: private init?(rawValue: [[ENUM_CLASS_RV_T]]) +// CHECK: private var rawValue: [[ENUM_CLASS_RV_T]] { get } +// CHECK: private typealias RawValue = [[ENUM_CLASS_RV_T]] +// CHECK: case privateEnumClassMember +// CHECK: } + +// CHECK: private static let PRIVATE_CONST: Bool + +// CHECK: private static var privateAliasVal: Leaky.PrivateAlias +// CHECK: private static var privateRecVal: Leaky.PrivateRec +// CHECK: private static var privateEnumVal: Leaky.PrivateEnum +// CHECK: private static var privateEnumClassVal: Leaky.PrivateEnumClass + +// CHECK: public typealias AliasToPrivateAlias = Leaky.PrivateAlias +// CHECK: public typealias AliasToPrivateRec = Leaky.PrivateRec +// CHECK: public typealias AliasToPrivateEnum = Leaky.PrivateEnum +// CHECK: public typealias AliasToPrivateEnumClass = Leaky.PrivateEnumClass + +// CHECK: public struct RecWithPrivateAlias { +// CHECK: public init() +// CHECK: public init(mem: Leaky.PrivateAlias) +// CHECK: public var mem: Leaky.PrivateAlias +// CHECK: } + +// CHECK: public struct RecWithPrivateRec { +// CHECK: public init() +// CHECK: public init(mem: Leaky.PrivateRec) +// CHECK: public var mem: Leaky.PrivateRec +// CHECK: } + +// CHECK: public struct RecWithPrivateEnum { +// CHECK: public init() +// CHECK: public init(mem: Leaky.PrivateEnum) +// CHECK: public var mem: Leaky.PrivateEnum +// CHECK: } + +// CHECK: public struct RecWithPrivateEnumClass { +// CHECK: public init() +// CHECK: public init(mem: Leaky.PrivateEnumClass) +// CHECK: public var mem: Leaky.PrivateEnumClass +// CHECK: } + +// CHECK: public struct RecWithPrivateConst { +// CHECK: public init() +// CHECK: public init(mem: Bool) +// CHECK: public var mem: Bool { get } +// CHECK: } + +// CHECK: public static func staticReturningPrivateAlias() -> Leaky.PrivateAlias +// CHECK: public static func staticReturningPrivateRec() -> Leaky.PrivateRec +// CHECK: public static func staticReturningPrivateEnum() -> Leaky.PrivateEnum +// CHECK: public static func staticReturningPrivateEnumClass() -> Leaky.PrivateEnumClass + +// CHECK: public static func staticTakingPrivateAlias(_ p: Leaky.PrivateAlias) +// CHECK: public static func staticTakingPrivateRec(_ p: Leaky.PrivateRec) +// CHECK: public static func staticTakingPrivateEnum(_ p: Leaky.PrivateEnum) +// CHECK: public static func staticTakingPrivateEnumClass(_ p: Leaky.PrivateEnumClass) + +// CHECK: public func methodReturningPrivateAlias() -> Leaky.PrivateAlias +// CHECK: public func methodReturningPrivateRec() -> Leaky.PrivateRec +// CHECK: public func methodReturningPrivateEnum() -> Leaky.PrivateEnum +// CHECK: public func methodReturningPrivateEnumClass() -> Leaky.PrivateEnumClass + +// CHECK: public func methodTakingPrivateAlias(_ p: Leaky.PrivateAlias) +// CHECK: public func methodTakingPrivateRec(_ p: Leaky.PrivateRec) +// CHECK: public func methodTakingPrivateEnum(_ p: Leaky.PrivateEnum) +// CHECK: public func methodTakingPrivateEnumClass(_ p: Leaky.PrivateEnumClass) + +// CHECK: public func defaultArgOfPrivateRec(_ a: Leaky.PrivateRec = cxxDefaultArg) +// CHECK: public func defaultArgOfPrivateEnum(_ a: Leaky.PrivateEnum = cxxDefaultArg) +// CHECK: public func defaultArgOfPrivateEnumClass(_ a: Leaky.PrivateEnumClass = cxxDefaultArg) +// CHECK: public func defaultArgOfPrivateConst(_ a: Bool = cxxDefaultArg) +// CHECK: public func defaultArgOfPrivateRecConst(_ a: Bool = cxxDefaultArg) + +// CHECK: } diff --git a/test/Interop/Cxx/class/access-inversion-typechecker.swift b/test/Interop/Cxx/class/access-inversion-typechecker.swift new file mode 100644 index 0000000000000..4359450f1211e --- /dev/null +++ b/test/Interop/Cxx/class/access-inversion-typechecker.swift @@ -0,0 +1,327 @@ +// Testing a C++ type whose public members expose private members. +// +// This test effectively documents the expected behavior at this time of writing, +// but does not necessarily specify it (in the deliberate sense). In other words, +// there may be behaviors captured in these tests that deserve amending. + +// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default + +import AccessInversion + +let _ = Leaky() // A sanity check that just instantiating this doesn't cause trouble + +func doSomething() { /* do nothing, actually :-) */ } + +func usePrivateAlias(a: inout Leaky.AliasToPrivateAlias) -> Leaky.AliasToPrivateAlias { + let leaky = Leaky() + var r = Leaky.RecWithPrivateAlias() + + // + // Binding (and annotating) PrivateAlias + // + + let _ = a + let _: Bool = a + let _: Leaky.AliasToPrivateAlias = a + let _: Leaky.PrivateAlias = a + // expected-error@-1 {{'PrivateAlias' is inaccessible due to 'private' protection level}} + + let _ = r.mem + let _: Bool = r.mem + let _: Leaky.AliasToPrivateAlias = r.mem + let _: Leaky.PrivateAlias = r.mem + // expected-error@-1 {{'PrivateAlias' is inaccessible due to 'private' protection level}} + + let _ = Leaky.staticReturningPrivateAlias() + let _: Bool = Leaky.staticReturningPrivateAlias() + let _: Leaky.AliasToPrivateAlias = Leaky.staticReturningPrivateAlias() + let _: Leaky.PrivateAlias = Leaky.staticReturningPrivateAlias() + // expected-error@-1 {{'PrivateAlias' is inaccessible due to 'private' protection level}} + + let _ = leaky.methodReturningPrivateAlias() + let _: Bool = leaky.methodReturningPrivateAlias() + let _: Leaky.AliasToPrivateAlias = leaky.methodReturningPrivateAlias() + let _: Leaky.PrivateAlias = leaky.methodReturningPrivateAlias() + // expected-error@-1 {{'PrivateAlias' is inaccessible due to 'private' protection level}} + + // + // Assigning/applying to PrivateAlias + // + + a = true + // a = a + a = r.mem + a = Leaky.staticReturningPrivateAlias() + a = leaky.methodReturningPrivateAlias() + + r.mem = true + r.mem = a + // r.mem = r.mem + r.mem = Leaky.staticReturningPrivateAlias() + r.mem = leaky.methodReturningPrivateAlias() + + Leaky.staticTakingPrivateAlias(true) + Leaky.staticTakingPrivateAlias(a) + Leaky.staticTakingPrivateAlias(r.mem) + Leaky.staticTakingPrivateAlias(Leaky.staticReturningPrivateAlias()) + Leaky.staticTakingPrivateAlias(leaky.methodReturningPrivateAlias()) + + leaky.methodTakingPrivateAlias(true) + leaky.methodTakingPrivateAlias(a) + leaky.methodTakingPrivateAlias(r.mem) + leaky.methodTakingPrivateAlias(Leaky.staticReturningPrivateAlias()) + leaky.methodTakingPrivateAlias(leaky.methodReturningPrivateAlias()) + + // + // Using PrivateAlias + // + + if a { doSomething() } + if r.mem { doSomething() } + if Leaky.staticReturningPrivateAlias() { doSomething() } + if leaky.methodReturningPrivateAlias() { doSomething() } +} + +func usePrivateRec(a: inout Leaky.AliasToPrivateRec) -> Leaky.AliasToPrivateRec { + let leaky = Leaky() + var r = Leaky.RecWithPrivateRec() + + // + // Binding (and annotating) PrivateRec + // + + let _ = a + let _: Leaky.AliasToPrivateRec = a + let _: Leaky.PrivateRec = a + // expected-error@-1 {{'PrivateRec' is inaccessible due to 'private' protection level}} + + let _ = r.mem + let _: Leaky.AliasToPrivateRec = r.mem + let _: Leaky.PrivateRec = r.mem + // expected-error@-1 {{'PrivateRec' is inaccessible due to 'private' protection level}} + + let _ = Leaky.staticReturningPrivateRec() + let _: Leaky.AliasToPrivateRec = Leaky.staticReturningPrivateRec() + let _: Leaky.PrivateRec = Leaky.staticReturningPrivateRec() + // expected-error@-1 {{'PrivateRec' is inaccessible due to 'private' protection level}} + + let _ = leaky.methodReturningPrivateRec() + let _: Leaky.AliasToPrivateRec = leaky.methodReturningPrivateRec() + let _: Leaky.PrivateRec = leaky.methodReturningPrivateRec() + // expected-error@-1 {{'PrivateRec' is inaccessible due to 'private' protection level}} + + // + // Assigning/applying to PrivateRec + // + + // a = a + a = r.mem + a = Leaky.staticReturningPrivateRec() + a = leaky.methodReturningPrivateRec() + + r.mem = a + // r.mem = r.mem + r.mem = Leaky.staticReturningPrivateRec() + r.mem = leaky.methodReturningPrivateRec() + + Leaky.staticTakingPrivateRec(a) + Leaky.staticTakingPrivateRec(r.mem) + Leaky.staticTakingPrivateRec(Leaky.staticReturningPrivateRec()) + Leaky.staticTakingPrivateRec(leaky.methodReturningPrivateRec()) + + leaky.methodTakingPrivateRec(a) + leaky.methodTakingPrivateRec(r.mem) + leaky.methodTakingPrivateRec(Leaky.staticReturningPrivateRec()) + leaky.methodTakingPrivateRec(leaky.methodReturningPrivateRec()) + + // + // Using PrivateRec + // + + // NOTE: privateRecMethod() is not accessible here even though it is + // a public method of PrivateRec. + + a.privateRecMethod() + // expected-error@-1 {{'privateRecMethod' is inaccessible due to 'private' protection level}} + r.mem.privateRecMethod() + // expected-error@-1 {{'privateRecMethod' is inaccessible due to 'private' protection level}} + Leaky.staticReturningPrivateRec().privateRecMethod() + // expected-error@-1 {{'privateRecMethod' is inaccessible due to 'private' protection level}} + leaky.methodReturningPrivateRec().privateRecMethod() + // expected-error@-1 {{'privateRecMethod' is inaccessible due to 'private' protection level}} +} + +func usePrivateEnum(a: inout Leaky.AliasToPrivateEnum) -> Leaky.AliasToPrivateEnum { + let leaky = Leaky() + var r = Leaky.RecWithPrivateEnum() + + // + // Binding (and annotating) PrivateEnum + // + + let _ = a + let _: Leaky.AliasToPrivateEnum = a + let _: Leaky.PrivateEnum = a + // expected-error@-1 {{'PrivateEnum' is inaccessible due to 'private' protection level}} + + let _ = r.mem + let _: Leaky.AliasToPrivateEnum = r.mem + let _: Leaky.PrivateEnum = r.mem + // expected-error@-1 {{'PrivateEnum' is inaccessible due to 'private' protection level}} + + let _ = Leaky.staticReturningPrivateEnum() + let _: Leaky.AliasToPrivateEnum = Leaky.staticReturningPrivateEnum() + let _: Leaky.PrivateEnum = Leaky.staticReturningPrivateEnum() + // expected-error@-1 {{'PrivateEnum' is inaccessible due to 'private' protection level}} + + let _ = leaky.methodReturningPrivateEnum() + let _: Leaky.AliasToPrivateEnum = leaky.methodReturningPrivateEnum() + let _: Leaky.PrivateEnum = leaky.methodReturningPrivateEnum() + // expected-error@-1 {{'PrivateEnum' is inaccessible due to 'private' protection level}} + + // + // Assigning/applying to PrivateEnum + // + + // a = a + a = r.mem + a = Leaky.staticReturningPrivateEnum() + a = leaky.methodReturningPrivateEnum() + + r.mem = a + // r.mem = r.mem + r.mem = Leaky.staticReturningPrivateEnum() + r.mem = leaky.methodReturningPrivateEnum() + + Leaky.staticTakingPrivateEnum(a) + Leaky.staticTakingPrivateEnum(r.mem) + Leaky.staticTakingPrivateEnum(Leaky.staticReturningPrivateEnum()) + Leaky.staticTakingPrivateEnum(leaky.methodReturningPrivateEnum()) + + leaky.methodTakingPrivateEnum(a) + leaky.methodTakingPrivateEnum(r.mem) + leaky.methodTakingPrivateEnum(Leaky.staticReturningPrivateEnum()) + leaky.methodTakingPrivateEnum(leaky.methodReturningPrivateEnum()) + + // + // Constructing and reading PrivateEnum + // + + // TODO: nested enum members are not being imported (#54905) + // let _ = Leaky.privateEnumMember + let rv0 = Leaky.AliasToPrivateEnum(rawValue: 0)! + let _ = Leaky.PrivateEnum(rawValue: 0)! + // expected-error@-1 {{'PrivateEnum' is inaccessible due to 'private' protection level}} + + let _ = rv0.rawValue + let _: Leaky.AliasToPrivateEnum.RawValue = rv0.rawValue + let _: Leaky.PrivateEnum.RawValue = rv0.rawValue + // expected-error@-1 {{'PrivateEnum' is inaccessible due to 'private' protection level}} +} + +func usePrivateEnumClass(a: inout Leaky.AliasToPrivateEnumClass) -> Leaky.AliasToPrivateEnumClass { + let leaky = Leaky() + var r = Leaky.RecWithPrivateEnumClass() + + // + // Binding (and annotating) PrivateEnumClass + // + + let _ = a + let _: Leaky.AliasToPrivateEnumClass = a + let _: Leaky.PrivateEnumClass = a + // expected-error@-1 {{'PrivateEnumClass' is inaccessible due to 'private' protection level}} + + let _ = r.mem + let _: Leaky.AliasToPrivateEnumClass = r.mem + let _: Leaky.PrivateEnumClass = r.mem + // expected-error@-1 {{'PrivateEnumClass' is inaccessible due to 'private' protection level}} + + let _ = Leaky.staticReturningPrivateEnumClass() + let _: Leaky.AliasToPrivateEnumClass = Leaky.staticReturningPrivateEnumClass() + let _: Leaky.PrivateEnumClass = Leaky.staticReturningPrivateEnumClass() + // expected-error@-1 {{'PrivateEnumClass' is inaccessible due to 'private' protection level}} + + let _ = leaky.methodReturningPrivateEnumClass() + let _: Leaky.AliasToPrivateEnumClass = leaky.methodReturningPrivateEnumClass() + let _: Leaky.PrivateEnumClass = leaky.methodReturningPrivateEnumClass() + // expected-error@-1 {{'PrivateEnumClass' is inaccessible due to 'private' protection level}} + + // + // Assigning/applying to PrivateEnumClass + // + + // a = a + a = r.mem + a = Leaky.staticReturningPrivateEnumClass() + a = leaky.methodReturningPrivateEnumClass() + + r.mem = a + // r.mem = r.mem + r.mem = Leaky.staticReturningPrivateEnumClass() + r.mem = leaky.methodReturningPrivateEnumClass() + + Leaky.staticTakingPrivateEnumClass(a) + Leaky.staticTakingPrivateEnumClass(r.mem) + Leaky.staticTakingPrivateEnumClass(Leaky.staticReturningPrivateEnumClass()) + Leaky.staticTakingPrivateEnumClass(leaky.methodReturningPrivateEnumClass()) + + leaky.methodTakingPrivateEnumClass(a) + leaky.methodTakingPrivateEnumClass(r.mem) + leaky.methodTakingPrivateEnumClass(Leaky.staticReturningPrivateEnumClass()) + leaky.methodTakingPrivateEnumClass(leaky.methodReturningPrivateEnumClass()) + + // + // Constructing and reading PrivateEnumClass + // + + // NOTE: private enum class members are not accessible even if we can access + // instances of the private enum class via + + let _ = Leaky.AliasToPrivateEnumClass.privateEnumClassMember + // expected-error@-1 {{'privateEnumClassMember' is inaccessible due to 'private' protection level}} + let _ = Leaky.PrivateEnumClass.privateEnumClassMember + // expected-error@-1 {{'PrivateEnumClass' is inaccessible due to 'private' protection level}} + let _: Leaky.AliasToPrivateEnum = .privateEnumClassMember + // expected-error@-1 {{type 'Leaky.AliasToPrivateEnum' (aka 'Leaky.PrivateEnum') has no member 'privateEnumClassMember'}} + // TODO: ^this is not really the right error message + + let rv0 = Leaky.AliasToPrivateEnumClass(rawValue: 0)! + let _ = Leaky.PrivateEnumClass(rawValue: 0)! + // expected-error@-1 {{'PrivateEnumClass' is inaccessible due to 'private' protection level}} + + let _ = rv0.rawValue + let _: Leaky.AliasToPrivateEnumClass.RawValue = rv0.rawValue + let _: Leaky.PrivateEnumClass.RawValue = rv0.rawValue + // expected-error@-1 {{'PrivateEnumClass' is inaccessible due to 'private' protection level}} + + switch rv0 { + case .privateEnumClassMember: + // expected-error@-1 {{'privateEnumClassMember' is inaccessible due to 'private' protection level}} + doSomething() + default: + doSomething() + } +} + +func usePrivateDefaultArgs(leaky: Leaky) { + leaky.defaultArgOfPrivateRec() + leaky.defaultArgOfPrivateEnum() + leaky.defaultArgOfPrivateEnumClass() + leaky.defaultArgOfPrivateConst() + leaky.defaultArgOfPrivateRecConst() +} + +let privateAlias = Leaky.staticReturningPrivateAlias() +// expected-error@-1 {{constant must be declared private or fileprivate because its type 'Leaky.PrivateAlias' (aka 'Bool') uses a private type}} +let privateRec = Leaky.staticReturningPrivateRec() +// expected-error@-1 {{constant must be declared private or fileprivate because its type 'Leaky.PrivateRec' uses a private type}} +let privateEnum = Leaky.staticReturningPrivateEnum() +// expected-error@-1 {{constant must be declared private or fileprivate because its type 'Leaky.PrivateEnum' uses a private type}} +let privateEnumClass = Leaky.staticReturningPrivateEnumClass() +// expected-error@-1 {{constant must be declared private or fileprivate because its type 'Leaky.PrivateEnumClass' uses a private type}} + +let aliasedPrivateAlias: Leaky.AliasToPrivateAlias = Leaky.staticReturningPrivateAlias() +let aliasedPrivateRec: Leaky.AliasToPrivateRec = Leaky.staticReturningPrivateRec() +let aliasedPrivateEnum: Leaky.AliasToPrivateEnum = Leaky.staticReturningPrivateEnum() +let aliasedPrivateEnumClass: Leaky.AliasToPrivateEnumClass = Leaky.staticReturningPrivateEnumClass() diff --git a/test/Interop/Cxx/class/access-specifiers-module-interface.swift b/test/Interop/Cxx/class/access-specifiers-module-interface.swift index 168a8df69e2fa..de8e86f177ccc 100644 --- a/test/Interop/Cxx/class/access-specifiers-module-interface.swift +++ b/test/Interop/Cxx/class/access-specifiers-module-interface.swift @@ -1,44 +1,81 @@ // Test module interface produced for C++ access specifiers test. -// In particular, we don't want any of the private members showing up here. +// Public C++ members should be imported with Swift-public access, and +// private C++ members should be imported with Swift-private access. -// RUN: %target-swift-ide-test -print-module -module-to-print=AccessSpecifiers -access-filter-public -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s +// RUN: %target-swift-ide-test -print-module -module-to-print=AccessSpecifiers -print-access -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s -// CHECK: struct PublicPrivate { -// CHECK-NEXT: init() -// CHECK-NEXT: static var PublicStaticMemberVar: Int32 -// CHECK-NEXT: mutating func publicMemberFunc() -// CHECK-NEXT: typealias PublicTypedef = Int32 -// CHECK-NEXT: struct PublicStruct { +// CHECK: public struct PublicPrivate { +// CHECK-NEXT: public init() +// CHECK-NEXT: public static var PublicStaticMemberVar: Int32 +// CHECK-NEXT: public mutating func publicMemberFunc() +// CHECK-NEXT: public typealias PublicTypedef = Int32 +// CHECK-NEXT: public struct PublicStruct { // CHECK-NEXT: init() // CHECK-NEXT: } -// CHECK-NEXT: struct PublicEnum : Hashable, Equatable, RawRepresentable { -// CHECK-NEXT: init(_ rawValue: [[ENUM_UNDERLYING_TYPE:Int32|UInt32]]) -// CHECK-NEXT: init(rawValue: [[ENUM_UNDERLYING_TYPE]]) -// CHECK-NEXT: var rawValue: [[ENUM_UNDERLYING_TYPE]] -// CHECK-NEXT: typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: public struct PublicEnum : Hashable, Equatable, RawRepresentable { +// CHECK-NEXT: public init(_ rawValue: [[ENUM_UNDERLYING_TYPE:Int32|UInt32]]) +// CHECK-NEXT: public init(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: public var rawValue: [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: public typealias RawValue = [[ENUM_UNDERLYING_TYPE]] // CHECK-NEXT: } -// CHECK-NEXT: @frozen enum PublicClosedEnum : [[ENUM_UNDERLYING_TYPE]], @unchecked Sendable { -// CHECK-NEXT: init?(rawValue: [[ENUM_UNDERLYING_TYPE]]) -// CHECK-NEXT: var rawValue: [[ENUM_UNDERLYING_TYPE]] { get } -// CHECK-NEXT: typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: @frozen public enum PublicClosedEnum : [[ENUM_UNDERLYING_TYPE]], @unchecked Sendable { +// CHECK-NEXT: public init?(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: public var rawValue: [[ENUM_UNDERLYING_TYPE]] { get } +// CHECK-NEXT: public typealias RawValue = [[ENUM_UNDERLYING_TYPE]] // CHECK-NEXT: case value1 // CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "value1") -// CHECK-NEXT: static var Value1: PublicPrivate.PublicClosedEnum { get } +// CHECK-NEXT: public static var Value1: PublicPrivate.PublicClosedEnum { get } // CHECK-NEXT: } -// CHECK-NEXT: enum PublicOpenEnum : [[ENUM_UNDERLYING_TYPE]], @unchecked Sendable { -// CHECK-NEXT: init?(rawValue: [[ENUM_UNDERLYING_TYPE]]) -// CHECK-NEXT: var rawValue: [[ENUM_UNDERLYING_TYPE]] { get } -// CHECK-NEXT: typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: public enum PublicOpenEnum : [[ENUM_UNDERLYING_TYPE]], @unchecked Sendable { +// CHECK-NEXT: public init?(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: public var rawValue: [[ENUM_UNDERLYING_TYPE]] { get } +// CHECK-NEXT: public typealias RawValue = [[ENUM_UNDERLYING_TYPE]] // CHECK-NEXT: case value1 // CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "value1") -// CHECK-NEXT: static var Value1: PublicPrivate.PublicOpenEnum { get } +// CHECK-NEXT: public static var Value1: PublicPrivate.PublicOpenEnum { get } // CHECK-NEXT: } -// CHECK-NEXT: struct PublicFlagEnum : OptionSet, @unchecked Sendable { -// CHECK-NEXT: init(rawValue: [[ENUM_UNDERLYING_TYPE]]) -// CHECK-NEXT: let rawValue: [[ENUM_UNDERLYING_TYPE]] -// CHECK-NEXT: typealias RawValue = [[ENUM_UNDERLYING_TYPE]] -// CHECK-NEXT: typealias Element = PublicPrivate.PublicFlagEnum -// CHECK-NEXT: typealias ArrayLiteralElement = PublicPrivate.PublicFlagEnum +// CHECK-NEXT: public struct PublicFlagEnum : OptionSet, @unchecked Sendable { +// CHECK-NEXT: public init(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: public let rawValue: [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: public typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: public typealias Element = PublicPrivate.PublicFlagEnum +// CHECK-NEXT: public typealias ArrayLiteralElement = PublicPrivate.PublicFlagEnum // CHECK-NEXT: } -// CHECK-NEXT: var PublicMemberVar: Int32 +// CHECK-NEXT: private static var PrivateStaticMemberVar: Int32 +// CHECK-NEXT: private mutating func privateMemberFunc() +// CHECK-NEXT: private typealias PrivateTypedef = Int32 +// CHECK-NEXT: private struct PrivateStruct { +// CHECK-NEXT: public init() +// CHECK-NEXT: } +// CHECK-NEXT: private struct PrivateEnum : Hashable, Equatable, RawRepresentable { +// CHECK-NEXT: private init(_ rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: private init(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: private var rawValue: [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: private typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: } +// CHECK-NEXT: @frozen private enum PrivateClosedEnum : [[ENUM_UNDERLYING_TYPE]], @unchecked Sendable { +// CHECK-NEXT: private init?(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: private var rawValue: [[ENUM_UNDERLYING_TYPE]] { get } +// CHECK-NEXT: private typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: case value1 +// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "value1") +// CHECK-NEXT: private static var Value1: PublicPrivate.PrivateClosedEnum { get } +// CHECK-NEXT: } +// CHECK-NEXT: private enum PrivateOpenEnum : [[ENUM_UNDERLYING_TYPE]], @unchecked Sendable { +// CHECK-NEXT: private init?(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: private var rawValue: [[ENUM_UNDERLYING_TYPE]] { get } +// CHECK-NEXT: private typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: case value1 +// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "value1") +// CHECK-NEXT: private static var Value1: PublicPrivate.PrivateOpenEnum { get } +// CHECK-NEXT: } +// CHECK-NEXT: private struct PrivateFlagEnum : OptionSet, @unchecked Sendable { +// CHECK-NEXT: private init(rawValue: [[ENUM_UNDERLYING_TYPE]]) +// CHECK-NEXT: private let rawValue: [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: private typealias RawValue = [[ENUM_UNDERLYING_TYPE]] +// CHECK-NEXT: private typealias Element = PublicPrivate.PrivateFlagEnum +// CHECK-NEXT: private typealias ArrayLiteralElement = PublicPrivate.PrivateFlagEnum +// CHECK-NEXT: } +// CHECK-NEXT: public var PublicMemberVar: Int32 +// CHECK-NEXT: private var PrivateMemberVar: Int32 // CHECK-NEXT: } diff --git a/test/Interop/Cxx/class/access-specifiers-typechecker.swift b/test/Interop/Cxx/class/access-specifiers-typechecker.swift index 7d9e431df0f61..ff26b8accb817 100644 --- a/test/Interop/Cxx/class/access-specifiers-typechecker.swift +++ b/test/Interop/Cxx/class/access-specifiers-typechecker.swift @@ -1,5 +1,4 @@ -// Test that C++ access specifiers are honored, i.e. private members aren't -// imported. +// Test that C++ access specifiers are honored. // RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-experimental-cxx-interop @@ -16,28 +15,33 @@ v.publicMemberFunc() var publicTypedefVar: PublicPrivate.PublicTypedef var publicStructVar: PublicPrivate.PublicStruct var publicEnumVar: PublicPrivate.PublicEnum -// TODO: These enum values don't yet appear to be imported correctly into the -// scope of PublicPrivate yet. Once they are, verify that they are accessible. -// print(PublicPrivate.PublicEnumValue1) -// print(PublicPrivate.PublicAnonymousEnumValue1) var publicClosedEnumVar: PublicPrivate.PublicClosedEnum var publicOpenEnumVar: PublicPrivate.PublicOpenEnum var publicFlagEnumVar: PublicPrivate.PublicFlagEnum +// TODO: nested enum members aren't being imported correctly yet (#54905) +// Once they are, verify that they are accessible. +// print(PublicPrivate.PublicEnumValue1) +// print(PublicPrivate.PublicAnonymousEnumValue) +print(PublicPrivate.PublicClosedEnum.value1) +print(PublicPrivate.PublicOpenEnum.value1) + // Cannot access any private members and types. v.PrivateMemberVar = 1 // expected-error {{'PrivateMemberVar' is inaccessible due to 'private' protection level}} -PublicPrivate.PrivateStaticMemberVar = 1 // expected-error {{'PublicPrivate' has no member 'PrivateStaticMemberVar'}} -v.privateMemberFunc() // expected-error {{value of type 'PublicPrivate' has no member 'privateMemberFunc'}} - -var privateTypedefVar: PublicPrivate.PrivateTypedef // expected-error {{'PrivateTypedef' is not a member type of struct 'AccessSpecifiers.PublicPrivate'}} -var privateStructVar: PublicPrivate.PrivateStruct // expected-error {{'PrivateStruct' is not a member type of struct 'AccessSpecifiers.PublicPrivate'}} -var privateEnumVar: PublicPrivate.PrivateEnum // expected-error {{'PrivateEnum' is not a member type of struct 'AccessSpecifiers.PublicPrivate'}} -// TODO: PrivateEnumValue1 and PrivateAnonymousEnumValue1 give the expected -// error, but only because these types of enums (private or public) aren't -// currently imported at all. Once that is fixed, remove this TODO. -print(PublicPrivate.PrivateEnumValue1) // expected-error {{'PublicPrivate' has no member 'PrivateEnumValue1'}} -print(PublicPrivate.PrivateAnonymousEnumValue1) // expected-error {{'PublicPrivate' has no member 'PrivateAnonymousEnumValue1'}} -var privateClosedEnumVar: PublicPrivate.PrivateClosedEnum // expected-error {{'PrivateClosedEnum' is not a member type of struct 'AccessSpecifiers.PublicPrivate'}} -var privateOpenEnumVar: PublicPrivate.PrivateOpenEnum // expected-error {{'PrivateOpenEnum' is not a member type of struct 'AccessSpecifiers.PublicPrivate'}} -var privateFlagEnumVar: PublicPrivate.PrivateFlagEnum // expected-error {{'PrivateFlagEnum' is not a member type of struct 'AccessSpecifiers.PublicPrivate'}} +PublicPrivate.PrivateStaticMemberVar = 1 // expected-error {{'PrivateStaticMemberVar' is inaccessible due to 'private' protection level}} +v.privateMemberFunc() // expected-error {{'privateMemberFunc' is inaccessible due to 'private' protection level}} + +var privateTypedefVar: PublicPrivate.PrivateTypedef // expected-error {{'PrivateTypedef' is inaccessible due to 'private' protection level}} +var privateStructVar: PublicPrivate.PrivateStruct // expected-error {{'PrivateStruct' is inaccessible due to 'private' protection level}} +var privateEnumVar: PublicPrivate.PrivateEnum // expected-error {{'PrivateEnum' is inaccessible due to 'private' protection level}} +var privateClosedEnumVar: PublicPrivate.PrivateClosedEnum // expected-error {{'PrivateClosedEnum' is inaccessible due to 'private' protection level}} +var privateOpenEnumVar: PublicPrivate.PrivateOpenEnum // expected-error {{'PrivateOpenEnum' is inaccessible due to 'private' protection level}} +var privateFlagEnumVar: PublicPrivate.PrivateFlagEnum // expected-error {{'PrivateFlagEnum' is inaccessible due to 'private' protection level}} + +// TODO: nested enum members aren't being imported correctly yet (#54905) +// Once they are, verify that this throws an error (similar to above). +// print(PublicPrivate.PrivateEnumValue1) +// print(PublicPrivate.PrivateAnonymousEnumValue1) +print(PublicPrivate.PrivateOpenEnum.value1) // expected-error {{'PrivateOpenEnum' is inaccessible due to 'private' protection level}} +print(PublicPrivate.PrivateClosedEnum.value1) // expected-error {{'PrivateClosedEnum' is inaccessible due to 'private' protection level}}