Skip to content

Commit 73b03ed

Browse files
authored
Merge pull request #85262 from DougGregor/clang-deserialization-near-miss
[Serialization] Allow near-misses when matching imported Clang declarations
2 parents 73fd67b + 1bae4da commit 73b03ed

File tree

10 files changed

+99
-4
lines changed

10 files changed

+99
-4
lines changed

include/swift/AST/Types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ enum class TypeMatchFlags {
372372
IgnoreSendability = 1 << 7,
373373
/// Ignore global actor isolation attributes on functions when matching types.
374374
IgnoreFunctionGlobalActorIsolation = 1 << 8,
375+
/// Require parameter labels to match.
376+
RequireMatchingParameterLabels = 1 << 9,
375377
};
376378
using TypeMatchOptions = OptionSet<TypeMatchFlags>;
377379

lib/AST/Type.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3604,6 +3604,11 @@ static bool matches(CanType t1, CanType t2, TypeMatchOptions matchMode,
36043604
OptionalUnwrapping::None)) {
36053605
return false;
36063606
}
3607+
3608+
if (matchMode.contains(TypeMatchFlags::RequireMatchingParameterLabels)&&
3609+
fn1Params[i].getLabel() != fn2Params[i].getLabel()) {
3610+
return false;
3611+
}
36073612
}
36083613

36093614
// Results are covariant.

lib/Serialization/Deserialization.cpp

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2000,6 +2000,34 @@ static bool isReExportedToModule(const ValueDecl *value,
20002000
return exportedName == expectedModule->getName().str();
20012001
}
20022002

