Skip to content

Commit 90c0509

Browse files
authored
Merge pull request #85095 from j-hui/template-arg-safety-in-req
2 parents 41acdeb + 929d0d8 commit 90c0509

File tree

3 files changed

+47
-38
lines changed

3 files changed

+47
-38
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8706,9 +8706,14 @@ ExplicitSafety ClangTypeExplicitSafety::evaluate(
87068706
if (auto recordDecl = clangType->getAsTagDecl()) {
87078707
// If we reached this point the types is not imported as a shared reference,
87088708
// so we don't need to check the bases whether they are shared references.
8709-
return evaluateOrDefault(evaluator,
8710-
ClangDeclExplicitSafety({recordDecl, false}),
8711-
ExplicitSafety::Unspecified);
8709+
auto req = ClangDeclExplicitSafety({recordDecl, false});
8710+
if (evaluator.hasActiveRequest(req))
8711+
// Cycles are allowed in templates, e.g.:
8712+
// template <typename> class Foo { ... }; // throws away template arg
8713+
// template <typename T> class Bar : Foo<Bar<T>> { ... };
8714+
// We need to avoid them here.
8715+
return ExplicitSafety::Unspecified;
8716+
return evaluateOrDefault(evaluator, req, ExplicitSafety::Unspecified);
87128717
}
87138718

87148719
// Everything else is safe.
@@ -8828,6 +8833,29 @@ ClangDeclExplicitSafety::evaluate(Evaluator &evaluator,
88288833
ClangTypeEscapability({recordDecl->getTypeForDecl(), nullptr}),
88298834
CxxEscapability::Unknown) != CxxEscapability::Unknown)
88308835
return ExplicitSafety::Safe;
8836+
8837+
// A template class is unsafe if any of its type arguments are unsafe.
8838+
// Note that this does not rely on the record being defined.
8839+
if (const auto *ctsd =
8840+
dyn_cast<clang::ClassTemplateSpecializationDecl>(recordDecl)) {
8841+
for (auto arg : ctsd->getTemplateArgs().asArray()) {
8842+
switch (arg.getKind()) {
8843+
case clang::TemplateArgument::Type:
8844+
if (hasUnsafeType(evaluator, arg.getAsType()))
8845+
return ExplicitSafety::Unsafe;
8846+
break;
8847+
case clang::TemplateArgument::Pack:
8848+
for (auto pkArg : arg.getPackAsArray()) {
8849+
if (pkArg.getKind() == clang::TemplateArgument::Type &&
8850+
hasUnsafeType(evaluator, pkArg.getAsType()))
8851+
return ExplicitSafety::Unsafe;
8852+
}
8853+
break;
8854+
default:
8855+
continue;
8856+
}
8857+
}
8858+
}
88318859

88328860
// If we don't have a definition, leave it unspecified.
88338861
recordDecl = recordDecl->getDefinition();
@@ -8841,7 +8869,7 @@ ClangDeclExplicitSafety::evaluate(Evaluator &evaluator,
88418869
return ExplicitSafety::Unsafe;
88428870
}
88438871
}
8844-
8872+
88458873
// Check the fields.
88468874
for (auto field : recordDecl->fields()) {
88478875
if (hasUnsafeType(evaluator, field->getType()))

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,40 +2300,6 @@ namespace {
23002300
}
23012301
}
23022302

2303-
if (const auto *ctsd =
2304-
dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
2305-
for (auto arg : ctsd->getTemplateArgs().asArray()) {
2306-
auto done = false;
2307-
auto checkUnsafe = [&](clang::TemplateArgument tyArg) {
2308-
if (tyArg.getKind() != clang::TemplateArgument::Type)
2309-
return;
2310-
2311-
auto safety =
2312-
evaluateOrDefault(Impl.SwiftContext.evaluator,
2313-
ClangTypeExplicitSafety({tyArg.getAsType()}),
2314-
ExplicitSafety::Unspecified);
2315-
2316-
if (safety == ExplicitSafety::Unsafe) {
2317-
result->addAttribute(new (Impl.SwiftContext)
2318-
UnsafeAttr(/*implicit=*/true));
2319-
done = true;
2320-
}
2321-
};
2322-
2323-
if (arg.getKind() == clang::TemplateArgument::Pack) {
2324-
for (auto pkArg : arg.getPackAsArray()) {
2325-
checkUnsafe(pkArg);
2326-
if (done)
2327-
break;
2328-
}
2329-
} else {
2330-
checkUnsafe(arg);
2331-
}
2332-
if (done)
2333-
break;
2334-
}
2335-
}
2336-
23372303
bool isNonEscapable = false;
23382304
if (evaluateOrDefault(
23392305
Impl.SwiftContext.evaluator,

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ using TTakePtr = TTake<int *>;
9494
using TTakeSafeTuple = TTake<SafeTuple>;
9595
using TTakeUnsafeTuple = TTake<UnsafeTuple>;
9696

97+
// An escapability or explicit safety annotation means a type is considered safe
98+
// even if it would otherwise be considered unsafe.
99+
template <typename> struct SWIFT_ESCAPABLE TEscape {};
100+
template <typename> struct __attribute__((swift_attr("safe"))) TSafe { void *ptr; };
101+
102+
using TEscapePtr = TEscape<int *>;
103+
using TEscapeUnsafeTuple = TEscape<UnsafeTuple>;
104+
using TSafePtr = TSafe<int *>;
105+
using TSafeTuple = TSafe<UnsafeTuple>;
106+
97107
struct HoldsShared {
98108
SharedObject* obj;
99109

@@ -213,3 +223,8 @@ func useTTakeUnsafeTuple(x: TTakeUnsafeTuple) {
213223
// expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}}
214224
_ = x // expected-note{{reference to parameter 'x' involves unsafe type}}
215225
}
226+
227+
func useTEscapePtr(x: TEscapePtr) { _ = x }
228+
func useTEscapeUnsafeTuple(x: TEscapeUnsafeTuple) { _ = x }
229+
func useTSafePtr(x: TSafePtr) { _ = x }
230+
func useTSafeTuple(x: TSafeTuple) { _ = x }

0 commit comments

Comments
 (0)