diff --git docs/ObjectiveCLiterals.rst docs/ObjectiveCLiterals.rst
index 8907c1e..7bbee4e 100644
--- docs/ObjectiveCLiterals.rst
+++ docs/ObjectiveCLiterals.rst
@@ -119,8 +119,8 @@ Objective-C provides a new syntax for boxing C expressions:
 
     @( <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,10 @@ types are supported:
     NSString *path = @(getenv("PATH"));       // [NSString stringWithUTF8String:(getenv("PATH"))]
     NSArray *pathComponents = [path componentsSeparatedByString:@":"];
 
+    // NS structs
+    NSValue *center = @(view.center);         // [NSValue valueWithPoint:view.center]
+    NSValue *frame = @(view.frame);           // [NSValue valueWithRect:view.frame]
+
 Boxed Enums
 -----------
 
@@ -218,6 +222,24 @@ character data is valid. Passing ``NULL`` as the character pointer will
 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 some C structures can be used:
+
+.. code-block:: objc
+
+    NSPoint p;
+    NSValue *point = @(p);          // valueWithPoint:
+    NSSize s;
+    NSValue *size = @(s);           // valueWithSize:
+
+The following list of structs supported, depends on target system:
+
+  - OSX: ``NSPoint``, ``NSSize``, ``NSRect``, ``NSRange``, ``NSEdgeInsets``
+  - iOS: ``CGPoint``, ``CGSize``, ``CGRect``, ``NSRange``, ``NSEdgeInsets``
+
 Container Literals
 ==================
 
@@ -539,6 +561,18 @@ checks. Here are examples of their use:
         }
     #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
diff --git include/clang/AST/Decl.h include/clang/AST/Decl.h
index 3e3d79f..cfec081 100644
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -3195,6 +3195,10 @@ class RecordDecl : public TagDecl {
   /// methods/nested types we allow deserialization of just the fields
   /// when needed.
   mutable bool LoadedFieldsFromExternalStorage : 1;
+
+  /// ObjCBoxable - This is true if this struct can be boxed into NSValue
+  bool ObjCBoxable : 1;
+
   friend class DeclContext;
 
 protected:
@@ -3248,6 +3252,9 @@ public:
 
   bool hasVolatileMember() const { return HasVolatileMember; }
   void setHasVolatileMember (bool val) { HasVolatileMember = val; }
+
+  bool isObjCBoxable() const { return ObjCBoxable; }
+  void setObjCBoxable() { ObjCBoxable = true; }
   
   /// \brief Determines whether this declaration represents the
   /// injected class name.
diff --git include/clang/AST/ExprObjC.h include/clang/AST/ExprObjC.h
index f296e8f..a637d66 100644
--- include/clang/AST/ExprObjC.h
+++ include/clang/AST/ExprObjC.h
@@ -13,7 +13,6 @@
 
 #ifndef LLVM_CLANG_AST_EXPROBJC_H
 #define LLVM_CLANG_AST_EXPROBJC_H
-
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/SelectorLocationsKind.h"
@@ -90,22 +89,31 @@ public:
 /// Also used for boxing non-parenthesized numeric literals;
 /// as in: @42 or \@true (c++/objc++) or \@__yes (c/objc).
 class ObjCBoxedExpr : public Expr {
-  Stmt *SubExpr;
+  Stmt **SubExprs;
   ObjCMethodDecl *BoxingMethod;
   SourceRange Range;
+  unsigned NumSubExprs;
 public:
-  ObjCBoxedExpr(Expr *E, QualType T, ObjCMethodDecl *method,
-                     SourceRange R)
+  ObjCBoxedExpr(const ASTContext &C, ArrayRef<Expr *> Exprs, QualType T,
+                ObjCMethodDecl *method, SourceRange R)
   : Expr(ObjCBoxedExprClass, T, VK_RValue, OK_Ordinary, 
-         E->isTypeDependent(), E->isValueDependent(), 
-         E->isInstantiationDependent(), E->containsUnexpandedParameterPack()), 
-         SubExpr(E), BoxingMethod(method), Range(R) {}
+         false, false, false, false),
+         SubExprs(nullptr), BoxingMethod(method), Range(R),
+         NumSubExprs(0) {
+           setSubExprs(C, Exprs);
+         }
+
   explicit ObjCBoxedExpr(EmptyShell Empty)
-  : Expr(ObjCBoxedExprClass, Empty) {}
-  
-  Expr *getSubExpr() { return cast<Expr>(SubExpr); }
-  const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
+  : Expr(ObjCBoxedExprClass, Empty), SubExprs(nullptr), NumSubExprs(0) {}
   
+  Expr *getSubExpr() { return cast<Expr>(SubExprs[0]); }
+  const Expr *getSubExpr() const { return cast<Expr>(SubExprs[0]); }
+
+  void setNumSubExprs(const ASTContext &C, unsigned NumSubExprs);
+  unsigned getNumSubExprs() const { return NumSubExprs; }
+
+  void setSubExprs(const ASTContext &C, ArrayRef<Expr *> Exprs);
+
   ObjCMethodDecl *getBoxingMethod() const {
     return BoxingMethod; 
   }
@@ -123,15 +131,15 @@ public:
   }
   
   // Iterators
