Author: alexdenisov Date: Fri Jun 26 00:28:36 2015 New Revision: 240761 URL: http://llvm.org/viewvc/llvm-project?rev=240761&view=rev Log: [ObjC] Add NSValue support for objc_boxed_expressions
Patch extends ObjCBoxedExpr to accept records (structs and unions): typedef struct __attribute__((objc_boxable)) _Color { int r, g, b; } Color; Color color; NSValue *boxedColor = @(color); // [NSValue valueWithBytes:&color objCType:@encode(Color)]; Modified: cfe/trunk/docs/ObjectiveCLiterals.rst cfe/trunk/include/clang/AST/ASTMutationListener.h cfe/trunk/include/clang/AST/ExprObjC.h cfe/trunk/include/clang/AST/NSAPI.h cfe/trunk/include/clang/AST/Type.h cfe/trunk/include/clang/Basic/Attr.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Serialization/ASTWriter.h cfe/trunk/lib/AST/NSAPI.cpp cfe/trunk/lib/AST/Type.cpp cfe/trunk/lib/CodeGen/CGObjC.cpp cfe/trunk/lib/Frontend/MultiplexConsumer.cpp cfe/trunk/lib/Lex/PPMacroExpansion.cpp cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/lib/Sema/SemaExprObjC.cpp cfe/trunk/lib/Serialization/ASTCommon.h cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/test/Index/annotate-literals.m cfe/trunk/test/PCH/subscripting-literals.m Modified: cfe/trunk/docs/ObjectiveCLiterals.rst URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ObjectiveCLiterals.rst?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/docs/ObjectiveCLiterals.rst (original) +++ cfe/trunk/docs/ObjectiveCLiterals.rst Fri Jun 26 00:28:36 2015 @@ -119,8 +119,8 @@ Objective-C provides a new syntax for bo @( <expression> ) -Expressions of scalar (numeric, enumerated, BOOL) and C string pointer -types are supported: +Expressions of scalar (numeric, enumerated, BOOL), C string pointer +and some C structures (via NSValue) are supported: .. code-block:: objc @@ -136,6 +136,12 @@ types are supported: NSString *path = @(getenv("PATH")); // [NSString stringWithUTF8String:(getenv("PATH"))] NSArray *pathComponents = [path componentsSeparatedByString:@":"]; + // NS structs + NSValue *center = @(view.center); // Point p = view.point; + // [NSValue valueWithBytes:&p objCType:@encode(Point)]; + NSValue *frame = @(view.frame); // Rect r = view.frame; + // [NSValue valueWithBytes:&r objCType:@encode(Rect)]; + Boxed Enums ----------- @@ -218,6 +224,42 @@ character data is valid. Passing ``NULL` raise an exception at runtime. When possible, the compiler will reject ``NULL`` character pointers used in boxed expressions. +Boxed C Structures +------------------ + +Boxed expressions support construction of NSValue objects. +It said that C structures can be used, the only requirement is: +structure should be marked with ``objc_boxable`` attribute. +To support older version of frameworks and/or third-party libraries +you may need to add the attribute via ``typedef``. + +.. code-block:: objc + + struct __attribute__((objc_boxable)) Point { + // ... + }; + + typedef struct __attribute__((objc_boxable)) _Size { + // ... + } Size; + + typedef struct _Rect { + // ... + } Rect; + + struct Point p; + NSValue *point = @(p); // ok + Size s; + NSValue *size = @(s); // ok + + Rect r; + NSValue *bad_rect = @(r); // error + + typedef struct __attribute__((objc_boxable)) _Rect Rect; + + NSValue *good_rect = @(r); // ok + + Container Literals ================== @@ -539,6 +581,22 @@ checks. Here are examples of their use: } #endif + #if __has_attribute(objc_boxable) + typedef struct __attribute__((objc_boxable)) _Rect Rect; + #endif + + #if __has_feature(objc_boxed_nsvalue_expressions) + CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"]; + animation.fromValue = @(layer.position); + animation.toValue = @(newPosition); + [layer addAnimation:animation forKey:@"move"]; + #else + CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"]; + animation.fromValue = [NSValue valueWithCGPoint:layer.position]; + animation.toValue = [NSValue valueWithCGPoint:newPosition]; + [layer addAnimation:animation forKey:@"move"]; + #endif + Code can use also ``__has_feature(objc_bool)`` to check for the availability of numeric literals support. This checks for the new ``__objc_yes / __objc_no`` keywords, which enable the use of Modified: cfe/trunk/include/clang/AST/ASTMutationListener.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTMutationListener.h?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTMutationListener.h (original) +++ cfe/trunk/include/clang/AST/ASTMutationListener.h Fri Jun 26 00:28:36 2015 @@ -14,6 +14,7 @@ #define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H namespace clang { + class Attr; class ClassTemplateDecl; class ClassTemplateSpecializationDecl; class CXXDestructorDecl; @@ -29,6 +30,7 @@ namespace clang { class ObjCInterfaceDecl; class ObjCPropertyDecl; class QualType; + class RecordDecl; class TagDecl; class VarDecl; class VarTemplateDecl; @@ -119,6 +121,14 @@ public: /// \param M The containing module in which the definition was made visible, /// if any. virtual void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) {} + + /// \brief An attribute was added to a RecordDecl + /// + /// \param Attr The attribute that was added to the Record + /// + /// \param Record The RecordDecl that got a new attribute + virtual void AddedAttributeToRecord(const Attr *Attr, + const RecordDecl *Record) {} // NOTE: If new methods are added they should also be added to // MultiplexASTMutationListener. Modified: cfe/trunk/include/clang/AST/ExprObjC.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprObjC.h?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ExprObjC.h (original) +++ cfe/trunk/include/clang/AST/ExprObjC.h Fri Jun 26 00:28:36 2015 @@ -86,7 +86,7 @@ public: }; /// ObjCBoxedExpr - used for generalized expression boxing. -/// as in: @(strdup("hello world")) or @(random()) +/// as in: @(strdup("hello world")), @(random()) or @(view.frame) /// Also used for boxing non-parenthesized numeric literals; /// as in: @42 or \@true (c++/objc++) or \@__yes (c/objc). class ObjCBoxedExpr : public Expr { Modified: cfe/trunk/include/clang/AST/NSAPI.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/NSAPI.h?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/NSAPI.h (original) +++ cfe/trunk/include/clang/AST/NSAPI.h Fri Jun 26 00:28:36 2015 @@ -37,8 +37,9 @@ public: ClassId_NSMutableSet, ClassId_NSCountedSet, ClassId_NSMutableOrderedSet, + ClassId_NSValue }; - static const unsigned NumClassIds = 10; + static const unsigned NumClassIds = 11; enum NSStringMethodKind { NSStr_stringWithString, Modified: cfe/trunk/include/clang/AST/Type.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Type.h (original) +++ cfe/trunk/include/clang/AST/Type.h Fri Jun 26 00:28:36 2015 @@ -1564,6 +1564,7 @@ public: bool isRecordType() const; bool isClassType() const; bool isStructureType() const; + bool isObjCBoxableRecordType() const; bool isInterfaceType() const; bool isStructureOrClassType() const; bool isUnionType() const; Modified: cfe/trunk/include/clang/Basic/Attr.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Attr.td (original) +++ cfe/trunk/include/clang/Basic/Attr.td Fri Jun 26 00:28:36 2015 @@ -1125,6 +1125,12 @@ def ObjCRuntimeName : Attr { let Documentation = [ObjCRuntimeNameDocs]; } +def ObjCBoxable : Attr { + let Spellings = [GNU<"objc_boxable">]; + let Subjects = SubjectList<[Record], ErrorDiag, "ExpectedStructOrUnion">; + let Documentation = [Undocumented]; +} + def OptimizeNone : InheritableAttr { let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">]; let Subjects = SubjectList<[Function, ObjCMethod]>; Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 26 00:28:36 2015 @@ -2081,12 +2081,16 @@ def err_attr_objc_ownership_redundant : "the type %0 is already explicitly ownership-qualified">; def err_undeclared_nsnumber : Error< "NSNumber must be available to use Objective-C literals">; +def err_undeclared_nsvalue : Error< + "NSValue must be available to use Objective-C boxed expressions">; def err_invalid_nsnumber_type : Error< "%0 is not a valid literal type for NSNumber">; def err_undeclared_nsstring : Error< "cannot box a string value because NSString has not been declared">; def err_objc_illegal_boxed_expression_type : Error< "illegal type %0 used in a boxed expression">; +def err_objc_non_trivially_copyable_boxed_expression_type : Error< + "non-trivially copyable type %0 cannot be used in a boxed expression">; def err_objc_incomplete_boxed_expression_type : Error< "incomplete type %0 used in a boxed expression">; def err_undeclared_nsarray : Error< Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 26 00:28:36 2015 @@ -702,9 +702,15 @@ public: /// \brief The declaration of the Objective-C NSNumber class. ObjCInterfaceDecl *NSNumberDecl; + /// \brief The declaration of the Objective-C NSValue class. + ObjCInterfaceDecl *NSValueDecl; + /// \brief Pointer to NSNumber type (NSNumber *). QualType NSNumberPointer; + /// \brief Pointer to NSValue type (NSValue *). + QualType NSValuePointer; + /// \brief The Objective-C NSNumber methods used to create NSNumber literals. ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; @@ -717,6 +723,9 @@ public: /// \brief The declaration of the stringWithUTF8String: method. ObjCMethodDecl *StringWithUTF8StringMethod; + /// \brief The declaration of the valueWithBytes:objCType: method. + ObjCMethodDecl *ValueWithBytesObjCTypeMethod; + /// \brief The declaration of the Objective-C NSArray class. ObjCInterfaceDecl *NSArrayDecl; @@ -5027,9 +5036,9 @@ public: /// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the /// '@' prefixed parenthesized expression. The type of the expression will - /// either be "NSNumber *" or "NSString *" depending on the type of - /// ValueType, which is allowed to be a built-in numeric type or - /// "char *" or "const char *". + /// either be "NSNumber *", "NSString *" or "NSValue *" depending on the type + /// of ValueType, which is allowed to be a built-in numeric type, "char *", + /// "const char *" or C structure with attribute 'objc_boxable'. ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr); ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Modified: cfe/trunk/include/clang/Serialization/ASTWriter.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTWriter.h?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/include/clang/Serialization/ASTWriter.h (original) +++ cfe/trunk/include/clang/Serialization/ASTWriter.h Fri Jun 26 00:28:36 2015 @@ -42,6 +42,7 @@ namespace llvm { namespace clang { class ASTContext; +class Attr; class NestedNameSpecifier; class CXXBaseSpecifier; class CXXCtorInitializer; @@ -60,6 +61,7 @@ class Module; class PreprocessedEntity; class PreprocessingRecord; class Preprocessor; +class RecordDecl; class Sema; class SourceManager; struct StoredDeclsList; @@ -302,6 +304,7 @@ private: unsigned Loc; unsigned Val; Module *Mod; + const Attr *Attribute; }; public: @@ -315,6 +318,8 @@ private: : Kind(Kind), Val(Val) {} DeclUpdate(unsigned Kind, Module *M) : Kind(Kind), Mod(M) {} + DeclUpdate(unsigned Kind, const Attr *Attribute) + : Kind(Kind), Attribute(Attribute) {} unsigned getKind() const { return Kind; } const Decl *getDecl() const { return Dcl; } @@ -324,6 +329,7 @@ private: } unsigned getNumber() const { return Val; } Module *getModule() const { return Mod; } + const Attr *getAttr() const { return Attribute; } }; typedef SmallVector<DeclUpdate, 1> UpdateRecord; @@ -860,6 +866,8 @@ public: void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override; + void AddedAttributeToRecord(const Attr *Attr, + const RecordDecl *Record) override; }; /// \brief AST and semantic-analysis consumer that generates a Modified: cfe/trunk/lib/AST/NSAPI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/AST/NSAPI.cpp (original) +++ cfe/trunk/lib/AST/NSAPI.cpp Fri Jun 26 00:28:36 2015 @@ -30,7 +30,8 @@ IdentifierInfo *NSAPI::getNSClassId(NSCl "NSNumber", "NSMutableSet", "NSCountedSet", - "NSMutableOrderedSet" + "NSMutableOrderedSet", + "NSValue" }; if (!ClassIds[K]) Modified: cfe/trunk/lib/AST/Type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/AST/Type.cpp (original) +++ cfe/trunk/lib/AST/Type.cpp Fri Jun 26 00:28:36 2015 @@ -364,6 +364,11 @@ bool Type::isStructureType() const { return RT->getDecl()->isStruct(); return false; } +bool Type::isObjCBoxableRecordType() const { + if (const RecordType *RT = getAs<RecordType>()) + return RT->getDecl()->hasAttr<ObjCBoxableAttr>(); + return false; +} bool Type::isInterfaceType() const { if (const RecordType *RT = getAs<RecordType>()) return RT->getDecl()->isInterface(); Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGObjC.cpp (original) +++ cfe/trunk/lib/CodeGen/CGObjC.cpp Fri Jun 26 00:28:36 2015 @@ -55,13 +55,15 @@ llvm::Value *CodeGenFunction::EmitObjCSt /// EmitObjCBoxedExpr - This routine generates code to call /// the appropriate expression boxing method. This will either be -/// one of +[NSNumber numberWith<Type>:], or +[NSString stringWithUTF8String:]. +/// one of +[NSNumber numberWith<Type>:], or +[NSString stringWithUTF8String:], +/// or [NSValue valueWithBytes:objCType:]. /// llvm::Value * CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) { // Generate the correct selector for this literal's concrete type. // Get the method. const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod(); + const Expr *SubExpr = E->getSubExpr(); assert(BoxingMethod && "BoxingMethod is null"); assert(BoxingMethod->isClassMethod() && "BoxingMethod must be a class method"); Selector Sel = BoxingMethod->getSelector(); @@ -74,7 +76,35 @@ CodeGenFunction::EmitObjCBoxedExpr(const llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl); CallArgList Args; - EmitCallArgs(Args, BoxingMethod, E->arg_begin(), E->arg_end()); + const ParmVarDecl *ArgDecl = *BoxingMethod->param_begin(); + QualType ArgQT = ArgDecl->getType().getUnqualifiedType(); + + // ObjCBoxedExpr supports boxing of structs and unions + // via [NSValue valueWithBytes:objCType:] + const QualType ValueType(SubExpr->getType().getCanonicalType()); + if (ValueType->isObjCBoxableRecordType()) { + // Emit CodeGen for first parameter + // and cast value to correct type + llvm::Value *Temporary = CreateMemTemp(SubExpr->getType()); + EmitAnyExprToMem(SubExpr, Temporary, Qualifiers(), /*isInit*/ true); + llvm::Value *BitCast = Builder.CreateBitCast(Temporary, + ConvertType(ArgQT)); + Args.add(RValue::get(BitCast), ArgQT); + + // Create char array to store type encoding + std::string Str; + getContext().getObjCEncodingForType(ValueType, Str); + llvm::GlobalVariable *GV = CGM.GetAddrOfConstantCString(Str); + + // Cast type encoding to correct type + const ParmVarDecl *EncodingDecl = BoxingMethod->parameters()[1]; + QualType EncodingQT = EncodingDecl->getType().getUnqualifiedType(); + llvm::Value *Cast = Builder.CreateBitCast(GV, ConvertType(EncodingQT)); + + Args.add(RValue::get(Cast), EncodingQT); + } else { + Args.add(EmitAnyExpr(SubExpr), ArgQT); + } RValue result = Runtime.GenerateMessageSend( *this, ReturnValueSlot(), BoxingMethod->getReturnType(), Sel, Receiver, Modified: cfe/trunk/lib/Frontend/MultiplexConsumer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/MultiplexConsumer.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/MultiplexConsumer.cpp (original) +++ cfe/trunk/lib/Frontend/MultiplexConsumer.cpp Fri Jun 26 00:28:36 2015 @@ -128,6 +128,8 @@ public: void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override; + void AddedAttributeToRecord(const Attr *Attr, + const RecordDecl *Record) override; private: std::vector<ASTMutationListener*> Listeners; @@ -226,6 +228,13 @@ void MultiplexASTMutationListener::Redef for (auto *L : Listeners) L->RedefinedHiddenDefinition(D, M); } + +void MultiplexASTMutationListener::AddedAttributeToRecord( + const Attr *Attr, + const RecordDecl *Record) { + for (auto *L : Listeners) + L->AddedAttributeToRecord(Attr, Record); +} } // end namespace clang Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Fri Jun 26 00:28:36 2015 @@ -1102,6 +1102,7 @@ static bool HasFeature(const Preprocesso .Case("objc_array_literals", LangOpts.ObjC2) .Case("objc_dictionary_literals", LangOpts.ObjC2) .Case("objc_boxed_expressions", LangOpts.ObjC2) + .Case("objc_boxed_nsvalue_expressions", LangOpts.ObjC2) .Case("arc_cf_code_audited", true) .Case("objc_bridge_id", true) .Case("objc_bridge_id_on_typedefs", true) Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Fri Jun 26 00:28:36 2015 @@ -91,8 +91,9 @@ Sema::Sema(Preprocessor &pp, ASTContext LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr), CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), - NSNumberDecl(nullptr), + NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), + ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), MSAsmLabelNameCounter(0), Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Jun 26 00:28:36 2015 @@ -20,6 +20,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -3990,6 +3991,34 @@ static void handleObjCRuntimeName(Sema & Attr.getAttributeSpellingListIndex())); } +// when a user wants to use objc_boxable with a union or struct +// but she doesn't have access to the declaration (legacy/third-party code) +// then she can 'enable' this feature via trick with a typedef +// e.g.: +// typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct; +static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { + bool notify = false; + + RecordDecl *RD = dyn_cast<RecordDecl>(D); + if (RD && RD->getDefinition()) { + RD = RD->getDefinition(); + notify = true; + } + + if (RD) { + ObjCBoxableAttr *BoxableAttr = ::new (S.Context) + ObjCBoxableAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex()); + RD->addAttr(BoxableAttr); + if (notify) { + // we need to notify ASTReader/ASTWriter about + // modification of existing declaration + if (ASTMutationListener *L = S.getASTMutationListener()) + L->AddedAttributeToRecord(BoxableAttr, RD); + } + } +} + static void handleObjCOwnershipAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (hasDeclarator(D)) return; @@ -4758,6 +4787,10 @@ static void ProcessDeclAttribute(Sema &S case AttributeList::AT_ObjCRuntimeName: handleObjCRuntimeName(S, D, Attr); break; + + case AttributeList::AT_ObjCBoxable: + handleObjCBoxable(S, D, Attr); + break; case AttributeList::AT_CFAuditedTransfer: handleCFAuditedTransferAttr(S, D, Attr); Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Fri Jun 26 00:28:36 2015 @@ -563,7 +563,6 @@ ExprResult Sema::BuildObjCBoxedExpr(Sour // Look for the appropriate method within NSNumber. BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(), ValueType); BoxedType = NSNumberPointer; - } else if (const EnumType *ET = ValueType->getAs<EnumType>()) { if (!ET->getDecl()->isComplete()) { Diag(SR.getBegin(), diag::err_objc_incomplete_boxed_expression_type) @@ -574,6 +573,109 @@ ExprResult Sema::BuildObjCBoxedExpr(Sour BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(), ET->getDecl()->getIntegerType()); BoxedType = NSNumberPointer; + } else if (ValueType->isObjCBoxableRecordType()) { + // Support for structure types, that marked as objc_boxable + // struct __attribute__((objc_boxable)) s { ... }; + + // Look up the NSValue class, if we haven't done so already. It's cached + // in the Sema instance. + if (!NSValueDecl) { + IdentifierInfo *NSValueId = + NSAPIObj->getNSClassId(NSAPI::ClassId_NSValue); + NamedDecl *IF = LookupSingleName(TUScope, NSValueId, + SR.getBegin(), Sema::LookupOrdinaryName); + NSValueDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF); + if (!NSValueDecl) { + if (getLangOpts().DebuggerObjCLiteral) { + // Create a stub definition of NSValue. + DeclContext *TU = Context.getTranslationUnitDecl(); + NSValueDecl = ObjCInterfaceDecl::Create(Context, TU, + SourceLocation(), NSValueId, + nullptr, SourceLocation()); + } else { + // Otherwise, require a declaration of NSValue. + Diag(SR.getBegin(), diag::err_undeclared_nsvalue); + return ExprError(); + } + } else if (!NSValueDecl->hasDefinition()) { + Diag(SR.getBegin(), diag::err_undeclared_nsvalue); + return ExprError(); + } + + // generate the pointer to NSValue type. + QualType NSValueObject = Context.getObjCInterfaceType(NSValueDecl); + NSValuePointer = Context.getObjCObjectPointerType(NSValueObject); + } + + if (!ValueWithBytesObjCTypeMethod) { + IdentifierInfo *II[] = { + &Context.Idents.get("valueWithBytes"), + &Context.Idents.get("objCType") + }; + Selector ValueWithBytesObjCType = Context.Selectors.getSelector(2, II); + + // Look for the appropriate method within NSValue. + BoxingMethod = NSValueDecl->lookupClassMethod(ValueWithBytesObjCType); + if (!BoxingMethod && getLangOpts().DebuggerObjCLiteral) { + // Debugger needs to work even if NSValue hasn't been defined. + TypeSourceInfo *ReturnTInfo = nullptr; + ObjCMethodDecl *M = ObjCMethodDecl::Create( + Context, + SourceLocation(), + SourceLocation(), + ValueWithBytesObjCType, + NSValuePointer, + ReturnTInfo, + NSValueDecl, + /*isInstance=*/false, + /*isVariadic=*/false, + /*isPropertyAccessor=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, + ObjCMethodDecl::Required, + /*HasRelatedResultType=*/false); + + SmallVector<ParmVarDecl *, 2> Params; + + ParmVarDecl *bytes = + ParmVarDecl::Create(Context, M, + SourceLocation(), SourceLocation(), + &Context.Idents.get("bytes"), + Context.VoidPtrTy.withConst(), + /*TInfo=*/nullptr, + SC_None, nullptr); + Params.push_back(bytes); + + QualType ConstCharType = Context.CharTy.withConst(); + ParmVarDecl *type = + ParmVarDecl::Create(Context, M, + SourceLocation(), SourceLocation(), + &Context.Idents.get("type"), + Context.getPointerType(ConstCharType), + /*TInfo=*/nullptr, + SC_None, nullptr); + Params.push_back(type); + + M->setMethodParams(Context, Params, None); + BoxingMethod = M; + } + + if (!validateBoxingMethod(*this, SR.getBegin(), NSValueDecl, + ValueWithBytesObjCType, BoxingMethod)) + return ExprError(); + + ValueWithBytesObjCTypeMethod = BoxingMethod; + } + + if (!ValueType.isTriviallyCopyableType(Context)) { + Diag(SR.getBegin(), + diag::err_objc_non_trivially_copyable_boxed_expression_type) + << ValueType << ValueExpr->getSourceRange(); + return ExprError(); + } + + BoxingMethod = ValueWithBytesObjCTypeMethod; + BoxedType = NSValuePointer; } if (!BoxingMethod) { @@ -582,13 +684,22 @@ ExprResult Sema::BuildObjCBoxedExpr(Sour return ExprError(); } - // Convert the expression to the type that the parameter requires. - ParmVarDecl *ParamDecl = BoxingMethod->parameters()[0]; - InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - ParamDecl); - ExprResult ConvertedValueExpr = PerformCopyInitialization(Entity, - SourceLocation(), - ValueExpr); + DiagnoseUseOfDecl(BoxingMethod, SR.getBegin()); + + ExprResult ConvertedValueExpr; + if (ValueType->isObjCBoxableRecordType()) { + InitializedEntity IE = InitializedEntity::InitializeTemporary(ValueType); + ConvertedValueExpr = PerformCopyInitialization(IE, ValueExpr->getExprLoc(), + ValueExpr); + } else { + // Convert the expression to the type that the parameter requires. + ParmVarDecl *ParamDecl = BoxingMethod->parameters()[0]; + InitializedEntity IE = InitializedEntity::InitializeParameter(Context, + ParamDecl); + ConvertedValueExpr = PerformCopyInitialization(IE, SourceLocation(), + ValueExpr); + } + if (ConvertedValueExpr.isInvalid()) return ExprError(); ValueExpr = ConvertedValueExpr.get(); Modified: cfe/trunk/lib/Serialization/ASTCommon.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.h?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTCommon.h (original) +++ cfe/trunk/lib/Serialization/ASTCommon.h Fri Jun 26 00:28:36 2015 @@ -36,7 +36,8 @@ enum DeclUpdateKind { UPD_MANGLING_NUMBER, UPD_STATIC_LOCAL_NUMBER, UPD_DECL_MARKED_OPENMP_THREADPRIVATE, - UPD_DECL_EXPORTED + UPD_DECL_EXPORTED, + UPD_ADDED_ATTR_TO_RECORD }; TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT); Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Jun 26 00:28:36 2015 @@ -3888,7 +3888,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, Reader.Context, ReadSourceRange(Record, Idx))); break; - case UPD_DECL_EXPORTED: + case UPD_DECL_EXPORTED: { unsigned SubmoduleID = readSubmoduleID(Record, Idx); auto *Exported = cast<NamedDecl>(D); if (auto *TD = dyn_cast<TagDecl>(Exported)) @@ -3912,5 +3912,13 @@ void ASTDeclReader::UpdateDecl(Decl *D, } break; } + + case UPD_ADDED_ATTR_TO_RECORD: + AttrVec Attrs; + Reader.ReadAttributes(F, Attrs, Record, Idx); + assert(Attrs.size() == 1); + D->addAttr(Attrs[0]); + break; + } } } Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Fri Jun 26 00:28:36 2015 @@ -4621,6 +4621,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(R case UPD_DECL_EXPORTED: Record.push_back(getSubmoduleID(Update.getModule())); break; + + case UPD_ADDED_ATTR_TO_RECORD: + WriteAttributes(llvm::makeArrayRef(Update.getAttr()), Record); + break; } } @@ -5769,3 +5773,11 @@ void ASTWriter::RedefinedHiddenDefinitio assert(D->isHidden() && "expected a hidden declaration"); DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_EXPORTED, M)); } + +void ASTWriter::AddedAttributeToRecord(const Attr *Attr, + const RecordDecl *Record) { + assert(!WritingAST && "Already writing the AST!"); + if (!Record->isFromASTFile()) + return; + DeclUpdates[Record].push_back(DeclUpdate(UPD_ADDED_ATTR_TO_RECORD, Attr)); +} Modified: cfe/trunk/test/Index/annotate-literals.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-literals.m?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/test/Index/annotate-literals.m (original) +++ cfe/trunk/test/Index/annotate-literals.m Fri Jun 26 00:28:36 2015 @@ -29,44 +29,61 @@ typedef unsigned char BOOL; + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt; @end -void test_literals(id k1, id o1, id k2, id o2, id k3) { +@interface NSValue ++ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type; +@end + +typedef struct __attribute__((objc_boxable)) _c_struct { + int dummy; +} c_struct; + +void test_literals(id k1, id o1, id k2, id o2, id k3, c_struct s) { id objects = @[ o1, o2 ]; id dict = @{ k1 : o1, k2 : o2, k3 : @17 }; + id val = @(s); } -// RUN: c-index-test -test-annotate-tokens=%s:33:1:37:1 %s | FileCheck -check-prefix=CHECK-LITERALS %s +// RUN: c-index-test -test-annotate-tokens=%s:41:1:46:1 %s | FileCheck -check-prefix=CHECK-LITERALS %s -// CHECK-LITERALS: Identifier: "id" [33:3 - 33:5] TypeRef=id:0:0 -// CHECK-LITERALS: Identifier: "objects" [33:6 - 33:13] VarDecl=objects:33:6 (Definition) -// CHECK-LITERALS: Punctuation: "=" [33:14 - 33:15] VarDecl=objects:33:6 (Definition) -// CHECK-LITERALS: Punctuation: "@" [33:16 - 33:17] UnexposedExpr= -// CHECK-LITERALS: Punctuation: "[" [33:17 - 33:18] UnexposedExpr= -// CHECK-LITERALS: Identifier: "o1" [33:19 - 33:21] DeclRefExpr=o1:32:30 -// CHECK-LITERALS: Punctuation: "," [33:21 - 33:22] UnexposedExpr= -// CHECK-LITERALS: Identifier: "o2" [33:23 - 33:25] DeclRefExpr=o2:32:44 -// CHECK-LITERALS: Punctuation: "]" [33:26 - 33:27] UnexposedExpr= -// CHECK-LITERALS: Punctuation: ";" [33:27 - 33:28] DeclStmt= -// CHECK-LITERALS: Identifier: "id" [34:3 - 34:5] TypeRef=id:0:0 -// CHECK-LITERALS: Identifier: "dict" [34:6 - 34:10] VarDecl=dict:34:6 (Definition) -// CHECK-LITERALS: Punctuation: "=" [34:11 - 34:12] VarDecl=dict:34:6 (Definition) -// CHECK-LITERALS: Punctuation: "@" [34:13 - 34:14] UnexposedExpr= -// CHECK-LITERALS: Punctuation: "{" [34:14 - 34:15] UnexposedExpr= -// CHECK-LITERALS: Identifier: "k1" [34:16 - 34:18] DeclRefExpr=k1:32:23 -// CHECK-LITERALS: Punctuation: ":" [34:19 - 34:20] UnexposedExpr= -// CHECK-LITERALS: Identifier: "o1" [34:21 - 34:23] DeclRefExpr=o1:32:30 -// CHECK-LITERALS: Punctuation: "," [34:23 - 34:24] UnexposedExpr= -// CHECK-LITERALS: Identifier: "k2" [35:16 - 35:18] DeclRefExpr=k2:32:37 -// CHECK-LITERALS: Punctuation: ":" [35:19 - 35:20] UnexposedExpr= -// CHECK-LITERALS: Identifier: "o2" [35:21 - 35:23] DeclRefExpr=o2:32:44 -// CHECK-LITERALS: Punctuation: "," [35:23 - 35:24] UnexposedExpr= -// CHECK-LITERALS: Identifier: "k3" [36:16 - 36:18] DeclRefExpr=k3:32:51 -// CHECK-LITERALS: Punctuation: ":" [36:19 - 36:20] UnexposedExpr= -// CHECK-LITERALS: Punctuation: "@" [36:21 - 36:22] UnexposedExpr= -// CHECK-LITERALS: Literal: "17" [36:22 - 36:24] IntegerLiteral= -// CHECK-LITERALS: Punctuation: "}" [36:25 - 36:26] UnexposedExpr= -// CHECK-LITERALS: Punctuation: ";" [36:26 - 36:27] DeclStmt= -// CHECK-LITERALS: Punctuation: "}" [37:1 - 37:2] CompoundStmt= +// CHECK-LITERALS: Identifier: "id" [41:3 - 41:5] TypeRef=id:0:0 +// CHECK-LITERALS: Identifier: "objects" [41:6 - 41:13] VarDecl=objects:41:6 (Definition) +// CHECK-LITERALS: Punctuation: "=" [41:14 - 41:15] VarDecl=objects:41:6 (Definition) +// CHECK-LITERALS: Punctuation: "@" [41:16 - 41:17] UnexposedExpr= +// CHECK-LITERALS: Punctuation: "[" [41:17 - 41:18] UnexposedExpr= +// CHECK-LITERALS: Identifier: "o1" [41:19 - 41:21] DeclRefExpr=o1:40:30 +// CHECK-LITERALS: Punctuation: "," [41:21 - 41:22] UnexposedExpr= +// CHECK-LITERALS: Identifier: "o2" [41:23 - 41:25] DeclRefExpr=o2:40:44 +// CHECK-LITERALS: Punctuation: "]" [41:26 - 41:27] UnexposedExpr= +// CHECK-LITERALS: Punctuation: ";" [41:27 - 41:28] DeclStmt= +// CHECK-LITERALS: Identifier: "id" [42:3 - 42:5] TypeRef=id:0:0 +// CHECK-LITERALS: Identifier: "dict" [42:6 - 42:10] VarDecl=dict:42:6 (Definition) +// CHECK-LITERALS: Punctuation: "=" [42:11 - 42:12] VarDecl=dict:42:6 (Definition) +// CHECK-LITERALS: Punctuation: "@" [42:13 - 42:14] UnexposedExpr= +// CHECK-LITERALS: Punctuation: "{" [42:14 - 42:15] UnexposedExpr= +// CHECK-LITERALS: Identifier: "k1" [42:16 - 42:18] DeclRefExpr=k1:40:23 +// CHECK-LITERALS: Punctuation: ":" [42:19 - 42:20] UnexposedExpr= +// CHECK-LITERALS: Identifier: "o1" [42:21 - 42:23] DeclRefExpr=o1:40:30 +// CHECK-LITERALS: Punctuation: "," [42:23 - 42:24] UnexposedExpr= +// CHECK-LITERALS: Identifier: "k2" [43:16 - 43:18] DeclRefExpr=k2:40:37 +// CHECK-LITERALS: Punctuation: ":" [43:19 - 43:20] UnexposedExpr= +// CHECK-LITERALS: Identifier: "o2" [43:21 - 43:23] DeclRefExpr=o2:40:44 +// CHECK-LITERALS: Punctuation: "," [43:23 - 43:24] UnexposedExpr= +// CHECK-LITERALS: Identifier: "k3" [44:16 - 44:18] DeclRefExpr=k3:40:51 +// CHECK-LITERALS: Punctuation: ":" [44:19 - 44:20] UnexposedExpr= +// CHECK-LITERALS: Punctuation: "@" [44:21 - 44:22] UnexposedExpr= +// CHECK-LITERALS: Literal: "17" [44:22 - 44:24] IntegerLiteral= +// CHECK-LITERALS: Punctuation: "}" [44:25 - 44:26] UnexposedExpr= +// CHECK-LITERALS: Punctuation: ";" [44:26 - 44:27] DeclStmt= +// CHECK-LITERALS: Identifier: "id" [45:3 - 45:5] TypeRef=id:0:0 +// CHECK-LITERALS: Identifier: "val" [45:6 - 45:9] VarDecl=val:45:6 (Definition) +// CHECK-LITERALS: Punctuation: "=" [45:10 - 45:11] VarDecl=val:45:6 (Definition) +// CHECK-LITERALS: Punctuation: "@" [45:12 - 45:13] UnexposedExpr= +// CHECK-LITERALS: Punctuation: "(" [45:13 - 45:14] ParenExpr= +// CHECK-LITERALS: Identifier: "s" [45:14 - 45:15] DeclRefExpr=s:40:64 +// CHECK-LITERALS: Punctuation: ")" [45:15 - 45:16] ParenExpr= +// CHECK-LITERALS: Punctuation: ";" [45:16 - 45:17] DeclStmt= +// CHECK-LITERALS: Punctuation: "}" [46:1 - 46:2] CompoundStmt= Modified: cfe/trunk/test/PCH/subscripting-literals.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/subscripting-literals.m?rev=240761&r1=240760&r2=240761&view=diff ============================================================================== --- cfe/trunk/test/PCH/subscripting-literals.m (original) +++ cfe/trunk/test/PCH/subscripting-literals.m Fri Jun 26 00:28:36 2015 @@ -30,6 +30,14 @@ @class NSString; +@interface NSValue ++ (NSValue *)valueWithBytes:(const void *)bytes objCType:(const char *)type; +@end + +typedef struct __attribute__((objc_boxable)) _some_struct { + int dummy; +} some_struct; + id testArray(int idx, id p) { NSMutableArray *array; array[idx] = p; @@ -44,4 +52,9 @@ void testDict(NSString *key, id newObjec NSDictionary *dict = @{ key: newObject, key: oldObject }; } +void testBoxableValue() { + some_struct ss; + id value = @(ss); +} + #endif _______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits