Skip to content

Commit 79545df

Browse files
committed
Merge remote-tracking branch 'origin/main' into rebranch
2 parents 821702e + eef4780 commit 79545df

File tree

8 files changed

+239
-11
lines changed

8 files changed

+239
-11
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -832,17 +832,24 @@ std::optional<T> matchSwiftAttrConsideringInheritance(
832832
/// Matches a `swift_attr("...")` on the record type pointed to by the given
833833
/// Clang type, searching base classes if it's a C++ class.
834834
///
835-
/// \param type A Clang pointer type.
835+
/// \param type A Clang pointer or reference type.
836836
/// \param patterns List of attribute name-value pairs to match.
837837
/// \returns Matched value or std::nullopt.
838838
template <typename T>
839839
std::optional<T> matchSwiftAttrOnRecordPtr(
840840
const clang::QualType &type,
841841
llvm::ArrayRef<std::pair<llvm::StringRef, T>> patterns) {
842+
clang::QualType pointeeType;
842843
if (const auto *ptrType = type->getAs<clang::PointerType>()) {
843-
if (const auto *recordDecl = ptrType->getPointeeType()->getAsRecordDecl()) {
844-
return matchSwiftAttrConsideringInheritance<T>(recordDecl, patterns);
845-
}
844+
pointeeType = ptrType->getPointeeType();
845+
} else if (const auto *refType = type->getAs<clang::ReferenceType>()) {
846+
pointeeType = refType->getPointeeType();
847+
} else {
848+
return std::nullopt;
849+
}
850+
851+
if (const auto *recordDecl = pointeeType->getAsRecordDecl()) {
852+
return matchSwiftAttrConsideringInheritance<T>(recordDecl, patterns);
846853
}
847854
return std::nullopt;
848855
}

lib/IRGen/GenReflection.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,8 @@ getRuntimeVersionThatSupportsDemanglingType(CanType type) {
315315
// where completing the metadata during demangling might cause cyclic
316316
// dependencies.
317317
static std::pair<llvm::Constant *, unsigned>
318-
getTypeRefByFunction(IRGenModule &IGM,
319-
CanGenericSignature sig,
320-
CanType t) {
318+
getTypeRefByFunction(IRGenModule &IGM, CanGenericSignature sig, CanType t,
319+
MangledTypeRefRole role) {
321320
IRGenMangler mangler(IGM.Context);
322321
std::string symbolName =
323322
mangler.mangleSymbolNameForMangledMetadataAccessorString(
@@ -433,7 +432,11 @@ getTypeRefByFunction(IRGenModule &IGM,
433432
// Form the mangled name with its relative reference.
434433
auto S = B.beginStruct();
435434
S.setPacked(true);
436-
S.add(llvm::ConstantInt::get(IGM.Int8Ty, 255));
435+
if (role == MangledTypeRefRole::DefaultAssociatedTypeWitness) {
436+
S.add(llvm::ConstantInt::get(
437+
IGM.Int8Ty,
438+
ProtocolRequirementFlags::AssociatedTypeInProtocolContextByte));
439+
}
437440
S.add(llvm::ConstantInt::get(IGM.Int8Ty, 9));
438441
S.addCompactFunctionReference(accessor);
439442

@@ -513,7 +516,7 @@ getTypeRefImpl(IRGenModule &IGM,
513516
// the field will be artificially hidden to reflectors.
514517
if (isAlwaysNoncopyable) {
515518
IGM.IRGen.noteUseOfTypeMetadata(type);
516-
return getTypeRefByFunction(IGM, sig, type);
519+
return getTypeRefByFunction(IGM, sig, type, role);
517520
}
518521
}
519522
LLVM_FALLTHROUGH;
@@ -524,12 +527,12 @@ getTypeRefImpl(IRGenModule &IGM,
524527
// ensuring that we can always reconstruct type metadata from a mangled name
525528
// in-process.
526529
IGM.IRGen.noteUseOfTypeMetadata(type);
527-
530+
528531
// If the minimum deployment target's runtime demangler wouldn't understand
529532
// this mangled name, then fall back to generating a "mangled name" with a
530533
// symbolic reference with a callback function.
531534
if (mangledNameIsUnknownToDeployTarget(IGM, type)) {
532-
return getTypeRefByFunction(IGM, sig, type);
535+
return getTypeRefByFunction(IGM, sig, type, role);
533536
}
534537

535538
break;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
public protocol Proto {
2+
associatedtype T: Proto
3+
4+
var value: T {get}
5+
}
6+
7+
public func makeThing<P: Proto>(_ t: P) -> some Proto {
8+
return ProtoImpl(t.value)
9+
}
10+
11+
public struct ProtoImpl<V>: Proto {
12+
public let genValue: V
13+
14+
public init(_ genValue: V) {
15+
self.genValue = genValue
16+
}
17+
18+
public var value: some Proto {
19+
return self
20+
}
21+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-build-swift-dylib(%t/%target-library-name(associated_type_by_mangled_name)) -target %target-cpu-apple-macosx15.0 -enable-library-evolution %S/Inputs/associated_type_by_mangled_name.swift -emit-module -emit-module-path %t/associated_type_by_mangled_name.swiftmodule -module-name associated_type_by_mangled_name
4+
// RUN: %target-codesign %t/%target-library-name(associated_type_by_mangled_name)
5+
6+
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx15.0 -I %t %s -emit-ir -o - | %FileCheck %s
7+
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx26.0 -I %t %s -emit-ir -o - | %FileCheck %s -check-prefix CHECK-SUPPORTED
8+
9+
// RUN: %target-build-swift -target %target-cpu-apple-macosx15.0 %s -lassociated_type_by_mangled_name -I %t -L %t -o %t/main15 %target-rpath(%t)
10+
// RUN: %target-codesign %t/main15
11+
12+
// RUN: %target-run %t/main15 %t/%target-library-name(associated_type_by_mangled_name)
13+
14+
// RUN: %target-build-swift -target %target-cpu-apple-macosx26.0 %s -lassociated_type_by_mangled_name -I %t -L %t -o %t/main26 %target-rpath(%t)
15+
// RUN: %target-codesign %t/main26
16+
17+
// RUN: %target-run %t/main26 %t/%target-library-name(associated_type_by_mangled_name)
18+
19+
// REQUIRES: executable_test
20+
// REQUIRES: OS=macosx
21+
// UNSUPPORTED: back_deployment_runtime || use_os_stdlib
22+
23+
import associated_type_by_mangled_name
24+
25+
protocol P: Sendable {
26+
associatedtype T: Proto
27+
func foo() -> T
28+
}
29+
30+
struct PImpl: P {
31+
func foo() -> some Proto {
32+
return ProtoImpl(2)
33+
}
34+
}
35+
36+
// CHECK: @"get_type_metadata 30nonisolated_nonsending_closure1PRzl31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcG.3" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 9, i32 trunc (i64 sub (i64 ptrtoint (ptr @"get_type_metadata 30nonisolated_nonsending_closure1PRzl31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcG" to i64), i64 ptrtoint (ptr getelementptr inbounds (<{ i8, i32, i8 }>, ptr @"get_type_metadata 30nonisolated_nonsending_closure1PRzl31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcG.3", i32 0, i32 1) to i64)) to i32), i8 0 }>
37+
// CHECK: define linkonce_odr hidden ptr @"$s31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcGACyxGAA0F0AAWl"() #1 {
38+
// CHECK: call swiftcc %swift.metadata_response @"$s31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcGMa"(i64 255)
39+
// CHECK: }
40+
41+
// CHECK-SUPPORTED-NOT: @"get_type_metadata 30nonisolated_nonsending_closure1PRzl31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcG.3"
42+
// CHECK-SUPPORTED: define linkonce_odr hidden ptr @"$s31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcGACyxGAA0F0AAWl"() #1 {
43+
// CHECK-SUPPORTED: call ptr @__swift_instantiateConcreteTypeFromMangledNameAbstract(ptr @"$s31associated_type_by_mangled_name9ProtoImplVyySiYaKYCcGMD")
44+
// CHECK-SUPPORTED: }
45+
struct MyStruct<T: P>: Proto {
46+
typealias Closure = nonisolated(nonsending) (Int) async throws -> Void
47+
48+
let x: T
49+
50+
public var value: some Proto {
51+
return ProtoImpl<Closure> { _ in }
52+
}
53+
}
54+
55+
print(makeThing(MyStruct(x: PImpl())))
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#pragma once
2+
3+
namespace NoAnnotations {
4+
5+
struct RefCountedType {
6+
int value;
7+
} __attribute__((swift_attr("import_reference")))
8+
__attribute__((swift_attr("retain:retainRefCounted")))
9+
__attribute__((swift_attr("release:releaseRefCounted")));
10+
11+
RefCountedType& getRefCountedByRef(); // expected-note {{'getRefCountedByRef()' is defined here}}
12+
RefCountedType& createRefCountedByRef(); // expected-note {{'createRefCountedByRef()' is defined here}}
13+
RefCountedType& copyRefCountedByRef(); // expected-note {{'copyRefCountedByRef()' is defined here}}
14+
15+
} // namespace NoAnnotations
16+
17+
void retainRefCounted(NoAnnotations::RefCountedType* obj);
18+
void releaseRefCounted(NoAnnotations::RefCountedType* obj);
19+
20+
namespace APIAnnotations {
21+
22+
struct RefCountedType {
23+
int value;
24+
} __attribute__((swift_attr("import_reference")))
25+
__attribute__((swift_attr("retain:retainAPIRefCounted")))
26+
__attribute__((swift_attr("release:releaseAPIRefCounted")));
27+
28+
RefCountedType& createByRef() __attribute__((swift_attr("returns_retained")));
29+
RefCountedType& getByRef() __attribute__((swift_attr("returns_unretained")));
30+
31+
32+
} // namespace APIAnnotations
33+
34+
void retainAPIRefCounted(APIAnnotations::RefCountedType* obj);
35+
void releaseAPIRefCounted(APIAnnotations::RefCountedType* obj);
36+
37+
namespace TypeAnnotation {
38+
39+
struct RefCountedType {
40+
int value;
41+
} __attribute__((swift_attr("import_reference")))
42+
__attribute__((swift_attr("retain:retainTypeRefCounted")))
43+
__attribute__((swift_attr("release:releaseTypeRefCounted")))
44+
__attribute__((swift_attr("returned_as_unretained_by_default")));
45+
46+
RefCountedType& getByRef();
47+
RefCountedType& createByRef();
48+
RefCountedType& copyByRef();
49+
50+
} // namespace TypeAnnotation
51+
52+
void retainTypeRefCounted(TypeAnnotation::RefCountedType* obj);
53+
void releaseTypeRefCounted(TypeAnnotation::RefCountedType* obj);
54+
55+
namespace BothAnnotations {
56+
57+
struct RefCountedType {
58+
int value;
59+
} __attribute__((swift_attr("import_reference")))
60+
__attribute__((swift_attr("retain:retainBothRefCounted")))
61+
__attribute__((swift_attr("release:releaseBothRefCounted")))
62+
__attribute__((swift_attr("returned_as_unretained_by_default")));
63+
64+
// Note: Type default at type level is unretained, but API annotation overrides
65+
RefCountedType& createByRef() __attribute__((swift_attr("returns_retained")));
66+
RefCountedType& getByRef();
67+
68+
} // namespace BothAnnotations
69+
70+
void retainBothRefCounted(BothAnnotations::RefCountedType* obj);
71+
void releaseBothRefCounted(BothAnnotations::RefCountedType* obj);

test/Interop/Cxx/foreign-reference/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,8 @@ module LoggingFrts {
8787
header "logging-frts.h"
8888
requires cplusplus
8989
}
90+
91+
module FRTReferenceReturns {
92+
header "frt-reference-returns.h"
93+
requires cplusplus
94+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: rm -rf %t
2+
// RUN: %target-typecheck-verify-swift -I %S%{fs-sep}Inputs -cxx-interoperability-mode=default -enable-experimental-feature WarnUnannotatedReturnOfCxxFrt -verify-additional-file %S%{fs-sep}Inputs%{fs-sep}frt-reference-returns.h
3+
4+
// REQUIRES: swift_feature_WarnUnannotatedReturnOfCxxFrt
5+
6+
import FRTReferenceReturns
7+
8+
func testNoAnnotations() {
9+
let _ = NoAnnotations.getRefCountedByRef()
10+
// expected-warning@-1 {{cannot infer the ownership of the returned value, annotate 'getRefCountedByRef()' with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED}}
11+
let _ = NoAnnotations.createRefCountedByRef()
12+
// expected-warning@-1 {{cannot infer the ownership of the returned value, annotate 'createRefCountedByRef()' with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED}}
13+
let _ = NoAnnotations.copyRefCountedByRef()
14+
// expected-warning@-1 {{cannot infer the ownership of the returned value, annotate 'copyRefCountedByRef()' with either SWIFT_RETURNS_RETAINED or SWIFT_RETURNS_UNRETAINED}}
15+
}
16+
17+
func testAPIAnnotations() {
18+
let _ = APIAnnotations.createByRef()
19+
let _ = APIAnnotations.getByRef()
20+
}
21+
22+
func testTypeAnnotation() {
23+
let _ = TypeAnnotation.getByRef()
24+
let _ = TypeAnnotation.createByRef()
25+
let _ = TypeAnnotation.copyByRef()
26+
}
27+
28+
func testBothAnnotations() {
29+
let _ = BothAnnotations.createByRef()
30+
let _ = BothAnnotations.getByRef()
31+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-swift-emit-sil -I %S/Inputs -cxx-interoperability-mode=default -disable-availability-checking -diagnostic-style llvm %s -validate-tbd-against-ir=none -Xcc -fignore-exceptions | %FileCheck %s
2+
3+
import FRTReferenceReturns
4+
5+
// Test that the ownership annotations work correctly for reference returns
6+
7+
func useAll() {
8+
let _ = NoAnnotations.getRefCountedByRef()
9+
// CHECK: sil [clang NoAnnotations.getRefCountedByRef] @{{.*}} : $@convention(c) () -> NoAnnotations.RefCountedType
10+
// Note: create/copy rule (default without ownership annotations) does not apply if return type is & to frt
11+
let _ = NoAnnotations.createRefCountedByRef()
12+
// CHECK: sil [clang NoAnnotations.createRefCountedByRef] @{{.*}} : $@convention(c) () -> NoAnnotations.RefCountedType
13+
let _ = NoAnnotations.copyRefCountedByRef()
14+
// CHECK: sil [clang NoAnnotations.copyRefCountedByRef] @{{.*}} : $@convention(c) () -> NoAnnotations.RefCountedType
15+
16+
// APIAnnotations - explicit ownership
17+
let _ = APIAnnotations.createByRef()
18+
// CHECK: sil [clang APIAnnotations.createByRef] @{{.*}} : $@convention(c) () -> @owned APIAnnotations.RefCountedType
19+
let _ = APIAnnotations.getByRef()
20+
// CHECK: sil [clang APIAnnotations.getByRef] @{{.*}} : $@convention(c) () -> APIAnnotations.RefCountedType
21+
22+
// TypeAnnotation - all unretained due to type default
23+
let _ = TypeAnnotation.getByRef()
24+
// CHECK: sil [clang TypeAnnotation.getByRef] @{{.*}} : $@convention(c) () -> TypeAnnotation.RefCountedType
25+
let _ = TypeAnnotation.createByRef()
26+
// CHECK: sil [clang TypeAnnotation.createByRef] @{{.*}} : $@convention(c) () -> TypeAnnotation.RefCountedType
27+
let _ = TypeAnnotation.copyByRef()
28+
// CHECK: sil [clang TypeAnnotation.copyByRef] @{{.*}} : $@convention(c) () -> TypeAnnotation.RefCountedType
29+
30+
// BothAnnotations - API overrides type
31+
let _ = BothAnnotations.createByRef()
32+
// CHECK: sil [clang BothAnnotations.createByRef] @{{.*}} : $@convention(c) () -> @owned BothAnnotations.RefCountedType
33+
let _ = BothAnnotations.getByRef()
34+
// CHECK: sil [clang BothAnnotations.getByRef] @{{.*}} : $@convention(c) () -> BothAnnotations.RefCountedType
35+
}

0 commit comments

Comments
 (0)