diff options
author | Alex Denisov <1101.debian@gmail.com> | 2015-06-26 05:28:36 +0000 |
---|---|---|
committer | Alex Denisov <1101.debian@gmail.com> | 2015-06-26 05:28:36 +0000 |
commit | fde64956f95c4f8733423be393281d8461a99447 (patch) | |
tree | 5767784a7a1b175d02f7a94e6da29dc83340b53e /clang/lib/Sema | |
parent | b41c0b44af467c9112b696077afa67dc0ad79b5a (diff) | |
download | bcm5719-llvm-fde64956f95c4f8733423be393281d8461a99447.tar.gz bcm5719-llvm-fde64956f95c4f8733423be393281d8461a99447.zip |
[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)];
llvm-svn: 240761
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 33 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 127 |
3 files changed, 154 insertions, 9 deletions
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index db1251f097f..18d7e9dcf54 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -91,8 +91,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, 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), diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 43790c2f37e..b8d08306859 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -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 &S, Decl *D, 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, Scope *scope, Decl *D, 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); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 9947fad70dd..c52b6f55a95 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -563,7 +563,6 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { // 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(SourceRange SR, Expr *ValueExpr) { 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(SourceRange SR, Expr *ValueExpr) { 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(); |