Skip to content

Commit 42cfda1

Browse files
authored
Merge pull request #85409 from hamishknight/fishers-landing
[ClangImporter] Check for builtin conformance in `importNumericLiteral`
2 parents 46f3f17 + cdffd55 commit 42cfda1

File tree

3 files changed

+62
-8
lines changed

3 files changed

+62
-8
lines changed

lib/AST/ASTContext.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,9 @@ struct ASTContext::Implementation {
525525

526526
/// The builtin initializer witness for a literal. Used when building
527527
/// LiteralExprs in fully-checked AST.
528-
llvm::DenseMap<const NominalTypeDecl *, ConcreteDeclRef> BuiltinInitWitness;
528+
llvm::DenseMap<std::pair<const NominalTypeDecl *, KnownProtocolKind>,
529+
ConcreteDeclRef>
530+
BuiltinInitWitness;
529531

530532
/// Mapping from the function decl to its original body's source range. This
531533
/// is populated if the body is reparsed from other source buffers.
@@ -1686,27 +1688,26 @@ ASTContext::getStringBuiltinInitDecl(NominalTypeDecl *stringDecl) const {
16861688
return getBuiltinInitDecl(stringDecl, builtinProtocolKind, fn);
16871689
}
16881690

1689-
ConcreteDeclRef
1690-
ASTContext::getBuiltinInitDecl(NominalTypeDecl *decl,
1691-
KnownProtocolKind builtinProtocolKind,
1692-
llvm::function_ref<DeclName (ASTContext &ctx)> initName) const {
1693-
auto &witness = getImpl().BuiltinInitWitness[decl];
1691+
ConcreteDeclRef ASTContext::getBuiltinInitDecl(
1692+
NominalTypeDecl *decl, KnownProtocolKind builtinProtocolKind,
1693+
llvm::function_ref<DeclName(ASTContext &ctx)> initName) const {
1694+
// Note the initializer name is expected to be unique for each protocol kind
1695+
// so we don't need it to be part of the key.
1696+
auto &witness = getImpl().BuiltinInitWitness[{decl, builtinProtocolKind}];
16941697
if (witness)
16951698
return witness;
16961699

16971700
auto type = decl->getDeclaredInterfaceType();
16981701
auto builtinProtocol = getProtocol(builtinProtocolKind);
16991702
auto builtinConformance = lookupConformance(type, builtinProtocol);
17001703
if (builtinConformance.isInvalid()) {
1701-
assert(false && "Missing required conformance");
17021704
witness = ConcreteDeclRef();
17031705
return witness;
17041706
}
17051707

17061708
auto *ctx = const_cast<ASTContext *>(this);
17071709
witness = builtinConformance.getWitnessByName(initName(*ctx));
17081710
if (!witness) {
1709-
assert(false && "Missing required witness");
17101711
witness = ConcreteDeclRef();
17111712
return witness;
17121713
}

lib/ClangImporter/ImportMacro.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
125125
return nullptr;
126126
}
127127

128+
auto &ctx = DC->getASTContext();
129+
auto *constantTyNominal = constantType->getAnyNominal();
130+
if (!constantTyNominal)
131+
return nullptr;
132+
128133
if (auto *integer = dyn_cast<clang::IntegerLiteral>(parsed)) {
129134
// Determine the value.
130135
llvm::APSInt value{integer->getValue(), clangTy->isUnsignedIntegerType()};
@@ -140,6 +145,16 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
140145
}
141146
}
142147

148+
// Make sure the destination type actually conforms to the builtin literal
149+
// protocol before attempting to import, otherwise we'll crash since
150+
// `createConstant` expects it to.
151+
// FIXME: We ought to be careful checking conformance here since it can
152+
// result in cycles. Additionally we ought to consider checking for the
153+
// non-builtin literal protocol to allow any ExpressibleByIntegerLiteral
154+
// type to be supported.
155+
if (!ctx.getIntBuiltinInitDecl(constantTyNominal))
156+
return nullptr;
157+
143158
return createMacroConstant(Impl, MI, name, DC, constantType,
144159
clang::APValue(value),
145160
ConstantConvertKind::None,
@@ -158,6 +173,16 @@ static ValueDecl *importNumericLiteral(ClangImporter::Implementation &Impl,
158173
value.changeSign();
159174
}
160175

176+
// Make sure the destination type actually conforms to the builtin literal
177+
// protocol before attempting to import, otherwise we'll crash since
178+
// `createConstant` expects it to.
179+
// FIXME: We ought to be careful checking conformance here since it can
180+
// result in cycles. Additionally we ought to consider checking for the
181+
// non-builtin literal protocol to allow any ExpressibleByFloatLiteral
182+
// type to be supported.
183+
if (!ctx.getFloatBuiltinInitDecl(constantTyNominal))
184+
return nullptr;
185+
161186
return createMacroConstant(Impl, MI, name, DC, constantType,
162187
clang::APValue(value),
163188
ConstantConvertKind::None,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
// RUN: %target-swift-frontend -typecheck -verify %t/main.swift -I %t -verify-additional-file %t/cmodule.h
4+
5+
// REQUIRES: objc_interop
6+
// REQUIRES: OS=macosx
7+
8+
//--- cmodule.h
9+
#import <CoreGraphics/CoreGraphics.h>
10+
#define intLiteralCGFloat ((CGFloat)0)
11+
// expected-note@-1 {{invalid numeric literal}}
12+
// expected-note@-2 {{macro 'intLiteralCGFloat' unavailable (cannot import)}}
13+
#define floatLiteralCGFloat ((CGFloat)0.0)
14+
// expected-note@-1 {{invalid numeric literal}}
15+
// expected-note@-2 {{macro 'floatLiteralCGFloat' unavailable (cannot import)}}
16+
17+
//--- module.modulemap
18+
module CModule [system] {
19+
header "cmodule.h"
20+
export *
21+
}
22+
23+
//--- main.swift
24+
import CModule
25+
26+
// Make sure we don't crash when attempting to import these.
27+
_ = intLiteralCGFloat // expected-error {{cannot find 'intLiteralCGFloat' in scope}}
28+
_ = floatLiteralCGFloat // expected-error {{cannot find 'floatLiteralCGFloat' in scope}}

0 commit comments

Comments
 (0)