mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ClangImporter] Avoid trying to import enums without definitions. (#11394)
This would fail later down the line anyway, meaning this does not
change the ultimate behavior of the importer, but since I added an
assertion that we're expecting a definition here in 2c68f8d49d, we
need to avoid even asking the question.
Also fix up a few other places where we aren't sure we'll have a
definition when calling these functions.
rdar://problem/33784466
This commit is contained in:
@@ -36,6 +36,9 @@ using namespace importer;
|
|||||||
/// Classify the given Clang enumeration to describe how to import it.
|
/// Classify the given Clang enumeration to describe how to import it.
|
||||||
void EnumInfo::classifyEnum(ASTContext &ctx, const clang::EnumDecl *decl,
|
void EnumInfo::classifyEnum(ASTContext &ctx, const clang::EnumDecl *decl,
|
||||||
clang::Preprocessor &pp) {
|
clang::Preprocessor &pp) {
|
||||||
|
assert(decl);
|
||||||
|
clang::PrettyStackTraceDecl trace(decl, clang::SourceLocation(),
|
||||||
|
pp.getSourceManager(), "classifying");
|
||||||
assert(decl->isThisDeclarationADefinition());
|
assert(decl->isThisDeclarationADefinition());
|
||||||
|
|
||||||
// Anonymous enumerations simply get mapped to constants of the
|
// Anonymous enumerations simply get mapped to constants of the
|
||||||
|
|||||||
@@ -1545,10 +1545,12 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
|
|||||||
// "Code" off the end of the name, if it's there, because it's
|
// "Code" off the end of the name, if it's there, because it's
|
||||||
// redundant.
|
// redundant.
|
||||||
if (auto enumDecl = dyn_cast<clang::EnumDecl>(D)) {
|
if (auto enumDecl = dyn_cast<clang::EnumDecl>(D)) {
|
||||||
auto enumInfo = getEnumInfo(enumDecl);
|
if (enumDecl->isThisDeclarationADefinition()) {
|
||||||
if (enumInfo.isErrorEnum() && baseName.size() > 4 &&
|
auto enumInfo = getEnumInfo(enumDecl);
|
||||||
camel_case::getLastWord(baseName) == "Code")
|
if (enumInfo.isErrorEnum() && baseName.size() > 4 &&
|
||||||
baseName = baseName.substr(0, baseName.size() - 4);
|
camel_case::getLastWord(baseName) == "Code")
|
||||||
|
baseName = baseName.substr(0, baseName.size() - 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Objective-C protocols may have the suffix "Protocol" appended if
|
// Objective-C protocols may have the suffix "Protocol" appended if
|
||||||
|
|||||||
@@ -806,16 +806,20 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImportResult VisitEnumType(const clang::EnumType *type) {
|
ImportResult VisitEnumType(const clang::EnumType *type) {
|
||||||
auto clangDecl = type->getDecl();
|
auto clangDecl = type->getDecl()->getDefinition();
|
||||||
|
if (!clangDecl) {
|
||||||
|
// FIXME: If the enum has a fixed underlying type, can we use that
|
||||||
|
// instead? Or import it opaquely somehow?
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
switch (Impl.getEnumKind(clangDecl)) {
|
switch (Impl.getEnumKind(clangDecl)) {
|
||||||
case EnumKind::Constants: {
|
case EnumKind::Constants: {
|
||||||
auto clangDef = clangDecl->getDefinition();
|
|
||||||
// Map anonymous enums with no fixed underlying type to Int /if/
|
// Map anonymous enums with no fixed underlying type to Int /if/
|
||||||
// they fit in an Int32. If not, this mapping isn't guaranteed to be
|
// they fit in an Int32. If not, this mapping isn't guaranteed to be
|
||||||
// consistent for all platforms we care about.
|
// consistent for all platforms we care about.
|
||||||
if (!clangDef->isFixed() &&
|
if (!clangDecl->isFixed() &&
|
||||||
clangDef->getNumPositiveBits() < 32 &&
|
clangDecl->getNumPositiveBits() < 32 &&
|
||||||
clangDef->getNumNegativeBits() <= 32)
|
clangDecl->getNumNegativeBits() <= 32)
|
||||||
return Impl.getNamedSwiftType(Impl.getStdlibModule(), "Int");
|
return Impl.getNamedSwiftType(Impl.getStdlibModule(), "Int");
|
||||||
|
|
||||||
// Import the underlying integer type.
|
// Import the underlying integer type.
|
||||||
@@ -1759,14 +1763,16 @@ DefaultArgumentKind ClangImporter::Implementation::inferDefaultArgument(
|
|||||||
return DefaultArgumentKind::None;
|
return DefaultArgumentKind::None;
|
||||||
|
|
||||||
// Option sets default to "[]" if they have "Options" in their name.
|
// Option sets default to "[]" if they have "Options" in their name.
|
||||||
if (const clang::EnumType *enumTy = type->getAs<clang::EnumType>())
|
if (const clang::EnumType *enumTy = type->getAs<clang::EnumType>()) {
|
||||||
if (nameImporter.getEnumKind(enumTy->getDecl()) == EnumKind::Options) {
|
const clang::EnumDecl *enumDef = enumTy->getDecl()->getDefinition();
|
||||||
auto enumName = enumTy->getDecl()->getName();
|
if (nameImporter.getEnumKind(enumDef) == EnumKind::Options) {
|
||||||
|
auto enumName = enumDef->getName();
|
||||||
for (auto word : reversed(camel_case::getWords(enumName))) {
|
for (auto word : reversed(camel_case::getWords(enumName))) {
|
||||||
if (camel_case::sameWordIgnoreFirstCase(word, "options"))
|
if (camel_case::sameWordIgnoreFirstCase(word, "options"))
|
||||||
return DefaultArgumentKind::EmptyArray;
|
return DefaultArgumentKind::EmptyArray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NSDictionary arguments default to [:] (or nil, if nullable) if "options",
|
// NSDictionary arguments default to [:] (or nil, if nullable) if "options",
|
||||||
// "attributes", or "userInfo" occur in the argument label or (if there is no
|
// "attributes", or "userInfo" occur in the argument label or (if there is no
|
||||||
|
|||||||
@@ -8,3 +8,13 @@ typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnum, "SwiftEnum") {
|
|||||||
ObjCEnumTwo,
|
ObjCEnumTwo,
|
||||||
ObjCEnumThree
|
ObjCEnumThree
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BareForwardEnum;
|
||||||
|
enum ForwardEnumWithUnderlyingType : int;
|
||||||
|
typedef SWIFT_ENUM_NAMED(NSInteger, ForwardObjCEnum, "ForwardSwiftEnum");
|
||||||
|
|
||||||
|
void forwardBarePointer(enum BareForwardEnum * _Nonnull);
|
||||||
|
void forwardWithUnderlyingValue(enum ForwardEnumWithUnderlyingType);
|
||||||
|
void forwardWithUnderlyingPointer(enum ForwardEnumWithUnderlyingType * _Nonnull);
|
||||||
|
void forwardObjCValue(ForwardObjCEnum);
|
||||||
|
void forwardObjCPointer(ForwardObjCEnum * _Nonnull);
|
||||||
|
|||||||
@@ -9,3 +9,11 @@ func test(_ value: SwiftEnum) {
|
|||||||
case .three: break
|
case .three: break
|
||||||
} // no error
|
} // no error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _: Int = forwardBarePointer // expected-error {{cannot convert value of type '(OpaquePointer) -> Void' to specified type 'Int'}}
|
||||||
|
let _: Int = forwardWithUnderlyingPointer // expected-error {{cannot convert value of type '(OpaquePointer) -> Void' to specified type 'Int'}}
|
||||||
|
let _: Int = forwardObjCPointer // expected-error {{cannot convert value of type '(OpaquePointer) -> Void' to specified type 'Int'}}
|
||||||
|
|
||||||
|
// FIXME: It would be nice to import these as unavailable somehow instead.
|
||||||
|
let _: Int = forwardWithUnderlyingValue // expected-error {{use of unresolved identifier 'forwardWithUnderlyingValue'}}
|
||||||
|
let _: Int = forwardObjCValue // expected-error {{use of unresolved identifier 'forwardObjCValue'}}
|
||||||
|
|||||||
Reference in New Issue
Block a user