diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e1c7f80493ee3..7d6bea27724f3 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -525,7 +525,9 @@ struct ASTContext::Implementation { /// The builtin initializer witness for a literal. Used when building /// LiteralExprs in fully-checked AST. - llvm::DenseMap BuiltinInitWitness; + llvm::DenseMap, + ConcreteDeclRef> + BuiltinInitWitness; /// Mapping from the function decl to its original body's source range. This /// is populated if the body is reparsed from other source buffers. @@ -1686,11 +1688,12 @@ ASTContext::getStringBuiltinInitDecl(NominalTypeDecl *stringDecl) const { return getBuiltinInitDecl(stringDecl, builtinProtocolKind, fn); } -ConcreteDeclRef -ASTContext::getBuiltinInitDecl(NominalTypeDecl *decl, - KnownProtocolKind builtinProtocolKind, - llvm::function_ref initName) const { - auto &witness = getImpl().BuiltinInitWitness[decl]; +ConcreteDeclRef ASTContext::getBuiltinInitDecl( + NominalTypeDecl *decl, KnownProtocolKind builtinProtocolKind, + llvm::function_ref initName) const { + // Note the initializer name is expected to be unique for each protocol kind + // so we don't need it to be part of the key. + auto &witness = getImpl().BuiltinInitWitness[{decl, builtinProtocolKind}]; if (witness) return witness; @@ -1698,7 +1701,6 @@ ASTContext::getBuiltinInitDecl(NominalTypeDecl *decl, auto builtinProtocol = getProtocol(builtinProtocolKind); auto builtinConformance = lookupConformance(type, builtinProtocol); if (builtinConformance.isInvalid()) { - assert(false && "Missing required conformance"); witness = ConcreteDeclRef(); return witness; } @@ -1706,7 +1708,6 @@ ASTContext::getBuiltinInitDecl(NominalTypeDecl *decl, auto *ctx = const_cast(this); witness = builtinConformance.getWitnessByName(initName(*ctx)); if (!witness) { - assert(false && "Missing required witness"); witness = ConcreteDeclRef(); return witness; } diff --git a/lib/ClangImporter/ImportMacro.cpp b/lib/ClangImporter/ImportMacro.cpp index 4715e669f7ae8..717341b8bbf8a 100644 --- a/lib/ClangImporter/ImportMacro.cpp +++ b/lib/ClangImporter/ImportMacro.cpp @@ -125,6 +125,11 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl, return nullptr; } + auto &ctx = DC->getASTContext(); + auto *constantTyNominal = constantType->getAnyNominal(); + if (!constantTyNominal) + return nullptr; + if (auto *integer = dyn_cast(parsed)) { // Determine the value. llvm::APSInt value{integer->getValue(), clangTy->isUnsignedIntegerType()}; @@ -140,6 +145,16 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl, } } + // Make sure the destination type actually conforms to the builtin literal + // protocol before attempting to import, otherwise we'll crash since + // `createConstant` expects it to. + // FIXME: We ought to be careful checking conformance here since it can + // result in cycles. Additionally we ought to consider checking for the + // non-builtin literal protocol to allow any ExpressibleByIntegerLiteral + // type to be supported. + if (!ctx.getIntBuiltinInitDecl(constantTyNominal)) + return nullptr; + return createMacroConstant(Impl, MI, name, DC, constantType, clang::APValue(value), ConstantConvertKind::None, @@ -158,6 +173,16 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl, value.changeSign(); } + // Make sure the destination type actually conforms to the builtin literal + // protocol before attempting to import, otherwise we'll crash since + // `createConstant` expects it to. + // FIXME: We ought to be careful checking conformance here since it can + // result in cycles. Additionally we ought to consider checking for the + // non-builtin literal protocol to allow any ExpressibleByFloatLiteral + // type to be supported. + if (!ctx.getFloatBuiltinInitDecl(constantTyNominal)) + return nullptr; + return createMacroConstant(Impl, MI, name, DC, constantType, clang::APValue(value), ConstantConvertKind::None, diff --git a/test/ClangImporter/rdar156524292.swift b/test/ClangImporter/rdar156524292.swift new file mode 100644 index 0000000000000..c6cd55289210b --- /dev/null +++ b/test/ClangImporter/rdar156524292.swift @@ -0,0 +1,28 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t +// RUN: %target-swift-frontend -typecheck -verify %t/main.swift -I %t -verify-additional-file %t/cmodule.h + +// REQUIRES: objc_interop +// REQUIRES: OS=macosx + +//--- cmodule.h +#import +#define intLiteralCGFloat ((CGFloat)0) +// expected-note@-1 {{invalid numeric literal}} +// expected-note@-2 {{macro 'intLiteralCGFloat' unavailable (cannot import)}} +#define floatLiteralCGFloat ((CGFloat)0.0) +// expected-note@-1 {{invalid numeric literal}} +// expected-note@-2 {{macro 'floatLiteralCGFloat' unavailable (cannot import)}} + +//--- module.modulemap +module CModule [system] { + header "cmodule.h" + export * +} + +//--- main.swift +import CModule + +// Make sure we don't crash when attempting to import these. +_ = intLiteralCGFloat // expected-error {{cannot find 'intLiteralCGFloat' in scope}} +_ = floatLiteralCGFloat // expected-error {{cannot find 'floatLiteralCGFloat' in scope}}