-  child_range children() { return child_range(&SubExpr, &SubExpr+1); }
+  child_range children() { return child_range(SubExprs, SubExprs + NumSubExprs); }
 
   typedef ConstExprIterator const_arg_iterator;
 
   const_arg_iterator arg_begin() const {
-    return reinterpret_cast<Stmt const * const*>(&SubExpr);
+    return SubExprs;
   }
   const_arg_iterator arg_end() const {
-    return reinterpret_cast<Stmt const * const*>(&SubExpr + 1);
+    return SubExprs + NumSubExprs;
   }
   
   friend class ASTStmtReader;
diff --git include/clang/AST/NSAPI.h include/clang/AST/NSAPI.h
index c1b6664..b076dc9 100644
--- include/clang/AST/NSAPI.h
+++ include/clang/AST/NSAPI.h
@@ -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,
diff --git include/clang/AST/Type.h include/clang/AST/Type.h
index 5db43b4..194d558 100644
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -1564,6 +1564,7 @@ public:
   bool isRecordType() const;
   bool isClassType() const;
   bool isStructureType() const;
+  bool isObjCBoxableStructureType() const;
   bool isInterfaceType() const;
   bool isStructureOrClassType() const;
   bool isUnionType() const;
diff --git include/clang/Basic/Attr.td include/clang/Basic/Attr.td
index 05a399a..982a579 100644
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1102,6 +1102,13 @@ def ObjCRuntimeName : Attr {
   let Documentation = [ObjCRuntimeNameDocs];
 }
 
+def ObjCBoxable : Attr {
+  let Spellings = [GNU<"objc_boxable">];
+  let Subjects = SubjectList<[Struct, TypedefName], ErrorDiag,
+        "ExpectedStructOrTypedef">;
+  let Documentation = [Undocumented];
+}
+
 def OptimizeNone : InheritableAttr {
   let Spellings = [GNU<"optnone">, CXX11<"clang", "optnone">];
   let Subjects = SubjectList<[Function, ObjCMethod]>;
diff --git include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/DiagnosticSemaKinds.td
index 03635ab..0fc6c99 100644
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2059,6 +2059,8 @@ def err_attr_objc_ownership_redundant : Error<
   "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<
diff --git include/clang/Sema/Sema.h include/clang/Sema/Sema.h
index 3f31071..f1167fd 100644
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -641,9 +641,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];
 
@@ -656,6 +662,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;
 
@@ -4836,9 +4845,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,
diff --git lib/AST/Expr.cpp lib/AST/Expr.cpp
index d4ec271..028bdf3 100644
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -4115,6 +4115,34 @@ Stmt::child_range UnaryExprOrTypeTraitExpr::children() {
   return child_range(&Argument.Ex, &Argument.Ex + 1);
 }
 
+// ObjCBoxedExpr
+void ObjCBoxedExpr::setSubExprs(const clang::ASTContext &C,
+                                ArrayRef<clang::Expr *> Exprs) {
+  unsigned NumSubExprs = Exprs.size();
+
+  Stmt **NewSubExprs = new (C) Stmt*[NumSubExprs];
+  for (unsigned i = 0; i != NumSubExprs; i++) {
+    Expr *E = Exprs[i];
+    if (E->isTypeDependent())
+      setTypeDependent(true);
+    if (E->isValueDependent())
+      setValueDependent(true);
+    if (E->isInstantiationDependent())
+      setInstantiationDependent(true);
+    if (E->containsUnexpandedParameterPack())
+      setContainsUnexpandedParameterPack(true);
+
+    NewSubExprs[i] = E;
+  }
+
+  if (SubExprs) {
+    C.Deallocate(SubExprs);
+  }
+
+  SubExprs = NewSubExprs;
+  this->NumSubExprs = NumSubExprs;
+}
+
 // ObjCMessageExpr
 Stmt::child_range ObjCMessageExpr::children() {
   Stmt **begin;
diff --git lib/AST/NSAPI.cpp lib/AST/NSAPI.cpp
index 033a87b..933051e 100644
--- lib/AST/NSAPI.cpp
+++ 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 lib/AST/Type.cpp lib/AST/Type.cpp
index 0e8b1e8..ebc7eb8 100644
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -364,6 +364,11 @@ bool Type::isStructureType() const {
     return RT->getDecl()->isStruct();
   return false;
 }
+bool Type::isObjCBoxableStructureType() const {
+  if (const RecordType *RT = getAs<RecordType>())
+    return RT->getDecl()->isStruct() && RT->getDecl()->isObjCBoxable();
+  return false;
+}
 bool Type::isInterfaceType() const {
   if (const RecordType *RT = getAs<RecordType>())
     return RT->getDecl()->isInterface();
diff --git lib/CodeGen/CGObjC.cpp lib/CodeGen/CGObjC.cpp
index dfad13a..6dc577c 100644
--- lib/CodeGen/CGObjC.cpp
+++ lib/CodeGen/CGObjC.cpp
@@ -55,7 +55,8 @@ 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) {
diff --git lib/Lex/PPMacroExpansion.cpp lib/Lex/PPMacroExpansion.cpp
index 3ceba05..d591e1f 100644
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -912,6 +912,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 lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclAttr.cpp
index fa61b97..bc2d707 100644
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -3847,6 +3847,24 @@ static void handleObjCRuntimeName(Sema &S, Decl *D,
                                  Attr.getAttributeSpellingListIndex()));
 }
 
