[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