diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 5a3d465625b0e..397bdd8cae0ac 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -7074,6 +7074,11 @@ static bool isSufficientlyTrivial(const clang::CXXRecordDecl *decl) { /// Checks if a record provides the required value type lifetime operations /// (copy and destroy). static bool hasCopyTypeOperations(const clang::CXXRecordDecl *decl) { + // Hack for a base type of std::optional from the Microsoft standard library. + if (decl->isInStdNamespace() && decl->getIdentifier() && + decl->getName() == "_Optional_construct_base") + return true; + // If we have no way of copying the type we can't import the class // at all because we cannot express the correct semantics as a swift // struct. diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index b746516551a14..b41c29e22a7d2 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2697,6 +2697,31 @@ namespace { // SemaLookup.cpp). if (!decl->isBeingDefined() && !decl->isDependentContext() && areRecordFieldsComplete(decl)) { + if (decl->hasInheritedConstructor() && + Impl.isCxxInteropCompatVersionAtLeast( + version::getUpcomingCxxInteropCompatVersion())) { + for (auto member : decl->decls()) { + if (auto usingDecl = dyn_cast(member)) { + for (auto usingShadowDecl : usingDecl->shadows()) { + if (auto ctorUsingShadowDecl = + dyn_cast( + usingShadowDecl)) { + auto baseCtorDecl = dyn_cast( + ctorUsingShadowDecl->getTargetDecl()); + if (!baseCtorDecl || baseCtorDecl->isDeleted()) + continue; + auto derivedCtorDecl = clangSema.findInheritingConstructor( + clang::SourceLocation(), baseCtorDecl, + ctorUsingShadowDecl); + if (!derivedCtorDecl->isDefined() && + !derivedCtorDecl->isDeleted()) + clangSema.DefineInheritingConstructor( + clang::SourceLocation(), derivedCtorDecl); + } + } + } + } + } if (decl->needsImplicitDefaultConstructor()) { clang::CXXConstructorDecl *ctor = clangSema.DeclareImplicitDefaultConstructor( @@ -3237,6 +3262,65 @@ namespace { llvm::None); } + /// Handles special functions such as subscripts and dereference operators. + bool processSpecialImportedFunc(FuncDecl *func, ImportedName importedName) { + auto dc = func->getDeclContext(); + + if (importedName.isSubscriptAccessor()) { + assert(func->getParameters()->size() == 1); + auto typeDecl = dc->getSelfNominalTypeDecl(); + auto parameter = func->getParameters()->get(0); + auto parameterType = parameter->getTypeInContext(); + if (!typeDecl || !parameterType) + return false; + if (parameter->isInOut()) + // Subscripts with inout parameters are not allowed in Swift. + return false; + // Subscript setter is marked as mutating in Swift even if the + // C++ `operator []` is `const`. + if (importedName.getAccessorKind() == + ImportedAccessorKind::SubscriptSetter && + !dc->isModuleScopeContext() && + !typeDecl->getDeclaredType()->isForeignReferenceType()) + func->setSelfAccessKind(SelfAccessKind::Mutating); + + auto &getterAndSetter = Impl.cxxSubscripts[{typeDecl, parameterType}]; + + switch (importedName.getAccessorKind()) { + case ImportedAccessorKind::SubscriptGetter: + getterAndSetter.first = func; + break; + case ImportedAccessorKind::SubscriptSetter: + getterAndSetter.second = func; + break; + default: + llvm_unreachable("invalid subscript kind"); + } + + Impl.markUnavailable(func, "use subscript"); + } + + if (importedName.isDereferenceAccessor()) { + auto typeDecl = dc->getSelfNominalTypeDecl(); + auto &getterAndSetter = Impl.cxxDereferenceOperators[typeDecl]; + + switch (importedName.getAccessorKind()) { + case ImportedAccessorKind::DereferenceGetter: + getterAndSetter.first = func; + break; + case ImportedAccessorKind::DereferenceSetter: + getterAndSetter.second = func; + break; + default: + llvm_unreachable("invalid dereference operator kind"); + } + + Impl.markUnavailable(func, "use .pointee property"); + } + + return true; + } + Decl *importFunctionDecl( const clang::FunctionDecl *decl, ImportedName importedName, llvm::Optional correctSwiftName, @@ -3556,69 +3640,14 @@ namespace { func->setImportAsStaticMember(); } } + // Someday, maybe this will need to be 'open' for C++ virtual methods. + func->setAccess(AccessLevel::Public); - bool makePrivate = false; - - if (importedName.isSubscriptAccessor() && !importFuncWithoutSignature) { - assert(func->getParameters()->size() == 1); - auto typeDecl = dc->getSelfNominalTypeDecl(); - auto parameter = func->getParameters()->get(0); - auto parameterType = parameter->getTypeInContext(); - if (!typeDecl || !parameterType) + if (!importFuncWithoutSignature) { + bool success = processSpecialImportedFunc(func, importedName); + if (!success) return nullptr; - if (parameter->isInOut()) - // Subscripts with inout parameters are not allowed in Swift. - return nullptr; - // Subscript setter is marked as mutating in Swift even if the - // C++ `operator []` is `const`. - if (importedName.getAccessorKind() == - ImportedAccessorKind::SubscriptSetter && - !dc->isModuleScopeContext() && - !typeDecl->getDeclaredType()->isForeignReferenceType()) - func->setSelfAccessKind(SelfAccessKind::Mutating); - - auto &getterAndSetter = Impl.cxxSubscripts[{ typeDecl, - parameterType }]; - - switch (importedName.getAccessorKind()) { - case ImportedAccessorKind::SubscriptGetter: - getterAndSetter.first = func; - break; - case ImportedAccessorKind::SubscriptSetter: - getterAndSetter.second = func; - break; - default: - llvm_unreachable("invalid subscript kind"); - } - - Impl.markUnavailable(func, "use subscript"); } - - if (importedName.isDereferenceAccessor() && - !importFuncWithoutSignature) { - auto typeDecl = dc->getSelfNominalTypeDecl(); - auto &getterAndSetter = Impl.cxxDereferenceOperators[typeDecl]; - - switch (importedName.getAccessorKind()) { - case ImportedAccessorKind::DereferenceGetter: - getterAndSetter.first = func; - break; - case ImportedAccessorKind::DereferenceSetter: - getterAndSetter.second = func; - break; - default: - llvm_unreachable("invalid dereference operator kind"); - } - - Impl.markUnavailable(func, "use .pointee property"); - makePrivate = true; - } - - if (makePrivate) - func->setAccess(AccessLevel::Private); - else - // Someday, maybe this will need to be 'open' for C++ virtual methods. - func->setAccess(AccessLevel::Public); } result->setIsObjC(false); @@ -3931,18 +3960,31 @@ namespace { } Decl *VisitUsingDecl(const clang::UsingDecl *decl) { - // Using declarations are not imported. + // See VisitUsingShadowDecl below. return nullptr; } Decl *VisitUsingShadowDecl(const clang::UsingShadowDecl *decl) { - // Only import types for now. - if (!isa(decl->getUnderlyingDecl())) + // Only import: + // 1. Types + // 2. C++ methods from privately inherited base classes + if (!isa(decl->getTargetDecl()) && + !(isa(decl->getTargetDecl()) && + Impl.isCxxInteropCompatVersionAtLeast( + version::getUpcomingCxxInteropCompatVersion()))) + return nullptr; + // Constructors (e.g. `using BaseClass::BaseClass`) are handled in + // VisitCXXRecordDecl, since we need them to determine whether a struct + // can be imported into Swift. + if (isa(decl->getTargetDecl())) return nullptr; ImportedName importedName; llvm::Optional correctSwiftName; std::tie(importedName, correctSwiftName) = importFullName(decl); + // Don't import something that doesn't have a name. + if (importedName.getDeclName().isSpecial()) + return nullptr; auto Name = importedName.getDeclName().getBaseIdentifier(); if (Name.empty()) return nullptr; @@ -3953,30 +3995,66 @@ namespace { return importCompatibilityTypeAlias(decl, importedName, *correctSwiftName); - auto DC = + auto importedDC = Impl.importDeclContextOf(decl, importedName.getEffectiveContext()); - if (!DC) + if (!importedDC) return nullptr; - Decl *SwiftDecl = Impl.importDecl(decl->getUnderlyingDecl(), getActiveSwiftVersion()); - if (!SwiftDecl) - return nullptr; + if (isa(decl->getTargetDecl())) { + Decl *SwiftDecl = Impl.importDecl(decl->getUnderlyingDecl(), getActiveSwiftVersion()); + if (!SwiftDecl) + return nullptr; - const TypeDecl *SwiftTypeDecl = dyn_cast(SwiftDecl); - if (!SwiftTypeDecl) - return nullptr; + const TypeDecl *SwiftTypeDecl = dyn_cast(SwiftDecl); + if (!SwiftTypeDecl) + 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); - Result->setUnderlyingType(SwiftTypeDecl->getDeclaredInterfaceType()); + auto Loc = Impl.importSourceLoc(decl->getLocation()); + auto Result = Impl.createDeclWithClangNode( + decl, + AccessLevel::Public, + Impl.importSourceLoc(decl->getBeginLoc()), + SourceLoc(), Name, + Loc, + /*genericparams*/nullptr, importedDC); + Result->setUnderlyingType(SwiftTypeDecl->getDeclaredInterfaceType()); + + return Result; + } + if (auto targetMethod = + dyn_cast(decl->getTargetDecl())) { + auto dc = dyn_cast(decl->getDeclContext()); + + auto targetDC = targetMethod->getDeclContext(); + auto targetRecord = dyn_cast(targetDC); + if (!targetRecord) + return nullptr; - return Result; + // If this struct is not inherited from the struct where the method is + // defined, bail. + if (!dc->isDerivedFrom(targetRecord)) + return nullptr; + + auto importedBaseMethod = dyn_cast_or_null( + Impl.importDecl(targetMethod, getActiveSwiftVersion())); + // This will be nullptr for a protected method of base class that is + // made public with a using declaration in a derived class. This is + // valid in C++ but we do not import such using declarations now. + // TODO: make this work for protected base methods. + if (!importedBaseMethod) + return nullptr; + auto clonedMethod = dyn_cast_or_null( + Impl.importBaseMemberDecl(importedBaseMethod, importedDC)); + if (!clonedMethod) + return nullptr; + + bool success = processSpecialImportedFunc(clonedMethod, importedName); + if (!success) + return nullptr; + + return clonedMethod; + } + return nullptr; } /// Add an @objc(name) attribute with the given, optional name expressed as @@ -8360,11 +8438,17 @@ ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl, if (Result && (!Result->getDeclContext()->isModuleScopeContext() || isa(Result->getDeclContext()))) { + // For using declarations that expose a method of a base class, the Clang + // decl is synthesized lazily when the method is actually used from Swift. + bool hasSynthesizedClangNode = + isa(ClangDecl) && isa(Result); + // Either the Swift declaration was from stdlib, // or we imported the underlying decl of the typedef, // or we imported the decl itself. bool ImportedCorrectly = !Result->getClangDecl() || SkippedOverTypedef || + hasSynthesizedClangNode || Result->getClangDecl()->getCanonicalDecl() == Canon; // Or the other type is a typedef, @@ -8387,7 +8471,7 @@ ClangImporter::Implementation::importDeclImpl(const clang::NamedDecl *ClangDecl, } assert(ImportedCorrectly); } - assert(Result->hasClangNode()); + assert(Result->hasClangNode() || hasSynthesizedClangNode); } #else (void)SkippedOverTypedef; diff --git a/lib/ClangImporter/ImportName.cpp b/lib/ClangImporter/ImportName.cpp index fc89ac152553d..896e3ebd07a68 100644 --- a/lib/ClangImporter/ImportName.cpp +++ b/lib/ClangImporter/ImportName.cpp @@ -1522,6 +1522,17 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D, return ImportedName(); result.effectiveContext = effectiveCtx; + // If this is a using declaration, import the name of the shadowed decl and + // adjust the context. + if (auto usingShadowDecl = dyn_cast(D)) { + auto targetDecl = usingShadowDecl->getTargetDecl(); + if (isa(targetDecl)) { + ImportedName baseName = importName(targetDecl, version, givenName); + baseName.effectiveContext = effectiveCtx; + return baseName; + } + } + // Gather information from the swift_async attribute, if there is one. llvm::Optional completionHandlerParamIndex; bool completionHandlerFlagIsZeroOnError = false; diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index 4933d8c758a08..b91363a75615a 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -663,9 +663,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation llvm::DenseMap, ValueDecl *> clonedBaseMembers; +public: ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext); -public: static size_t getImportedBaseMemberDeclArity(const ValueDecl *valueDecl); // Cache for already-specialized function templates and any thunks they may diff --git a/lib/ClangImporter/SwiftLookupTable.cpp b/lib/ClangImporter/SwiftLookupTable.cpp index beb18b7748f18..d584dcb0de343 100644 --- a/lib/ClangImporter/SwiftLookupTable.cpp +++ b/lib/ClangImporter/SwiftLookupTable.cpp @@ -1991,6 +1991,12 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table, } } } + if (auto usingDecl = dyn_cast(named)) { + for (auto usingShadowDecl : usingDecl->shadows()) { + if (isa(usingShadowDecl->getTargetDecl())) + addEntryToLookupTable(table, usingShadowDecl, nameImporter); + } + } } /// Returns the nearest parent of \p module that is marked \c explicit in its diff --git a/test/Interop/Cxx/class/Inputs/constructors.h b/test/Interop/Cxx/class/Inputs/constructors.h index 7493fc91cf785..252a5451ac8f0 100644 --- a/test/Interop/Cxx/class/Inputs/constructors.h +++ b/test/Interop/Cxx/class/Inputs/constructors.h @@ -80,10 +80,4 @@ struct DeletedCopyConstructor { DeletedCopyConstructor(const DeletedCopyConstructor &) = delete; }; -// TODO: we should be able to import this constructor correctly. Until we can, -// make sure not to crash. -struct UsingBaseConstructor : ConstructorWithParam { - using ConstructorWithParam::ConstructorWithParam; -}; - #endif // TEST_INTEROP_CXX_CLASS_INPUTS_CONSTRUCTORS_H diff --git a/test/Interop/Cxx/class/inheritance/Inputs/module.modulemap b/test/Interop/Cxx/class/inheritance/Inputs/module.modulemap index f3638d85acbe5..ec5f16a09d0fa 100644 --- a/test/Interop/Cxx/class/inheritance/Inputs/module.modulemap +++ b/test/Interop/Cxx/class/inheritance/Inputs/module.modulemap @@ -28,6 +28,11 @@ module TypeAliases { header "type-aliases.h" } +module UsingBaseMembers { + header "using-base-members.h" + requires cplusplus +} + module VirtualMethods { header "virtual-methods.h" requires cplusplus diff --git a/test/Interop/Cxx/class/inheritance/Inputs/using-base-members.h b/test/Interop/Cxx/class/inheritance/Inputs/using-base-members.h new file mode 100644 index 0000000000000..f526d40aa0b53 --- /dev/null +++ b/test/Interop/Cxx/class/inheritance/Inputs/using-base-members.h @@ -0,0 +1,47 @@ +struct PublicBase { +private: + int value = 123; + +public: + int publicGetter() const { return value; } + void publicSetter(int v) { value = v; } + void notExposed() const {} +}; + +struct PublicBasePrivateInheritance : private PublicBase { + using PublicBase::publicGetter; + using PublicBase::publicSetter; +}; + +struct PublicBaseProtectedInheritance : protected PublicBase { + using PublicBase::publicGetter; + using PublicBase::publicSetter; +}; + +struct IntBox { + int value; + IntBox(int value) : value(value) {} + IntBox(unsigned value) : value(value) {} +}; + +struct UsingBaseConstructorWithParam : IntBox { + using IntBox::IntBox; +}; + +struct Empty {}; + +struct UsingBaseConstructorEmpty : private Empty { + using Empty::Empty; + + int value = 456; +}; + +// TODO: make this work for protected base methods as well +//struct ProtectedBase { +//protected: +// int protectedGetter() const { return 456; } +//}; +// +//struct ProtectedMemberPrivateInheritance : private ProtectedBase { +// using ProtectedBase::protectedGetter; +//}; diff --git a/test/Interop/Cxx/class/inheritance/using-base-members-module-interface.swift b/test/Interop/Cxx/class/inheritance/using-base-members-module-interface.swift new file mode 100644 index 0000000000000..36a09ff1a9fd3 --- /dev/null +++ b/test/Interop/Cxx/class/inheritance/using-base-members-module-interface.swift @@ -0,0 +1,33 @@ +// RUN: %target-swift-ide-test -print-module -module-to-print=UsingBaseMembers -I %S/Inputs -source-filename=x -cxx-interoperability-mode=upcoming-swift | %FileCheck %s + +// CHECK: struct PublicBase { +// CHECK-NEXT: init() +// CHECK-NEXT: func publicGetter() -> Int32 +// CHECK-NEXT: mutating func publicSetter(_ v: Int32) +// CHECK-NEXT: func notExposed() +// CHECK-NEXT: } + +// CHECK: struct PublicBasePrivateInheritance { +// CHECK-NEXT: init() +// CHECK-NEXT: func publicGetter() -> Int32 +// CHECK-NEXT: mutating func publicSetter(_ v: Int32) +// CHECK-NEXT: } + +// CHECK: struct PublicBaseProtectedInheritance { +// CHECK-NEXT: init() +// CHECK-NEXT: func publicGetter() -> Int32 +// CHECK-NEXT: mutating func publicSetter(_ v: Int32) +// CHECK-NEXT: } + +// CHECK: struct UsingBaseConstructorWithParam { +// CHECK-NEXT: init(_: IntBox) +// CHECK-NEXT: init(_: UInt32) +// CHECK-NEXT: init(_: Int32) +// CHECK-NEXT: var value: Int32 +// CHECK-NEXT: } + +// CHECK: struct UsingBaseConstructorEmpty { +// CHECK-NEXT: init() +// CHECK-NEXT: init(_: Empty) +// CHECK-NEXT: var value: Int32 +// CHECK-NEXT: } diff --git a/test/Interop/Cxx/class/inheritance/using-base-members-typechecker.swift b/test/Interop/Cxx/class/inheritance/using-base-members-typechecker.swift new file mode 100644 index 0000000000000..5fda933fe9c04 --- /dev/null +++ b/test/Interop/Cxx/class/inheritance/using-base-members-typechecker.swift @@ -0,0 +1,16 @@ +// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -cxx-interoperability-mode=upcoming-swift + +import UsingBaseMembers + +let a = PublicBasePrivateInheritance() +let _ = a.publicGetter() +a.notExposed() // expected-error {{value of type 'PublicBasePrivateInheritance' has no member 'notExposed'}} + +let b = PublicBaseProtectedInheritance() +let _ = b.publicGetter() +b.notExposed() // expected-error {{value of type 'PublicBaseProtectedInheritance' has no member 'notExposed'}} + +let _ = UsingBaseConstructorWithParam(566 as Int32) +let _ = UsingBaseConstructorWithParam(566 as UInt32) + +let _ = UsingBaseConstructorEmpty() diff --git a/test/Interop/Cxx/class/inheritance/using-base-members.swift b/test/Interop/Cxx/class/inheritance/using-base-members.swift new file mode 100644 index 0000000000000..7c4b30bef8730 --- /dev/null +++ b/test/Interop/Cxx/class/inheritance/using-base-members.swift @@ -0,0 +1,36 @@ +// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -cxx-interoperability-mode=upcoming-swift) +// +// REQUIRES: executable_test + +import StdlibUnittest +import UsingBaseMembers + +var UsingBaseTestSuite = TestSuite("Using Base Members") + +UsingBaseTestSuite.test("PublicBasePrivateInheritance") { + var p = PublicBasePrivateInheritance() + expectEqual(123, p.publicGetter()) + p.publicSetter(456) + expectEqual(456, p.publicGetter()) +} + +UsingBaseTestSuite.test("PublicBaseProtectedInheritance") { + var p = PublicBaseProtectedInheritance() + expectEqual(123, p.publicGetter()) + p.publicSetter(987) + expectEqual(987, p.publicGetter()) +} + +UsingBaseTestSuite.test("UsingBaseConstructorWithParam") { + let p1 = UsingBaseConstructorWithParam(566 as Int32) + expectEqual(566, p1.value) + let p2 = UsingBaseConstructorWithParam(987 as UInt32) + expectEqual(987, p2.value) +} + +UsingBaseTestSuite.test("UsingBaseConstructorEmpty") { + let p = UsingBaseConstructorEmpty() + expectEqual(456, p.value) +} + +runAllTests() diff --git a/test/Interop/Cxx/operators/Inputs/member-inline.h b/test/Interop/Cxx/operators/Inputs/member-inline.h index 07647ac16b6a7..32707040d6f1c 100644 --- a/test/Interop/Cxx/operators/Inputs/member-inline.h +++ b/test/Interop/Cxx/operators/Inputs/member-inline.h @@ -431,4 +431,13 @@ class SubscriptSetterConst { T *p; }; +struct DerivedFromConstIteratorPrivatelyWithUsingDecl : private ConstIterator { + using ConstIterator::operator*; +}; + +struct DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl + : private AmbiguousOperatorStar { + using AmbiguousOperatorStar::operator*; +}; + #endif diff --git a/test/Interop/Cxx/operators/member-inline-module-interface.swift b/test/Interop/Cxx/operators/member-inline-module-interface.swift index bd133d22d0efb..bd8bccd1b40e7 100644 --- a/test/Interop/Cxx/operators/member-inline-module-interface.swift +++ b/test/Interop/Cxx/operators/member-inline-module-interface.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-ide-test -print-module -module-to-print=MemberInline -I %S/Inputs -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s +// RUN: %target-swift-ide-test -print-module -module-to-print=MemberInline -I %S/Inputs -source-filename=x -cxx-interoperability-mode=upcoming-swift | %FileCheck %s // CHECK: struct LoadableIntWrapper { // CHECK: func successor() -> LoadableIntWrapper @@ -242,3 +242,26 @@ // CHECK-NEXT: @available(*, unavailable, message: "use .pointee property") // CHECK-NEXT: func __operatorStar() -> UnsafePointer // CHECK-NEXT: } + +// CHECK: struct DerivedFromConstIterator { +// CHECK-NEXT: init() +// TODO: @available(*, unavailable, message: "use .pointee property") +// CHECK-NEXT: func __operatorStar() -> UnsafePointer +// TODO: `var pointee` should be printed here +// CHECK-NEXT: } + +// CHECK: struct DerivedFromConstIteratorPrivatelyWithUsingDecl { +// CHECK-NEXT: init() +// CHECK-NEXT: var pointee: Int32 { get } +// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property") +// CHECK-NEXT: func __operatorStar() -> UnsafePointer +// CHECK-NEXT: } + +// CHECK: struct DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl { +// CHECK-NEXT: init() +// CHECK-NEXT: var pointee: Int32 +// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property") +// CHECK-NEXT: mutating func __operatorStar() -> UnsafeMutablePointer +// CHECK-NEXT: @available(*, unavailable, message: "use .pointee property") +// CHECK-NEXT: func __operatorStar() -> UnsafePointer +// CHECK-NEXT: } diff --git a/test/Interop/Cxx/operators/member-inline-typechecker.swift b/test/Interop/Cxx/operators/member-inline-typechecker.swift index b115bac1ae0b4..9722c321ac2ac 100644 --- a/test/Interop/Cxx/operators/member-inline-typechecker.swift +++ b/test/Interop/Cxx/operators/member-inline-typechecker.swift @@ -1,4 +1,4 @@ -// RUN: %target-typecheck-verify-swift -I %S/Inputs -enable-experimental-cxx-interop +// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=upcoming-swift import MemberInline @@ -70,3 +70,6 @@ let immortalIncrement = myCounter.successor() // expected-error {{value of type let derivedConstIter = DerivedFromConstIteratorPrivately() derivedConstIter.pointee // expected-error {{value of type 'DerivedFromConstIteratorPrivately' has no member 'pointee'}} + +let derivedConstIterWithUD = DerivedFromConstIteratorPrivatelyWithUsingDecl() +let _ = derivedConstIterWithUD.pointee diff --git a/test/Interop/Cxx/operators/member-inline.swift b/test/Interop/Cxx/operators/member-inline.swift index 235f77a0e778b..119cc9a6c92e8 100644 --- a/test/Interop/Cxx/operators/member-inline.swift +++ b/test/Interop/Cxx/operators/member-inline.swift @@ -1,4 +1,4 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop) +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -cxx-interoperability-mode=upcoming-swift) // // REQUIRES: executable_test @@ -383,4 +383,16 @@ OperatorsTestSuite.test("SubscriptSetterConst") { setterConst[0] = 10 } +OperatorsTestSuite.test("DerivedFromConstIteratorPrivatelyWithUsingDecl.pointee") { + let stars = DerivedFromConstIteratorPrivatelyWithUsingDecl() + let res = stars.pointee + expectEqual(234, res) +} + +OperatorsTestSuite.test("DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl.pointee") { + let stars = DerivedFromAmbiguousOperatorStarPrivatelyWithUsingDecl() + let res = stars.pointee + expectEqual(567, res) +} + runAllTests() diff --git a/test/Interop/Cxx/stdlib/use-std-optional.swift b/test/Interop/Cxx/stdlib/use-std-optional.swift index bf574963f9d58..3fb3915451838 100644 --- a/test/Interop/Cxx/stdlib/use-std-optional.swift +++ b/test/Interop/Cxx/stdlib/use-std-optional.swift @@ -1,7 +1,6 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -Xcc -std=c++17) +// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -cxx-interoperability-mode=upcoming-swift -Xcc -std=c++17) // // REQUIRES: executable_test -// REQUIRES: SR68068 import StdlibUnittest import StdOptional diff --git a/tools/swift-ide-test/swift-ide-test.cpp b/tools/swift-ide-test/swift-ide-test.cpp index b3323a583637f..c75535b252f42 100644 --- a/tools/swift-ide-test/swift-ide-test.cpp +++ b/tools/swift-ide-test/swift-ide-test.cpp @@ -796,6 +796,11 @@ static llvm::cl::opt llvm::cl::desc("Enable C++ interop."), llvm::cl::cat(Category), llvm::cl::init(false)); +static llvm::cl::opt + CxxInteropVersion("cxx-interoperability-mode", + llvm::cl::desc("C++ interop mode."), + llvm::cl::cat(Category)); + static llvm::cl::opt CxxInteropGettersSettersAsProperties("cxx-interop-getters-setters-as-properties", llvm::cl::desc("Imports getters and setters as computed properties."), @@ -4383,6 +4388,14 @@ int main(int argc, char *argv[]) { if (options::EnableCxxInterop) { InitInvok.getLangOptions().EnableCXXInterop = true; } + if (!options::CxxInteropVersion.empty()) { + InitInvok.getLangOptions().EnableCXXInterop = true; + if (options::CxxInteropVersion == "upcoming-swift") + InitInvok.getLangOptions().cxxInteropCompatVersion = + version::Version({version::getUpcomingCxxInteropCompatVersion()}); + else + llvm::errs() << "invalid CxxInteropVersion\n"; + } if (options::CxxInteropGettersSettersAsProperties) { InitInvok.getLangOptions().CxxInteropGettersSettersAsProperties = true; }