Skip to content

Commit fe2f857

Browse files
authored
Merge pull request #64043 from apple/ns-option-linkage-conflict
Fix ASTMangler mangling NS_OPTION differently in C++ mode
2 parents d6be820 + 709321b commit fe2f857

File tree

9 files changed

+137
-12
lines changed

9 files changed

+137
-12
lines changed

include/swift/AST/ASTMangler.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,8 +384,11 @@ class ASTMangler : public Mangler {
384384
static Optional<SpecialContext>
385385
getSpecialManglingContext(const ValueDecl *decl, bool useObjCProtocolNames);
386386

387-
static const clang::NamedDecl *
388-
getClangDeclForMangling(const ValueDecl *decl);
387+
static bool isCXXCFOptionsDefinition(const ValueDecl *decl);
388+
static const clang::TypedefType *
389+
getTypeDefForCXXCFOptionsDefinition(const ValueDecl *decl);
390+
391+
static const clang::NamedDecl *getClangDeclForMangling(const ValueDecl *decl);
389392

390393
void appendExistentialLayout(
391394
const ExistentialLayout &layout, GenericSignature sig,

include/swift/AST/ClangModuleLoader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ class ClangModuleLoader : public ModuleLoader {
288288
/// Determine the effective Clang context for the given Swift nominal type.
289289
virtual EffectiveClangContext getEffectiveClangContext(
290290
const NominalTypeDecl *nominal) = 0;
291+
292+
virtual const clang::TypedefType *
293+
getTypeDefForCXXCFOptionsDefinition(const clang::Decl *candidateDecl) = 0;
291294
};
292295

293296
/// Describes a C++ template instantiation error.

include/swift/ClangImporter/ClangImporter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,9 @@ class ClangImporter final : public ClangModuleLoader {
560560

561561
/// Enable the symbolic import experimental feature for the given callback.
562562
void withSymbolicFeatureEnabled(llvm::function_ref<void(void)> callback);
563+
564+
const clang::TypedefType *getTypeDefForCXXCFOptionsDefinition(
565+
const clang::Decl *candidateDecl) override;
563566
};
564567

565568
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,

lib/AST/ASTMangler.cpp

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -484,12 +484,19 @@ void ASTMangler::beginManglingWithAutoDiffOriginalFunction(
484484
appendOperator(attr->Name);
485485
return;
486486
}
487+
488+
auto beginManglingClangDecl = [&](const clang::NamedDecl *decl) {
489+
beginManglingWithoutPrefix();
490+
appendOperator(decl->getName());
491+
};
492+
487493
// For imported Clang declarations, use the Clang name in order to match how
488494
// DifferentiationMangler handles these.
489-
auto clangDecl = getClangDeclForMangling(afd);
490-
if (clangDecl) {
491-
beginManglingWithoutPrefix();
492-
appendOperator(clangDecl->getName());
495+
if (auto clangDecl = getClangDeclForMangling(afd)) {
496+
beginManglingClangDecl(clangDecl);
497+
return;
498+
} else if (auto typedefType = getTypeDefForCXXCFOptionsDefinition(afd)) {
499+
beginManglingClangDecl(typedefType->getDecl());
493500
return;
494501
}
495502
beginMangling();
@@ -2170,7 +2177,13 @@ ASTMangler::getSpecialManglingContext(const ValueDecl *decl,
21702177
if (auto *clangDecl = cast_or_null<clang::NamedDecl>(decl->getClangDecl())){
21712178
bool hasNameForLinkage;
21722179
if (auto *tagDecl = dyn_cast<clang::TagDecl>(clangDecl))
2173-
hasNameForLinkage = tagDecl->hasNameForLinkage();
2180+
// Clang does not always populate the fields that determine if a tag
2181+
// decl has a linkage name. This is particularly the case for the
2182+
// C++ definition of CF_OPTIONS in the sdk. However, we use the
2183+
// name of the backing typedef as a linkage name, despite
2184+
// the enum itself not having one.
2185+
hasNameForLinkage =
2186+
tagDecl->hasNameForLinkage() || isCXXCFOptionsDefinition(decl);
21742187
else
21752188
hasNameForLinkage = !clangDecl->getDeclName().isEmpty();
21762189
if (hasNameForLinkage) {
@@ -2510,11 +2523,26 @@ void ASTMangler::appendProtocolName(const ProtocolDecl *protocol,
25102523
appendDeclName(protocol);
25112524
}
25122525

2513-
const clang::NamedDecl *ASTMangler::getClangDeclForMangling(const ValueDecl *vd) {
2514-
auto namedDecl = dyn_cast_or_null<clang::NamedDecl>(vd->getClangDecl());
2526+
bool ASTMangler::isCXXCFOptionsDefinition(const ValueDecl *decl) {
2527+
return getTypeDefForCXXCFOptionsDefinition(decl);
2528+
}
2529+
2530+
const clang::TypedefType *
2531+
ASTMangler::getTypeDefForCXXCFOptionsDefinition(const ValueDecl *decl) {
2532+
const clang::Decl *clangDecl = decl->getClangDecl();
2533+
if (!clangDecl)
2534+
return nullptr;
2535+
2536+
const auto &clangModuleLoader = decl->getASTContext().getClangModuleLoader();
2537+
return clangModuleLoader->getTypeDefForCXXCFOptionsDefinition(clangDecl);
2538+
}
2539+
2540+
const clang::NamedDecl *
2541+
ASTMangler::getClangDeclForMangling(const ValueDecl *vd) {
2542+
auto namedDecl = dyn_cast_or_null<clang::NamedDecl>(vd->getClangDecl());
25152543
if (!namedDecl)
25162544
return nullptr;
2517-
2545+
25182546
// Use an anonymous enum's enclosing typedef for the mangled name, if
25192547
// present. This matches C++'s rules for linkage names of tag declarations.
25202548
if (namedDecl->getDeclName().isEmpty())
@@ -2576,8 +2604,20 @@ void ASTMangler::appendAnyGenericType(const GenericTypeDecl *decl) {
25762604
auto tryAppendClangName = [this, decl]() -> bool {
25772605
auto *nominal = dyn_cast<NominalTypeDecl>(decl);
25782606
auto namedDecl = getClangDeclForMangling(decl);
2579-
if (!namedDecl)
2607+
if (!namedDecl) {
2608+
if (auto typedefType = getTypeDefForCXXCFOptionsDefinition(decl)) {
2609+
// To make sure the C++ definition of CF_OPTIONS mangles the
2610+
// same way as the Objective-C definition, we mangle using the
2611+
// name of the backing typedef, but pretend as if it was an enum.
2612+
// See CFAvailability.h to understand how the definitions differ
2613+
// in C++ and Objective-C
2614+
appendIdentifier(typedefType->getDecl()->getName());
2615+
appendOperator("V");
2616+
return true;
2617+
}
2618+
25802619
return false;
2620+
}
25812621

25822622
// Mangle ObjC classes using their runtime names.
25832623
auto interface = dyn_cast<clang::ObjCInterfaceDecl>(namedDecl);

lib/ClangImporter/ClangImporter.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6670,6 +6670,35 @@ void ClangImporter::withSymbolicFeatureEnabled(
66706670
oldImportSymbolicCXXDecls.get());
66716671
}
66726672

6673+
const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
6674+
const clang::Decl *candidateDecl) {
6675+
6676+
if (!Impl.SwiftContext.LangOpts.EnableCXXInterop)
6677+
return nullptr;
6678+
6679+
auto enumDecl = dyn_cast<clang::EnumDecl>(candidateDecl);
6680+
if (!enumDecl)
6681+
return nullptr;
6682+
6683+
if (!enumDecl->getDeclName().isEmpty())
6684+
return nullptr;
6685+
6686+
if (auto typedefType = dyn_cast<clang::TypedefType>(
6687+
enumDecl->getIntegerType().getTypePtr())) {
6688+
if (auto enumExtensibilityAttr =
6689+
typedefType->getDecl()->getAttr<clang::EnumExtensibilityAttr>();
6690+
enumExtensibilityAttr &&
6691+
enumExtensibilityAttr->getExtensibility() ==
6692+
clang::EnumExtensibilityAttr::Open &&
6693+
typedefType->getDecl()->hasAttr<clang::FlagEnumAttr>()) {
6694+
return Impl.isUnavailableInSwift(typedefType->getDecl()) ? typedefType
6695+
: nullptr;
6696+
}
6697+
}
6698+
6699+
return nullptr;
6700+
}
6701+
66736702
bool importer::requiresCPlusPlus(const clang::Module *module) {
66746703
// The libc++ modulemap doesn't currently declare the requirement.
66756704
if (module->getTopLevelModuleName() == "std")

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ namespace {
12441244
// Otherwise, if this was imported from a Clang declaration, use that
12451245
// declaration's name as the ABI name.
12461246
} else if (auto clangDecl =
1247-
Mangle::ASTMangler::getClangDeclForMangling(Type)) {
1247+
Mangle::ASTMangler::getClangDeclForMangling(Type)) {
12481248
// Class template specializations need to use their mangled name so
12491249
// that each specialization gets its own metadata. A class template
12501250
// specialization's Swift name will always be the mangled name, so just
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#if __has_attribute(enum_extensibility)
2+
#define __CF_ENUM_ATTRIBUTES __attribute__((enum_extensibility(open)))
3+
#define __CF_CLOSED_ENUM_ATTRIBUTES __attribute__((enum_extensibility(closed)))
4+
#define __CF_OPTIONS_ATTRIBUTES \
5+
__attribute__((flag_enum, enum_extensibility(open)))
6+
#else
7+
#define __CF_ENUM_ATTRIBUTES
8+
#define __CF_CLOSED_ENUM_ATTRIBUTES
9+
#define __CF_OPTIONS_ATTRIBUTES
10+
#endif
11+
12+
#if (__cplusplus)
13+
#define CF_OPTIONS(_type, _name) \
14+
_type __attribute__((availability(swift, unavailable))) _name; \
15+
enum __CF_OPTIONS_ATTRIBUTES : _name
16+
#else
17+
#define CF_OPTIONS(_type, _name) \
18+
enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; \
19+
enum _name : _type
20+
#endif
21+
22+
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)
23+
24+
typedef NS_OPTIONS(int, StandardNSOption) {
25+
StandardNSOption1,
26+
StandardNSOption2
27+
};

test/Interop/Cxx/enum/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,7 @@ module CenumsNSOptionsExternC [extern_c] {
3232
header "c-enums-NS_OPTIONS_without_extern_C.h"
3333
requires cplusplus
3434
}
35+
36+
module CFAvailability {
37+
header "CFAvailability.h"
38+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %empty-directory(%t/cache)
2+
// RUN: %target-swift-frontend %s -I %S/Inputs -c -enable-experimental-cxx-interop -o %t/object.o
3+
// RUN: %llvm-nm %t/object.o > %t/results.txt
4+
// RUN: %target-swift-frontend %s -I %S/Inputs -c -enable-objc-interop -o %t/object.o
5+
// RUN: %llvm-nm %t/object.o >> %t/results.txt
6+
// RUN: cat %t/results.txt | %FileCheck %s
7+
8+
// REQUIRES: objc_interop
9+
10+
import CFAvailability
11+
12+
// Verify that this functions linkage name is the name with or without cxx interop enabled
13+
public func useNSOption(foo param: StandardNSOption) {}
14+
15+
// CHECK: [[FUNC_LINKAGE_NAME:\$s.*useNSOption.*$]]
16+
// CHECK: [[FUNC_LINKAGE_NAME]]

0 commit comments

Comments
 (0)