[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
This revision was automatically updated to reflect the committed changes. Closed by commit rL355662: [ObjC] Emit a boxed expression as a compile-time constant if the (authored by ahatanak, committed by ). Herald added a project: LLVM. Herald added a subscriber: llvm-commits. Changed prior to commit: https://reviews.llvm.org/D58729?vs=189809=189811#toc Repository: rL LLVM CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 Files: cfe/trunk/include/clang/AST/ExprObjC.h cfe/trunk/include/clang/Basic/DiagnosticGroups.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/CodeGen/CGExprConstant.cpp cfe/trunk/lib/CodeGen/CGObjC.cpp cfe/trunk/lib/Sema/SemaExprObjC.cpp cfe/trunk/test/CodeGenObjC/boxing.m cfe/trunk/test/SemaObjC/boxing-illegal.m cfe/trunk/test/SemaObjC/objc-literal-sig.m cfe/trunk/test/SemaObjC/transfer-boxed-string-nullability.m cfe/trunk/test/SemaObjCXX/literals.mm Index: cfe/trunk/include/clang/AST/ExprObjC.h === --- cfe/trunk/include/clang/AST/ExprObjC.h +++ cfe/trunk/include/clang/AST/ExprObjC.h @@ -138,6 +138,12 @@ return BoxingMethod; } + // Indicates whether this boxed expression can be emitted as a compile-time + // constant. + bool isExpressibleAsConstantInitializer() const { +return !BoxingMethod && SubExpr; + } + SourceLocation getAtLoc() const { return Range.getBegin(); } SourceLocation getBeginLoc() const LLVM_READONLY { return Range.getBegin(); } Index: cfe/trunk/include/clang/Basic/DiagnosticGroups.td === --- cfe/trunk/include/clang/Basic/DiagnosticGroups.td +++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td @@ -404,6 +404,7 @@ def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [ObjCPointerIntrospectPerformSelector]>; def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">; def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">; +def ObjCBoxing : DiagGroup<"objc-boxing">; def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">; def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">; def ExplicitInitializeCall : DiagGroup<"explicit-initialize-call">; Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td === --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -918,6 +918,9 @@ "inconsistent number of instance variables specified">; def warn_undef_method_impl : Warning<"method definition for %0 not found">, InGroup>; +def warn_objc_boxing_invalid_utf8_string : Warning< + "string is ill-formed as UTF-8 and will become a null %0 when boxed">, + InGroup; def warn_conflicting_overriding_ret_types : Warning< "conflicting return type in " Index: cfe/trunk/test/SemaObjC/boxing-illegal.m === --- cfe/trunk/test/SemaObjC/boxing-illegal.m +++ cfe/trunk/test/SemaObjC/boxing-illegal.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes -fpascal-strings %s typedef long NSInteger; typedef unsigned long NSUInteger; @@ -57,6 +57,19 @@ box = @(*(enum ForwE*)p); // expected-error {{incomplete type 'enum ForwE' used in a boxed expression}} } +@interface NSString +@end + +void testStringLiteral() { + NSString *s; + s = @("abc"); + s = @(u8"abc"); + s = @(u"abc"); // expected-error {{illegal type 'unsigned short *' used in a boxed expression}} + s = @(U"abc"); // expected-error {{illegal type 'unsigned int *' used in a boxed expression}} + s = @(L"abc"); // expected-error {{illegal type 'int *' used in a boxed expression}} + s = @("\pabc"); // expected-error {{illegal type 'unsigned char *' used in a boxed expression}} +} + // rdar://1205 @class NSMutableDictionary; Index: cfe/trunk/test/SemaObjC/objc-literal-sig.m === --- cfe/trunk/test/SemaObjC/objc-literal-sig.m +++ cfe/trunk/test/SemaObjC/objc-literal-sig.m @@ -39,6 +39,8 @@ // All tests are doubled to make sure that a bad method is not saved // and then used un-checked. +const char *getStr(void); + void test_sig() { (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} @@ -46,6 +48,6 @@ id array2 = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}} id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak marked an inline comment as done. ahatanak added inline comments. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:922 +def warn_objc_boxing_invalid_utf8_string : Warning< + "string is ill-formed as UTF-8 and will become a null NSString* when boxed">, + InGroup; rjmccall wrote: > ahatanak wrote: > > rjmccall wrote: > > > Might as well use the `NSStringPointer` type we stash on Sema so that > > > this will be the right type even in more obscure environments. > > I wasn't exactly sure when `NSStringPointer` can be anything other than > > `NSString *`. > Hmm. It's possible that it can't be for boxing, but I'm pretty sure it can > be overridden for string literals, and it's not ridiculous that we'd allow > that to be changed for arbitrary boxing as well, so this is good idea > regardless. I agree, it's probably a good idea. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
rjmccall accepted this revision. rjmccall added inline comments. This revision is now accepted and ready to land. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:922 +def warn_objc_boxing_invalid_utf8_string : Warning< + "string is ill-formed as UTF-8 and will become a null NSString* when boxed">, + InGroup; ahatanak wrote: > rjmccall wrote: > > Might as well use the `NSStringPointer` type we stash on Sema so that this > > will be the right type even in more obscure environments. > I wasn't exactly sure when `NSStringPointer` can be anything other than > `NSString *`. Hmm. It's possible that it can't be for boxing, but I'm pretty sure it can be overridden for string literals, and it's not ridiculous that we'd allow that to be changed for arbitrary boxing as well, so this is good idea regardless. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak added inline comments. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:922 +def warn_objc_boxing_invalid_utf8_string : Warning< + "string is ill-formed as UTF-8 and will become a null NSString* when boxed">, + InGroup; rjmccall wrote: > Might as well use the `NSStringPointer` type we stash on Sema so that this > will be the right type even in more obscure environments. I wasn't exactly sure when `NSStringPointer` can be anything other than `NSString *`. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak updated this revision to Diff 189809. ahatanak marked an inline comment as done. ahatanak added a comment. Use the type of `NSStringPointer` in the diagnostic string. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 Files: include/clang/AST/ExprObjC.h include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGObjC.cpp lib/Sema/SemaExprObjC.cpp test/CodeGenObjC/boxing.m test/SemaObjC/boxing-illegal.m test/SemaObjC/objc-literal-sig.m test/SemaObjC/transfer-boxed-string-nullability.m test/SemaObjCXX/literals.mm Index: test/SemaObjCXX/literals.mm === --- test/SemaObjCXX/literals.mm +++ test/SemaObjCXX/literals.mm @@ -50,6 +50,9 @@ + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; @end +@interface NSString +@end + template struct ConvertibleTo { operator T(); @@ -185,3 +188,8 @@ void test_dictionary_colon() { id dict = @{ key : value }; } + +void testConstExpr() { + constexpr NSString *t0 = @"abc"; + constexpr NSString *t1 = @("abc"); +} Index: test/SemaObjC/transfer-boxed-string-nullability.m === --- test/SemaObjC/transfer-boxed-string-nullability.m +++ test/SemaObjC/transfer-boxed-string-nullability.m @@ -16,13 +16,23 @@ void takesNonNull(NSString * _Nonnull ptr); void testBoxedString() { + // No diagnostic emitted as this doesn't need a stringWithUTF8String message + // send. + takesNonNull(@("hey")); + takesNonNull(@(u8"hey")); + + // If the string isn't a valid UTF-8 string, a diagnostic is emitted since the + // boxed expression turns into a message send. + takesNonNull(@(u8"\xFF")); // expected-warning {{string is ill-formed as UTF-8}} + takesNonNull(@(u8"\xC0\x80")); // expected-warning {{string is ill-formed as UTF-8}} + const char *str = "hey"; takesNonNull([NSString stringWithUTF8String:str]); takesNonNull(@(str)); #ifndef NOWARN - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} -#else - // expected-no-diagnostics + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} #endif } Index: test/SemaObjC/objc-literal-sig.m === --- test/SemaObjC/objc-literal-sig.m +++ test/SemaObjC/objc-literal-sig.m @@ -39,6 +39,8 @@ // All tests are doubled to make sure that a bad method is not saved // and then used un-checked. +const char *getStr(void); + void test_sig() { (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} @@ -46,6 +48,6 @@ id array2 = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}} id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} id dict2 = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} - id str = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} - id str2 = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str2 = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} } Index: test/SemaObjC/boxing-illegal.m === --- test/SemaObjC/boxing-illegal.m +++ test/SemaObjC/boxing-illegal.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes -fpascal-strings %s typedef long NSInteger;
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
rjmccall added inline comments. Comment at: include/clang/Basic/DiagnosticGroups.td:407 def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">; +def ObjCBoxing : DiagGroup<"objc-boxing">; def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">; Sure. If we decide to add more things to this warning group, we can pull this one out into a sub-group with a more targeted name. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:922 +def warn_objc_boxing_invalid_utf8_string : Warning< + "string is ill-formed as UTF-8 and will become a null NSString* when boxed">, + InGroup; Might as well use the `NSStringPointer` type we stash on Sema so that this will be the right type even in more obscure environments. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak updated this revision to Diff 189657. ahatanak marked 2 inline comments as done. ahatanak added a comment. Improve diagnostic message. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 Files: include/clang/AST/ExprObjC.h include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGObjC.cpp lib/Sema/SemaExprObjC.cpp test/CodeGenObjC/boxing.m test/SemaObjC/boxing-illegal.m test/SemaObjC/objc-literal-sig.m test/SemaObjC/transfer-boxed-string-nullability.m test/SemaObjCXX/literals.mm Index: test/SemaObjCXX/literals.mm === --- test/SemaObjCXX/literals.mm +++ test/SemaObjCXX/literals.mm @@ -50,6 +50,9 @@ + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; @end +@interface NSString +@end + template struct ConvertibleTo { operator T(); @@ -185,3 +188,8 @@ void test_dictionary_colon() { id dict = @{ key : value }; } + +void testConstExpr() { + constexpr NSString *t0 = @"abc"; + constexpr NSString *t1 = @("abc"); +} Index: test/SemaObjC/transfer-boxed-string-nullability.m === --- test/SemaObjC/transfer-boxed-string-nullability.m +++ test/SemaObjC/transfer-boxed-string-nullability.m @@ -16,13 +16,23 @@ void takesNonNull(NSString * _Nonnull ptr); void testBoxedString() { + // No diagnostic emitted as this doesn't need a stringWithUTF8String message + // send. + takesNonNull(@("hey")); + takesNonNull(@(u8"hey")); + + // If the string isn't a valid UTF-8 string, a diagnostic is emitted since the + // boxed expression turns into a message send. + takesNonNull(@(u8"\xFF")); // expected-warning {{string is ill-formed as UTF-8}} + takesNonNull(@(u8"\xC0\x80")); // expected-warning {{string is ill-formed as UTF-8}} + const char *str = "hey"; takesNonNull([NSString stringWithUTF8String:str]); takesNonNull(@(str)); #ifndef NOWARN - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} -#else - // expected-no-diagnostics + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} #endif } Index: test/SemaObjC/objc-literal-sig.m === --- test/SemaObjC/objc-literal-sig.m +++ test/SemaObjC/objc-literal-sig.m @@ -39,6 +39,8 @@ // All tests are doubled to make sure that a bad method is not saved // and then used un-checked. +const char *getStr(void); + void test_sig() { (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} @@ -46,6 +48,6 @@ id array2 = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}} id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} id dict2 = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} - id str = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} - id str2 = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str2 = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} } Index: test/SemaObjC/boxing-illegal.m === --- test/SemaObjC/boxing-illegal.m +++ test/SemaObjC/boxing-illegal.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes -fpascal-strings %s typedef long NSInteger; typedef unsigned long NSUInteger; @@
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
rjmccall added inline comments. Comment at: include/clang/Basic/DiagnosticGroups.td:322 def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">; +def InvalidUTF8String : DiagGroup<"invalid-utf8-string">; def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">; I think this warning group should mention that this is specific to ObjC boxing somehow. Comment at: include/clang/Basic/DiagnosticSemaKinds.td:5807 "Clang encodes unprefixed narrow string literals as UTF-8">; +def warn_invalid_utf8_string : Warning<"invalid UTF-8 string">, InGroup; def err_array_init_different_type : Error< Maybe "string is ill-formed as UTF-8 and will become a null NSString* when boxed", where the type is whatever the type of the box-expression would be? Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak updated this revision to Diff 189630. ahatanak added a comment. Diagnose invalid UTF-8 strings in boxed expressions. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 Files: include/clang/AST/ExprObjC.h include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGObjC.cpp lib/Sema/SemaExprObjC.cpp test/CodeGenObjC/boxing.m test/SemaObjC/boxing-illegal.m test/SemaObjC/objc-literal-sig.m test/SemaObjC/transfer-boxed-string-nullability.m test/SemaObjCXX/literals.mm Index: test/SemaObjCXX/literals.mm === --- test/SemaObjCXX/literals.mm +++ test/SemaObjCXX/literals.mm @@ -50,6 +50,9 @@ + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; @end +@interface NSString +@end + template struct ConvertibleTo { operator T(); @@ -185,3 +188,8 @@ void test_dictionary_colon() { id dict = @{ key : value }; } + +void testConstExpr() { + constexpr NSString *t0 = @"abc"; + constexpr NSString *t1 = @("abc"); +} Index: test/SemaObjC/transfer-boxed-string-nullability.m === --- test/SemaObjC/transfer-boxed-string-nullability.m +++ test/SemaObjC/transfer-boxed-string-nullability.m @@ -16,13 +16,23 @@ void takesNonNull(NSString * _Nonnull ptr); void testBoxedString() { + // No diagnostic emitted as this doesn't need a stringWithUTF8String message + // send. + takesNonNull(@("hey")); + takesNonNull(@(u8"hey")); + + // If the string isn't a valid UTF-8 string, a diagnostic is emitted since the + // boxed expression turns into a message send. + takesNonNull(@(u8"\xFF")); // expected-warning {{invalid UTF-8 string}} + takesNonNull(@(u8"\xC0\x80")); // expected-warning {{invalid UTF-8 string}} + const char *str = "hey"; takesNonNull([NSString stringWithUTF8String:str]); takesNonNull(@(str)); #ifndef NOWARN - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} -#else - // expected-no-diagnostics + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} #endif } Index: test/SemaObjC/objc-literal-sig.m === --- test/SemaObjC/objc-literal-sig.m +++ test/SemaObjC/objc-literal-sig.m @@ -39,6 +39,8 @@ // All tests are doubled to make sure that a bad method is not saved // and then used un-checked. +const char *getStr(void); + void test_sig() { (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} @@ -46,6 +48,6 @@ id array2 = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}} id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} id dict2 = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} - id str = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} - id str2 = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str2 = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} } Index: test/SemaObjC/boxing-illegal.m === --- test/SemaObjC/boxing-illegal.m +++ test/SemaObjC/boxing-illegal.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes -fpascal-strings %s typedef long NSInteger; typedef unsigned long NSUInteger; @@ -57,6 +57,19 @@ box = @(*(enum
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
rjmccall added inline comments. Comment at: test/SemaObjC/boxing-illegal.m:70 + s = @(L"abc"); // expected-error {{illegal type 'int *' used in a boxed expression}} + s = @("\pabc"); // expected-error {{illegal type 'unsigned char *' used in a boxed expression}} +} ahatanak wrote: > ahatanak wrote: > > rjmccall wrote: > > > I don't know what `\p` is supposed to be or why it apparently changes the > > > type of the literal to `unsigned char *`, but none of these are ordinary > > > string literals that are invalid as UTF-8. I mean something like "\xFF", > > > which still has type `char *` but will fail to parse as UTF-8, which will > > > cause normal boxing to fail and return `nil`. > > Fixed and added test cases. Boxed expressions now have to be valid UTF-8 > > string literals in order to be emitted as compile-time constants. > > > > If the string literal in a boxed expression is an invalid UTF-8 string, > > should we reject it the same way we reject other kinds of string literals > > (e.g., UTF-16)? > Or at least warn about it. Thanks, fix looks good. I think a warning would be extremely reasonable. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak marked an inline comment as done. ahatanak added inline comments. Comment at: test/SemaObjC/boxing-illegal.m:70 + s = @(L"abc"); // expected-error {{illegal type 'int *' used in a boxed expression}} + s = @("\pabc"); // expected-error {{illegal type 'unsigned char *' used in a boxed expression}} +} ahatanak wrote: > rjmccall wrote: > > I don't know what `\p` is supposed to be or why it apparently changes the > > type of the literal to `unsigned char *`, but none of these are ordinary > > string literals that are invalid as UTF-8. I mean something like "\xFF", > > which still has type `char *` but will fail to parse as UTF-8, which will > > cause normal boxing to fail and return `nil`. > Fixed and added test cases. Boxed expressions now have to be valid UTF-8 > string literals in order to be emitted as compile-time constants. > > If the string literal in a boxed expression is an invalid UTF-8 string, > should we reject it the same way we reject other kinds of string literals > (e.g., UTF-16)? Or at least warn about it. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak added inline comments. Comment at: test/SemaObjC/boxing-illegal.m:70 + s = @(L"abc"); // expected-error {{illegal type 'int *' used in a boxed expression}} + s = @("\pabc"); // expected-error {{illegal type 'unsigned char *' used in a boxed expression}} +} rjmccall wrote: > I don't know what `\p` is supposed to be or why it apparently changes the > type of the literal to `unsigned char *`, but none of these are ordinary > string literals that are invalid as UTF-8. I mean something like "\xFF", > which still has type `char *` but will fail to parse as UTF-8, which will > cause normal boxing to fail and return `nil`. Fixed and added test cases. Boxed expressions now have to be valid UTF-8 string literals in order to be emitted as compile-time constants. If the string literal in a boxed expression is an invalid UTF-8 string, should we reject it the same way we reject other kinds of string literals (e.g., UTF-16)? Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak updated this revision to Diff 189436. ahatanak marked 2 inline comments as done. ahatanak added a comment. If the string literal used for the boxed expression isn't a valid UTF-8 string, don't emit a compile-time constant. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 Files: include/clang/AST/ExprObjC.h lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGObjC.cpp lib/Sema/SemaExprObjC.cpp test/CodeGenObjC/boxing.m test/SemaObjC/boxing-illegal.m test/SemaObjC/objc-literal-sig.m test/SemaObjC/transfer-boxed-string-nullability.m test/SemaObjCXX/literals.mm Index: test/SemaObjCXX/literals.mm === --- test/SemaObjCXX/literals.mm +++ test/SemaObjCXX/literals.mm @@ -50,6 +50,9 @@ + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; @end +@interface NSString +@end + template struct ConvertibleTo { operator T(); @@ -185,3 +188,8 @@ void test_dictionary_colon() { id dict = @{ key : value }; } + +void testConstExpr() { + constexpr NSString *t0 = @"abc"; + constexpr NSString *t1 = @("abc"); +} Index: test/SemaObjC/transfer-boxed-string-nullability.m === --- test/SemaObjC/transfer-boxed-string-nullability.m +++ test/SemaObjC/transfer-boxed-string-nullability.m @@ -16,12 +16,24 @@ void takesNonNull(NSString * _Nonnull ptr); void testBoxedString() { + // No diagnostic emitted as this doesn't need a stringWithUTF8String message + // send. + takesNonNull(@("hey")); + takesNonNull(@(u8"hey")); + + // If the string isn't a valid UTF-8 string, a diagnostic is emitted since the + // boxed expression turns into a message send. + takesNonNull(@(u8"\xFF")); + takesNonNull(@(u8"\xC8")); + const char *str = "hey"; takesNonNull([NSString stringWithUTF8String:str]); takesNonNull(@(str)); #ifndef NOWARN - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} - // expected-warning@-3 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-7 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} + // expected-warning@-5 {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} #else // expected-no-diagnostics #endif Index: test/SemaObjC/objc-literal-sig.m === --- test/SemaObjC/objc-literal-sig.m +++ test/SemaObjC/objc-literal-sig.m @@ -39,6 +39,8 @@ // All tests are doubled to make sure that a bad method is not saved // and then used un-checked. +const char *getStr(void); + void test_sig() { (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} @@ -46,6 +48,6 @@ id array2 = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}} id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} id dict2 = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} - id str = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} - id str2 = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str2 = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} } Index: test/SemaObjC/boxing-illegal.m === --- test/SemaObjC/boxing-illegal.m +++ test/SemaObjC/boxing-illegal.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes -fpascal-strings %s typedef long NSInteger; typedef unsigned long NSUInteger; @@ -57,6 +57,19 @@ box = @(*(enum ForwE*)p); // expected-error {{incomplete type 'enum ForwE' used in a boxed
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
rjmccall added inline comments. Comment at: test/SemaObjC/boxing-illegal.m:70 + s = @(L"abc"); // expected-error {{illegal type 'int *' used in a boxed expression}} + s = @("\pabc"); // expected-error {{illegal type 'unsigned char *' used in a boxed expression}} +} I don't know what `\p` is supposed to be or why it apparently changes the type of the literal to `unsigned char *`, but none of these are ordinary string literals that are invalid as UTF-8. I mean something like "\xFF", which still has type `char *` but will fail to parse as UTF-8, which will cause normal boxing to fail and return `nil`. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak added inline comments. Comment at: lib/Sema/SemaExprObjC.cpp:534 +NSStringPointer, NSStringPointer); +return new (Context) ObjCBoxedExpr(SL, BoxedType, nullptr, SR); + } rjmccall wrote: > ahatanak wrote: > > rjmccall wrote: > > > You're implicitly dropping sugar from the source expression here; I > > > really think you should preserve that, and if it means you end up having > > > to look through array-decay expressions, that's not the end of the world. > > > > > > The need for a special case here is just to allow us to compile these > > > even if there isn't a boxing method available? > > > > > > Do you need to restrict the type of the string literal so that it doesn't > > > apply to e.g. wide strings? > > Line 516 checks that the pointee type has the same unqualified type as > > 'char'. If the string literal inside the parentheses is of a wider type > > (e.g., `@(u"abc")`), this piece of code won't be executed, and a diagnostic > > is emitted later ("illegal type 'const char16_t *' used in a boxed > > expression"). > > > > The original motivation for special-casing string literals inside boxed > > expressions was to silence the `-Wnullable-to-nonnull-conversion` warning > > mentioned here: https://oleb.net/2018/@keypath/. The warning is issued > > because the return type of `stringWithUTF8String` is nullable. > > > > ``` > > ... > > + (nullable instancetype)stringWithUTF8String:(const char > > *)nullTerminatedCString; > > ... > > > > NSString * _Nonnull ptr = @("abc"); // expected-error {{implicit > > conversion from nullable pointer 'NSString * _Nullable' to non-nullable > > pointer type 'NSString * _Nonnull'}} > > ``` > I see. So in addition to guaranteeing to skip the boxing call, you'd like to > adjust the type to report the result as non-null, which we can do because > we're unconditionally making a constant string. Makes sense. > > However, I think you need to check that the string is valid UTF-8 or else > this is semantics-changing, since such strings are rejected by > `+stringWithUTF8String:` (which is why it returns a nullable pointer at all). > It should be alright to warn about strings that are statically known to be > invalid UTF-8, but you'll then need to emit them using the normal boxing > method. clang already rejects boxed expressions that are string literals with a character encoding incompatible with UTF-8. Also, we reach this part of the code only if the string is UTF-8 or ASCII (see the assertion I added). I added a test case to test/SemaObjC/boxing-illegal.m that shows clang rejects strings incompatible with UTF-8. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak updated this revision to Diff 188794. ahatanak marked 4 inline comments as done. ahatanak added a comment. Address review comments. - Preserve sugar when creating an `ObjCBoxedExpr` in `Sema::BuildObjCBoxedExpr`. - Add a test case to test/SemaObjC/boxing-illegal.m that shows clang rejects a string literal in a boxed expression if its character encoding is incompatible with UTF-8. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 Files: include/clang/AST/ExprObjC.h lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGObjC.cpp lib/Sema/SemaExprObjC.cpp test/CodeGenObjC/boxing.m test/SemaObjC/boxing-illegal.m test/SemaObjC/objc-literal-sig.m test/SemaObjC/transfer-boxed-string-nullability.m test/SemaObjCXX/literals.mm Index: test/SemaObjCXX/literals.mm === --- test/SemaObjCXX/literals.mm +++ test/SemaObjCXX/literals.mm @@ -50,6 +50,9 @@ + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; @end +@interface NSString +@end + template struct ConvertibleTo { operator T(); @@ -185,3 +188,8 @@ void test_dictionary_colon() { id dict = @{ key : value }; } + +void testConstExpr() { + constexpr NSString *t0 = @"abc"; + constexpr NSString *t1 = @("abc"); +} Index: test/SemaObjC/transfer-boxed-string-nullability.m === --- test/SemaObjC/transfer-boxed-string-nullability.m +++ test/SemaObjC/transfer-boxed-string-nullability.m @@ -16,6 +16,11 @@ void takesNonNull(NSString * _Nonnull ptr); void testBoxedString() { + // No diagnostic emitted as this doesn't need a stringWithUTF8String message + // send. + takesNonNull(@("hey")); + takesNonNull(@(u8"hey")); + const char *str = "hey"; takesNonNull([NSString stringWithUTF8String:str]); takesNonNull(@(str)); Index: test/SemaObjC/objc-literal-sig.m === --- test/SemaObjC/objc-literal-sig.m +++ test/SemaObjC/objc-literal-sig.m @@ -39,6 +39,8 @@ // All tests are doubled to make sure that a bad method is not saved // and then used un-checked. +const char *getStr(void); + void test_sig() { (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} @@ -46,6 +48,6 @@ id array2 = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}} id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} id dict2 = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} - id str = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} - id str2 = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str2 = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} } Index: test/SemaObjC/boxing-illegal.m === --- test/SemaObjC/boxing-illegal.m +++ test/SemaObjC/boxing-illegal.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s +// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes -fpascal-strings %s typedef long NSInteger; typedef unsigned long NSUInteger; @@ -57,6 +57,19 @@ box = @(*(enum ForwE*)p); // expected-error {{incomplete type 'enum ForwE' used in a boxed expression}} } +@interface NSString +@end + +void testStringLiteral() { + NSString *s; + s = @("abc"); + s = @(u8"abc"); + s = @(u"abc"); // expected-error {{illegal type 'unsigned short *' used in a boxed expression}} + s = @(U"abc"); // expected-error {{illegal type 'unsigned int *' used in a boxed expression}} + s = @(L"abc"); // expected-error {{illegal type 'int *' used in a boxed expression}} + s = @("\pabc"); // expected-error {{illegal type 'unsigned char *' used in a boxed expression}} +} + // rdar://1205 @class NSMutableDictionary; Index: test/CodeGenObjC/boxing.m === --- test/CodeGenObjC/boxing.m +++ test/CodeGenObjC/boxing.m @@ -53,6 +53,9 @@ + (id)stringWithUTF8String:(const char *)nullTerminatedCString; @end +// CHECK: [[V0:%.*]] = type opaque +// CHECK: [[STRUCT_NSCONSTANT_STRING_TAG:%.*]] = type { i32*, i32, i8*, i64 } + // CHECK: [[WithIntMeth:@.*]] =
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
rjmccall added inline comments. Comment at: lib/Sema/SemaExprObjC.cpp:534 +NSStringPointer, NSStringPointer); +return new (Context) ObjCBoxedExpr(SL, BoxedType, nullptr, SR); + } ahatanak wrote: > rjmccall wrote: > > You're implicitly dropping sugar from the source expression here; I really > > think you should preserve that, and if it means you end up having to look > > through array-decay expressions, that's not the end of the world. > > > > The need for a special case here is just to allow us to compile these even > > if there isn't a boxing method available? > > > > Do you need to restrict the type of the string literal so that it doesn't > > apply to e.g. wide strings? > Line 516 checks that the pointee type has the same unqualified type as > 'char'. If the string literal inside the parentheses is of a wider type > (e.g., `@(u"abc")`), this piece of code won't be executed, and a diagnostic > is emitted later ("illegal type 'const char16_t *' used in a boxed > expression"). > > The original motivation for special-casing string literals inside boxed > expressions was to silence the `-Wnullable-to-nonnull-conversion` warning > mentioned here: https://oleb.net/2018/@keypath/. The warning is issued > because the return type of `stringWithUTF8String` is nullable. > > ``` > ... > + (nullable instancetype)stringWithUTF8String:(const char > *)nullTerminatedCString; > ... > > NSString * _Nonnull ptr = @("abc"); // expected-error {{implicit conversion > from nullable pointer 'NSString * _Nullable' to non-nullable pointer type > 'NSString * _Nonnull'}} > ``` I see. So in addition to guaranteeing to skip the boxing call, you'd like to adjust the type to report the result as non-null, which we can do because we're unconditionally making a constant string. Makes sense. However, I think you need to check that the string is valid UTF-8 or else this is semantics-changing, since such strings are rejected by `+stringWithUTF8String:` (which is why it returns a nullable pointer at all). It should be alright to warn about strings that are statically known to be invalid UTF-8, but you'll then need to emit them using the normal boxing method. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak marked an inline comment as done. ahatanak added inline comments. Comment at: lib/Sema/SemaExprObjC.cpp:534 +NSStringPointer, NSStringPointer); +return new (Context) ObjCBoxedExpr(SL, BoxedType, nullptr, SR); + } rjmccall wrote: > You're implicitly dropping sugar from the source expression here; I really > think you should preserve that, and if it means you end up having to look > through array-decay expressions, that's not the end of the world. > > The need for a special case here is just to allow us to compile these even if > there isn't a boxing method available? > > Do you need to restrict the type of the string literal so that it doesn't > apply to e.g. wide strings? Line 516 checks that the pointee type has the same unqualified type as 'char'. If the string literal inside the parentheses is of a wider type (e.g., `@(u"abc")`), this piece of code won't be executed, and a diagnostic is emitted later ("illegal type 'const char16_t *' used in a boxed expression"). The original motivation for special-casing string literals inside boxed expressions was to silence the `-Wnullable-to-nonnull-conversion` warning mentioned here: https://oleb.net/2018/@keypath/. The warning is issued because the return type of `stringWithUTF8String` is nullable. ``` ... + (nullable instancetype)stringWithUTF8String:(const char *)nullTerminatedCString; ... NSString * _Nonnull ptr = @("abc"); // expected-error {{implicit conversion from nullable pointer 'NSString * _Nullable' to non-nullable pointer type 'NSString * _Nonnull'}} ``` Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
rjmccall added inline comments. Comment at: lib/CodeGen/CGExprConstant.cpp:1793 + "this boxed expression can't be emitted as a compile-time constant"); + return emitConstantObjCStringLiteral(cast(E->getSubExpr()), + E->getType(), CGM); `IgnoreParens`. Comment at: lib/Sema/SemaExprObjC.cpp:534 +NSStringPointer, NSStringPointer); +return new (Context) ObjCBoxedExpr(SL, BoxedType, nullptr, SR); + } You're implicitly dropping sugar from the source expression here; I really think you should preserve that, and if it means you end up having to look through array-decay expressions, that's not the end of the world. The need for a special case here is just to allow us to compile these even if there isn't a boxing method available? Do you need to restrict the type of the string literal so that it doesn't apply to e.g. wide strings? Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58729/new/ https://reviews.llvm.org/D58729 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parentheses is a string literal
ahatanak created this revision. ahatanak added reviewers: rjmccall, arphaman. ahatanak added a project: clang. Herald added subscribers: jdoerfert, dexonsmith, jkorous. clang currently emits an expression like `@("abc")` as a message send to `stringWithUTF8String`. This patch makes changes so that a compile-time constant is emitted instead when the expression inside the parentheses is a string literal. I think it's possible to do the same optimization for constant expressions that evaluate to zero-terminated strings (see the example below), but I'm leaving that for future work. constexpr const char *foo() { return "abc"; } void test() { NSString *s = @(foo()); } The original motivation for the patch is to silence the `-Wnullable-to-nonnull-conversion` warning that clang started emitting after r317727: The https://oleb.net/2018/@keypath/. rdar://problem/42684601 Repository: rC Clang https://reviews.llvm.org/D58729 Files: include/clang/AST/ExprObjC.h lib/AST/ExprConstant.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGObjC.cpp lib/Sema/SemaExprObjC.cpp test/CodeGenObjC/boxing.m test/SemaObjC/objc-literal-sig.m test/SemaObjC/transfer-boxed-string-nullability.m test/SemaObjCXX/literals.mm Index: test/SemaObjCXX/literals.mm === --- test/SemaObjCXX/literals.mm +++ test/SemaObjCXX/literals.mm @@ -50,6 +50,9 @@ + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; @end +@interface NSString +@end + template struct ConvertibleTo { operator T(); @@ -185,3 +188,8 @@ void test_dictionary_colon() { id dict = @{ key : value }; } + +void testConstExpr() { + constexpr NSString *t0 = @"abc"; + constexpr NSString *t1 = @("abc"); +} Index: test/SemaObjC/transfer-boxed-string-nullability.m === --- test/SemaObjC/transfer-boxed-string-nullability.m +++ test/SemaObjC/transfer-boxed-string-nullability.m @@ -16,6 +16,10 @@ void takesNonNull(NSString * _Nonnull ptr); void testBoxedString() { + // No diagnostic emitted as this doesn't need a stringWithUTF8String message + // send. + takesNonNull(@("hey")); + const char *str = "hey"; takesNonNull([NSString stringWithUTF8String:str]); takesNonNull(@(str)); Index: test/SemaObjC/objc-literal-sig.m === --- test/SemaObjC/objc-literal-sig.m +++ test/SemaObjC/objc-literal-sig.m @@ -39,6 +39,8 @@ // All tests are doubled to make sure that a bad method is not saved // and then used un-checked. +const char *getStr(void); + void test_sig() { (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} (void)@__objc_yes; // expected-error{{literal construction method 'numberWithBool:' has incompatible signature}} @@ -46,6 +48,6 @@ id array2 = @[ @17 ]; // expected-error{{literal construction method 'arrayWithObjects:count:' has incompatible signature}} id dict = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} id dict2 = @{ @"hello" : @17 }; // expected-error{{literal construction method 'dictionaryWithObjects:forKeys:count:' has incompatible signature}} - id str = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} - id str2 = @("hello"); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} + id str2 = @(getStr()); // expected-error{{literal construction method 'stringWithUTF8String:' has incompatible signature}} } Index: test/CodeGenObjC/boxing.m === --- test/CodeGenObjC/boxing.m +++ test/CodeGenObjC/boxing.m @@ -53,6 +53,9 @@ + (id)stringWithUTF8String:(const char *)nullTerminatedCString; @end +// CHECK: [[V0:%.*]] = type opaque +// CHECK: [[STRUCT_NSCONSTANT_STRING_TAG:%.*]] = type { i32*, i32, i8*, i64 } + // CHECK: [[WithIntMeth:@.*]] = private unnamed_addr constant [15 x i8] c"numberWithInt:\00" // CHECK: [[WithIntSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[WithIntMeth]] // CHECK: [[WithCharMeth:@.*]] = private unnamed_addr constant [16 x i8] c"numberWithChar:\00" @@ -65,8 +68,12 @@ // CHECK: [[WithUnsignedIntegerSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds ([27 x i8], [27 x i8]* [[WithUnsignedIntegerMeth]] // CHECK: [[stringWithUTF8StringMeth:@.*]] = private unnamed_addr constant [22 x i8] c"stringWithUTF8String:\00" // CHECK: [[stringWithUTF8StringSEL:@.*]] = private externally_initialized global i8* getelementptr inbounds