+static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) {
+  RecordDecl *RD = nullptr;
+  if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+    const RecordType *RT = TD->getUnderlyingType()->getAs<RecordType>();
+    RD = RT->getDecl();
+  } else {
+    RD = dyn_cast<RecordDecl>(D);
+  }
+
+  if (RD) {
+    RD->setObjCBoxable();
+  }
+
+  D->addAttr(::new (S.Context)
+             ObjCBoxableAttr(Attr.getRange(), S.Context,
+                             Attr.getAttributeSpellingListIndex()));
+}
+
 static void handleObjCOwnershipAttr(Sema &S, Decl *D,
                                     const AttributeList &Attr) {
   if (hasDeclarator(D)) return;
@@ -4578,6 +4596,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 lib/Sema/SemaExprObjC.cpp lib/Sema/SemaExprObjC.cpp
index 52a384f..53105cf 100644
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -305,7 +305,7 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
   
   // Use the effective source range of the literal, including the leading '@'.
   return MaybeBindToTemporary(
-           new (Context) ObjCBoxedExpr(Number, NSNumberPointer, Method,
+           new (Context) ObjCBoxedExpr(Context, Number, NSNumberPointer, Method,
                                        SourceRange(AtLoc, NR.getEnd())));
 }
 
@@ -446,7 +446,8 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
 ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
   if (ValueExpr->isTypeDependent()) {
     ObjCBoxedExpr *BoxedExpr = 
-      new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, nullptr, SR);
+      new (Context) ObjCBoxedExpr(Context, ValueExpr, Context.DependentTy,
+                                  nullptr, SR);
     return BoxedExpr;
   }
   ObjCMethodDecl *BoxingMethod = nullptr;
@@ -456,12 +457,65 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
   if (RValue.isInvalid()) {
     return ExprError();
   }
+
+  MutableArrayRef<Expr *> Args;
+  unsigned NumArgs;
+
   ValueExpr = RValue.get();
   QualType ValueType(ValueExpr->getType());
