Skip to content
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
59 changes: 54 additions & 5 deletions lib/Sema/LegalConstExprVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,6 @@ checkSupportedWithSectionAttribute(const Expr *expr,
}
continue;
}

// No auto-closures
if (isa<AbstractClosureExpr>(expr)) {
return std::make_pair(expr, Default);
}

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

// Allow specific patterns of AutoClosureExpr, which is used in static func
// references. E.g. "MyStruct.staticFunc" is:
// - autoclosure_expr type="() -> ()"
// - call_expr type="()"
// - dot_syntax_call_expr
// - declref_expr decl="MyStruct.staticFunc"
// - dot_self_expr type="MyStruct.Type"
// - type_expr type="MyStruct.Type"
if (auto autoClosureExpr = dyn_cast<AutoClosureExpr>(expr)) {
auto subExpr = autoClosureExpr->getUnwrappedCurryThunkExpr();
if (auto dotSyntaxCall = dyn_cast<DotSyntaxCallExpr>(subExpr)) {
if (auto declRef = dyn_cast<DeclRefExpr>(dotSyntaxCall->getFn())) {
if (auto funcDecl = dyn_cast<FuncDecl>(declRef->getDecl())) {
// Check if it's a function on a concrete non-generic type
if (!funcDecl->hasGenericParamList() &&
!funcDecl->getDeclContext()->isGenericContext() &&
funcDecl->isStatic()) {
if (auto args = dotSyntaxCall->getArgs()) {
if (args->size() == 1) {
// Check that the single arg is a DotSelfExpr with only a
// direct concrete TypeExpr inside
if (auto dotSelfExpr =
dyn_cast<DotSelfExpr>(args->get(0).getExpr())) {
if (const TypeExpr *typeExpr =
dyn_cast<TypeExpr>(dotSelfExpr->getSubExpr())) {
auto baseType = typeExpr->getType();
if (baseType && baseType->is<MetatypeType>()) {
auto instanceType =
baseType->getMetatypeInstanceType();
if (auto nominal =
instanceType
->getNominalOrBoundGenericNominal()) {
if (!nominal->hasGenericParamList() &&
!nominal->getDeclContext()->isGenericContext() &&
!nominal->isResilient()) {
continue;
}
}
}
}
}
}
}
}
}
}
}
return std::make_pair(expr, Default);
}

// Other closure expressions (auto-closures) are not allowed
if (isa<AbstractClosureExpr>(expr))
return std::make_pair(expr, Default);

// DotSelfExpr for metatype references (but only a direct TypeExpr inside)
if (const DotSelfExpr *dotSelfExpr = dyn_cast<DotSelfExpr>(expr)) {
if (const TypeExpr *typeExpr =
Expand Down
24 changes: 23 additions & 1 deletion test/ConstValues/SectionSyntactic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,41 @@
func foo() -> Int { return 42 }
func bar(x: Int) -> String { return "test" }

// function references
// global function references
@section("mysection") let funcRef1 = foo // ok
@section("mysection") let funcRef2 = bar // ok
@section("mysection") let funcRef3: ()->Int = foo // ok
@section("mysection") let funcRef4: @convention(c) ()->Int = foo // ok

struct Q {
func memberFunc() {}
static func staticFunc() {}
func genericFunc<T>(t: T) {}
static func staticGenericFunc<T>(t: T) {}
}

// non-global function references
@section("mysection") let staticFuncRef1 = Q.staticFunc // ok
extension Q { @section("mysection") static let staticFuncRef2 = staticFunc } // ok
@section("mysection") let staticFuncRef3 = Bool.random // ok

// invalid function references (should be rejected)
@section("mysection") let invalidFuncRef1 = foo()
// expected-error@-1{{not supported in a constant expression}}
@section("mysection") let invalidFuncRef2 = Bool.self.random
// expected-error@-1{{not supported in a constant expression}}
@section("mysection") let invalidFuncRef3 = (Bool.self as Bool.Type).random
// expected-error@-1{{not supported in a constant expression}}
@section("mysection") let invalidFuncRef4 = Q.memberFunc
// expected-error@-1{{not supported in a constant expression}}
extension Q { @section("mysection") static let invalidFuncRef5 = memberFunc }
// expected-error@-1{{not supported in a constant expression}}
extension Q { @section("mysection") static let invalidFuncRef6: (Int)->() = genericFunc(Q()) }
// expected-error@-1{{not supported in a constant expression}}
extension Q { @section("mysection") static let invalidFuncRef7: (Q) -> (Int) -> () = genericFunc }
// expected-error@-1{{not supported in a constant expression}}
extension Q { @section("mysection") static let invalidFuncRef8: (Int)->() = staticGenericFunc }
// expected-error@-1{{not supported in a constant expression}}

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