diff --git a/lib/Sema/LegalConstExprVerifier.cpp b/lib/Sema/LegalConstExprVerifier.cpp index 51c9a4ade5055..62f3c611def0c 100644 --- a/lib/Sema/LegalConstExprVerifier.cpp +++ b/lib/Sema/LegalConstExprVerifier.cpp @@ -234,11 +234,6 @@ checkSupportedWithSectionAttribute(const Expr *expr, } continue; } - - // No auto-closures - if (isa(expr)) { - return std::make_pair(expr, Default); - } // Function conversions are allowed if the conversion is to '@convention(c)' if (auto functionConvExpr = dyn_cast(expr)) { @@ -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(expr)) { + auto subExpr = autoClosureExpr->getUnwrappedCurryThunkExpr(); + if (auto dotSyntaxCall = dyn_cast(subExpr)) { + if (auto declRef = dyn_cast(dotSyntaxCall->getFn())) { + if (auto funcDecl = dyn_cast(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(args->get(0).getExpr())) { + if (const TypeExpr *typeExpr = + dyn_cast(dotSelfExpr->getSubExpr())) { + auto baseType = typeExpr->getType(); + if (baseType && baseType->is()) { + 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(expr)) + return std::make_pair(expr, Default); + // DotSelfExpr for metatype references (but only a direct TypeExpr inside) if (const DotSelfExpr *dotSelfExpr = dyn_cast(expr)) { if (const TypeExpr *typeExpr = diff --git a/test/ConstValues/SectionSyntactic.swift b/test/ConstValues/SectionSyntactic.swift index cd5fe579b1f88..ce2165a25cc36 100644 --- a/test/ConstValues/SectionSyntactic.swift +++ b/test/ConstValues/SectionSyntactic.swift @@ -43,12 +43,24 @@ 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) {} + static func staticGenericFunc(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}} @@ -56,6 +68,16 @@ func bar(x: Int) -> String { return "test" } // 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