Skip to content

Commit 17dd298

Browse files
Xazax-hunGabor Horvath
authored andcommitted
🍒[6.0][cxx-interop] Fix reverse interop crash when using raw modules
Explanation: A low-level clang API was used that relies on a cached value being present. This fix is changing that API call to another that calculates the value if the cache is not yet populated. Scope: C++ reverse interop. Risk: Low, replacing an API call with a different that has the same semantics (other than calculating the value when the cache is empty). Testing: Regression test added. Issue: rdar://132746445 Reviewer: @egorzhdan Original PR: #75714
1 parent f8e35f0 commit 17dd298

File tree

2 files changed

+123
-5
lines changed

2 files changed

+123
-5
lines changed

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,10 @@ class ModuleWriter {
286286
if (!isa<clang::TypeDecl>(typeDecl->getClangDecl()))
287287
return;
288288
// Get the underlying clang type from a type alias decl or record decl.
289-
auto clangType =
290-
clang::QualType(
291-
cast<clang::TypeDecl>(typeDecl->getClangDecl())->getTypeForDecl(),
292-
0)
293-
.getCanonicalType();
289+
auto clangDecl = typeDecl->getClangDecl();
290+
auto clangType = clangDecl->getASTContext()
291+
.getTypeDeclType(cast<clang::TypeDecl>(clangDecl))
292+
.getCanonicalType();
294293
if (!isa<clang::RecordType>(clangType.getTypePtr()))
295294
return;
296295
auto it = seenClangTypes.insert(clangType.getTypePtr());
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -typecheck %t/use-span.swift -typecheck -module-name UseSpan -emit-clang-header-path %t/UseSpan.h -I %t -enable-experimental-cxx-interop -Xcc -Xclang -Xcc -fmodule-format=raw -Xcc -std=c++20 -clang-header-expose-decls=all-public
5+
6+
// RUN: %target-interop-build-clangxx -std=c++20 -c %t/use-span.cpp -I %t -o %t/swift-cxx-execution.o
7+
// RUN: %target-interop-build-swift %t/use-span.swift -o %t/swift-cxx-execution -Xlinker %t/swift-cxx-execution.o -module-name UseSpan -Xfrontend -entry-point-function-name -Xfrontend swiftMain -I %t -O -Xcc --std=c++20
8+
9+
// RUN: %target-codesign %t/swift-cxx-execution
10+
// RUN: %target-run %t/swift-cxx-execution | %FileCheck %s
11+
12+
// FIXME swift-ci linux tests do not support std::span
13+
// UNSUPPORTED: OS=linux-gnu
14+
15+
// REQUIRES: executable_test
16+
17+
//--- header.h
18+
#include <string>
19+
#include <span>
20+
21+
using Span = std::span<int>;
22+
using SpanOfString = std::span<std::string>;
23+
24+
namespace ns {
25+
using SpanOfConstUInt8 = std::span<const uint8_t>;
26+
}
27+
28+
static int staticArr[] = {1, 2, 3};
29+
static Span staticSpan = {staticArr};
30+
31+
//--- module.modulemap
32+
module CxxTest {
33+
header "header.h"
34+
requires cplusplus
35+
export *
36+
}
37+
38+
//--- use-span.swift
39+
import CxxTest
40+
41+
public func createEmptySpan() -> Span {
42+
return Span()
43+
}
44+
45+
public func printSpan() {
46+
print("{\(staticSpan[0]), \(staticSpan[1]), \(staticSpan[2])}")
47+
}
48+
49+
public func printSpan(_ sp: Span) {
50+
print("{\(sp[0]), \(sp[1]), \(sp[2])}")
51+
}
52+
53+
public func printSpanOfString(_ sp: SpanOfString) {
54+
print("{\(sp[0]), \(sp[1]), \(sp[2])}")
55+
}
56+
57+
public func passthroughSpan(_ sp: Span) -> Span {
58+
return sp;
59+
}
60+
61+
public func changeSpan(_ sp: inout Span) {
62+
sp[0] = 0;
63+
}
64+
65+
public func mapSpan(_ sp: Span) {
66+
let result = sp.map { $0 + 3 }
67+
print(result)
68+
}
69+
70+
public typealias SpanConstUInt8 = ns.SpanOfConstUInt8
71+
72+
public func receiveSpanAlias(_ sp1: SpanConstUInt8, _ sp2: SpanConstUInt8) {
73+
}
74+
75+
//--- use-span.cpp
76+
#include <cassert>
77+
#include "header.h"
78+
#include "UseSpan.h"
79+
80+
81+
int main() {
82+
using namespace swift;
83+
{
84+
Span emptySpan = UseSpan::createEmptySpan();
85+
assert(emptySpan.empty());
86+
assert(emptySpan.size() == 0);
87+
88+
int arr[] = {4, 5, 6};
89+
Span sp = {arr};
90+
UseSpan::printSpan();
91+
UseSpan::printSpan(sp);
92+
assert(staticSpan[0] == 1);
93+
assert(sp[0] == 4);
94+
}
95+
// CHECK: {1, 2, 3}
96+
// CHECK-NEXT: {4, 5, 6}
97+
{
98+
std::string strArr[] = {"", "a", "abc"};
99+
SpanOfString strSp = {strArr};
100+
UseSpan::printSpanOfString(strSp);
101+
}
102+
// CHECK-NEXT: {, a, abc}
103+
{
104+
int arr[] = {4, 5, 6};
105+
Span sp = {arr};
106+
UseSpan::printSpan(UseSpan::passthroughSpan(sp));
107+
UseSpan::changeSpan(sp);
108+
UseSpan::printSpan(sp);
109+
}
110+
// CHECK-NEXT: {4, 5, 6}
111+
// CHECK-NEXT: {0, 5, 6}
112+
{
113+
int arr[] = {4, 5, 6};
114+
Span sp = {arr};
115+
UseSpan::mapSpan(sp);
116+
}
117+
// CHECK-NEXT: [7, 8, 9]
118+
return 0;
119+
}

0 commit comments

Comments
 (0)