llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Peter Rong (DataCorrupted)
<details>
<summary>Changes</summary>
Under `-fobjc-arc`, an ObjC collection literal used as a file-scope initializer
(e.g. `static NSDictionary *d = @{@<!-- -->5 : @<!-- -->1};`) drops the
targeted `err_objc_literal_nonconstant_at_file_scope` message and falls back to
the generic C `err_init_element_is_not_constant` — "initializer element is not
a compile-time constant", pointed at the whole `@{...}`. This was very
confusing to our developers as it is inaccurate: the initializer _is_
compiler-time constant in the eyes of developers.
We fix this by unwrap `ExprWithCleanups` and implicit cast both `Init` and
`Culprit` at the top of the ObjC diagnostic block in
`CheckForConstantInitializer`, so classification and element iteration find the
underlying `ObjCObjectLiteral` regardless of ARC wrapping.
We also unwrap implicit casts before the per-key `isa<ObjCStringLiteral>`
check in the dictionary literal branch. Bare `@"..."` keys are typically
wrapped in `<BitCast>` to `id`; without the unwrap, legitimate
string-literal keys failed the isa check and the diagnostic misreported the
offender as the key when the actual failure was the value.
Added a `clang/test/SemaObjC/objc-constant-literal-dict-key-restrictions.m`
with two RUN lines (macOS without ARC + iOS simulator with ARC) covering
non-string-literal keys under both paths.
[Assisted-by](https://t.ly/Dkjjk): Opus 4.8
---
Full diff: https://github.com/llvm/llvm-project/pull/209688.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaDecl.cpp (+9-2)
- (added) clang/test/SemaObjC/objc-constant-literal-dict-key-restrictions.m
(+45)
``````````diff
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7e1b23c971a9c..5dbc5b653ec42 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12917,6 +12917,14 @@ bool Sema::CheckForConstantInitializer(Expr *Init,
unsigned DiagID) {
if (Init->isConstantInitializer(Context, /*ForRef=*/false, &Culprit))
return false;
+ // Under ARC, the initializer is wrapped in `ExprWithCleanups` +
+ // `ImplicitCastExpr <ARCReclaimReturnedObject>`. Unwrap both
+ // here so the ObjC-specific path fires under ARC too.
+ Init = Init->IgnoreImpCasts();
+ if (auto *EWC = dyn_cast<ExprWithCleanups>(Init))
+ Init = EWC->getSubExpr()->IgnoreImpCasts();
+ Culprit = Culprit->IgnoreImpCasts();
+
// Emit ObjC-specific diagnostics for non-constant literals at file scope.
if (getLangOpts().ObjCConstantLiterals && isa<ObjCObjectLiteral>(Culprit)) {
@@ -12937,8 +12945,7 @@ bool Sema::CheckForConstantInitializer(Expr *Init,
unsigned DiagID) {
for (size_t I = 0, N = DLE->getNumElements(); I != N; ++I) {
const ObjCDictionaryElement Elm = DLE->getKeyValueElement(I);
- // Check that the key is a string literal and is constant.
- if (!isa<ObjCStringLiteral>(Elm.Key) ||
+ if (!isa<ObjCStringLiteral>(Elm.Key->IgnoreImpCasts()) ||
!Elm.Key->isConstantInitializer(Context)) {
Diag(Elm.Key->getExprLoc(),
diag::err_objc_literal_nonconstant_at_file_scope)
diff --git a/clang/test/SemaObjC/objc-constant-literal-dict-key-restrictions.m
b/clang/test/SemaObjC/objc-constant-literal-dict-key-restrictions.m
new file mode 100644
index 0000000000000..14eb989eafb08
--- /dev/null
+++ b/clang/test/SemaObjC/objc-constant-literal-dict-key-restrictions.m
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-macosx11.0.0
-fobjc-runtime=macosx-11.0.0 -fobjc-constant-literals
-fconstant-nsnumber-literals -fconstant-nsarray-literals
-fconstant-nsdictionary-literals -verify %s
+// RUN: %clang_cc1 -fsyntax-only -triple arm64-apple-ios15.1.0-simulator
-fobjc-runtime=ios-15.1.0 -fobjc-arc -fobjc-constant-literals
-fconstant-nsnumber-literals -fconstant-nsarray-literals
-fconstant-nsdictionary-literals -verify %s
+
+#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32
|| NS_BUILD_32_LIKE_64
+typedef unsigned long NSUInteger;
+#else
+typedef unsigned int NSUInteger;
+#endif
+
+@class NSString;
+
+@interface NSNumber
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithBool:(unsigned char)value;
+@end
+
+@interface NSArray
++ (id)arrayWithObjects:(const id[])objects count:(NSUInteger)cnt;
+@end
+
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id[])objects forKeys:(const id[])keys
count:(NSUInteger)cnt;
+@end
+
+// ---- Accepted: NSString literal keys with constant literal values ---------
+
+static NSDictionary *const dASCII = @{@"a" : @1, @"m" : @2, @"z" : @3};
+static NSDictionary *const dEmpty = @{};
+
+// ---- Rejected: non-NSString-literal key -----------------------------------
+
+static NSDictionary *const dNumberKey = @{@5 : @1}; // expected-error {{a
dictionary literal can only be used at file scope if its contents are all also
constant literals and its keys are string literals}}
+static NSDictionary *const dBoxedKey = @{@(1 + 2) : @1}; // expected-error {{a
dictionary literal can only be used at file scope if its contents are all also
constant literals and its keys are string literals}}
+static NSDictionary *const dBoolKey = @{@__objc_yes : @1}; // expected-error
{{a dictionary literal can only be used at file scope if its contents are all
also constant literals and its keys are string literals}}
+
+// The error points at the specific offending key, not the whole `@{...}`.
+static NSDictionary *const dSecondKeyBad = @{@"ok" : @1, @2 : @2}; //
expected-error {{a dictionary literal can only be used at file scope if its
contents are all also constant literals and its keys are string literals}}
+
+// ---- Rejected: non-literal key (constant variable reference) --------------
+//
+// `someStringConstantVar` is an NSString, but it's a DeclRefExpr, not an
+// ObjCStringLiteral. Hits the same "not a string literal" branch as `@5`.
+
+static NSString *const someStringConstantVar = @"foo";
+static NSDictionary *const dConstVarKey = @{someStringConstantVar : @1}; //
expected-error {{a dictionary literal can only be used at file scope if its
contents are all also constant literals and its keys are string literals}}
``````````
</details>
https://github.com/llvm/llvm-project/pull/209688
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits