Skip to content

Commit 6fed3d1

Browse files
authored
Merge pull request #6990 from jrose-apple/available-is-better-than-unavailable
[ClangImporter] Prefer available enum elements over unavailable ones.
2 parents 9580f41 + 3411fc3 commit 6fed3d1

File tree

6 files changed

+123
-65
lines changed

6 files changed

+123
-65
lines changed

lib/ClangImporter/ClangAdapter.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -671,15 +671,9 @@ bool importer::isUnavailableInSwift(
671671
if (enableObjCInterop && isObjCId(decl))
672672
return true;
673673

674-
// FIXME: Somewhat duplicated from importAttributes(), but this is a
675-
// more direct path.
676-
if (decl->getAvailability() == clang::AR_Unavailable)
674+
if (decl->isUnavailable())
677675
return true;
678676

679-
// Apply the deprecated-as-unavailable filter.
680-
if (!platformAvailability.deprecatedAsUnavailableFilter)
681-
return false;
682-
683677
for (auto *attr : decl->specific_attrs<clang::AvailabilityAttr>()) {
684678
if (attr->getPlatform()->getName() == "swift")
685679
return true;
@@ -689,12 +683,15 @@ bool importer::isUnavailableInSwift(
689683
continue;
690684
}
691685

692-
clang::VersionTuple version = attr->getDeprecated();
693-
if (version.empty())
694-
continue;
695-
if (platformAvailability.deprecatedAsUnavailableFilter(version.getMajor(),
696-
version.getMinor()))
697-
return true;
686+
if (platformAvailability.deprecatedAsUnavailableFilter) {
687+
clang::VersionTuple version = attr->getDeprecated();
688+
if (version.empty())
689+
continue;
690+
if (platformAvailability.deprecatedAsUnavailableFilter(
691+
version.getMajor(), version.getMinor())) {
692+
return true;
693+
}
694+
}
698695
}
699696

700697
return false;

lib/ClangImporter/ImportDecl.cpp

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

18021802
namespace {
1803+
/// Customized llvm::DenseMapInfo for storing borrowed APSInts.
1804+
struct APSIntRefDenseMapInfo {
1805+
static inline const llvm::APSInt *getEmptyKey() {
1806+
return llvm::DenseMapInfo<const llvm::APSInt *>::getEmptyKey();
1807+
}
1808+
static inline const llvm::APSInt *getTombstoneKey() {
1809+
return llvm::DenseMapInfo<const llvm::APSInt *>::getTombstoneKey();
1810+
}
1811+
static unsigned getHashValue(const llvm::APSInt *ptrVal) {
1812+
assert(ptrVal != getEmptyKey() && ptrVal != getTombstoneKey());
1813+
return llvm::hash_value(*ptrVal);
1814+
}
1815+
static bool isEqual(const llvm::APSInt *lhs, const llvm::APSInt *rhs) {
1816+
if (lhs == rhs) return true;
1817+
if (lhs == getEmptyKey() || rhs == getEmptyKey()) return false;
1818+
if (lhs == getTombstoneKey() || rhs == getTombstoneKey()) return false;
1819+
return *lhs == *rhs;
1820+
}
1821+
};
1822+
18031823
/// \brief Convert Clang declarations into the corresponding Swift
18041824
/// declarations.
18051825
class SwiftDeclConverter
@@ -2481,36 +2501,87 @@ namespace {
24812501
addEnumeratorsAsMembers = true;
24822502
break;
24832503
}
2484-
2485-
for (auto ec = decl->enumerator_begin(), ecEnd = decl->enumerator_end();
2486-
ec != ecEnd; ++ec) {
2504+
2505+
llvm::SmallDenseMap<const llvm::APSInt *,
2506+
PointerUnion<const clang::EnumConstantDecl *,
2507+
EnumElementDecl *>, 8,
2508+
APSIntRefDenseMapInfo> canonicalEnumConstants;
2509+
2510+
if (enumKind == EnumKind::Enum) {
2511+
for (auto constant : decl->enumerators()) {
2512+
if (Impl.isUnavailableInSwift(constant))
2513+
continue;
2514+
canonicalEnumConstants.insert({&constant->getInitVal(), constant});
2515+
}
2516+
}
2517+
2518+
for (auto constant : decl->enumerators()) {
24872519
Decl *enumeratorDecl;
24882520
Decl *swift2EnumeratorDecl = nullptr;
24892521
switch (enumKind) {
24902522
case EnumKind::Constants:
24912523
case EnumKind::Unknown:
2492-
enumeratorDecl = Impl.importDecl(*ec, getActiveSwiftVersion());
2524+
enumeratorDecl = Impl.importDecl(constant, getActiveSwiftVersion());
24932525
swift2EnumeratorDecl =
2494-
Impl.importDecl(*ec, ImportNameVersion::Swift2);
2526+
Impl.importDecl(constant, ImportNameVersion::Swift2);
24952527
break;
24962528
case EnumKind::Options:
24972529
enumeratorDecl =
24982530
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2499-
.importOptionConstant(*ec, decl, enumeratorContext);
2531+
.importOptionConstant(constant, decl, enumeratorContext);
25002532
swift2EnumeratorDecl =
25012533
SwiftDeclConverter(Impl, ImportNameVersion::Swift2)
2502-
.importOptionConstant(*ec, decl, enumeratorContext);
2534+
.importOptionConstant(constant, decl, enumeratorContext);
25032535
break;
2504-
case EnumKind::Enum:
2505-
enumeratorDecl =
2506-
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2507-
.importEnumCase(*ec, decl, cast<EnumDecl>(enumeratorContext));
2536+
case EnumKind::Enum: {
2537+
auto canonicalCaseIter =
2538+
canonicalEnumConstants.find(&constant->getInitVal());
2539+
2540+
if (canonicalCaseIter == canonicalEnumConstants.end()) {
2541+
// Unavailable declarations get no special treatment.
2542+
enumeratorDecl =
2543+
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2544+
.importEnumCase(constant, decl,
2545+
cast<EnumDecl>(enumeratorContext));
2546+
} else {
2547+
const clang::EnumConstantDecl *unimported =
2548+
canonicalCaseIter->
2549+
second.dyn_cast<const clang::EnumConstantDecl *>();
2550+
2551+
// Import the canonical enumerator for this case first.
2552+
if (unimported) {
2553+
enumeratorDecl = SwiftDeclConverter(Impl, getActiveSwiftVersion())
2554+
.importEnumCase(unimported, decl,
2555+
cast<EnumDecl>(enumeratorContext));
2556+
if (enumeratorDecl) {
2557+
canonicalCaseIter->getSecond() =
2558+
cast<EnumElementDecl>(enumeratorDecl);
2559+
}
2560+
} else {
2561+
enumeratorDecl =
2562+
canonicalCaseIter->second.get<EnumElementDecl *>();
2563+
}
2564+
2565+
if (unimported != constant && enumeratorDecl) {
2566+
ImportedName importedName =
2567+
Impl.importFullName(constant, getActiveSwiftVersion());
2568+
Identifier name = importedName.getDeclName().getBaseName();
2569+
if (!name.empty()) {
2570+
auto original = cast<ValueDecl>(enumeratorDecl);
2571+
enumeratorDecl = importEnumCaseAlias(name, constant, original,
2572+
decl, enumeratorContext);
2573+
}
2574+
}
2575+
}
2576+
25082577
swift2EnumeratorDecl =
25092578
SwiftDeclConverter(Impl, ImportNameVersion::Swift2)
2510-
.importEnumCase(*ec, decl, cast<EnumDecl>(enumeratorContext),
2579+
.importEnumCase(constant, decl,
2580+
cast<EnumDecl>(enumeratorContext),
25112581
enumeratorDecl);
25122582
break;
25132583
}
2584+
}
25142585
if (!enumeratorDecl)
25152586
continue;
25162587

@@ -2532,7 +2603,7 @@ namespace {
25322603
if (errorWrapper) {
25332604
auto enumeratorValue = cast<ValueDecl>(enumeratorDecl);
25342605
auto alias = importEnumCaseAlias(enumeratorValue->getName(),
2535-
*ec,
2606+
constant,
25362607
enumeratorValue,
25372608
decl,
25382609
enumeratorContext,
@@ -4751,14 +4822,6 @@ Decl *SwiftDeclConverter::importEnumCase(const clang::EnumConstantDecl *decl,
47514822
bool negative = false;
47524823
llvm::APSInt rawValue = decl->getInitVal();
47534824

4754-
// Did we already import an enum constant for this enum with the
4755-
// same value? If so, import it as a standalone constant.
4756-
auto insertResult =
4757-
Impl.EnumConstantValues.insert({{clangEnum, rawValue}, nullptr});
4758-
if (!insertResult.second)
4759-
return importEnumCaseAlias(name, decl, insertResult.first->second,
4760-
clangEnum, theEnum);
4761-
47624825
if (clangEnum->getIntegerType()->isSignedIntegerOrEnumerationType() &&
47634826
rawValue.slt(0)) {
47644827
rawValue = -rawValue;
@@ -4776,7 +4839,6 @@ Decl *SwiftDeclConverter::importEnumCase(const clang::EnumConstantDecl *decl,
47764839
auto element = Impl.createDeclWithClangNode<EnumElementDecl>(
47774840
decl, Accessibility::Public, SourceLoc(), name, TypeLoc(), SourceLoc(),
47784841
rawValueExpr, theEnum);
4779-
insertResult.first->second = element;
47804842

47814843
// Give the enum element the appropriate type.
47824844
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<

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,10 +1405,11 @@ const AvailableAttr *TypeChecker::getDeprecated(const Decl *D) {
14051405

14061406
/// Returns true if some declaration lexically enclosing the reference
14071407
/// matches the passed in predicate and false otherwise.
1408-
static bool someEnclosingDeclMatches(SourceRange ReferenceRange,
1409-
const DeclContext *ReferenceDC,
1410-
TypeChecker &TC,
1411-
std::function<bool(const Decl *)> Pred) {
1408+
static bool
1409+
someEnclosingDeclMatches(SourceRange ReferenceRange,
1410+
const DeclContext *ReferenceDC,
1411+
TypeChecker &TC,
1412+
llvm::function_ref<bool(const Decl *)> Pred) {
14121413
ASTContext &Ctx = TC.Context;
14131414

14141415
// Climb the DeclContext hierarchy to see if any of the containing
@@ -1500,7 +1501,7 @@ bool TypeChecker::isInsideUnavailableDeclaration(
15001501

15011502
bool TypeChecker::isInsideDeprecatedDeclaration(SourceRange ReferenceRange,
15021503
const DeclContext *ReferenceDC){
1503-
std::function<bool(const Decl *)> IsDeprecated = [](const Decl *D) {
1504+
auto IsDeprecated = [](const Decl *D) {
15041505
return D->getAttrs().getDeprecated(D->getASTContext());
15051506
};
15061507

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)