Skip to content

Commit aed4b00

Browse files
committed
Merge pull request #6990 from jrose-apple/available-is-better-than-unavailable
[ClangImporter] Prefer available enum elements over unavailable ones.
1 parent d8dcd8f commit aed4b00

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
@@ -1788,6 +1788,26 @@ applyPropertyOwnership(VarDecl *prop,
17881788
}
17891789

17901790
namespace {
1791+
/// Customized llvm::DenseMapInfo for storing borrowed APSInts.
1792+
struct APSIntRefDenseMapInfo {
1793+
static inline const llvm::APSInt *getEmptyKey() {
1794+
return llvm::DenseMapInfo<const llvm::APSInt *>::getEmptyKey();
1795+
}
1796+
static inline const llvm::APSInt *getTombstoneKey() {
1797+
return llvm::DenseMapInfo<const llvm::APSInt *>::getTombstoneKey();
1798+
}
1799+
static unsigned getHashValue(const llvm::APSInt *ptrVal) {
1800+
assert(ptrVal != getEmptyKey() && ptrVal != getTombstoneKey());
1801+
return llvm::hash_value(*ptrVal);
1802+
}
1803+
static bool isEqual(const llvm::APSInt *lhs, const llvm::APSInt *rhs) {
1804+
if (lhs == rhs) return true;
1805+
if (lhs == getEmptyKey() || rhs == getEmptyKey()) return false;
1806+
if (lhs == getTombstoneKey() || rhs == getTombstoneKey()) return false;
1807+
return *lhs == *rhs;
1808+
}
1809+
};
1810+
17911811
/// \brief Convert Clang declarations into the corresponding Swift
17921812
/// declarations.
17931813
class SwiftDeclConverter
@@ -2469,36 +2489,87 @@ namespace {
24692489
addEnumeratorsAsMembers = true;
24702490
break;
24712491
}
2472-
2473-
for (auto ec = decl->enumerator_begin(), ecEnd = decl->enumerator_end();
2474-
ec != ecEnd; ++ec) {
2492+
2493+
llvm::SmallDenseMap<const llvm::APSInt *,
2494+
PointerUnion<const clang::EnumConstantDecl *,
2495+
EnumElementDecl *>, 8,
2496+
APSIntRefDenseMapInfo> canonicalEnumConstants;
2497+
2498+
if (enumKind == EnumKind::Enum) {
2499+
for (auto constant : decl->enumerators()) {
2500+
if (Impl.isUnavailableInSwift(constant))
2501+
continue;
2502+
canonicalEnumConstants.insert({&constant->getInitVal(), constant});
2503+
}
2504+
}
2505+
2506+
for (auto constant : decl->enumerators()) {
24752507
Decl *enumeratorDecl;
24762508
Decl *swift2EnumeratorDecl = nullptr;
24772509
switch (enumKind) {
24782510
case EnumKind::Constants:
24792511
case EnumKind::Unknown:
2480-
enumeratorDecl = Impl.importDecl(*ec, getActiveSwiftVersion());
2512+
enumeratorDecl = Impl.importDecl(constant, getActiveSwiftVersion());
24812513
swift2EnumeratorDecl =
2482-
Impl.importDecl(*ec, ImportNameVersion::Swift2);
2514+
Impl.importDecl(constant, ImportNameVersion::Swift2);
24832515
break;
24842516
case EnumKind::Options:
24852517
enumeratorDecl =
24862518
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2487-
.importOptionConstant(*ec, decl, enumeratorContext);
2519+
.importOptionConstant(constant, decl, enumeratorContext);
24882520
swift2EnumeratorDecl =
24892521
SwiftDeclConverter(Impl, ImportNameVersion::Swift2)
2490-
.importOptionConstant(*ec, decl, enumeratorContext);
2522+
.importOptionConstant(constant, decl, enumeratorContext);
24912523
break;
2492-
case EnumKind::Enum:
2493-
enumeratorDecl =
2494-
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2495-
.importEnumCase(*ec, decl, cast<EnumDecl>(enumeratorContext));
2524+
case EnumKind::Enum: {
2525+
auto canonicalCaseIter =
2526+
canonicalEnumConstants.find(&constant->getInitVal());
2527+
2528+
if (canonicalCaseIter == canonicalEnumConstants.end()) {
2529+
// Unavailable declarations get no special treatment.
2530+
enumeratorDecl =
2531+
SwiftDeclConverter(Impl, getActiveSwiftVersion())
2532+
.importEnumCase(constant, decl,
2533+
cast<EnumDecl>(enumeratorContext));
2534+
} else {
2535+
const clang::EnumConstantDecl *unimported =
2536+
canonicalCaseIter->
2537+
second.dyn_cast<const clang::EnumConstantDecl *>();
2538+
2539+
// Import the canonical enumerator for this case first.
2540+
if (unimported) {
2541+
enumeratorDecl = SwiftDeclConverter(Impl, getActiveSwiftVersion())
2542+
.importEnumCase(unimported, decl,
2543+
cast<EnumDecl>(enumeratorContext));
2544+
if (enumeratorDecl) {
2545+
canonicalCaseIter->getSecond() =
2546+
cast<EnumElementDecl>(enumeratorDecl);
2547+
}
2548+
} else {
2549+
enumeratorDecl =
2550+
canonicalCaseIter->second.get<EnumElementDecl *>();
2551+
}
2552+
2553+
if (unimported != constant && enumeratorDecl) {
2554+
ImportedName importedName =
2555+
Impl.importFullName(constant, getActiveSwiftVersion());
2556+
Identifier name = importedName.getDeclName().getBaseName();
2557+
if (!name.empty()) {
2558+
auto original = cast<ValueDecl>(enumeratorDecl);
2559+
enumeratorDecl = importEnumCaseAlias(name, constant, original,
2560+
decl, enumeratorContext);
2561+
}
2562+
}
2563+
}
2564+
24962565
swift2EnumeratorDecl =
24972566
SwiftDeclConverter(Impl, ImportNameVersion::Swift2)
2498-
.importEnumCase(*ec, decl, cast<EnumDecl>(enumeratorContext),
2567+
.importEnumCase(constant, decl,
2568+
cast<EnumDecl>(enumeratorContext),
24992569
enumeratorDecl);
25002570
break;
25012571
}
2572+
}
25022573
if (!enumeratorDecl)
25032574
continue;
25042575

@@ -2520,7 +2591,7 @@ namespace {
25202591
if (errorWrapper) {
25212592
auto enumeratorValue = cast<ValueDecl>(enumeratorDecl);
25222593
auto alias = importEnumCaseAlias(enumeratorValue->getName(),
2523-
*ec,
2594+
constant,
25242595
enumeratorValue,
25252596
decl,
25262597
enumeratorContext,
@@ -4739,14 +4810,6 @@ Decl *SwiftDeclConverter::importEnumCase(const clang::EnumConstantDecl *decl,
47394810
bool negative = false;
47404811
llvm::APSInt rawValue = decl->getInitVal();
47414812

4742-
// Did we already import an enum constant for this enum with the
4743-
// same value? If so, import it as a standalone constant.
4744-
auto insertResult =
4745-
Impl.EnumConstantValues.insert({{clangEnum, rawValue}, nullptr});
4746-
if (!insertResult.second)
4747-
return importEnumCaseAlias(name, decl, insertResult.first->second,
4748-
clangEnum, theEnum);
4749-
47504813
if (clangEnum->getIntegerType()->isSignedIntegerOrEnumerationType() &&
47514814
rawValue.slt(0)) {
47524815
rawValue = -rawValue;
@@ -4764,7 +4827,6 @@ Decl *SwiftDeclConverter::importEnumCase(const clang::EnumConstantDecl *decl,
47644827
auto element = Impl.createDeclWithClangNode<EnumElementDecl>(
47654828
decl, Accessibility::Public, SourceLoc(), name, TypeLoc(), SourceLoc(),
47664829
rawValueExpr, theEnum);
4767-
insertResult.first->second = element;
47684830

47694831
// Give the enum element the appropriate type.
47704832
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
@@ -1334,10 +1334,11 @@ const AvailableAttr *TypeChecker::getDeprecated(const Decl *D) {
13341334

13351335
/// Returns true if some declaration lexically enclosing the reference
13361336
/// matches the passed in predicate and false otherwise.
1337-
static bool someEnclosingDeclMatches(SourceRange ReferenceRange,
1338-
const DeclContext *ReferenceDC,
1339-
TypeChecker &TC,
1340-
std::function<bool(const Decl *)> Pred) {
1337+
static bool
1338+
someEnclosingDeclMatches(SourceRange ReferenceRange,
1339+
const DeclContext *ReferenceDC,
1340+
TypeChecker &TC,
1341+
llvm::function_ref<bool(const Decl *)> Pred) {
13411342
ASTContext &Ctx = TC.Context;
13421343

13431344
// Climb the DeclContext hierarchy to see if any of the containing
@@ -1429,7 +1430,7 @@ bool TypeChecker::isInsideUnavailableDeclaration(
14291430

14301431
bool TypeChecker::isInsideDeprecatedDeclaration(SourceRange ReferenceRange,
14311432
const DeclContext *ReferenceDC){
1432-
std::function<bool(const Decl *)> IsDeprecated = [](const Decl *D) {
1433+
auto IsDeprecated = [](const Decl *D) {
14331434
return D->getAttrs().getDeprecated(D->getASTContext());
14341435
};
14351436

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)