summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/NSAPI.cpp3
-rw-r--r--clang/lib/AST/Type.cpp5
-rw-r--r--clang/lib/CodeGen/CGObjC.cpp34
-rw-r--r--clang/lib/Frontend/MultiplexConsumer.cpp9
-rw-r--r--clang/lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--clang/lib/Sema/Sema.cpp3
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp33
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp127
-rw-r--r--clang/lib/Serialization/ASTCommon.h3
-rw-r--r--clang/lib/Serialization/ASTReaderDecl.cpp10
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp12
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));
+}
OpenPOWER on IntegriCloud