[Strict memory safety] Only diagnose unsafe types in the canonical type

Typealiases involving unsafe types that resolve to safe types
should not be diagnosed.
This commit is contained in:
Doug Gregor
2025-04-18 18:43:27 -07:00
parent 235242e8b3
commit 0405f61207
3 changed files with 39 additions and 17 deletions

View File

@@ -1216,12 +1216,14 @@ ExplicitSafety Decl::getExplicitSafety() const {
ExplicitSafety::Unspecified);
}
// Inference: Check the enclosing context.
if (auto enclosingDC = getDeclContext()) {
// Is this an extension with @safe or @unsafe on it?
if (auto ext = dyn_cast<ExtensionDecl>(enclosingDC)) {
if (auto extSafety = getExplicitSafetyFromAttrs(ext))
return *extSafety;
// Inference: Check the enclosing context, unless this is a type.
if (!isa<TypeDecl>(this)) {
if (auto enclosingDC = getDeclContext()) {
// Is this an extension with @safe or @unsafe on it?
if (auto ext = dyn_cast<ExtensionDecl>(enclosingDC)) {
if (auto extSafety = getExplicitSafetyFromAttrs(ext))
return *extSafety;
}
}
}

View File

@@ -372,21 +372,28 @@ void swift::diagnoseUnsafeType(ASTContext &ctx, SourceLoc loc, Type type,
if (!ctx.LangOpts.hasFeature(Feature::StrictMemorySafety))
return;
if (!type->isUnsafe() && !type->getCanonicalType()->isUnsafe())
if (!type->getCanonicalType()->isUnsafe())
return;
// Look for a specific @unsafe nominal type.
Type specificType;
type.findIf([&specificType](Type type) {
if (auto typeDecl = type->getAnyNominal()) {
if (typeDecl->getExplicitSafety() == ExplicitSafety::Unsafe) {
specificType = type;
return false;
// Look for a specific @unsafe nominal type along the way.
auto findSpecificUnsafeType = [](Type type) {
Type specificType;
(void)type.findIf([&specificType](Type type) {
if (auto typeDecl = type->getAnyNominal()) {
if (typeDecl->getExplicitSafety() == ExplicitSafety::Unsafe) {
specificType = type;
return false;
}
}
}
return false;
});
return false;
});
return specificType;
};
Type specificType = findSpecificUnsafeType(type);
if (!specificType)
specificType = findSpecificUnsafeType(type->getCanonicalType());
diagnose(specificType ? specificType : type);
}

View File

@@ -271,3 +271,16 @@ struct UnsafeWrapTest {
@safe @unsafe
struct ConfusedStruct { } // expected-error{{struct 'ConfusedStruct' cannot be both @safe and @unsafe}}
@unsafe
struct UnsafeContainingUnspecified {
typealias A = Int
func getA() -> A { 0 }
}
@unsafe func f(x: UnsafeContainingUnspecified) {
let a = unsafe x.getA()
_ = a
}