Skip to content

Commit 1dcb223

Browse files
committed
Allow referencing static functions in @section expressions
1 parent 8748213 commit 1dcb223

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

lib/Sema/LegalConstExprVerifier.cpp

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,6 @@ checkSupportedWithSectionAttribute(const Expr *expr,
222222
if (isa<KeyPathExpr>(expr))
223223
return std::make_pair(expr, KeyPath);
224224

225-
// Closure expressions are not supported in constant expressions
226-
if (isa<AbstractClosureExpr>(expr))
227-
return std::make_pair(expr, Closure);
228-
229225
// Function conversions are allowed if the conversion is to '@convention(c)'
230226
if (auto functionConvExpr = dyn_cast<FunctionConversionExpr>(expr)) {
231227
if (auto targetFnTy =
@@ -256,6 +252,60 @@ checkSupportedWithSectionAttribute(const Expr *expr,
256252
return std::make_pair(expr, OpaqueDeclRef);
257253
}
258254

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