Skip to content

Commit b699f1c

Browse files
committed
[ClangImporter] Fix IUO ordering bug
The IUO-ness of imported declarations is not actually computed by IsImplicitlyUnwrappedOptionalRequest. Instead, ClangImporter manually sets the bit to `true` after the declaration’s type is imported and expects IsImplicitlyUnwrappedOptionalRequest to always set it to `false` for all other imported declarations. Normally, declaration types are imported greedily as soon as the declaration is created. However, a ClangImporter refactoring in swiftlang#61026 deferred the import of a VarDecl’s type, and therefore the setting of its IUO bit, until the first time InterfaceTypeRequest is evaluated. It turns out that there is nothing to guarantee that InterfaceTypeRequest will be evaluated before IsImplicitlyUnwrappedOptionalRequest, so if isImplicitlyUnwrappedOptional() was fetched before getInterfaceType() was called, it would return an incorrect result. The only known client that accesses the information in this order is the API digester, but in theory any part of the compiler could fall into this trap. Force the evaluation of InterfaceTypeRequest during IsImplicitlyUnwrappedOptionalRequest when necessary to compute the IUO bit for an imported VarDecl, and add a test to prove that this fixes the observed bug in the API digester.
1 parent a8c4323 commit b699f1c

File tree

4 files changed

+29
-0
lines changed

4 files changed

+29
-0
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,20 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator,
18541854
}
18551855

18561856
case DeclKind::Var:
1857+
if (decl->hasClangNode()) {
1858+
// ClangImporter does not use this request to compute whether imported
1859+
// declarations are IUOs; instead, it explicitly sets the bit itself when
1860+
// it imports the declaration's type. For most declarations this is done
1861+
// greedily, but for VarDecls, it is deferred until `getInterfaceType()`
1862+
// is called for the first time. (See apple/swift#61026.)
1863+
//
1864+
// Force the interface type, then see if a result for this request is now
1865+
// cached.
1866+
// FIXME: This is a little gross.
1867+
(void)decl->getInterfaceType();
1868+
if (auto cachedResult = this->getCachedResult())
1869+
return *cachedResult;
1870+
}
18571871
TyR = cast<VarDecl>(decl)->getTypeReprOrParentPatternTypeRepr();
18581872
break;
18591873

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void *ImportedIUOVar;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module ImportedIUO {
2+
header "imported_iuo.h"
3+
}

test/api-digester/imported_iuo.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
RUN: %empty-directory(%t)
2+
RUN: %api-digester -dump-sdk -module ImportedIUO -o %t/digest.json -module-cache-path %t/module-cache %clang-importer-sdk-nosource -I %S/Inputs/ImportedIUO -avoid-location
3+
RUN: %FileCheck --input-file %t/digest.json %s
4+
5+
CHECK: "name": "ImportedIUOVar",
6+
CHECK-NEXT: "printedName": "ImportedIUOVar",
7+
CHECK-NEXT: "children": [
8+
CHECK-NEXT: {
9+
CHECK-NEXT: "kind": "TypeNominal",
10+
CHECK-NEXT: "name": "ImplicitlyUnwrappedOptional",
11+
CHECK-NEXT: "printedName": "Swift.UnsafeMutableRawPointer!",

0 commit comments

Comments
 (0)