[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:
Jordan Rose
2017-08-09 13:51:03 -07:00
committed by GitHub
parent a5127e5709
commit 43c0289dd4
5 changed files with 41 additions and 12 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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'}}