2003+
namespace {
2004+
/// The result of a type comparison.
2005+
enum class TypeComparison {
2006+
NotEqual,
2007+
Equal,
2008+
NearMatch,
2009+
};
2010+
2011+
TypeComparison compareTypes(CanType type1, CanType type2, bool nearMatchOk) {
2012+
if (type1->isEqual(type2))
2013+
return TypeComparison::Equal;
2014+
2015+
if (nearMatchOk) {
2016+
TypeMatchOptions options = TypeMatchFlags::RequireMatchingParameterLabels;
2017+
options |= TypeMatchFlags::AllowTopLevelOptionalMismatch;
2018+
options |= TypeMatchFlags::AllowNonOptionalForIUOParam;
2019+
options |= TypeMatchFlags::IgnoreNonEscapingForOptionalFunctionParam;
2020+
options |= TypeMatchFlags::IgnoreFunctionSendability;
2021+
options |= TypeMatchFlags::IgnoreSendability;
2022+
options |= TypeMatchFlags::IgnoreFunctionGlobalActorIsolation;
2023+
if (type1->matches(type2, options))
2024+
return TypeComparison::NearMatch;
2025+
}
2026+
2027+
return TypeComparison::NotEqual;
2028+
}
2029+
}
2030+
20032031
/// Remove values from \p values that don't match the expected type or module.
20042032
///
20052033
/// Any of \p expectedTy, \p expectedModule, or \p expectedGenericSig can be
@@ -2015,8 +2043,10 @@ static void filterValues(Type expectedTy, ModuleDecl *expectedModule,
20152043
if (expectedTy)
20162044
canTy = expectedTy->getCanonicalType();
20172045

2046+
llvm::TinyPtrVector<ValueDecl *> clangNearMatches;
2047+
20182048
auto newEnd = std::remove_if(values.begin(), values.end(),
2019-
[=](ValueDecl *value) {
2049+
[=, &clangNearMatches](ValueDecl *value) {
20202050
// Ignore anything that was parsed (vs. deserialized), because a serialized
20212051
// module cannot refer to it.
20222052
if (value->getDeclContext()->getParentSourceFile())
@@ -2026,7 +2056,14 @@ static void filterValues(Type expectedTy, ModuleDecl *expectedModule,
20262056
return true;
20272057

20282058
// If we're expecting a type, make sure this decl has the expected type.
2029-
if (canTy && !value->getInterfaceType()->isEqual(canTy))
2059+
TypeComparison typesMatch = TypeComparison::Equal;
2060+
if (canTy) {
2061+
typesMatch = compareTypes(canTy,
2062+
value->getInterfaceType()->getCanonicalType(),
2063+
importedFromClang);
2064+
}
2065+
2066+
if (typesMatch == TypeComparison::NotEqual)
20302067
return true;
20312068

20322069
if (value->isStatic() != isStatic)
@@ -2075,9 +2112,20 @@ static void filterValues(Type expectedTy, ModuleDecl *expectedModule,
20752112
cast<ConstructorDecl>(value)->getInitKind() != *ctorInit)
20762113
return true;
20772114
}
2115+
2116+
// Record near matches.
2117+
if (typesMatch == TypeComparison::NearMatch) {
2118+
clangNearMatches.push_back(value);
2119+
return true;
2120+
}
2121+
2122+
ASSERT(typesMatch == TypeComparison::Equal);
20782123
return false;
20792124
});
20802125
values.erase(newEnd, values.end());
2126+
2127+
if (values.empty())
2128+
values.append(clangNearMatches.begin(), clangNearMatches.end());
20812129
}
20822130

20832131
/// Look for nested types in all files of \p extensionModule except from the \p thisFile.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void takes_a_void_pointer(const void * _Nonnull pointer);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void takes_a_void_pointer(const void * _Nullable pointer);

test/SIL/Serialization/Inputs/extern_with_nonnull.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
#if USE_EXTERN
12
@_extern(c, "takes_a_void_pointer")
23
public func takes_a_void_pointer(_ pointer: UnsafeRawPointer)
4+
#elseif USE_C_MODULE
5+
import CTakesPtrNonNull
6+
#else
7+
#error("Not configured")
8+
#endif
39

410
@_alwaysEmitIntoClient
511
public func callWithNonNull() {

test/SIL/Serialization/Inputs/extern_with_nullable.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
#if USE_EXTERN
12
@_extern(c, "takes_a_void_pointer")
23
public func takes_a_void_pointer(_ pointer: UnsafeRawPointer?)
4+
#elseif USE_C_MODULE
5+
import CTakesPtrNullable
6+
#else
7+
#error("Not configured")
8+
#endif
39

410
@_alwaysEmitIntoClient
511
public func callWithNullable() {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module CTakesPtrNullable {
2+
header "c_takes_ptr_nullable.h"
3+
}
4+
5+
module CTakesPtrNonNull {
6+
header "c_takes_ptr_nonnull.h"
7+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -DUSE_C_MODULE -I %S/Inputs -o %t %S/Inputs/extern_with_nullable.swift -module-name c_with_nullable -enable-experimental-feature Extern
3+
// RUN: %target-swift-frontend -emit-module -DUSE_C_MODULE -I %S/Inputs -o %t %S/Inputs/extern_with_nonnull.swift -module-name c_with_nonnull -enable-experimental-feature Extern
4+
// RUN: %target-swift-frontend -emit-sil -o %t -I %t -primary-file %s -module-name main -O -enable-experimental-feature Extern
5+
6+
// RUN: %target-swift-frontend -emit-ir -o %t -I %t -primary-file %s -module-name main -O -enable-experimental-feature Extern
7+
8+
// Don't crash or otherwise fail when inlining multiple functions that reference
9+
// C declarations of the same name but different types at the SIL level.
10+
11+
// REQUIRES: swift_feature_Extern
12+
13+
import c_with_nullable
14+
import c_with_nonnull
15+
16+
public func main() {
17+
callWithNullable()
18+
callWithNonNull()
19+
}

test/SIL/Serialization/extern_collision.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -emit-module -enable-experimental-feature Extern -o %t %S/Inputs/extern_with_nullable.swift
3-
// RUN: %target-swift-frontend -emit-module -enable-experimental-feature Extern -o %t %S/Inputs/extern_with_nonnull.swift
2+
// RUN: %target-swift-frontend -emit-module -DUSE_EXTERN -enable-experimental-feature Extern -o %t %S/Inputs/extern_with_nullable.swift
3+
// RUN: %target-swift-frontend -emit-module -DUSE_EXTERN -enable-experimental-feature Extern -o %t %S/Inputs/extern_with_nonnull.swift
44
// RUN: %target-swift-frontend -emit-sil -o %t -I %t -primary-file %s -module-name main -O
55

66
// REQUIRES: swift_feature_Extern

0 commit comments

Comments
 (0)