Skip to content

Commit 03d726c

Browse files
committed
[Sema Diagnostics][OSLog] Make the miscellaneous diagnostics that
checks the constantness of arguments passed to the new os log APIs ignore the log level and log object which can be dynamic.
1 parent dcf119b commit 03d726c

File tree

4 files changed

+47
-0
lines changed

4 files changed

+47
-0
lines changed

include/swift/AST/KnownIdentifiers.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ IDENTIFIER_(nsError)
203203

204204
// Custom string interpolation type used by os log APIs.
205205
IDENTIFIER(OSLogMessage)
206+
// Types that are specialy handled in diagnostics for the os log APIs.
207+
IDENTIFIER(OSLog)
208+
IDENTIFIER(OSLogType)
206209

207210
// Atomics ordering type identifiers.
208211
IDENTIFIER(AtomicLoadOrdering)

include/swift/AST/SemanticAttrs.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ SEMANTICS_ATTR(OPTIMIZE_SIL_SPECIALIZE_GENERIC_SIZE_NEVER,
7171
SEMANTICS_ATTR(OSLOG_MESSAGE_INIT_INTERPOLATION, "oslog.message.init_interpolation")
7272
SEMANTICS_ATTR(OSLOG_MESSAGE_INIT_STRING_LITERAL, "oslog.message.init_stringliteral")
7373
SEMANTICS_ATTR(OSLOG_REQUIRES_CONSTANT_ARGUMENTS, "oslog.requires_constant_arguments")
74+
SEMANTICS_ATTR(OSLOG_LOG_WITH_LEVEL, "oslog.log_with_level")
7475
SEMANTICS_ATTR(ATOMICS_REQUIRES_CONSTANT_ORDERINGS, "atomics.requires_constant_orderings")
7576

7677
SEMANTICS_ATTR(TYPE_CHECKER_OPEN_EXISTENTIAL, "typechecker._openExistential(_:do:)")

lib/Sema/ConstantnessSemaDiagnostics.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,30 @@ static bool isAtomicOrderingDecl(StructDecl *structDecl) {
5252
structName == astContext.Id_AtomicUpdateOrdering);
5353
}
5454

55+
/// Return true iff the given nominal type decl \p nominal has a name that
56+
/// matches one of the known OSLog types that need not be a constant in the new
57+
/// os_log APIs.
58+
static bool isOSLogDynamicObject(NominalTypeDecl *nominal) {
59+
ASTContext &astContext = nominal->getASTContext();
60+
Identifier name = nominal->getName();
61+
return (name == astContext.Id_OSLog || name == astContext.Id_OSLogType);
62+
}
63+
5564
/// Return true iff the parameter \p param of function \c funDecl is required to
5665
/// be a constant. This is true if either the function is an os_log function or
5766
/// it is an atomics operation and the parameter represents the ordering.
5867
static bool isParamRequiredToBeConstant(FuncDecl *funcDecl, ParamDecl *param) {
5968
assert(funcDecl && param && "funcDecl and param must not be null");
6069
if (hasSemanticsAttr(funcDecl, semantics::OSLOG_REQUIRES_CONSTANT_ARGUMENTS))
6170
return true;
71+
if (hasSemanticsAttr(funcDecl, semantics::OSLOG_LOG_WITH_LEVEL)) {
72+
// We are looking at a top-level os_log function that accepts level and
73+
// possibly custom log object. Those need not be constants, but every other
74+
// parameter must be.
75+
Type paramType = param->getType();
76+
NominalTypeDecl *nominal = paramType->getNominalOrBoundGenericNominal();
77+
return !nominal || !isOSLogDynamicObject(nominal);
78+
}
6279
if (!hasSemanticsAttr(funcDecl,
6380
semantics::ATOMICS_REQUIRES_CONSTANT_ORDERINGS))
6481
return false;

test/Sema/diag_constantness_check_os_log.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,29 @@ func testOSLogInterpolationExtension(a: MyStruct) {
118118
// the appendInterpolation overload is not marked as constant_evaluable.
119119
_osLogTestHelper("Error at line: \(a: a)")
120120
}
121+
122+
// Test that @_semantics("oslog.log_with_level") permits values of type OSLog and
123+
// OSLogType to not be constants.
124+
125+
class OSLog { }
126+
class OSLogType { }
127+
128+
@_semantics("oslog.log_with_level")
129+
func osLogWithLevel(_ level: OSLogType, log: OSLog, _ message: OSLogMessage) {
130+
}
131+
132+
func testNonConstantLogObjectLevel(
133+
level: OSLogType,
134+
log: OSLog,
135+
message: OSLogMessage
136+
) {
137+
osLogWithLevel(level, log: log, "message with no payload")
138+
var levelOpt: OSLogType? = nil
139+
levelOpt = level
140+
141+
let logClosure = { log }
142+
osLogWithLevel(levelOpt!, log: logClosure(), "A string \("hello")")
143+
144+
osLogWithLevel(level, log: log, message)
145+
// expected-error@-1 {{argument must be a string interpolation}}
146+
}

0 commit comments

Comments
 (0)