From f64bc202a2bcdf7b10f418ad52aaa7366c8ffef9 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 23 Feb 2012 22:51:36 +0000 Subject: [PATCH] objective-c++: Type of an objc string literal is NSString, not 'id'. // rdar://10907410 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151296 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 10 ++++++++++ lib/Sema/SemaExprObjC.cpp | 18 +++++++++++++++--- ...eceiver-undefined-larger-than-voidptr-ret.m | 2 +- test/PCH/objc_exprs.m | 2 +- test/SemaObjC/NSString-type.m | 10 ++++++++++ test/SemaObjCXX/NSString-type.mm | 10 ++++++++++ 6 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 test/SemaObjC/NSString-type.m create mode 100644 test/SemaObjCXX/NSString-type.mm diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 26e9195962..723dd1748d 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -218,6 +218,8 @@ class ASTContext : public RefCountedBase { QualType ObjCConstantStringType; mutable RecordDecl *CFConstantStringTypeDecl; + + QualType ObjCNSStringType; /// \brief The typedef declaration for the Objective-C "instancetype" type. TypedefDecl *ObjCInstanceTypeDecl; @@ -944,6 +946,14 @@ public: return ObjCConstantStringType; } + QualType getObjCNSStringType() const { + return ObjCNSStringType; + } + + void setObjCNSStringType(QualType T) { + ObjCNSStringType = T; + } + /// \brief Retrieve the type that 'id' has been defined to, which may be /// different from the built-in 'id' if 'id' has been typedef'd. QualType getObjCIdRedefinitionType() const { diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index e0420c1faf..ec5329c4d4 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -113,9 +113,21 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, Ty = Context.getObjCConstantStringInterface(); Ty = Context.getObjCObjectPointerType(Ty); } else { - // If there is no NSString interface defined then treat constant - // strings as untyped objects and let the runtime figure it out later. - Ty = Context.getObjCIdType(); + // If there is no NSString interface defined, implicitly declare + // a @class NSString; and use that instead. This is to make sure + // type of an NSString literal is represented correctly, instead of + // being an 'id' type. + Ty = Context.getObjCNSStringType(); + if (Ty.isNull()) { + ObjCInterfaceDecl *NSStringIDecl = + ObjCInterfaceDecl::Create (Context, + Context.getTranslationUnitDecl(), + SourceLocation(), NSIdent, + 0, SourceLocation()); + Ty = Context.getObjCInterfaceType(NSStringIDecl); + Context.setObjCNSStringType(Ty); + } + Ty = Context.getObjCObjectPointerType(Ty); } } diff --git a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m index eba72bac9f..96bc7a9b3e 100644 --- a/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m +++ b/test/Analysis/nil-receiver-undefined-larger-than-voidptr-ret.m @@ -48,7 +48,7 @@ void createFoo4() { } void createFoo5() { - MyClass *obj = @""; + MyClass *obj = (id)@""; double d = [obj doubleM]; // no-warning } diff --git a/test/PCH/objc_exprs.m b/test/PCH/objc_exprs.m index c37968b7b9..1f971e7941 100644 --- a/test/PCH/objc_exprs.m +++ b/test/PCH/objc_exprs.m @@ -6,7 +6,7 @@ // RUN: %clang_cc1 -fblocks -include-pch %t -fsyntax-only -verify %s // Expressions -int *A1 = (objc_string)0; // expected-warning {{aka 'id'}} +int *A1 = (objc_string)0; // expected-warning {{aka 'NSString *'}} char A2 = (objc_encode){}; // expected-error {{not a compile-time constant}} \ expected-warning {{char [2]}} diff --git a/test/SemaObjC/NSString-type.m b/test/SemaObjC/NSString-type.m new file mode 100644 index 0000000000..3b4857ae0e --- /dev/null +++ b/test/SemaObjC/NSString-type.m @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -verify %s +// rdar://10907410 + +void test(id pid, Class pclass) { + void (^block)(void) = @"help"; // expected-error {{initializing 'void (^)(void)' with an expression of incompatible type 'NSString *'}} + void (^block1)(void) = pid; + void (^block2)(void) = @"help"; // expected-error {{initializing 'void (^)(void)' with an expression of incompatible type 'NSString *'}} + void (^block3)(void) = @"help"; // expected-error {{initializing 'void (^)(void)' with an expression of incompatible type 'NSString *'}} +} + diff --git a/test/SemaObjCXX/NSString-type.mm b/test/SemaObjCXX/NSString-type.mm new file mode 100644 index 0000000000..10338667b7 --- /dev/null +++ b/test/SemaObjCXX/NSString-type.mm @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -verify %s +// rdar://10907410 + +void test(id pid, Class pclass) { + void (^block)(void) = @"help"; // expected-error {{cannot initialize a variable of type 'void (^)()' with an rvalue of type 'NSString *'}} + void (^block1)(void) = pid; + void (^block2)(void) = @"help"; // expected-error {{cannot initialize a variable of type 'void (^)()' with an rvalue of type 'NSString *'}} + void (^block3)(void) = @"help"; // expected-error {{cannot initialize a variable of type 'void (^)()' with an rvalue of type 'NSString *'}} +} +