Skip to content

Commit b409e55

Browse files
committed
Allow referencing static functions in @section expressions
1 parent 5f578ad commit b409e55

File tree

2 files changed

+77
-6
lines changed

2 files changed

+77
-6
lines changed

lib/Sema/LegalConstExprVerifier.cpp

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,11 +234,6 @@ checkSupportedWithSectionAttribute(const Expr *expr,
234234
}
235235
continue;
236236
}
237-
238-
// No auto-closures
239-
if (isa<AbstractClosureExpr>(expr)) {
240-
return std::make_pair(expr, Default);
241-
}
242237

243238
// Function conversions are allowed if the conversion is to '@convention(c)'
244239
if (auto functionConvExpr = dyn_cast<FunctionConversionExpr>(expr)) {
@@ -270,6 +265,60 @@ checkSupportedWithSectionAttribute(const Expr *expr,
270265
return std::make_pair(expr, OpaqueDeclRef);
271266
}
272267

268+
// Allow specific patterns of AutoClosureExpr, which is used in static func
269+
// references. E.g. "MyStruct.staticFunc" is:
270+
// - autoclosure_expr type="() -> ()"
271+
// - call_expr type="()"
272+
// - dot_syntax_call_expr
273+
// - declref_expr decl="MyStruct.staticFunc"
274+
// - dot_self_expr type="MyStruct.Type"
275+
// - type_expr type="MyStruct.Type"
276+
if (auto autoClosureExpr = dyn_cast<AutoClosureExpr>(expr)) {
277+
auto subExpr = autoClosureExpr->getUnwrappedCurryThunkExpr();
278+
if (auto dotSyntaxCall = dyn_cast<DotSyntaxCallExpr>(subExpr)) {
279+
if (auto declRef = dyn_cast<DeclRefExpr>(dotSyntaxCall->getFn())) {
280+
if (auto funcDecl = dyn_cast<FuncDecl>(declRef->getDecl())) {
281+
// Check if it's a function on a concrete non-generic type
282+
if (!funcDecl->hasGenericParamList() &&
283+
!funcDecl->getDeclContext()->isGenericContext() &&
284+
funcDecl->isStatic()) {
285+
if (auto args = dotSyntaxCall->getArgs()) {
286+
if (args->size() == 1) {
287+
// Check that the single arg is a DotSelfExpr with only a
288+
// direct concrete TypeExpr inside
289+
if (auto dotSelfExpr =
290+
dyn_cast<DotSelfExpr>(args->get(0).getExpr())) {
291+
if (const TypeExpr *typeExpr =
292+
dyn_cast<TypeExpr>(dotSelfExpr->getSubExpr())) {
293+
auto baseType = typeExpr->getType();
294+
if (baseType && baseType->is<MetatypeType>()) {
295+
auto instanceType =
296+
baseType->getMetatypeInstanceType();
297+
if (auto nominal =
298+
instanceType
299+
->getNominalOrBoundGenericNominal()) {
300+
if (!nominal->hasGenericParamList() &&
301+
!nominal->getDeclContext()->isGenericContext() &&
302+
!nominal->isResilient()) {
303+
continue;
304+
}
305+
}
306+
}
307+
}
308+
}
309+
}
310+
}
311+
}
312+
}
313+
}
314+
}
315+
return std::make_pair(expr, Default);
316+
}
317+
318+
// Other closure expressions (auto-closures) are not allowed
319+
if (isa<AbstractClosureExpr>(expr))
320+
return std::make_pair(expr, Default);
321+
273322
// DotSelfExpr for metatype references (but only a direct TypeExpr inside)
274323
if (const DotSelfExpr *dotSelfExpr = dyn_cast<DotSelfExpr>(expr)) {
275324
if (const TypeExpr *typeExpr =

test/ConstValues/SectionSyntactic.swift

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,41 @@
4343
func foo() -> Int { return 42 }
4444
func bar(x: Int) -> String { return "test" }
4545

46-
// function references
46+
// global function references
4747
@section("mysection") let funcRef1 = foo // ok
4848
@section("mysection") let funcRef2 = bar // ok
4949
@section("mysection") let funcRef3: ()->Int = foo // ok
5050
@section("mysection") let funcRef4: @convention(c) ()->Int = foo // ok
5151

52+
struct Q {
53+
func memberFunc() {}
54+
static func staticFunc() {}
55+
func genericFunc<T>(t: T) {}
56+
static func staticGenericFunc<T>(t: T) {}
57+
}
58+
59+
// non-global function references
60+
@section("mysection") let staticFuncRef1 = Q.staticFunc // ok
61+
extension Q { @section("mysection") static let staticFuncRef2 = staticFunc } // ok
62+
@section("mysection") let staticFuncRef3 = Bool.random // ok
63+
5264
// invalid function references (should be rejected)
5365
@section("mysection") let invalidFuncRef1 = foo()
5466
// expected-error@-1{{not supported in a constant expression}}
5567
@section("mysection") let invalidFuncRef2 = Bool.self.random
5668
// expected-error@-1{{not supported in a constant expression}}
5769
@section("mysection") let invalidFuncRef3 = (Bool.self as Bool.Type).random
5870
// expected-error@-1{{not supported in a constant expression}}
71+
@section("mysection") let invalidFuncRef4 = Q.memberFunc
72+
// expected-error@-1{{not supported in a constant expression}}
73+
extension Q { @section("mysection") static let invalidFuncRef5 = memberFunc }
74+
// expected-error@-1{{not supported in a constant expression}}
75+
extension Q { @section("mysection") static let invalidFuncRef6: (Int)->() = genericFunc(Q()) }
76+
// expected-error@-1{{not supported in a constant expression}}
77+
extension Q { @section("mysection") static let invalidFuncRef7: (Q) -> (Int) -> () = genericFunc }
78+
// expected-error@-1{{not supported in a constant expression}}
79+
extension Q { @section("mysection") static let invalidFuncRef8: (Int)->() = staticGenericFunc }
80+
// expected-error@-1{{not supported in a constant expression}}
5981

6082
// generic function references (should be rejected)
6183
@section("mysection") let invalidGenericFunc = [Int].randomElement

0 commit comments

Comments
 (0)