-  if (const PointerType *PT = ValueType->getAs<PointerType>()) {
-    QualType PointeeType = PT->getPointeeType();
-    if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) {
+  if (ValueType->isBuiltinType() || ValueType->isEnumeralType()) {
+    // We support numeric, char, BOOL/bool and Enum types.
+    // Enum types treat as Integer.
+    // Check for a top-level character literal.
+    if (const CharacterLiteral *Char =
+        dyn_cast<CharacterLiteral>(ValueExpr->IgnoreParens())) {
+      // In C, character literals have type 'int'. That's not the type we want
+      // to use to determine the Objective-c literal kind.
+      switch (Char->getKind()) {
+      case CharacterLiteral::Ascii:
+        ValueType = Context.CharTy;
+        break;
+
+      case CharacterLiteral::Wide:
+        ValueType = Context.getWideCharType();
+        break;
+
+      case CharacterLiteral::UTF16:
+        ValueType = Context.Char16Ty;
+        break;
+
+      case CharacterLiteral::UTF32:
+        ValueType = Context.Char32Ty;
+        break;
+      }
+    }
+
+    if (const EnumType *ET = ValueType->getAs<EnumType>()) {
+      if (!ET->getDecl()->isComplete()) {
+        Diag(SR.getBegin(), diag::err_objc_incomplete_boxed_expression_type)
+        << ValueType << ValueExpr->getSourceRange();
+        return ExprError();
+      }
+
+      ValueType = ET->getDecl()->getIntegerType();
+    }
+
+    CheckForIntOverflow(ValueExpr);
+    // FIXME:  Do I need to do anything special with BoolTy expressions?
+
+    // Look for the appropriate method within NSNumber.
+    BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(), ValueType);
+    BoxedType = NSNumberPointer;
+
+    NumArgs = 1;
+    SmallVector<Expr *, 1> ArgsV;
+    ArgsV.push_back(ValueExpr);
+    Args = ArgsV;
+  } else if (const PointerType *PT = ValueType->getAs<PointerType>()) {
+    // Support of NSString construction
 
+    // Check if we can construct NSString from chars
+    if (Context.hasSameUnqualifiedType(PT->getPointeeType(), Context.CharTy)) {
       if (!NSStringDecl) {
         IdentifierInfo *NSStringId =
           NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
@@ -527,53 +581,137 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
       
       BoxingMethod = StringWithUTF8StringMethod;
       BoxedType = NSStringPointer;
+
+      NumArgs = 1;
+      SmallVector<Expr *, 1> ArgsV;
+      ArgsV.push_back(ValueExpr);
+      Args = ArgsV;
     }
-  } else if (ValueType->isBuiltinType()) {
-    // The other types we support are numeric, char and BOOL/bool. We could also
-    // provide limited support for structure types, such as NSRange, NSRect, and
-    // NSSize. See NSValue (NSValueGeometryExtensions) in <Foundation/NSGeometry.h>
-    // for more details.
+  } else if (ValueType->isObjCBoxableStructureType()) {
+    // Support for structure types, that marked as objc_boxable
+    // struct s { ... } __attribute__((objc_boxable));
+
+    // 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();
+      }
 
-    // Check for a top-level character literal.
-    if (const CharacterLiteral *Char =
-        dyn_cast<CharacterLiteral>(ValueExpr->IgnoreParens())) {
-      // In C, character literals have type 'int'. That's not the type we want
-      // to use to determine the Objective-c literal kind.
-      switch (Char->getKind()) {
-      case CharacterLiteral::Ascii:
-        ValueType = Context.CharTy;
-        break;
-        
-      case CharacterLiteral::Wide:
-        ValueType = Context.getWideCharType();
-        break;
-        
-      case CharacterLiteral::UTF16:
-        ValueType = Context.Char16Ty;
-        break;
-        
-      case CharacterLiteral::UTF32:
-        ValueType = Context.Char32Ty;
-        break;
+      // 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 NSString 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;
     }
-    CheckForIntOverflow(ValueExpr);
-    // FIXME:  Do I need to do anything special with BoolTy expressions?
-    
-    // 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)
-        << ValueType << ValueExpr->getSourceRange();
+    BoxingMethod = ValueWithBytesObjCTypeMethod;
+    BoxedType = NSValuePointer;
+
+    QualType ExprPtrType = Context.getPointerType(ValueExpr->getType());
+    SourceLocation ESL = ValueExpr->getSourceRange().getBegin();
+    UnaryOperator *UO = new (Context) UnaryOperator(ValueExpr, UO_AddrOf,
+                                                    ExprPtrType,
+                                                    VK_RValue, OK_Ordinary,
+                                                    ESL);
+    CXXCastPath Path;
+    QualType ConstVoidType = Context.getPointerType(Context.VoidTy.withConst());
+    ImplicitCastExpr *ICE = ImplicitCastExpr::Create(Context,
+                                                     ConstVoidType,
+                                                     CK_BitCast,
+                                                     UO,
+                                                     &Path,
+                                                     VK_RValue);
+
+    NumArgs = 2;
+    SmallVector<Expr *, 2> ArgsV;
+    ArgsV.push_back(ICE);
+
+    TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(ValueExpr->getType());
+    ExprResult OEE = BuildObjCEncodeExpression(SourceLocation(),
+                                               TSI,
+                                               SourceLocation());
+    if (OEE.isInvalid()) {
       return ExprError();
     }
-
-    BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(),
-                                            ET->getDecl()->getIntegerType());
-    BoxedType = NSNumberPointer;
+    ArgsV.push_back(OEE.get());
+    Args = ArgsV;
   }
 
   if (!BoxingMethod) {
@@ -582,20 +720,25 @@ 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);
-  if (ConvertedValueExpr.isInvalid())
-    return ExprError();
-  ValueExpr = ConvertedValueExpr.get();
-  
+  DiagnoseUseOfDecl(BoxingMethod, SR.getBegin());
+
+  for (unsigned i = 0; i < NumArgs; i++) {
+    Expr *E = Args[i];
+    // Convert the expression to the type that the parameter requires.
+    ParmVarDecl *ParamDecl = BoxingMethod->parameters()[i];
+    InitializedEntity IE = InitializedEntity::InitializeParameter(Context,
+                                                                  ParamDecl);
+    ExprResult ConvertedValueExpr = PerformCopyInitialization(IE,
+                                                              SourceLocation(),
+                                                              E);
+    if (ConvertedValueExpr.isInvalid())
+      return ExprError();
+    Args[i] = ConvertedValueExpr.get();
+  }
+
   ObjCBoxedExpr *BoxedExpr = 
