@@ -1865,10 +1865,28 @@ namespace {
1865
1865
break ;
1866
1866
}
1867
1867
1868
+ // / A table mapping each raw value used in this enum to the clang or
1869
+ // / Swift decl for the "canonical" constant corresponding to that raw
1870
+ // / value. The clang decls represent cases that haven't yet been imported;
1871
+ // / the Swift decls represent cases that have been imported before.
1872
+ // /
1873
+ // / The problem we are trying to solve here is that C allows several
1874
+ // / constants in the same enum to have the same raw value, but Swift does
1875
+ // / not. We must therefore resolve collisions by selecting one case to be
1876
+ // / the "canonical" one that will be imported as an \c EnumElementDecl
1877
+ // / and importing the others as static \c VarDecl aliases of it. This
1878
+ // / map knows which constants are canonical and can map a constant's raw
1879
+ // / value to its corresponding canonical constant.
1880
+ // /
1881
+ // / Note that unavailable constants don't get inserted into this table,
1882
+ // / so if an unavailable constant has no available alias, it simply won't
1883
+ // / be present here. (Potential raw value conflicts doesn't really matter
1884
+ // / for them because they will be imported as unavailable anyway.)
1868
1885
llvm::SmallDenseMap<llvm::APSInt,
1869
1886
PointerUnion<const clang::EnumConstantDecl *,
1870
1887
EnumElementDecl *>, 8 > canonicalEnumConstants;
1871
1888
1889
+ // Fill in `canonicalEnumConstants` if it will be used.
1872
1890
if (enumKind == EnumKind::NonFrozenEnum ||
1873
1891
enumKind == EnumKind::FrozenEnum) {
1874
1892
for (auto constant : decl->enumerators ()) {
@@ -1943,24 +1961,32 @@ namespace {
1943
1961
SwiftDeclConverter (Impl, getActiveSwiftVersion ())
1944
1962
.importEnumCase (constant, decl, cast<EnumDecl>(result));
1945
1963
} else {
1946
- const clang::EnumConstantDecl *unimported =
1964
+ // Will initially be nullptr if `canonicalCaseIter` points to a
1965
+ // memoized result.
1966
+ const clang::EnumConstantDecl *canonConstant =
1947
1967
canonicalCaseIter->
1948
1968
second.dyn_cast <const clang::EnumConstantDecl *>();
1949
1969
1950
- // Import the canonical enumerator for this case first.
1951
- if (unimported) {
1970
+ // First, either import the canonical constant for this case,
1971
+ // or extract the memoized result of a previous import (and use it
1972
+ // to populate `canonConstant`).
1973
+ if (canonConstant) {
1952
1974
enumeratorDecl = SwiftDeclConverter (Impl, getActiveSwiftVersion ())
1953
- .importEnumCase (unimported , decl, cast<EnumDecl>(result));
1975
+ .importEnumCase (canonConstant , decl, cast<EnumDecl>(result));
1954
1976
if (enumeratorDecl) {
1977
+ // Memoize so we end up in the `else` branch next time.
1955
1978
canonicalCaseIter->getSecond () =
1956
1979
cast<EnumElementDecl>(enumeratorDecl);
1957
1980
}
1958
1981
} else {
1959
1982
enumeratorDecl =
1960
1983
canonicalCaseIter->second .get <EnumElementDecl *>();
1984
+ canonConstant =
1985
+ cast<clang::EnumConstantDecl>(enumeratorDecl->getClangDecl ());
1961
1986
}
1962
1987
1963
- if (unimported != constant && enumeratorDecl) {
1988
+ // If `constant` wasn't the `canonConstant`, import it as an alias.
1989
+ if (canonConstant != constant && enumeratorDecl) {
1964
1990
ImportedName importedName =
1965
1991
Impl.importFullName (constant, getActiveSwiftVersion ());
1966
1992
Identifier name = importedName.getBaseIdentifier (Impl.SwiftContext );
@@ -1976,6 +2002,7 @@ namespace {
1976
2002
}
1977
2003
}
1978
2004
2005
+ // Now import each of the constant's alternate names.
1979
2006
Impl.forEachDistinctName (constant,
1980
2007
[&](ImportedName newName,
1981
2008
ImportNameVersion nameVersion) -> bool {
@@ -2026,6 +2053,19 @@ namespace {
2026
2053
}
2027
2054
}
2028
2055
2056
+ // We don't always add an imported canonical constant to the enum's
2057
+ // members right away, but we should have by the time we leave the loop.
2058
+ // Verify that they are all in the enum's member list. (rdar://148213237)
2059
+ if (CONDITIONAL_ASSERT_enabled ()) {
2060
+ for (const auto &entry : canonicalEnumConstants) {
2061
+ auto importedCase = entry.second .dyn_cast <EnumElementDecl *>();
2062
+ if (!importedCase)
2063
+ continue ;
2064
+
2065
+ ASSERT (llvm::is_contained (result->getCurrentMembers (), importedCase));
2066
+ }
2067
+ }
2068
+
2029
2069
return result;
2030
2070
}
2031
2071
0 commit comments