Skip to content

Fix crash with invalid private @inlinable function #31060

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/swift/AST/ASTTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ SWIFT_TYPEID(PropertyWrapperBackingPropertyInfo)
SWIFT_TYPEID(PropertyWrapperTypeInfo)
SWIFT_TYPEID(Requirement)
SWIFT_TYPEID(ResilienceExpansion)
SWIFT_TYPEID(FragileFunctionKind)
SWIFT_TYPEID(Type)
SWIFT_TYPEID(TypePair)
SWIFT_TYPEID(TypeWitnessAndDecl)
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ASTTypeIDs.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct PropertyWrapperMutability;
class ProtocolDecl;
class Requirement;
enum class ResilienceExpansion : unsigned;
struct FragileFunctionKind;
class SourceFile;
class Type;
class ValueDecl;
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -4930,7 +4930,7 @@ class VarDecl : public AbstractStorageDecl {
PointerUnion<PatternBindingDecl *, Stmt *, VarDecl *> Parent;

VarDecl(DeclKind kind, bool isStatic, Introducer introducer,
bool issCaptureList, SourceLoc nameLoc, Identifier name,
bool isCaptureList, SourceLoc nameLoc, Identifier name,
DeclContext *dc, StorageIsMutable_t supportsMutation);

public:
Expand Down
24 changes: 24 additions & 0 deletions include/swift/AST/DeclContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,26 @@ struct ConformanceDiagnostic {
ProtocolDecl *ExistingExplicitProtocol;
};

/// Used in diagnostic %selects.
struct FragileFunctionKind {
enum Kind : unsigned {
Transparent,
Inlinable,
AlwaysEmitIntoClient,
DefaultArgument,
PropertyInitializer,
None
};

Kind kind = None;
bool allowUsableFromInline = false;

friend bool operator==(FragileFunctionKind lhs, FragileFunctionKind rhs) {
return (lhs.kind == rhs.kind &&
lhs.allowUsableFromInline == rhs.allowUsableFromInline);
}
};

/// A DeclContext is an AST object which acts as a semantic container
/// for declarations. As a policy matter, we currently define
/// contexts broadly: a lambda expression in a function is a new
Expand Down Expand Up @@ -469,6 +489,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
/// are used.
ResilienceExpansion getResilienceExpansion() const;

/// Get the fragile function kind for the code in this context, which
/// is used for diagnostics.
FragileFunctionKind getFragileFunctionKind() const;

/// Returns true if this context may possibly contain members visible to
/// AnyObject dynamic lookup.
bool mayContainMembersAccessedByDynamicLookup() const;
Expand Down
15 changes: 8 additions & 7 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -672,10 +672,10 @@ class StructuralTypeRequest :
bool isCached() const { return true; }
};

/// Request the most optimal resilience expansion for the code in the context.
class ResilienceExpansionRequest :
public SimpleRequest<ResilienceExpansionRequest,
ResilienceExpansion(DeclContext*),
/// Request the fragile function kind for the context.
class FragileFunctionKindRequest :
public SimpleRequest<FragileFunctionKindRequest,
FragileFunctionKind(DeclContext*),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -684,15 +684,16 @@ class ResilienceExpansionRequest :
friend SimpleRequest;

// Evaluation.
ResilienceExpansion evaluate(Evaluator &eval, DeclContext *context) const;
FragileFunctionKind evaluate(Evaluator &eval, DeclContext *context) const;

public:
// Caching.
bool isCached() const { return true; }
};

void simple_display(llvm::raw_ostream &out,
const ResilienceExpansion &value);
void simple_display(llvm::raw_ostream &out, FragileFunctionKind value);

void simple_display(llvm::raw_ostream &out, ResilienceExpansion value);