-    new (Context) ObjCBoxedExpr(ValueExpr, BoxedType,
-                                      BoxingMethod, SR);
+    new (Context) ObjCBoxedExpr(Context, Args, BoxedType,
+                                BoxingMethod, SR);
   return MaybeBindToTemporary(BoxedExpr);
 }
 
diff --git lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTReaderStmt.cpp
index e40b1d9..5a3d370 100644
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -923,7 +923,7 @@ void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
 void ASTStmtReader::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   VisitExpr(E);
   // could be one of several IntegerLiteral, FloatLiteral, etc.
-  E->SubExpr = Reader.ReadSubStmt();
+  E->setSubExprs(Reader.getContext(), Reader.ReadSubExpr());
   E->BoxingMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
   E->Range = ReadSourceRange(Record, Idx);
 }
diff --git lib/Serialization/ASTWriterStmt.cpp lib/Serialization/ASTWriterStmt.cpp
index 97ed06f..609f1ca 100644
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -868,7 +868,8 @@ void ASTStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
 
 void ASTStmtWriter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   VisitExpr(E);
-  Writer.AddStmt(E->getSubExpr());
+  for (auto SE : E->children())
+    Writer.AddStmt(SE);
   Writer.AddDeclRef(E->getBoxingMethod(), Record);
   Writer.AddSourceRange(E->getSourceRange(), Record);
   Code = serialization::EXPR_OBJC_BOXED_EXPRESSION;
