diff --git a/lib/Sema/ConstantnessSemaDiagnostics.cpp b/lib/Sema/ConstantnessSemaDiagnostics.cpp index 49f9334697c55..369be3feda885 100644 --- a/lib/Sema/ConstantnessSemaDiagnostics.cpp +++ b/lib/Sema/ConstantnessSemaDiagnostics.cpp @@ -92,6 +92,13 @@ static bool hasConstantEvaluableAttr(ValueDecl *decl) { return hasSemanticsAttr(decl, semantics::CONSTANT_EVALUABLE); } +/// Return true iff the \p decl is annotated with oslog.message.init semantics +/// attribute. +static bool isOSLogMessageInitializer(ValueDecl *decl) { + return hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_STRING_LITERAL) || + hasSemanticsAttr(decl, semantics::OSLOG_MESSAGE_INIT_INTERPOLATION); +} + /// Check whether \p expr is a compile-time constant. It must either be a /// literal_expr, which does not include array and dictionary literal, or a /// closure expression, which is considered a compile-time constant of a @@ -162,12 +169,6 @@ static Expr *checkConstantness(Expr *expr) { if (!isa(expr)) return expr; - if (NominalTypeDecl *nominal = - expr->getType()->getNominalOrBoundGenericNominal()) { - if (nominal->getName() == nominal->getASTContext().Id_OSLogMessage) - return expr; - } - ApplyExpr *apply = cast(expr); ValueDecl *calledValue = apply->getCalledValue(); if (!calledValue) @@ -179,10 +180,18 @@ static Expr *checkConstantness(Expr *expr) { continue; } + AbstractFunctionDecl *callee = dyn_cast(calledValue); + if (!callee) + return expr; + + // If this is an application of OSLogMessage initializer, fail the check + // as this type must be created from string interpolations. + if (isOSLogMessageInitializer(callee)) + return expr; + // If this is a constant_evaluable function, check whether the arguments are // constants. - AbstractFunctionDecl *callee = dyn_cast(calledValue); - if (!callee || !hasConstantEvaluableAttr(callee)) + if (!hasConstantEvaluableAttr(callee)) return expr; expressionsToCheck.push_back(apply->getArg()); } diff --git a/test/SILOptimizer/OSLogMandatoryOptTest.swift b/test/SILOptimizer/OSLogMandatoryOptTest.swift index 3ea45c0a316a7..1bfca455b15a2 100644 --- a/test/SILOptimizer/OSLogMandatoryOptTest.swift +++ b/test/SILOptimizer/OSLogMandatoryOptTest.swift @@ -635,3 +635,41 @@ extension TestProtocolSelfTypeCapture { } } +// Test that SwiftUI's preview transformations work with the logging APIs. + +// A function similar to the one used by SwiftUI preview to wrap string +// literals. +@_semantics("constant_evaluable") +@_transparent +public func __designTimeStringStub( + _ key: String, + fallback: OSLogMessage +) -> OSLogMessage { + fallback +} + +// CHECK-LABEL: @${{.*}}testSwiftUIPreviewWrappingyy +func testSwiftUIPreviewWrapping() { + _osLogTestHelper(__designTimeStringStub("key", fallback: "percent: %")) + // CHECK: string_literal utf8 "percent: %%" + // CHECK-NOT: OSLogMessage + // CHECK-NOT: OSLogInterpolation + // CHECK-LABEL: end sil function '${{.*}}testSwiftUIPreviewWrappingyy +} + + +func functionTakingClosure(_ x: () -> Void) { } + +func testWrappingWithinClosures(x: Int) { + functionTakingClosure { + _osLogTestHelper( + __designTimeStringStub( + "key", + fallback: "escaping of percent: %")) + // CHECK-LABEL: @${{.*}}testWrappingWithinClosures1xySi_tFyyXEfU_ + // CHECK: string_literal utf8 "escaping of percent: %%" + // CHECK-NOT: OSLogMessage + // CHECK-NOT: OSLogInterpolation + // CHECK-LABEL: end sil function '${{.*}}testWrappingWithinClosures1xySi_tFyyXEfU_ + } +} diff --git a/test/Sema/diag_constantness_check_os_log.swift b/test/Sema/diag_constantness_check_os_log.swift index 57bc1ee002173..dc29825573e06 100644 --- a/test/Sema/diag_constantness_check_os_log.swift +++ b/test/Sema/diag_constantness_check_os_log.swift @@ -155,3 +155,32 @@ func testNonConstantLogObjectLevel( osLogWithLevel(level, log: log, message) // expected-error@-1 {{argument must be a string interpolation}} } + +// Test that log messages can be wrapped in constant_evaluable functions. + +// A function similar to the one used by SwiftUI preview to wrap string +// literals. +@_semantics("constant_evaluable") +public func __designTimeStringStub( + _ key: String, + fallback: OSLogMessage +) -> OSLogMessage { + fallback +} + +func testSwiftUIPreviewWrapping() { + // This should not produce any diagnostics. + _osLogTestHelper(__designTimeStringStub("key", fallback: "A literal message")) +} + +public func nonConstantFunction( + _ key: String, + fallback: OSLogMessage +) -> OSLogMessage { + fallback +} + +func testLogMessageWrappingDiagnostics() { + _osLogTestHelper(nonConstantFunction("key", fallback: "A literal message")) + // expected-error@-1{{argument must be a string interpolation}} +}