diff --git a/include/swift/AST/ClangModuleLoader.h b/include/swift/AST/ClangModuleLoader.h index 46dec5027aafa..2125f1f2b7482 100644 --- a/include/swift/AST/ClangModuleLoader.h +++ b/include/swift/AST/ClangModuleLoader.h @@ -306,6 +306,9 @@ class ClangModuleLoader : public ModuleLoader { virtual EffectiveClangContext getEffectiveClangContext( const NominalTypeDecl *nominal) = 0; + virtual const clang::TypedefType * + getTypeDefForCXXCFOptionsDefinition(const clang::Decl *candidateDecl) = 0; + virtual SourceLoc importSourceLocation(clang::SourceLocation loc) = 0; }; diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index a7ac2669b0a9c..709162ceb91d1 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -609,8 +609,8 @@ class ClangImporter final : public ClangModuleLoader { /// Enable the symbolic import experimental feature for the given callback. void withSymbolicFeatureEnabled(llvm::function_ref callback); - static const clang::TypedefType *getTypedefForCXXCFOptionsDefinition( - const clang::Decl *candidateDecl, const ASTContext &ctx); + const clang::TypedefType *getTypeDefForCXXCFOptionsDefinition( + const clang::Decl *candidateDecl) override; SourceLoc importSourceLocation(clang::SourceLocation loc) override; }; diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 2a72558bf1a6c..cb41be4007823 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -2548,8 +2548,8 @@ ASTMangler::getTypeDefForCXXCFOptionsDefinition(const ValueDecl *decl) { if (!clangDecl) return nullptr; - auto &ctx = decl->getASTContext(); - return ClangImporter::getTypedefForCXXCFOptionsDefinition(clangDecl, ctx); + const auto &clangModuleLoader = decl->getASTContext().getClangModuleLoader(); + return clangModuleLoader->getTypeDefForCXXCFOptionsDefinition(clangDecl); } const clang::NamedDecl * diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index f2539d9b54ee4..2c69da402fdcb 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -7023,23 +7023,26 @@ void ClangImporter::withSymbolicFeatureEnabled( oldImportSymbolicCXXDecls.get()); } -const clang::TypedefType *ClangImporter::getTypedefForCXXCFOptionsDefinition( - const clang::Decl *candidateDecl, const ASTContext &ctx) { - if (!ctx.LangOpts.EnableCXXInterop) +const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition( + const clang::Decl *candidateDecl) { + + if (!Impl.SwiftContext.LangOpts.EnableCXXInterop) return nullptr; auto enumDecl = dyn_cast(candidateDecl); if (!enumDecl) return nullptr; + if (!enumDecl->getDeclName().isEmpty()) return nullptr; const clang::ElaboratedType *elaboratedType = - enumDecl->getIntegerType()->getAs(); + dyn_cast(enumDecl->getIntegerType().getTypePtr()); if (auto typedefType = elaboratedType ? dyn_cast(elaboratedType->desugar()) - : enumDecl->getIntegerType()->getAs()) { + : dyn_cast( + enumDecl->getIntegerType().getTypePtr())) { auto enumExtensibilityAttr = elaboratedType ? enumDecl->getAttr() @@ -7052,13 +7055,8 @@ const clang::TypedefType *ClangImporter::getTypedefForCXXCFOptionsDefinition( enumExtensibilityAttr->getExtensibility() == clang::EnumExtensibilityAttr::Open && hasFlagEnumAttr) { - // Make sure the typedef is marked as unavailable in Swift. - auto typedefDecl = typedefType->getDecl(); - for (auto *attr : - typedefDecl->specific_attrs()) { - if (attr->getPlatform()->getName() == "swift") - return typedefType; - } + return Impl.isUnavailableInSwift(typedefType->getDecl()) ? typedefType + : nullptr; } } diff --git a/lib/ClangImporter/ImportType.cpp b/lib/ClangImporter/ImportType.cpp index 80dd134733c60..fe915dd30a9dc 100644 --- a/lib/ClangImporter/ImportType.cpp +++ b/lib/ClangImporter/ImportType.cpp @@ -2646,30 +2646,44 @@ ArgumentAttrs ClangImporter::Implementation::inferDefaultArgument( } } else if (const clang::TypedefType *typedefType = type->getAs()) { - clang::TypedefNameDecl *typedefDecl = typedefType->getDecl(); - // Find the next decl in the same context. If this typedef is a part of an - // NS/CF_OPTIONS declaration, the next decl will be an enum. - auto declsInContext = typedefDecl->getDeclContext()->decls(); - auto declIter = llvm::find(declsInContext, typedefDecl); - if (declIter != declsInContext.end()) - declIter++; - if (declIter != declsInContext.end()) { - if (auto enumDecl = dyn_cast(*declIter)) { - if (auto cfOptionsTy = - ClangImporter::getTypedefForCXXCFOptionsDefinition( - enumDecl, nameImporter.getContext())) { - if (cfOptionsTy->getDecl() == typedefDecl) { - auto enumName = typedefDecl->getName(); - ArgumentAttrs argumentAttrs(DefaultArgumentKind::None, true, - enumName); - for (auto word : llvm::reverse(camel_case::getWords(enumName))) { - if (camel_case::sameWordIgnoreFirstCase(word, "options")) { - argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray; - } - } - return argumentAttrs; - } + // Get the AvailabilityAttr that would be set from CF/NS_OPTIONS + if (importer::isUnavailableInSwift(typedefType->getDecl(), nullptr, true)) { + // If we've taken this branch it means we have an enum type, and it is + // likely an integer or NSInteger that is being used by NS/CF_OPTIONS to + // behave like a C enum in the presence of C++. + auto enumName = typedefType->getDecl()->getName(); + ArgumentAttrs argumentAttrs(DefaultArgumentKind::None, true, enumName); + auto camelCaseWords = camel_case::getWords(enumName); + for (auto it = camelCaseWords.rbegin(); it != camelCaseWords.rend(); + ++it) { + auto word = *it; + auto next = std::next(it); + if (camel_case::sameWordIgnoreFirstCase(word, "options")) { + argumentAttrs.argumentKind = DefaultArgumentKind::EmptyArray; + return argumentAttrs; } + if (camel_case::sameWordIgnoreFirstCase(word, "units")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "domain")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "action")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "event")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "events") && + next != camelCaseWords.rend() && + camel_case::sameWordIgnoreFirstCase(*next, "control")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "state")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "unit")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "position") && + next != camelCaseWords.rend() && + camel_case::sameWordIgnoreFirstCase(*next, "scroll")) + return argumentAttrs; + if (camel_case::sameWordIgnoreFirstCase(word, "edge")) + return argumentAttrs; } } } diff --git a/test/Interop/Cxx/enum/Inputs/c-enums-withOptions-omit.h b/test/Interop/Cxx/enum/Inputs/c-enums-withOptions-omit.h index 81b407ed60e48..daeced9d2377f 100644 --- a/test/Interop/Cxx/enum/Inputs/c-enums-withOptions-omit.h +++ b/test/Interop/Cxx/enum/Inputs/c-enums-withOptions-omit.h @@ -1,57 +1,39 @@ -typedef unsigned NSUInteger; - -#define __CF_OPTIONS_ATTRIBUTES __attribute__((flag_enum,enum_extensibility(open))) -#if (__cplusplus) -#define CF_OPTIONS(_type, _name) __attribute__((availability(swift,unavailable))) _type _name; enum __CF_OPTIONS_ATTRIBUTES : _name -#else -#define CF_OPTIONS(_type, _name) enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; enum _name : _type -#endif - -typedef CF_OPTIONS(NSUInteger, NSEnumerationOptions) { - NSEnumerationConcurrent = (1UL << 0), - NSEnumerationReverse = (1UL << 1), -}; +// Enum usage that is bitwise-able and assignable in C++, aka how CF_OPTIONS +// does things. +typedef int __attribute__((availability(swift, unavailable))) NSEnumerationOptions; +enum : NSEnumerationOptions { NSEnumerationConcurrent, NSEnumerationReverse }; @interface NSSet - (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts ; @end -typedef CF_OPTIONS(NSUInteger, NSOrderedCollectionDifferenceCalculationOptions) { +typedef int __attribute__((availability(swift, unavailable))) NSOrderedCollectionDifferenceCalculationOptions; +enum : NSOrderedCollectionDifferenceCalculationOptions { NSOrderedCollectionDifferenceCalculationOptions1, NSOrderedCollectionDifferenceCalculationOptions2 }; -typedef CF_OPTIONS(NSUInteger, NSCalendarUnit) { - NSCalendarUnit1, - NSCalendarUnit2 -}; +typedef int __attribute__((availability(swift, unavailable))) NSCalendarUnit; +enum : NSCalendarUnit { NSCalendarUnit1, NSCalendarUnit2 }; -typedef CF_OPTIONS(NSUInteger, NSSearchPathDomainMask) { - NSSearchPathDomainMask1, - NSSearchPathDomainMask2 -}; +typedef int __attribute__((availability(swift, unavailable))) NSSearchPathDomainMask; +enum : NSSearchPathDomainMask { NSSearchPathDomainMask1, NSSearchPathDomainMask2 }; -typedef CF_OPTIONS(NSUInteger, NSControlCharacterAction) { - NSControlCharacterAction1, - NSControlCharacterAction2 -}; +typedef int __attribute__((availability(swift, unavailable))) NSControlCharacterAction; +enum : NSControlCharacterAction { NSControlCharacterAction1, NSControlCharacterAction2 }; -typedef CF_OPTIONS(NSUInteger, UIControlState) { - UIControlState1, - UIControlState2 -}; +typedef int __attribute__((availability(swift, unavailable))) UIControlState; +enum : UIControlState { UIControlState1, UIControlState2 }; -typedef CF_OPTIONS(NSUInteger, UITableViewCellStateMask) { - UITableViewCellStateMask1, - UITableViewCellStateMask2 -}; +typedef int __attribute__((availability(swift, unavailable))) UITableViewCellStateMask; +enum : UITableViewCellStateMask { UITableViewCellStateMask1, UITableViewCellStateMask2 }; -typedef CF_OPTIONS(NSUInteger, UIControlEvents) { - UIControlEvents1, - UIControlEvents2 -}; +typedef int __attribute__((availability(swift, unavailable))) UIControlEvents; +enum : UIControlEvents { UIControlEvents1, UIControlEvents2 }; -typedef CF_OPTIONS(NSUInteger, UITableViewScrollPosition) { +typedef int __attribute__((availability(swift, unavailable))) +UITableViewScrollPosition; +enum : UITableViewScrollPosition { UITableViewScrollPosition1, UITableViewScrollPosition2 }; diff --git a/test/Interop/Cxx/objc-correctness/Inputs/customNSOptions.h b/test/Interop/Cxx/objc-correctness/Inputs/customNSOptions.h deleted file mode 100644 index b666f4d713027..0000000000000 --- a/test/Interop/Cxx/objc-correctness/Inputs/customNSOptions.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "CFOptions.h" - -typedef CF_OPTIONS(unsigned, MyControlFlags) { - MyControlFlagsNone = 0, - MyControlFlagsFirst -}; diff --git a/test/Interop/Cxx/objc-correctness/Inputs/module.modulemap b/test/Interop/Cxx/objc-correctness/Inputs/module.modulemap index 9d3a9bf5ac1f0..1d273bf94ff87 100644 --- a/test/Interop/Cxx/objc-correctness/Inputs/module.modulemap +++ b/test/Interop/Cxx/objc-correctness/Inputs/module.modulemap @@ -9,10 +9,6 @@ module CxxClassWithNSStringInit { requires cplusplus } -module CustomNSOptions { - header "customNSOptions.h" -} - module NSOptionsMangling { header "NSOptionsMangling.h" } diff --git a/test/Interop/Cxx/objc-correctness/custom-nsoptions.swift b/test/Interop/Cxx/objc-correctness/custom-nsoptions.swift deleted file mode 100644 index b91ab7d4c8d64..0000000000000 --- a/test/Interop/Cxx/objc-correctness/custom-nsoptions.swift +++ /dev/null @@ -1,16 +0,0 @@ -// RUN: rm -rf %t -// RUN: mkdir -p %t/pch - -// RUN: %target-typecheck-verify-swift -verify-ignore-unknown -I %S/Inputs -enable-objc-interop -enable-experimental-cxx-interop - -// RUN: %target-swift-frontend -emit-pch -enable-objc-interop -enable-experimental-cxx-interop -o %t/pch/customNSOptions.pch %S/Inputs/customNSOptions.h -// RUN: %target-typecheck-verify-swift -D BRIDGING_HEADER -I %S/Inputs -import-objc-header %t/pch/customNSOptions.pch -enable-objc-interop -enable-experimental-cxx-interop %s - -// REQUIRES: objc_interop - -#if !BRIDGING_HEADER -import CustomNSOptions -#endif - -let flags1: MyControlFlags = [] -let flags2: MyControlFlags = [.first]