/// Request the custom attribute which attaches a function builder to the
/// given declaration.
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,8 @@ SWIFT_REQUEST(TypeChecker, RequiresOpaqueAccessorsRequest, bool(VarDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, RequiresOpaqueModifyCoroutineRequest,
bool(AbstractStorageDecl *), SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ResilienceExpansionRequest,
ResilienceExpansion(DeclContext *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, FragileFunctionKindRequest,
FragileFunctionKind(DeclContext *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SelfAccessKindRequest, SelfAccessKind(FuncDecl *),
SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, StorageImplInfoRequest,
Expand Down
89 changes: 60 additions & 29 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,19 +312,31 @@ bool DeclContext::isGenericContext() const {
return false;
}

/// Get the most optimal resilience expansion for the body of this function.
/// If the body is able to be inlined into functions in other resilience
/// domains, this ensures that only sufficiently-conservative access patterns
/// are used.
ResilienceExpansion DeclContext::getResilienceExpansion() const {
auto fragileKind = getFragileFunctionKind();
switch (fragileKind.kind) {
case FragileFunctionKind::Transparent:
case FragileFunctionKind::Inlinable:
case FragileFunctionKind::AlwaysEmitIntoClient:
case FragileFunctionKind::DefaultArgument:
case FragileFunctionKind::PropertyInitializer:
return ResilienceExpansion::Minimal;
case FragileFunctionKind::None:
return ResilienceExpansion::Maximal;
}

llvm_unreachable("Bad fragile function kind");
}

FragileFunctionKind DeclContext::getFragileFunctionKind() const {
auto &context = getASTContext();
return evaluateOrDefault(context.evaluator,
ResilienceExpansionRequest { const_cast<DeclContext *>(this) },
ResilienceExpansion::Minimal);
FragileFunctionKindRequest { const_cast<DeclContext *>(this) },
{FragileFunctionKind::None, false});
}

ResilienceExpansion
swift::ResilienceExpansionRequest::evaluate(Evaluator &evaluator,
FragileFunctionKind
swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator,
DeclContext *context) const {
for (const auto *dc = context->getLocalContext(); dc && dc->isLocalContext();
dc = dc->getParent()) {
Expand All @@ -336,14 +348,19 @@ swift::ResilienceExpansionRequest::evaluate(Evaluator &evaluator,
auto *VD = cast<ValueDecl>(dc->getAsDecl());
assert(VD->hasParameterList());

auto access =
auto effectiveAccess =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
auto formalAccess =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/false);
if (effectiveAccess.isPublic()) {
return {FragileFunctionKind::DefaultArgument,
!formalAccess.isPublic()};
}

if (access.isPublic())
return ResilienceExpansion::Minimal;

return ResilienceExpansion::Maximal;
return {FragileFunctionKind::None,
/*allowUsableFromInline=*/false};
}

// Stored property initializer contexts use minimal resilience expansion
Expand All @@ -354,12 +371,14 @@ swift::ResilienceExpansionRequest::evaluate(Evaluator &evaluator,
NTD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
if (!nominalAccess.isPublic())
return ResilienceExpansion::Maximal;
return {FragileFunctionKind::None,
/*allowUsableFromInline=*/false};

if (NTD->isFormallyResilient())
return ResilienceExpansion::Maximal;
return {FragileFunctionKind::None,
/*allowUsableFromInline=*/false};

return ResilienceExpansion::Minimal;
return {FragileFunctionKind::PropertyInitializer, true};
}
}

Expand All @@ -375,32 +394,44 @@ swift::ResilienceExpansionRequest::evaluate(Evaluator &evaluator,

// If the function is not externally visible, we will not be serializing
// its body.
if (!funcAccess.isPublic())
break;
if (!funcAccess.isPublic()) {
return {FragileFunctionKind::None,
/*allowUsableFromInline=*/false};
}

// If the function is public, @_transparent implies @inlinable.
if (AFD->isTransparent())
return ResilienceExpansion::Minimal;
if (AFD->isTransparent()) {
return {FragileFunctionKind::Transparent,
/*allowUsableFromInline=*/true};
}

if (AFD->getAttrs().hasAttribute<InlinableAttr>())
return ResilienceExpansion::Minimal;
if (AFD->getAttrs().hasAttribute<InlinableAttr>()) {
return {FragileFunctionKind::Inlinable,
/*allowUsableFromInline=*/true};
}

if (AFD->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
return ResilienceExpansion::Minimal;
if (AFD->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>()) {
return {FragileFunctionKind::AlwaysEmitIntoClient,
/*allowUsableFromInline=*/true};
}

// If a property or subscript is @inlinable or @_alwaysEmitIntoClient,
// the accessors are @inlinable or @_alwaysEmitIntoClient also.
if (auto accessor = dyn_cast<AccessorDecl>(AFD)) {
auto *storage = accessor->getStorage();
if (storage->getAttrs().getAttribute<InlinableAttr>())
return ResilienceExpansion::Minimal;
if (storage->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
return ResilienceExpansion::Minimal;
if (storage->getAttrs().getAttribute<InlinableAttr>()) {
return {FragileFunctionKind::Inlinable,
/*allowUsableFromInline=*/true};
}
if (storage->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>()) {
return {FragileFunctionKind::AlwaysEmitIntoClient,
/*allowUsableFromInline=*/true};
}
}
}
}

return ResilienceExpansion::Maximal;
return {FragileFunctionKind::None, false};
}

/// Determine whether the innermost context is generic.
Expand Down
38 changes: 36 additions & 2 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -616,8 +616,42 @@ void swift::simple_display(llvm::raw_ostream &os, PropertyWrapperMutability m) {
}

void swift::simple_display(llvm::raw_ostream &out,
const ResilienceExpansion &value) {
out << value;
ResilienceExpansion value) {
switch (value) {
case ResilienceExpansion::Minimal:
out << "minimal";
break;
case ResilienceExpansion::Maximal:
out << "maximal";
break;
}
}

void swift::simple_display(llvm::raw_ostream &out,
FragileFunctionKind value) {
switch (value.kind) {
case FragileFunctionKind::Transparent:
out << "transparent";
break;
case FragileFunctionKind::Inlinable:
out << "inlinable";
break;
case FragileFunctionKind::AlwaysEmitIntoClient:
out << "alwaysEmitIntoClient";
break;
case FragileFunctionKind::DefaultArgument:
out << "defaultArgument";
break;
case FragileFunctionKind::PropertyInitializer:
out << "propertyInitializer";
break;
case FragileFunctionKind::None:
out << "none";
break;
}

out << ", allowUsableFromInline: "
<< (value.allowUsableFromInline ? "true" : "false");
}

//----------------------------------------------------------------------------//
Expand Down
Loading