Skip to content

Commit 8da5f31

Browse files
committed
SE-0492: Add support for closures (with no captures) into @section expressions
1 parent 8748213 commit 8da5f31

File tree

4 files changed

+72
-9
lines changed

4 files changed

+72
-9
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,8 @@ ERROR(const_unsupported_type_expr,none,
832832
"type expressions not supported in a constant expression", ())
833833
ERROR(const_unsupported_closure,none,
834834
"closures not supported in a constant expression", ())
835+
ERROR(const_unsupported_closure_with_captures,none,
836+
"closures with captures not supported in a constant expression", ())
835837
ERROR(const_unsupported_keypath,none,
836838
"keypaths not supported in a constant expression", ())
837839
ERROR(const_opaque_decl_ref,none,

lib/Sema/LegalConstExprVerifier.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ enum IllegalConstErrorDiagnosis {
4646
TypeExpression,
4747
KeyPath,
4848
Closure,
49+
ClosureWithCaptures,
4950
OpaqueDeclRef,
5051
OpaqueFuncDeclRef,
5152
NonConventionCFunc,
@@ -82,6 +83,9 @@ static void diagnoseError(const Expr *errorExpr,
8283
case Closure:
8384
diags.diagnose(errorLoc, diag::const_unsupported_closure);
8485
break;
86+
case ClosureWithCaptures:
87+
diags.diagnose(errorLoc, diag::const_unsupported_closure_with_captures);
88+
break;
8589
case OpaqueDeclRef:
8690
diags.diagnose(errorLoc, diag::const_opaque_decl_ref);
8791
break;
@@ -222,9 +226,19 @@ checkSupportedWithSectionAttribute(const Expr *expr,
222226
if (isa<KeyPathExpr>(expr))
223227
return std::make_pair(expr, KeyPath);
224228

225-
// Closure expressions are not supported in constant expressions
226-
if (isa<AbstractClosureExpr>(expr))
227-
return std::make_pair(expr, Closure);
229+
// Closures are allowed if they have no captures
230+
if (auto closureExpr = dyn_cast<ClosureExpr>(expr)) {
231+
TypeChecker::computeCaptures(const_cast<ClosureExpr *>(closureExpr));
232+
if (!closureExpr->getCaptureInfo().isTrivial()) {
233+
return std::make_pair(expr, ClosureWithCaptures);
234+
}
235+
continue;
236+
}
237+
238+
// No auto-closures
239+
if (isa<AbstractClosureExpr>(expr)) {
240+
return std::make_pair(expr, Default);
241+
}
228242

229243
// Function conversions are allowed if the conversion is to '@convention(c)'
230244
if (auto functionConvExpr = dyn_cast<FunctionConversionExpr>(expr)) {

test/ConstValues/SectionIR.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ func bar(x: Int) -> String { return "test" }
2828
@section("mysection") let funcRef1 = foo // ok
2929
@section("mysection") let funcRef2 = bar // ok
3030

31+
// closures
32+
@section("mysection") let closure1 = { }
33+
@section("mysection") let closure2 = { return 42 }
34+
@section("mysection") let closure3 = { (x: Int) in return x + 1 }
35+
@section("mysection") let closure4: () -> Void = { }
36+
@section("mysection") let closure5: (Int) -> Int = { x in x * 2 }
37+
@section("mysection") let closure6: @convention(c) (Int) -> Int = { x in x * 2 }
38+
struct W {
39+
@section("mysection") static let closure7: @convention(c) (Int) -> Int = { x in x * 2 }
40+
}
41+
3142
// metatypes - TODO
3243
//@section("mysection") let metatype1 = Int.self
3344

@@ -56,6 +67,15 @@ func bar(x: Int) -> String { return "test" }
5667
// CHECK: @"$s9SectionIR12boolLiteral2Sbvp" = {{.*}}constant %TSb zeroinitializer, section "mysection"
5768
// CHECK: @"$s9SectionIR8funcRef1Siycvp" = {{.*}}constant %swift.function { ptr @"$s9SectionIR3fooSiyF{{.*}}", ptr null }, section "mysection"
5869
// CHECK: @"$s9SectionIR8funcRef2ySSSicvp" = {{.*}}constant %swift.function { ptr @"$s9SectionIR3bar1xSSSi_tF{{.*}}", ptr null }, section "mysection"
70+
71+
// CHECK: @"$s9SectionIR8closure1yycvp" = {{.*}}constant %swift.function { {{.*}} }, section "mysection"
72+
// CHECK: @"$s9SectionIR8closure2Siycvp" = {{.*}}constant %swift.function { {{.*}} }, section "mysection"
73+
// CHECK: @"$s9SectionIR8closure3yS2icvp" = {{.*}}constant %swift.function { {{.*}} }, section "mysection"
74+
// CHECK: @"$s9SectionIR8closure4yycvp" = {{.*}}constant %swift.function { {{.*}} }, section "mysection"
75+
// CHECK: @"$s9SectionIR8closure5yS2icvp" = {{.*}}constant %swift.function { {{.*}} }, section "mysection"
76+
// CHECK: @"$s9SectionIR8closure6yS2iXCvp" = {{.*}}constant ptr @"$s9SectionIR8closure6yS2iXCvpfiS2icfU_To", section "mysection"
77+
// CHECK: @"$s9SectionIR1WV8closure7yS2iXCvpZ" = {{.*}}constant ptr @"$s9SectionIR1WV8closure7yS2iXCvpZfiS2icfU_To", section "mysection"
78+
5979
// CHECK: @"$s9SectionIR6tuple1Si_S2iSdSbtvp" = {{.*}}constant <{ %TSi, %TSi, %TSi, {{.*}} }> <{ %TSi <{ {{i64|i32}} 1 }>, %TSi <{ {{i64|i32}} 2 }>, %TSi <{ {{i64|i32}} 3 }>, {{.*}} }>, section "mysection"
6080
// CHECK: @"$s9SectionIR6tuple2Si_SfSbtvp" = {{.*}}constant <{ %TSi, %TSf, %TSb }> <{ %TSi <{ {{i64|i32}} 42 }>, %TSf <{ float 0x40091EB860000000 }>, %TSb zeroinitializer }>, section "mysection"
6181
// CHECK: @"$s9SectionIR6tuple3Siyc_SSSictvp" = {{.*}}constant <{ %swift.function, %swift.function }> <{ %swift.function { ptr @"$s9SectionIR3fooSiyF{{.*}}", ptr null }, %swift.function { ptr @"$s9SectionIR3bar1xSSSi_tF{{.*}}", ptr null } }>, section "mysection"

test/ConstValues/SectionSyntactic.swift

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,46 @@ func bar(x: Int) -> String { return "test" }
5353
@section("mysection") let invalidFuncRef1 = foo()
5454
// expected-error@-1{{not supported in a constant expression}}
5555
@section("mysection") let invalidFuncRef2 = Bool.self.random
56-
// expected-error@-1{{closures not supported in a constant expression}}
56+
// expected-error@-1{{not supported in a constant expression}}
5757
@section("mysection") let invalidFuncRef3 = (Bool.self as Bool.Type).random
5858
// expected-error@-1{{not supported in a constant expression}}
5959

6060
// generic function references (should be rejected)
6161
@section("mysection") let invalidGenericFunc = [Int].randomElement
6262
// expected-error@-1{{not supported in a constant expression}}
6363

64-
// closures (should be rejected)
65-
@section("mysection") let invalidClosure1 = { }
66-
// expected-error@-1{{closures not supported in a constant expression}}
67-
@section("mysection") let invalidClosure2 = { return 42 }
68-
// expected-error@-1{{closures not supported in a constant expression}}
64+
// closures
65+
@section("mysection") let closure1 = { } // ok
66+
@section("mysection") let closure2 = { return 42 } // ok
67+
@section("mysection") let closure3 = { (x: Int) in return x + 1 } // ok
68+
@section("mysection") let closure4: () -> Void = { } // ok
69+
@section("mysection") let closure5: (Int) -> Int = { x in x * 2 } // ok
70+
@section("mysection") let closure6: @convention(c) (Int) -> Int = { x in x * 2 } // ok
71+
struct W {
72+
@section("mysection") static let closure7: @convention(c) (Int) -> Int = { x in x * 2 } // ok
73+
}
74+
75+
let capturedVar = 10
76+
class TestClass {}
77+
var capturedMutableVar = TestClass()
78+
79+
// closures with captures (should be rejected)
80+
@section("mysection") let invalidClosure1 = { capturedVar }
81+
// expected-error@-1{{closures with captures not supported in a constant expression}}
82+
@section("mysection") let invalidClosure2 = { return capturedVar + 1 }
83+
// expected-error@-1{{closures with captures not supported in a constant expression}}
84+
@section("mysection") let invalidClosure3 = { [capturedVar] in return capturedVar }
85+
// expected-error@-1{{not supported in a constant expression}}
86+
@section("mysection") let invalidClosure4 = { [weak capturedMutableVar] in return capturedMutableVar }
87+
// expected-error@-1{{not supported in a constant expression}}
88+
@section("mysection") let invalidClosure5 = { [unowned capturedMutableVar] in return capturedMutableVar }
89+
// expected-error@-1{{not supported in a constant expression}}
90+
@section("mysection") let invalidClosure6 = { [capturedVar, capturedMutableVar] in return 42 }
91+
// expected-error@-1{{not supported in a constant expression}}
92+
@section("mysection") let invalidClosure7 = { [renamed = capturedVar] in return renamed * 2 }
93+
// expected-error@-1{{not supported in a constant expression}}
94+
@section("mysection") let invalidClosure8 = { [computed = capturedVar + 5] in return computed }
95+
// expected-error@-1{{not supported in a constant expression}}
6996

7097
struct S { }
7198
enum E { case a }

0 commit comments

Comments
 (0)