Skip to content

Commit 613bdc2

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 #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 2379b44 commit 613bdc2

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
@@ -2057,6 +2057,20 @@ IsImplicitlyUnwrappedOptionalRequest::evaluate(Evaluator &evaluator,
20572057
}
20582058

20592059
case DeclKind::Var:
2060+
if (decl->hasClangNode()) {
2061+
// ClangImporter does not use this request to compute whether imported
2062+
// declarations are IUOs; instead, it explicitly sets the bit itself when
2063+
// it imports the declaration's type. For most declarations this is done
2064+
// greedily, but for VarDecls, it is deferred until `getInterfaceType()`
2065+
// is called for the first time. (See apple/swift#61026.)
2066+
//
2067+
// Force the interface type, then see if a result for this request is now
2068+
// cached.
2069+
// FIXME: This is a little gross.
2070+
(void)decl->getInterfaceType();
2071+
if (auto cachedResult = this->getCachedResult())
2072+
return *cachedResult;
2073+
}
20602074
TyR = cast<VarDecl>(decl)->getTypeReprOrParentPatternTypeRepr();
20612075
break;
20622076

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)