diff --git test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h
new file mode 100644
index 0000000..f1244c8
--- /dev/null
+++ test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h
@@ -0,0 +1,61 @@
+#ifndef NSVALUE_BOXED_EXPRESSIONS_SUPPORT_H
+#define NSVALUE_BOXED_EXPRESSIONS_SUPPORT_H
+
+#define BOXABLE __attribute__((objc_boxable))
+
+typedef unsigned long NSUInteger;
+typedef double CGFloat;
+
+BOXABLE typedef struct _NSRange {
+    NSUInteger location;
+    NSUInteger length;
+} NSRange;
+
+BOXABLE typedef struct _NSPoint {
+    CGFloat x;
+    CGFloat y;
+} NSPoint;
+
+BOXABLE typedef struct _NSSize {
+    CGFloat width;
+    CGFloat height;
+} NSSize;
+
+BOXABLE typedef struct _NSRect {
+    NSPoint origin;
+    NSSize size;
+} NSRect;
+
+struct CGPoint {
+  CGFloat x;
+  CGFloat y;
+};
+BOXABLE typedef struct CGPoint CGPoint;
+
+struct CGSize {
+  CGFloat width;
+  CGFloat height;
+};
+BOXABLE typedef struct CGSize CGSize;
+
+struct CGRect {
+  CGPoint origin;
+  CGSize size;
+};
+BOXABLE typedef struct CGRect CGRect;
+
+struct NSEdgeInsets {
+  CGFloat top;
+  CGFloat left;
+  CGFloat bottom;
+  CGFloat right;
+};
+BOXABLE typedef struct NSEdgeInsets NSEdgeInsets;
+
+@interface NSValue
+
++ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
+
+@end
+
+#endif // NSVALUE_BOXED_EXPRESSIONS_SUPPORT_H
diff --git test/CodeGenObjC/nsvalue-objc-boxable-ios-arc.m test/CodeGenObjC/nsvalue-objc-boxable-ios-arc.m
new file mode 100644
index 0000000..13b4cc5
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-ios-arc.m
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -I %S/Inputs -triple armv7-apple-ios8.0.0 -emit-llvm -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+#import "nsvalue-boxed-expressions-support.h"
+
+// CHECK:      [[CLASS:@.*]]        = external global %struct._class_t
+// CHECK:      [[NSVALUE:@.*]]      = {{.*}}[[CLASS]]{{.*}}
+// CHECK:      [[RANGE_STR:.*]]     = {{.*}}_NSRange=II{{.*}}
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithBytes:objCType:{{.*}}
+// CHECK:      [[VALUE_SEL:@.*]]    = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[POINT_STR:.*]]     = {{.*}}CGPoint=dd{{.*}}
+// CHECK:      [[SIZE_STR:.*]]      = {{.*}}CGSize=dd{{.*}}
+// CHECK:      [[RECT_STR:.*]]      = {{.*}}CGRect={CGPoint=dd}{CGSize=dd}}{{.*}}
+// CHECK:      [[EDGE_STR:.*]]      = {{.*}}NSEdgeInsets=dddd{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]      = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[RANGE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RANGE_CAST:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RANGE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *range = @(ns_range);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doPoint()
+void doPoint() {
+  // CHECK:      [[POINT:%.*]]      = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[POINT]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[POINT_CAST:%.*]] = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  CGPoint cg_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[POINT_CAST]], i8* {{.*}}[[POINT_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *point = @(cg_point);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doSize()
+void doSize() {
+  // CHECK:      [[SIZE:%.*]]      = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[SIZE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SIZE_CAST:%.*]] = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  CGSize cg_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[SIZE_CAST]], i8* {{.*}}[[SIZE_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *size = @(cg_size);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doRect()
+void doRect() {
+  // CHECK:      [[RECT:%.*]]      = alloca %struct.CGRect{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RECT_CAST:%.*]] = bitcast %struct.CGRect* [[RECT]] to i8*
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]{{.*}}
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  CGPoint cg_point = { .x = 42, .y = 24 };
+  CGSize cg_size = { .width = 42, .height = 24 };
+  CGRect cg_rect = { .origin = cg_point, .size = cg_size };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RECT_CAST]], i8*{{.*}}[[RECT_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *rect = @(cg_rect);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doNSEdgeInsets()
+void doNSEdgeInsets() {
+  // CHECK:      [[EDGE:%.*]]      = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[EDGE_CAST:%.*]] = bitcast %struct.NSEdgeInsets* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[EDGE_CAST]], i8*{{.*}}[[EDGE_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
diff --git test/CodeGenObjC/nsvalue-objc-boxable-ios.m test/CodeGenObjC/nsvalue-objc-boxable-ios.m
new file mode 100644
index 0000000..855a36d
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-ios.m
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -I %S/Inputs -triple armv7-apple-ios8.0.0 -emit-llvm -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+#import "nsvalue-boxed-expressions-support.h"
+
+// CHECK:      [[CLASS:@.*]]        = external global %struct._class_t
+// CHECK:      [[NSVALUE:@.*]]      = {{.*}}[[CLASS]]{{.*}}
+// CHECK:      [[RANGE_STR:.*]]     = {{.*}}_NSRange=II{{.*}}
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithBytes:objCType:{{.*}}
+// CHECK:      [[VALUE_SEL:@.*]]    = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[POINT_STR:.*]]     = {{.*}}CGPoint=dd{{.*}}
+// CHECK:      [[SIZE_STR:.*]]      = {{.*}}CGSize=dd{{.*}}
+// CHECK:      [[RECT_STR:.*]]      = {{.*}}CGRect={CGPoint=dd}{CGSize=dd}}{{.*}}
+// CHECK:      [[EDGE_STR:.*]]      = {{.*}}NSEdgeInsets=dddd{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]      = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[RANGE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RANGE_CAST:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RANGE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  NSValue *range = @(ns_range);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doPoint()
+void doPoint() {
+  // CHECK:      [[POINT:%.*]]      = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[POINT]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[POINT_CAST:%.*]] = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  CGPoint cg_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[POINT_CAST]], i8* {{.*}}[[POINT_STR]]{{.*}})
+  NSValue *point = @(cg_point);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doSize()
+void doSize() {
+  // CHECK:      [[SIZE:%.*]]      = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[SIZE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SIZE_CAST:%.*]] = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  CGSize cg_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[SIZE_CAST]], i8* {{.*}}[[SIZE_STR]]{{.*}})
+  NSValue *size = @(cg_size);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doRect()
+void doRect() {
+  // CHECK:      [[RECT:%.*]]      = alloca %struct.CGRect{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RECT_CAST:%.*]] = bitcast %struct.CGRect* [[RECT]] to i8*
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]{{.*}}
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  CGPoint cg_point = { .x = 42, .y = 24 };
+  CGSize cg_size = { .width = 42, .height = 24 };
+  CGRect cg_rect = { .origin = cg_point, .size = cg_size };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RECT_CAST]], i8*{{.*}}[[RECT_STR]]{{.*}})
+  NSValue *rect = @(cg_rect);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doNSEdgeInsets()
+void doNSEdgeInsets() {
+  // CHECK:      [[EDGE:%.*]]      = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[EDGE_CAST:%.*]] = bitcast %struct.NSEdgeInsets* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[EDGE_CAST]], i8*{{.*}}[[EDGE_STR]]{{.*}})
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      ret void
+}
+
diff --git test/CodeGenObjC/nsvalue-objc-boxable-mac-arc.m test/CodeGenObjC/nsvalue-objc-boxable-mac-arc.m
new file mode 100644
index 0000000..dd29813
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-mac-arc.m
@@ -0,0 +1,94 @@
+// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-macosx -emit-llvm -fobjc-arc -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+#import "nsvalue-boxed-expressions-support.h"
+
+// CHECK:      [[CLASS:@.*]]        = external global %struct._class_t
+// CHECK:      [[NSVALUE:@.*]]      = {{.*}}[[CLASS]]{{.*}}
+// CHECK:      [[RANGE_STR:.*]]     = {{.*}}_NSRange=QQ{{.*}}
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithBytes:objCType:{{.*}}
+// CHECK:      [[VALUE_SEL:@.*]]    = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[POINT_STR:.*]]     = {{.*}}_NSPoint=dd{{.*}}
+// CHECK:      [[SIZE_STR:.*]]      = {{.*}}_NSSize=dd{{.*}}
+// CHECK:      [[RECT_STR:.*]]      = {{.*}}_NSRect={_NSPoint=dd}{_NSSize=dd}}{{.*}}
+// CHECK:      [[EDGE_STR:.*]]      = {{.*}}NSEdgeInsets=dddd{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]      = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[RANGE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RANGE_CAST:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RANGE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *range = @(ns_range);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doPoint()
+void doPoint() {
+  // CHECK:      [[POINT:%.*]]      = bitcast %struct._NSPoint* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[POINT]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[POINT_CAST:%.*]] = bitcast %struct._NSPoint* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSPoint ns_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[POINT_CAST]], i8* {{.*}}[[POINT_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *point = @(ns_point);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doSize()
+void doSize() {
+  // CHECK:      [[SIZE:%.*]]      = bitcast %struct._NSSize* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[SIZE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SIZE_CAST:%.*]] = bitcast %struct._NSSize* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSSize ns_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[SIZE_CAST]], i8* {{.*}}[[SIZE_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *size = @(ns_size);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doRect()
+void doRect() {
+  // CHECK:      [[RECT:%.*]]      = alloca %struct._NSRect{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RECT_CAST:%.*]] = bitcast %struct._NSRect* [[RECT]] to i8*
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]{{.*}}
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSPoint ns_point = { .x = 42, .y = 24 };
+  NSSize ns_size = { .width = 42, .height = 24 };
+  NSRect ns_rect = { .origin = ns_point, .size = ns_size };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RECT_CAST]], i8*{{.*}}[[RECT_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *rect = @(ns_rect);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doNSEdgeInsets()
+void doNSEdgeInsets() {
+  // CHECK:      [[EDGE:%.*]]      = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[EDGE_CAST:%.*]] = bitcast %struct.NSEdgeInsets* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[EDGE_CAST]], i8*{{.*}}[[EDGE_STR]]{{.*}})
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
diff --git test/CodeGenObjC/nsvalue-objc-boxable-mac.m test/CodeGenObjC/nsvalue-objc-boxable-mac.m
new file mode 100644
index 0000000..27e3c7c
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-mac.m
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -I %S/Inputs -triple x86_64-apple-macosx -emit-llvm -O2 -disable-llvm-optzns -o - %s | FileCheck %s
+
+#import "nsvalue-boxed-expressions-support.h"
+
+// CHECK:      [[CLASS:@.*]]        = external global %struct._class_t
+// CHECK:      [[NSVALUE:@.*]]      = {{.*}}[[CLASS]]{{.*}}
+// CHECK:      [[RANGE_STR:.*]]     = {{.*}}_NSRange=QQ{{.*}}
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithBytes:objCType:{{.*}}
+// CHECK:      [[VALUE_SEL:@.*]]    = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[POINT_STR:.*]]     = {{.*}}_NSPoint=dd{{.*}}
+// CHECK:      [[SIZE_STR:.*]]      = {{.*}}_NSSize=dd{{.*}}
+// CHECK:      [[RECT_STR:.*]]      = {{.*}}_NSRect={_NSPoint=dd}{_NSSize=dd}}{{.*}}
+// CHECK:      [[EDGE_STR:.*]]      = {{.*}}NSEdgeInsets=dddd{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]      = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[RANGE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RANGE_CAST:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RANGE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  NSValue *range = @(ns_range);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doPoint()
+void doPoint() {
+  // CHECK:      [[POINT:%.*]]      = bitcast %struct._NSPoint* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[POINT]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]   = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[POINT_CAST:%.*]] = bitcast %struct._NSPoint* {{.*}}
+  // CHECK:      [[SEL:%.*]]        = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]       = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSPoint ns_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[POINT_CAST]], i8* {{.*}}[[POINT_STR]]{{.*}})
+  NSValue *point = @(ns_point);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doSize()
+void doSize() {
+  // CHECK:      [[SIZE:%.*]]      = bitcast %struct._NSSize* {{.*}}
+  // CHECK:      call void @llvm.memcpy{{.*}}[[SIZE]]{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SIZE_CAST:%.*]] = bitcast %struct._NSSize* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSSize ns_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[SIZE_CAST]], i8* {{.*}}[[SIZE_STR]]{{.*}})
+  NSValue *size = @(ns_size);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doRect()
+void doRect() {
+  // CHECK:      [[RECT:%.*]]      = alloca %struct._NSRect{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[RECT_CAST:%.*]] = bitcast %struct._NSRect* [[RECT]] to i8*
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]{{.*}}
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSPoint ns_point = { .x = 42, .y = 24 };
+  NSSize ns_size = { .width = 42, .height = 24 };
+  NSRect ns_rect = { .origin = ns_point, .size = ns_size };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[RECT_CAST]], i8*{{.*}}[[RECT_STR]]{{.*}})
+  NSValue *rect = @(ns_rect);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doNSEdgeInsets()
+void doNSEdgeInsets() {
+  // CHECK:      [[EDGE:%.*]]      = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[EDGE_CAST:%.*]] = bitcast %struct.NSEdgeInsets* {{.*}}
+  // CHECK:      [[SEL:%.*]]       = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[EDGE_CAST]], i8*{{.*}}[[EDGE_STR]]{{.*}})
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      ret void
+}
+
diff --git test/Lexer/has_attribute_objc_boxable.m test/Lexer/has_attribute_objc_boxable.m
new file mode 100644
index 0000000..e172ecaba
--- /dev/null
+++ test/Lexer/has_attribute_objc_boxable.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -E %s -o - | FileCheck %s
+
+#if __has_attribute(objc_boxable)
+int has_objc_boxable_attribute();
+#endif
+
+// CHECK: has_objc_boxable_attribute
+
diff --git test/Lexer/has_feature_boxed_nsvalue_expressions.m test/Lexer/has_feature_boxed_nsvalue_expressions.m
new file mode 100644
index 0000000..8c66bcb
--- /dev/null
+++ test/Lexer/has_feature_boxed_nsvalue_expressions.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -E %s -o - | FileCheck %s
+
+#if __has_feature(objc_boxed_nsvalue_expressions)
+int has_objc_boxed_nsvalue_expressions();
+#endif
+
+// CHECK: has_objc_boxed_nsvalue_expressions
+
diff --git test/SemaObjC/objc-boxed-expressions-nsvalue.m test/SemaObjC/objc-boxed-expressions-nsvalue.m
new file mode 100644
index 0000000..bf38d09
--- /dev/null
+++ test/SemaObjC/objc-boxed-expressions-nsvalue.m
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1  -fsyntax-only -triple x86_64-apple-macosx10.9 -verify %s
+
+#define BOXABLE __attribute__((objc_boxable))
+
+typedef struct _NSPoint {
+  int dummy;
+} NSPoint BOXABLE;
+
+typedef struct _NSSize {
+  int dummy;
+} NSSize BOXABLE;
+
+typedef struct _NSRect {
+  int dummy;
+} NSRect BOXABLE;
+
+typedef struct _CGPoint {
+  int dummy;
+} CGPoint BOXABLE;
+
+typedef struct _CGSize {
+  int dummy;
+} CGSize BOXABLE;
+
+typedef struct _CGRect {
+  int dummy;
+} CGRect BOXABLE;
+
+typedef struct _NSRange {
+  int dummy;
+} NSRange BOXABLE;
+
+typedef struct _NSEdgeInsets {
+  int dummy;
+} NSEdgeInsets;
+
+BOXABLE typedef struct _NSEdgeInsets NSEdgeInsets;
+
+typedef struct _SomeStruct {
+  double d;
+} SomeStruct;
+
+void checkNSValueDiagnostic() {
+  NSRect rect;
+  id value = @(rect); // expected-error{{NSValue must be available to use Objective-C boxed expressions}}
+}
+
+@interface NSValue
+
++ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
+
+@end
+
+int main() {
+  NSPoint ns_point;
+  id ns_point_value = @(ns_point);
+
+  NSSize ns_size;
+  id ns_size_value = @(ns_size);
+
+  NSRect ns_rect;
+  id ns_rect_value = @(ns_rect);
+
+  CGPoint cg_point;
+  id cg_point_value = @(cg_point);
+
+  CGSize cg_size;
+  id cg_size_value = @(cg_size);
+
+  CGRect cg_rect;
+  id cg_rect_value = @(cg_rect);
+
+  NSRange ns_range;
+  id ns_range_value = @(ns_range);
+
+  NSEdgeInsets edge_insets;
+  id edge_insets_object = @(edge_insets);
+
+  SomeStruct s;
+  id err = @(s); // expected-error{{illegal type 'SomeStruct' (aka 'struct _SomeStruct') used in a boxed expression}}
+}
