Skip to content

Commit d6499b8

Browse files
author
Gabor Horvath
committed
[cxx-interop] Check the safety of C++ template arguments
Swift imports template specializations as a standalone type (not as an instantiation of a generic) so unsafety is not propagated from the template arguments to the specialization. This PR propagates this information explicitly.
1 parent dd11207 commit d6499b8

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,29 @@ namespace {
21862186
dc);
21872187
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = result;
21882188

2189+
// We have to do this after populating ImportedDecls to avoid importing
2190+
// the same multiple times.
2191+
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::SafeInterop) &&
2192+
Impl.SwiftContext.LangOpts.hasFeature(
2193+
Feature::AllowUnsafeAttribute)) {
2194+
if (const auto *ctsd =
2195+
dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
2196+
for (auto arg : ctsd->getTemplateArgs().asArray()) {
2197+
if (arg.getKind() != clang::TemplateArgument::Type)
2198+
continue;
2199+
auto SwiftType = Impl.importTypeIgnoreIUO(
2200+
arg.getAsType(), ImportTypeKind::Abstract,
2201+
[](Diagnostic &&diag) {}, false, Bridgeability::None,
2202+
ImportTypeAttrs());
2203+
if (SwiftType && SwiftType->isUnsafe()) {
2204+
auto attr = new (Impl.SwiftContext) UnsafeAttr(/*implicit=*/true);
2205+
result->getAttrs().add(attr);
2206+
break;
2207+
}
2208+
}
2209+
}
2210+
}
2211+
21892212
if (recordHasMoveOnlySemantics(decl)) {
21902213
if (decl->isInStdNamespace() && decl->getName() == "promise") {
21912214
// Do not import std::promise.
@@ -8396,6 +8419,13 @@ static bool importAsUnsafe(ClangImporter::Implementation &impl,
83968419
if (isa<ClassDecl>(MappedDecl))
83978420
return false;
83988421

8422+
// Most STL containers have std::allocator as their default allocator. We need
8423+
// to consider std::allocator safe for the STL containers to be ever
8424+
// considered safe.
8425+
if (decl->isInStdNamespace() && decl->getIdentifier() &&
8426+
decl->getName() == "allocator")
8427+
return false;
8428+
83998429
if (const auto *record = dyn_cast<clang::RecordDecl>(decl))
84008430
return evaluateOrDefault(
84018431
context.evaluator,

test/Interop/Cxx/class/safe-interop-mode.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module Test {
1818
//--- Inputs/nonescapable.h
1919
#include "swift/bridging"
2020
#include <span>
21+
#include <vector>
2122

2223
struct SWIFT_NONESCAPABLE View {
2324
__attribute__((swift_attr("@lifetime(immortal)")))
@@ -54,6 +55,8 @@ struct MyContainer {
5455

5556
using SpanOfInt = std::span<int>;
5657
using SpanOfIntAlias = SpanOfInt;
58+
using VecOfPtr = std::vector<int*>;
59+
using VecOfInt = std::vector<int>;
5760

5861
//--- test.swift
5962

@@ -85,7 +88,14 @@ func useCfType(x: CFArray) {
8588
func useString(x: std.string) {
8689
}
8790

88-
// expected-warning@+1{{global function 'useCppSpan' has an interface that is not memory-safe}}
91+
// expected-warning@+1{{global function 'useVecOfPtr' has an interface that is not memory-safe; use '@unsafe' to indicate that its use is unsafe}}
92+
func useVecOfPtr(x: VecOfPtr) { // expected-note{{reference to unsafe type alias 'VecOfPtr'}}
93+
}
94+
95+
func useVecOfInt(x: VecOfInt) {
96+
}
97+
98+
// expected-warning@+1{{global function 'useCppSpan' has an interface that is not memory-safe; use '@unsafe' to indicate that its use is unsafe}}
8999
func useCppSpan(x: SpanOfInt) { // expected-note{{reference to unsafe type alias 'SpanOfInt'}}
90100
}
91101

0 commit comments

Comments
 (0)