Skip to content

Commit 3411fc3

Browse files
committed
[ClangImporter] Prefer available enum elements over unavailable ones.
...and avoid making aliases from one unavailable declaration to another. If it's unavailable, we can just import it as a normal case and not worry about it. This fixes an issue where Sema would try to diagnose the body of an "alias" for referring to unavailable declarations. (Background: enum cases in Swift have to have unique values, so we import any duplicate values as static properties. Pattern matching logic has a hack to recognize these particular static properties as being "case-like".) This commit also sinks enum element uniqueness checking into importing the enum, instead of keeping a global map we never consult again. This should save a small bit of memory. rdar://problem/30025723
1 parent c054713 commit 3411fc3

File tree

4 files changed

+107
-47
lines changed

4 files changed

+107
-47
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,6 +1792,26 @@ applyPropertyOwnership(VarDecl *prop,
17921792
}
17931793

17941794
namespace {
1795+
/// Customized llvm::DenseMapInfo for storing borrowed APSInts.
1796+
struct APSIntRefDenseMapInfo {
1797+
static inline const llvm::APSInt *getEmptyKey() {
1798+
return llvm::DenseMapInfo<const llvm::APSInt *>::getEmptyKey();
1799+
}
1800+
static inline const llvm::APSInt *getTombstoneKey() {
1801+
return llvm::DenseMapInfo<const llvm::APSInt *>::getTombstoneKey();
1802+
}
1803+
static unsigned getHashValue(const llvm::APSInt *ptrVal) {
1804+
assert(ptrVal != getEmptyKey() && ptrVal != getTombstoneKey());
1805+
return llvm::hash_value(*ptrVal);
1806+
}
1807+
static bool isEqual(const llvm::APSInt *lhs, const llvm::APSInt *rhs) {
1808+
if (lhs == rhs) return true;
1809+
if (lhs == getEmptyKey() || rhs == getEmptyKey()) return false;
1810+
if (lhs == getTombstoneKey() || rhs == getTombstoneKey()) return false;
1811+
return *lhs == *rhs;
1812+
}
1813+
};
1814+
17951815
/// \brief Convert Clang declarations into the corresponding Swift
17961816
/// declarations.
17971817
class SwiftDeclConverter
@@ -2473,36 +2493,87 @@ namespace {
24732493
addEnumeratorsAsMembers = true;
24742494
break;
24752495
}
2476-
2477-
for (auto ec = decl->enumerator_begin(), ecEnd = decl->enumerator_end();
2478-
ec != ecEnd; ++ec) {
2496+
2497+
llvm::SmallDenseMap<const llvm::APSInt *,
2498+
PointerUnion<const clang::EnumConstantDecl *,
2499+
EnumElementDecl *>, 8,
2500+
APSIntRefDenseMapInfo> canonicalEnumConstants;
2501+
2502+
if (enumKind == EnumKind::Enum) {
2503+
for (auto constant : decl->enumerators()) {
2504+
if (Impl.isUnavailableInSwift(constant))
2505+
continue;
2506+
canonicalEnumConstants.insert({&constant->getInitVal(), constant});
2507+
}
2508+
}
2509+
2510+
for (auto constant : decl->enumerators()) {
24792511
Decl *enumeratorDecl;
24802512
Decl *swift2EnumeratorDecl = nullptr;
24812513
switch (enumKind) {
24822514
case EnumKind::Constants:
24832515
case EnumKind::Unknown:
2484-
enumeratorDecl = Impl.importDecl(*ec, getActiveSwiftVersion());
2516+
enumeratorDecl = Impl.importDecl(constant, getActiveSwiftVersion());
24852517
swift2EnumeratorDecl =
2486-
Impl.importDecl(*ec, ImportNameVersion::Swift2);
2518+
Impl.importDecl(constant, ImportNameVersion::Swift2);
24872519
break;
24882520
case EnumKind::Options:
24892521
enumeratorDecl =
24902522
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2491-
.importOptionConstant(*ec, decl, enumeratorContext);
2523+
.importOptionConstant(constant, decl, enumeratorContext);
24922524
swift2EnumeratorDecl =
24932525
SwiftDeclConverter(Impl, ImportNameVersion::Swift2)
2494-
.importOptionConstant(*ec, decl, enumeratorContext);
2526+
.importOptionConstant(constant, decl, enumeratorContext);
24952527
break;
2496-
case EnumKind::Enum:
2497-
enumeratorDecl =
2498-
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2499-
.importEnumCase(*ec, decl, cast<EnumDecl>(enumeratorContext));
2528+
case EnumKind::Enum: {
2529+
auto canonicalCaseIter =
2530+
canonicalEnumConstants.find(&constant->getInitVal());
2531+
2532+
if (canonicalCaseIter == canonicalEnumConstants.end()) {
2533+
// Unavailable declarations get no special treatment.
2534+
enumeratorDecl =
2535+
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2536+
.importEnumCase(constant, decl,
2537+
cast<EnumDecl>(enumeratorContext));
2538+
} else {
2539+
const clang::EnumConstantDecl *unimported =
2540+
canonicalCaseIter->
2541+
second.dyn_cast<const clang::EnumConstantDecl *>();
2542+
2543+
// Import the canonical enumerator for this case first.
2544+
if (unimported) {
2545+
enumeratorDecl = SwiftDeclConverter(Impl, getActiveSwiftVersion())
2546+
.importEnumCase(unimported, decl,
2547+
cast<EnumDecl>(enumeratorContext));
2548+
if (enumeratorDecl) {
2549+
canonicalCaseIter->getSecond() =
2550+
cast<EnumElementDecl>(enumeratorDecl);
2551+
}
2552+
} else {
2553+
enumeratorDecl =
2554+
canonicalCaseIter->second.get<EnumElementDecl *>();
2555+
}
2556+
2557+
if (unimported != constant && enumeratorDecl) {
2558+
ImportedName importedName =
2559+
Impl.importFullName(constant, getActiveSwiftVersion());
2560+
Identifier name = importedName.getDeclName().getBaseName();
2561+
if (!name.empty()) {
2562+
auto original = cast<ValueDecl>(enumeratorDecl);
2563+
enumeratorDecl = importEnumCaseAlias(name, constant, original,
2564+
decl, enumeratorContext);
2565+
}
2566+
}
2567+
}
2568+
25002569
swift2EnumeratorDecl =
25012570
SwiftDeclConverter(Impl, ImportNameVersion::Swift2)
2502-
.importEnumCase(*ec, decl, cast<EnumDecl>(enumeratorContext),
2571+
.importEnumCase(constant, decl,
2572+
cast<EnumDecl>(enumeratorContext),
25032573
enumeratorDecl);
25042574
break;
25052575
}
2576+
}
25062577
if (!enumeratorDecl)
25072578
continue;
25082579

@@ -2524,7 +2595,7 @@ namespace {
25242595
if (errorWrapper) {
25252596
auto enumeratorValue = cast<ValueDecl>(enumeratorDecl);
25262597
auto alias = importEnumCaseAlias(enumeratorValue->getName(),
2527-
*ec,
2598+
constant,
25282599
enumeratorValue,
25292600
decl,
25302601
enumeratorContext,
@@ -4743,14 +4814,6 @@ Decl *SwiftDeclConverter::importEnumCase(const clang::EnumConstantDecl *decl,
47434814
bool negative = false;
47444815
llvm::APSInt rawValue = decl->getInitVal();
47454816

4746-
// Did we already import an enum constant for this enum with the
4747-
// same value? If so, import it as a standalone constant.
4748-
auto insertResult =
4749-
Impl.EnumConstantValues.insert({{clangEnum, rawValue}, nullptr});
4750-
if (!insertResult.second)
4751-
return importEnumCaseAlias(name, decl, insertResult.first->second,
4752-
clangEnum, theEnum);
4753-
47544817
if (clangEnum->getIntegerType()->isSignedIntegerOrEnumerationType() &&
47554818
rawValue.slt(0)) {
47564819
rawValue = -rawValue;
@@ -4768,7 +4831,6 @@ Decl *SwiftDeclConverter::importEnumCase(const clang::EnumConstantDecl *decl,
47684831
auto element = Impl.createDeclWithClangNode<EnumElementDecl>(
47694832
decl, Accessibility::Public, SourceLoc(), name, TypeLoc(), SourceLoc(),
47704833
rawValueExpr, theEnum);
4771-
insertResult.first->second = element;
47724834

47734835
// Give the enum element the appropriate type.
47744836
element->computeType();

lib/ClangImporter/ImporterImpl.h

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -410,37 +410,12 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
410410
LookupTableMap &getLookupTables() { return LookupTables; }
411411

412412
private:
413-
class EnumConstantDenseMapInfo {
414-
public:
415-
using PairTy = std::pair<const clang::EnumDecl *, llvm::APSInt>;
416-
using PointerInfo = llvm::DenseMapInfo<const clang::EnumDecl *>;
417-
static inline PairTy getEmptyKey() {
418-
return {PointerInfo::getEmptyKey(), llvm::APSInt(/*bitwidth=*/1)};
419-
}
420-
static inline PairTy getTombstoneKey() {
421-
return {PointerInfo::getTombstoneKey(), llvm::APSInt(/*bitwidth=*/1)};
422-
}
423-
static unsigned getHashValue(const PairTy &pair) {
424-
return llvm::combineHashValue(PointerInfo::getHashValue(pair.first),
425-
llvm::hash_value(pair.second));
426-
}
427-
static bool isEqual(const PairTy &lhs, const PairTy &rhs) {
428-
return lhs == rhs;
429-
}
430-
};
431-
432413
/// A mapping from imported declarations to their "alternate" declarations,
433414
/// for cases where a single Clang declaration is imported to two
434415
/// different Swift declarations.
435416
llvm::DenseMap<Decl *, TinyPtrVector<ValueDecl *>> AlternateDecls;
436417

437418
public:
438-
/// \brief Keep track of enum constant values that have been imported.
439-
llvm::DenseMap<std::pair<const clang::EnumDecl *, llvm::APSInt>,
440-
EnumElementDecl *,
441-
EnumConstantDenseMapInfo>
442-
EnumConstantValues;
443-
444419
/// \brief Keep track of initializer declarations that correspond to
445420
/// imported methods.
446421
llvm::DenseMap<

test/ClangImporter/enum.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil %s -verify
2+
// RUN: not %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %s 2>&1 | %FileCheck %s
23
// -- Check that we can successfully round-trip.
34
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -D IRGEN -emit-ir %s >/dev/null
45

56
// REQUIRES: objc_interop
67

8+
// At one point we diagnosed enum case aliases that referred to unavailable
9+
// cases in their (synthesized) implementation.
10+
// CHECK-NOT: unknown
11+
712
import Foundation
813
import user_objc
914

@@ -106,6 +111,15 @@ extension NSAliasesEnum {
106111
}
107112
}
108113

114+
#if !IRGEN
115+
_ = NSUnavailableAliasesEnum.originalAU
116+
_ = NSUnavailableAliasesEnum.aliasAU // expected-error {{'aliasAU' is unavailable}}
117+
_ = NSUnavailableAliasesEnum.originalUA // expected-error {{'originalUA' is unavailable}}
118+
_ = NSUnavailableAliasesEnum.aliasUA
119+
_ = NSUnavailableAliasesEnum.originalUU // expected-error {{'originalUU' is unavailable}}
120+
_ = NSUnavailableAliasesEnum.aliasUU // expected-error {{'aliasUU' is unavailable}}
121+
#endif
122+
109123
// Test NS_SWIFT_NAME:
110124
_ = XMLNode.Kind.DTDKind == .invalid
111125

test/Inputs/clang-importer-sdk/usr/include/Foundation.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,15 @@ typedef NS_ENUM(unsigned char, NSAliasesEnum) {
381381
NSAliasesDifferentValue = 2
382382
};
383383

384+
typedef NS_ENUM(unsigned char, NSUnavailableAliasesEnum) {
385+
NSUnavailableAliasesOriginalAU = 0,
386+
NSUnavailableAliasesAliasAU __attribute__((unavailable)) = 0,
387+
NSUnavailableAliasesOriginalUA __attribute__((unavailable)) = 1,
388+
NSUnavailableAliasesAliasUA = 1,
389+
NSUnavailableAliasesOriginalUU __attribute__((unavailable)) = 2,
390+
NSUnavailableAliasesAliasUU __attribute__((unavailable)) = 2,
391+
};
392+
384393
NS_ENUM(NSInteger, NSMalformedEnumMissingTypedef) {
385394
NSMalformedEnumMissingTypedefValue
386395
};

0 commit comments

Comments
 (0)