diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/NSAPI.cpp | 3 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 5 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 34 | ||||
-rw-r--r-- | clang/lib/Frontend/MultiplexConsumer.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-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 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTCommon.h | 3 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 12 |
11 files changed, 226 insertions, 14 deletions
diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 2749100e14a..a9b10ed451c 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -30,7 +30,8 @@ IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { "NSNumber", "NSMutableSet", "NSCountedSet", - "NSMutableOrderedSet" + "NSMutableOrderedSet", + "NSValue" }; if (!ClassIds[K]) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 3ac11719409..541bd1ebdf8 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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(); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 9981fccb3e9..747326e4c5b 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -55,13 +55,15 @@ llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E) /// 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 ObjCBoxedExpr *E) { 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, diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp index a53f4d2a5a1..91ee100f639 100644 --- a/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/clang/lib/Frontend/MultiplexConsumer.cpp @@ -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::RedefinedHiddenDefinition(const NamedDecl *D, 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 diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 5e0b283bd77..ea0af924736 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1102,6 +1102,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .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) 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(); diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h index 79d1817159c..f21e8a7ea03 100644 --- a/clang/lib/Serialization/ASTCommon.h +++ b/clang/lib/Serialization/ASTCommon.h @@ -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); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index f27426bd34b..dd0e29cde6c 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -3888,7 +3888,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile, 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, ModuleFile &ModuleFile, } break; } + + case UPD_ADDED_ATTR_TO_RECORD: + AttrVec Attrs; + Reader.ReadAttributes(F, Attrs, Record, Idx); + assert(Attrs.size() == 1); + D->addAttr(Attrs[0]); + break; + } } } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 1a8d616efa8..0d15b17c7ce 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -4621,6 +4621,10 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { 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::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { 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)); +} |