[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cfe-commits
Subject:    [PATCH] D58729: Emit boxed expression as a compile-time constant if the expression inside the parent
From:       Akira Hatanaka via Phabricator via cfe-commits <cfe-commits () lists ! llvm ! org>
Date:       2019-02-28 22:47:06
Message-ID: 7965a83ea1ef55b65026baca0b40dab3 () localhost ! localdomain
[Download RAW message or body]

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::BuildObjCBoxedE=
xpr`.
- Add a test case to test/SemaObjC/boxing-illegal.m that shows clang reject=
s a string literal in a boxed expression if its character encoding is incom=
patible 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


["D58729.188794.patch" (text/x-patch)]

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<NSCopying> \
[])keys count:(unsigned long)cnt;  @end
 
+@interface NSString
+@end
+
 template<typename T>
 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://13333205
 @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:@.*]] = 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 ([22 x i8], [22 x i8]* [[stringWithUTF8StringMeth]] +// CHECK: \
[[STR0:.*]] = private unnamed_addr constant [4 x i8] c"abc\00", section \
"__TEXT,__cstring,cstring_literals", align 1 +// CHECK: [[UNNAMED_CFSTRING:.*]] = \
private global [[STRUCT_NSCONSTANT_STRING_TAG]] { i32* getelementptr inbounds ([0 x \
i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* \
getelementptr inbounds ([4 x i8], [4 x i8]* [[STR0]], i32 0, i32 0), i64 3 }, section \
"__DATA,__cfstring", align 8  
 int main() {
+  // CHECK: [[T:%.*]] = alloca [[V0]]*, align 8
+
   // CHECK: load i8*, i8** [[WithIntSEL]]
   int i; @(i);
   // CHECK: load i8*, i8** [[WithCharSEL]]
@@ -92,4 +99,7 @@
   Color col = Red;
   // CHECK: load i8*, i8** [[WithIntegerSEL]]
   @(col);
+
+  // CHECK: store [[V0]]* bitcast ([[STRUCT_NSCONSTANT_STRING_TAG]]* \
[[UNNAMED_CFSTRING]] to [[V0]]*), [[V0]]** [[T]], align 8 +  NSString *t = @("abc");
 }
Index: lib/Sema/SemaExprObjC.cpp
===================================================================
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -524,6 +524,21 @@
         NSStringPointer = Context.getObjCObjectPointerType(NSStringObject);
       }
 
+      // The boxed expression can be emitted as a compile time constant if it is
+      // a string literal whose character encoding is compatible with UTF-8.
+      if (auto *CE = dyn_cast<ImplicitCastExpr>(ValueExpr))
+        if (CE->getCastKind() == CK_ArrayToPointerDecay)
+          if (auto *SL =
+                  dyn_cast<StringLiteral>(CE->getSubExpr()->IgnoreParens())) {
+            assert((SL->isAscii() || SL->isUTF8()) &&
+                   "unexpected character encoding");
+            BoxedType = Context.getAttributedType(
+                AttributedType::getNullabilityAttrKind(
+                    NullabilityKind::NonNull),
+                NSStringPointer, NSStringPointer);
+            return new (Context) ObjCBoxedExpr(CE, BoxedType, nullptr, SR);
+          }
+
       if (!StringWithUTF8StringMethod) {
         IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String");
         Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II);
Index: lib/CodeGen/CGObjC.cpp
===================================================================
--- lib/CodeGen/CGObjC.cpp
+++ lib/CodeGen/CGObjC.cpp
@@ -14,6 +14,7 @@
 #include "CGObjCRuntime.h"
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
+#include "ConstantEmitter.h"
 #include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
@@ -60,7 +61,12 @@
   // Get the method.
   const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod();
   const Expr *SubExpr = E->getSubExpr();
-  assert(BoxingMethod && "BoxingMethod is null");
+
+  if (E->isExpressibleAsConstantInitializer()) {
+    ConstantEmitter ConstEmitter(CGM);
+    return ConstEmitter.tryEmitAbstract(E, E->getType());
+  }
+
   assert(BoxingMethod->isClassMethod() && "BoxingMethod must be a class method");
   Selector Sel = BoxingMethod->getSelector();
 
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1611,6 +1611,7 @@
   ConstantLValue VisitConstantExpr(const ConstantExpr *E);
   ConstantLValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
   ConstantLValue VisitStringLiteral(const StringLiteral *E);
+  ConstantLValue VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
   ConstantLValue VisitObjCEncodeExpr(const ObjCEncodeExpr *E);
   ConstantLValue VisitObjCStringLiteral(const ObjCStringLiteral *E);
   ConstantLValue VisitPredefinedExpr(const PredefinedExpr *E);
@@ -1773,10 +1774,24 @@
   return CGM.GetAddrOfConstantStringFromObjCEncode(E);
 }
 
+static ConstantLValue emitConstantObjCStringLiteral(const StringLiteral *S,
+                                                    QualType T,
+                                                    CodeGenModule &CGM) {
+  auto C = CGM.getObjCRuntime().GenerateConstantString(S);
+  return C.getElementBitCast(CGM.getTypes().ConvertTypeForMem(T));
+}
+
 ConstantLValue
 ConstantLValueEmitter::VisitObjCStringLiteral(const ObjCStringLiteral *E) {
-  auto C = CGM.getObjCRuntime().GenerateConstantString(E->getString());
-  return C.getElementBitCast(CGM.getTypes().ConvertTypeForMem(E->getType()));
+  return emitConstantObjCStringLiteral(E->getString(), E->getType(), CGM);
+}
+
+ConstantLValue
+ConstantLValueEmitter::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
+  assert(E->isExpressibleAsConstantInitializer() &&
+         "this boxed expression can't be emitted as a compile-time constant");
+  auto *SL = cast<StringLiteral>(E->getSubExpr()->IgnoreParenCasts());
+  return emitConstantObjCStringLiteral(SL, E->getType(), CGM);
 }
 
 ConstantLValue
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -1743,6 +1743,8 @@
   case Expr::CXXTypeidExprClass:
   case Expr::CXXUuidofExprClass:
     return true;
+  case Expr::ObjCBoxedExprClass:
+    return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer();
   case Expr::CallExprClass:
     return IsStringLiteralCall(cast<CallExpr>(E));
   // For GCC compatibility, &&label has static storage duration.
@@ -5794,6 +5796,8 @@
   bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
       { return Success(E); }
   bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
+    if (E->isExpressibleAsConstantInitializer())
+      return Success(E);
     if (Info.noteFailure())
       EvaluateIgnoredValue(Info, E->getSubExpr());
     return Error(E);
Index: include/clang/AST/ExprObjC.h
===================================================================
--- include/clang/AST/ExprObjC.h
+++ 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(); }


[Attachment #4 (text/plain)]

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic