diff --git docs/ObjectiveCLiterals.rst docs/ObjectiveCLiterals.rst
index 8907c1e..cede83d 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,12 @@ types are supported:
     NSString *path = @(getenv("PATH"));       // [NSString stringWithUTF8String:(getenv("PATH"))]
     NSArray *pathComponents = [path componentsSeparatedByString:@":"];
 
+    // NS structs
+    NSValue *center = @(view.center);         // Point p = view.point;
+                                              // [NSValue valueWithBytes:&p objCType:@encode(Point)];
+    NSValue *frame = @(view.frame);           // Rect r = view.frame;
+                                              // [NSValue valueWithBytes:&r objCType:@encode(Rect)];
+
 Boxed Enums
 -----------
 
@@ -218,6 +224,42 @@ character data is valid. Passing ``NULL`` 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 C structures can be used, the only requirement is:
+structure should be marked with ``objc_boxable`` attribute.
+To support older version of frameworks and/or third-party libraries
+you may need to add the attribute via ``typedef``.
+
+.. code-block:: objc
+
+    struct Point {
+        // ...
+    } __attribute__((objc_boxable));
+
+    typedef struct _Size {
+        // ...
+    } Size __attribute__((objc_boxable));
+
+    typedef struct _Rect {
+        // ...
+    } Rect;
+
+    struct Point p;
+    NSValue *point = @(p);          // ok
+    Size s;
+    NSValue *size = @(s);           // ok
+
+    Rect r;
+    NSValue *bad_rect = @(r);       // error
+
+    __attribute__((objc_boxable)) typedef struct _Rect Rect;
+
+    NSValue *good_rect = @(r);      // ok
+
+
 Container Literals
 ==================
 
@@ -539,6 +581,22 @@ checks. Here are examples of their use:
         }
     #endif
 
+    #if __has_attribute(objc_boxable)
+        __attribute__((objc_boxable)) typedef struct _Rect Rect;
+    #endif
+
+    #if __has_feature(objc_boxed_nsvalue_expressions)
+        CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"];
+        animation.fromValue = @(layer.position);
+        animation.toValue = @(newPosition);
+        [layer addAnimation:animation forKey:@"move"];
+    #else
+        CABasicAnimation animation = [CABasicAnimation animationWithKeyPath:@"position"];
+        animation.fromValue = [NSValue valueWithCGPoint:layer.position];
+        animation.toValue = [NSValue valueWithCGPoint:newPosition];
+        [layer addAnimation:animation forKey:@"move"];
+    #endif
+
 Code can use also ``__has_feature(objc_bool)`` to check for the
 availability of numeric literals support. This checks for the new
 ``__objc_yes / __objc_no`` keywords, which enable the use of
diff --git docs/ReleaseNotes.rst docs/ReleaseNotes.rst
index c6dc6aa..6774da5 100644
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -48,9 +48,10 @@ Major New Features
 ------------------
 
 - Use of the ``__declspec`` language extension for declaration attributes now
-  requires passing the -fms-extensions or -fborland compiler flag. This language
-  extension is also enabled when compiling CUDA code, but its use should be
-  viewed as an implementation detail that is subject to change.
+requires passing the -fms-extensions or -fborland compiler flag. This language
+extension is also enabled when compiling CUDA code, but its use should be
+viewed as an implementation detail that is subject to change.
+
 
 Improvements to Clang's diagnostics
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git include/clang/AST/Decl.h include/clang/AST/Decl.h
index 451f9da..8a39c22 100644
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -3244,6 +3244,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:
@@ -3297,6 +3301,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..c2339c2 100644
--- include/clang/AST/ExprObjC.h
+++ include/clang/AST/ExprObjC.h
@@ -86,28 +86,58 @@ public:
 };
 
 /// ObjCBoxedExpr - used for generalized expression boxing.
-/// as in: @(strdup("hello world")) or @(random())
+/// as in: @(strdup("hello world")), @(random()) or @(view.frame)
 /// Also used for boxing non-parenthesized numeric literals;
 /// as in: @42 or \@true (c++/objc++) or \@__yes (c/objc).
 class ObjCBoxedExpr : public Expr {
-  Stmt *SubExpr;
+  // Most expressions need only one sub-expression (e.g. @("hello world")),
+  // but NSValue expressions need two parameters:
+  // actual expression (e.g. view.frame) and @encode (e.g. @encode(CGRect))
+  SmallVector<Stmt *, 2> SubExprs;
   ObjCMethodDecl *BoxingMethod;
   SourceRange Range;
+  unsigned NumSubExprs;
 public:
-  ObjCBoxedExpr(Expr *E, QualType T, ObjCMethodDecl *method,
-                     SourceRange R)
+  ObjCBoxedExpr(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(2), BoxingMethod(method), Range(R),
+         NumSubExprs(0) {
+           setSubExprs(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(2), NumSubExprs(0) {}
   
+  Expr *getSubExpr(int n) { return cast<Expr>(SubExprs[n]); }
+  const Expr *getSubExpr(int n) const { return cast<Expr>(SubExprs[n]); }
+
+  unsigned getNumSubExprs() const { return NumSubExprs; }
+
+  void setSubExprs(ArrayRef<Expr *> Exprs) {
+    unsigned NumSubExprs = Exprs.size();
+    assert(NumSubExprs < 3 && "Too many sub-expressions");
+
+    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);
+
+      SubExprs[i] = E;
+    }
+    
+    this->NumSubExprs = NumSubExprs;
+  }
+
   ObjCMethodDecl *getBoxingMethod() const {
-    return BoxingMethod; 
+    return BoxingMethod;
   }
   
   SourceLocation getAtLoc() const { return Range.getBegin(); }
@@ -123,15 +153,16 @@ public:
   }
   
   // Iterators
-  child_range children() { return child_range(&SubExpr, &SubExpr+1); }
+  child_range children() { return child_range(SubExprs.data(),
+                                              SubExprs.data() + NumSubExprs); }
 
   typedef ConstExprIterator const_arg_iterator;
 
   const_arg_iterator arg_begin() const {
-    return reinterpret_cast<Stmt const * const*>(&SubExpr);
+    return SubExprs.data();
   }
   const_arg_iterator arg_end() const {
-    return reinterpret_cast<Stmt const * const*>(&SubExpr + 1);
+    return SubExprs.data() + NumSubExprs;
   }
   
   friend class ASTStmtReader;
diff --git include/clang/AST/NSAPI.h include/clang/AST/NSAPI.h
index fc994c1..ce2c7ce 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 8cd29b7..043d8e5 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 c310d25..9c071e1 100644
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -1108,6 +1108,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 9ccd5ad..59517bb 100644
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2080,6 +2080,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 a702058..c3ea341 100644
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -653,9 +653,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];
 
@@ -668,6 +674,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;
 
@@ -4923,9 +4932,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/NSAPI.cpp lib/AST/NSAPI.cpp
index 2749100..a9b10ed 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/StmtPrinter.cpp lib/AST/StmtPrinter.cpp
index dc4f996..2fb520a 100644
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -2069,7 +2069,7 @@ void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
 
 void StmtPrinter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   OS << "@";
-  Visit(E->getSubExpr());
+  Visit(E->getSubExpr(0));
 }
 
 void StmtPrinter::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
diff --git lib/AST/Type.cpp lib/AST/Type.cpp
index 09bb769..7cbb9ed 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 ef9a92d..4855d94 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/Frontend/Rewrite/RewriteModernObjC.cpp lib/Frontend/Rewrite/RewriteModernObjC.cpp
index e13cdb3..28fed79 100644
--- lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -2677,7 +2677,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
   MsgExprs.push_back(SelExp);
   
   // User provided sub-expression is the 3rd, and last, argument.
-  Expr *subExpr  = Exp->getSubExpr();
+  Expr *subExpr  = Exp->getSubExpr(0);
   if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(subExpr)) {
     QualType type = ICE->getType();
     const Expr *SubExpr = ICE->IgnoreParenImpCasts();
diff --git lib/Lex/PPMacroExpansion.cpp lib/Lex/PPMacroExpansion.cpp
index 9046ad5..82395c4 100644
--- lib/Lex/PPMacroExpansion.cpp
+++ lib/Lex/PPMacroExpansion.cpp
@@ -1101,6 +1101,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 31fe055..84c36f1 100644
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -3906,6 +3906,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;
@@ -4674,6 +4692,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/SemaExpr.cpp lib/Sema/SemaExpr.cpp
index 7ab269c..07f0ae1 100644
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -8231,7 +8231,7 @@ Sema::ObjCLiteralKind Sema::CheckLiteralKind(Expr *FromE) {
     case Stmt::BlockExprClass:
       return LK_Block;
     case Stmt::ObjCBoxedExprClass: {
-      Expr *Inner = cast<ObjCBoxedExpr>(FromE)->getSubExpr()->IgnoreParens();
+      Expr *Inner = cast<ObjCBoxedExpr>(FromE)->getSubExpr(0)->IgnoreParens();
       switch (Inner->getStmtClass()) {
         case Stmt::IntegerLiteralClass:
         case Stmt::FloatingLiteralClass:
diff --git lib/Sema/SemaExprObjC.cpp lib/Sema/SemaExprObjC.cpp
index 63b7485..0a8ea89 100644
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -456,12 +456,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 +580,140 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
       
       BoxingMethod = StringWithUTF8StringMethod;
       BoxedType = NSStringPointer;
-    }
-  } 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.
 
-    // 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;
+      NumArgs = 1;
+      SmallVector<Expr *, 1> ArgsV;
+      ArgsV.push_back(ValueExpr);
+      Args = ArgsV;
+    }
+  } 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();
       }
+
+      // generate the pointer to NSValue type.
+      QualType NSValueObject = Context.getObjCInterfaceType(NSValueDecl);
+      NSValuePointer = Context.getObjCObjectPointerType(NSValueObject);
     }
-    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();
-      return ExprError();
+    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;
     }
 
-    BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(),
-                                            ET->getDecl()->getIntegerType());
-    BoxedType = NSNumberPointer;
+    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);
+
+    std::string Str;
+    Context.getObjCEncodingForType(ValueExpr->getType(), Str);
+
+    llvm::APInt ArrSize = llvm::APInt(32, Str.size() + 1);
+    QualType StrType = Context.getConstantArrayType(Context.CharTy,
+                                                    ArrSize, ArrayType::Normal,
+                                                     0);
+    StringLiteral *SL = StringLiteral::Create(Context, Str, StringLiteral::Ascii,
+                                 /*Pascal=*/false, StrType, SourceLocation());
+
+    ArgsV.push_back(SL);
+    Args = ArgsV;
   }
 
   if (!BoxingMethod) {
@@ -582,20 +722,24 @@ 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(Args, BoxedType, BoxingMethod, SR);
   return MaybeBindToTemporary(BoxedExpr);
 }
 
diff --git lib/Sema/TreeTransform.h lib/Sema/TreeTransform.h
index f5249fd..36e7310 100644
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -9834,12 +9834,12 @@ TreeTransform<Derived>::TransformObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformObjCBoxedExpr(ObjCBoxedExpr *E) {
-  ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+  ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr(0));
   if (SubExpr.isInvalid())
     return ExprError();
 
   if (!getDerived().AlwaysRebuild() &&
-      SubExpr.get() == E->getSubExpr())
+      SubExpr.get() == E->getSubExpr(0))
     return E;
 
   return getDerived().RebuildObjCBoxedExpr(E->getSourceRange(), SubExpr.get());
diff --git lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTReaderStmt.cpp
index d1ecd46..47e9ab3 100644
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -922,8 +922,13 @@ void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
 
 void ASTStmtReader::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   VisitExpr(E);
-  // could be one of several IntegerLiteral, FloatLiteral, etc.
-  E->SubExpr = Reader.ReadSubStmt();
+  unsigned NumSubExprs = Record[Idx++];
+  assert(NumSubExprs <= 2 && "can hold up to two sub-expressions");
+  SmallVector<Expr *, 2> SubExprs;
+  for (unsigned I = 0; I < NumSubExprs; I++) {
+    SubExprs.push_back(Reader.ReadSubExpr());
+  }
+  E->setSubExprs(SubExprs);
   E->BoxingMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
   E->Range = ReadSourceRange(Record, Idx);
 }
diff --git lib/Serialization/ASTWriterStmt.cpp lib/Serialization/ASTWriterStmt.cpp
index ec822f0..5d75218 100644
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -868,7 +868,10 @@ void ASTStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
 
 void ASTStmtWriter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   VisitExpr(E);
-  Writer.AddStmt(E->getSubExpr());
+  Record.push_back(E->getNumSubExprs());
+  for (unsigned i = 0; i < E->getNumSubExprs(); i++) {
+    Writer.AddStmt(E->getSubExpr(i));
+  }
   Writer.AddDeclRef(E->getBoxingMethod(), Record);
   Writer.AddSourceRange(E->getSourceRange(), Record);
   Code = serialization::EXPR_OBJC_BOXED_EXPRESSION;
diff --git lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 58c27d4..a32aebb 100644
--- lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -1905,7 +1905,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
       os << "NSDictionary literal is an object with a +0 retain count";
     }
     else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
-      if (isNumericLiteralExpression(BL->getSubExpr()))
+      if (isNumericLiteralExpression(BL->getSubExpr(0)))
         os << "NSNumber literal is an object with a +0 retain count";
       else {
         const ObjCInterfaceDecl *BoxClass = nullptr;
diff --git test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h
new file mode 100644
index 0000000..90c443a
--- /dev/null
+++ test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h
@@ -0,0 +1,63 @@
+#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
+
+NSRange getRange();
+
+#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..1153c2f
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-ios-arc.m
@@ -0,0 +1,115 @@
+// 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.lifetime.start{{.*}}
+  // 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:      ret void
+}
+
+// CHECK-LABEL: define void @doPoint()
+void doPoint() {
+  // CHECK:      [[POINT:%.*]]      = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      call void @llvm.lifetime.start{{.*}}
+  // 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:      ret void
+}
+
+// CHECK-LABEL: define void @doSize()
+void doSize() {
+  // CHECK:      [[SIZE:%.*]]      = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      call void @llvm.lifetime.start{{.*}}
+  // 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:      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:      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:      ret void
+}
+
+// CHECK-LABEL: define void @doRangeRValue() 
+void doRangeRValue() {
+  // CHECK:     [[COERCE:%.*]]          = alloca %struct._NSRange{{.*}}
+  // CHECK:     [[RECV_PTR:%.*]]        = load {{.*}} [[NSVALUE]]
+  // CHECK:     call {{.*}} @getRange {{.*}} [[COERCE]]{{.*}}
+  // CHECK:     [[COERCE_CAST:%.*]]     = bitcast %struct._NSRange* [[COERCE]]{{.*}}
+  // CHECK:     [[SEL:%.*]]             = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:     [[RECV:%.*]]            = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:     call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[COERCE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  // CHECK:     call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *range_rvalue = @(getRange());
+  // CHECK:     call void @objc_release
+  // CHECK:     ret void
+}
+
diff --git test/CodeGenObjC/nsvalue-objc-boxable-ios.m test/CodeGenObjC/nsvalue-objc-boxable-ios.m
new file mode 100644
index 0000000..582f17e
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-ios.m
@@ -0,0 +1,103 @@
+// 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.lifetime.start{{.*}}
+  // 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.lifetime.start{{.*}}
+  // 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.lifetime.start{{.*}}
+  // 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
+}
+
+// CHECK-LABEL: define void @doRangeRValue() 
+void doRangeRValue() {
+  // CHECK:     [[COERCE:%.*]]          = alloca %struct._NSRange{{.*}}
+  // CHECK:     [[RECV_PTR:%.*]]        = load {{.*}} [[NSVALUE]]
+  // CHECK:     call {{.*}} @getRange {{.*}} [[COERCE]]{{.*}}
+  // CHECK:     [[COERCE_CAST:%.*]]     = bitcast %struct._NSRange* [[COERCE]]{{.*}}
+  // CHECK:     [[SEL:%.*]]             = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:     [[RECV:%.*]]            = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:     call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[COERCE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  NSValue *range_rvalue = @(getRange());
+  // 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..56da050
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-mac-arc.m
@@ -0,0 +1,119 @@
+// 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.lifetime.start{{.*}}
+  // 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:      ret void
+}
+
+// CHECK-LABEL: define void @doPoint()
+void doPoint() {
+  // CHECK:      [[POINT:%.*]]      = bitcast %struct._NSPoint* {{.*}}
+  // CHECK:      call void @llvm.lifetime.start{{.*}}
+  // 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:      ret void
+}
+
+// CHECK-LABEL: define void @doSize()
+void doSize() {
+  // CHECK:      [[SIZE:%.*]]      = bitcast %struct._NSSize* {{.*}}
+  // CHECK:      call void @llvm.lifetime.start{{.*}}
+  // 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:      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:      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:      ret void
+}
+
+// CHECK-LABEL: define void @doRangeRValue() 
+void doRangeRValue() {
+  // CHECK:     [[COERCE:%.*]]          = alloca %struct._NSRange{{.*}}
+  // CHECK:     [[RECV_PTR:%.*]]        = load {{.*}} [[NSVALUE]]
+  // CHECK:     [[RVAL:%.*]]            = call {{.*}} @getRange()
+  // CHECK:     [[COERCE_CAST:%.*]]     = bitcast %struct._NSRange* [[COERCE]]{{.*}}
+  // CHECK:     [[COERCE_CAST_PTR:%.*]] = getelementptr {{.*}} [[COERCE_CAST]], {{.*}}
+  // CHECK:     [[EXTR_RVAL:%.*]]       = extractvalue {{.*}} [[RVAL]]{{.*}}
+  // CHECK:     store {{.*}}[[EXTR_RVAL]]{{.*}}[[COERCE_CAST_PTR]]{{.*}}
+  // CHECK:     [[COERCE_CAST:%.*]]     = bitcast %struct._NSRange* [[COERCE]]{{.*}}
+  // CHECK:     [[SEL:%.*]]             = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:     [[RECV:%.*]]            = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:     call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[COERCE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  // CHECK:     call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *range_rvalue = @(getRange());
+  // CHECK:     call void @objc_release
+  // CHECK:     ret void
+}
+
diff --git test/CodeGenObjC/nsvalue-objc-boxable-mac.m test/CodeGenObjC/nsvalue-objc-boxable-mac.m
new file mode 100644
index 0000000..695e934
--- /dev/null
+++ test/CodeGenObjC/nsvalue-objc-boxable-mac.m
@@ -0,0 +1,107 @@
+// 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.lifetime.start{{.*}}
+  // 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.lifetime.start{{.*}}
+  // 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.lifetime.start{{.*}}
+  // 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
+}
+
+// CHECK-LABEL: define void @doRangeRValue() 
+void doRangeRValue() {
+  // CHECK:     [[COERCE:%.*]]          = alloca %struct._NSRange{{.*}}
+  // CHECK:     [[RECV_PTR:%.*]]        = load {{.*}} [[NSVALUE]]
+  // CHECK:     [[RVAL:%.*]]            = call {{.*}} @getRange()
+  // CHECK:     [[COERCE_CAST:%.*]]     = bitcast %struct._NSRange* [[COERCE]]{{.*}}
+  // CHECK:     [[COERCE_CAST_PTR:%.*]] = getelementptr {{.*}} [[COERCE_CAST]], {{.*}}
+  // CHECK:     [[EXTR_RVAL:%.*]]       = extractvalue {{.*}} [[RVAL]]{{.*}}
+  // CHECK:     store {{.*}}[[EXTR_RVAL]]{{.*}}[[COERCE_CAST_PTR]]{{.*}}
+  // CHECK:     [[COERCE_CAST:%.*]]     = bitcast %struct._NSRange* [[COERCE]]{{.*}}
+  // CHECK:     [[SEL:%.*]]             = load i8*, i8** [[VALUE_SEL]]
+  // CHECK:     [[RECV:%.*]]            = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:     call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[COERCE_CAST]], i8* {{.*}}[[RANGE_STR]]{{.*}})
+  NSValue *range_rvalue = @(getRange());
+  // CHECK: ret void
+}
+
diff --git test/Index/annotate-literals.m test/Index/annotate-literals.m
index 20bfd2c..68121b9 100644
--- test/Index/annotate-literals.m
+++ test/Index/annotate-literals.m
@@ -29,44 +29,61 @@ typedef unsigned char BOOL;
 + (id)dictionaryWithObjects:(const id [])objects forKeys:(const id [])keys count:(unsigned long)cnt;
 @end
 
-void test_literals(id k1, id o1, id k2, id o2, id k3) {
+@interface NSValue
++ (NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type;
+@end
+
+typedef struct _c_struct {
+  int dummy;
+} c_struct __attribute__((objc_boxable));
+
+void test_literals(id k1, id o1, id k2, id o2, id k3, c_struct s) {
   id objects = @[ o1, o2 ];
   id dict = @{ k1 : o1,
                k2 : o2,
                k3 : @17 };
+  id val = @(s);
 }
 
 
-// RUN: c-index-test -test-annotate-tokens=%s:33:1:37:1 %s | FileCheck -check-prefix=CHECK-LITERALS %s
+// RUN: c-index-test -test-annotate-tokens=%s:41:1:46:1 %s | FileCheck -check-prefix=CHECK-LITERALS %s
 
-// CHECK-LITERALS: Identifier: "id" [33:3 - 33:5] TypeRef=id:0:0
-// CHECK-LITERALS: Identifier: "objects" [33:6 - 33:13] VarDecl=objects:33:6 (Definition)
-// CHECK-LITERALS: Punctuation: "=" [33:14 - 33:15] VarDecl=objects:33:6 (Definition)
-// CHECK-LITERALS: Punctuation: "@" [33:16 - 33:17] UnexposedExpr=
-// CHECK-LITERALS: Punctuation: "[" [33:17 - 33:18] UnexposedExpr=
-// CHECK-LITERALS: Identifier: "o1" [33:19 - 33:21] DeclRefExpr=o1:32:30
-// CHECK-LITERALS: Punctuation: "," [33:21 - 33:22] UnexposedExpr=
-// CHECK-LITERALS: Identifier: "o2" [33:23 - 33:25] DeclRefExpr=o2:32:44
-// CHECK-LITERALS: Punctuation: "]" [33:26 - 33:27] UnexposedExpr=
-// CHECK-LITERALS: Punctuation: ";" [33:27 - 33:28] DeclStmt=
-// CHECK-LITERALS: Identifier: "id" [34:3 - 34:5] TypeRef=id:0:0
-// CHECK-LITERALS: Identifier: "dict" [34:6 - 34:10] VarDecl=dict:34:6 (Definition)
-// CHECK-LITERALS: Punctuation: "=" [34:11 - 34:12] VarDecl=dict:34:6 (Definition)
-// CHECK-LITERALS: Punctuation: "@" [34:13 - 34:14] UnexposedExpr=
-// CHECK-LITERALS: Punctuation: "{" [34:14 - 34:15] UnexposedExpr=
-// CHECK-LITERALS: Identifier: "k1" [34:16 - 34:18] DeclRefExpr=k1:32:23
-// CHECK-LITERALS: Punctuation: ":" [34:19 - 34:20] UnexposedExpr=
-// CHECK-LITERALS: Identifier: "o1" [34:21 - 34:23] DeclRefExpr=o1:32:30
-// CHECK-LITERALS: Punctuation: "," [34:23 - 34:24] UnexposedExpr=
-// CHECK-LITERALS: Identifier: "k2" [35:16 - 35:18] DeclRefExpr=k2:32:37
-// CHECK-LITERALS: Punctuation: ":" [35:19 - 35:20] UnexposedExpr=
-// CHECK-LITERALS: Identifier: "o2" [35:21 - 35:23] DeclRefExpr=o2:32:44
-// CHECK-LITERALS: Punctuation: "," [35:23 - 35:24] UnexposedExpr=
-// CHECK-LITERALS: Identifier: "k3" [36:16 - 36:18] DeclRefExpr=k3:32:51
-// CHECK-LITERALS: Punctuation: ":" [36:19 - 36:20] UnexposedExpr=
-// CHECK-LITERALS: Punctuation: "@" [36:21 - 36:22] UnexposedExpr=
-// CHECK-LITERALS: Literal: "17" [36:22 - 36:24] IntegerLiteral=
-// CHECK-LITERALS: Punctuation: "}" [36:25 - 36:26] UnexposedExpr=
-// CHECK-LITERALS: Punctuation: ";" [36:26 - 36:27] DeclStmt=
-// CHECK-LITERALS: Punctuation: "}" [37:1 - 37:2] CompoundStmt=
+// CHECK-LITERALS: Identifier: "id" [41:3 - 41:5] TypeRef=id:0:0
+// CHECK-LITERALS: Identifier: "objects" [41:6 - 41:13] VarDecl=objects:41:6 (Definition)
+// CHECK-LITERALS: Punctuation: "=" [41:14 - 41:15] VarDecl=objects:41:6 (Definition)
+// CHECK-LITERALS: Punctuation: "@" [41:16 - 41:17] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: "[" [41:17 - 41:18] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o1" [41:19 - 41:21] DeclRefExpr=o1:40:30
+// CHECK-LITERALS: Punctuation: "," [41:21 - 41:22] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o2" [41:23 - 41:25] DeclRefExpr=o2:40:44
+// CHECK-LITERALS: Punctuation: "]" [41:26 - 41:27] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: ";" [41:27 - 41:28] DeclStmt=
+// CHECK-LITERALS: Identifier: "id" [42:3 - 42:5] TypeRef=id:0:0
+// CHECK-LITERALS: Identifier: "dict" [42:6 - 42:10] VarDecl=dict:42:6 (Definition)
+// CHECK-LITERALS: Punctuation: "=" [42:11 - 42:12] VarDecl=dict:42:6 (Definition)
+// CHECK-LITERALS: Punctuation: "@" [42:13 - 42:14] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: "{" [42:14 - 42:15] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "k1" [42:16 - 42:18] DeclRefExpr=k1:40:23
+// CHECK-LITERALS: Punctuation: ":" [42:19 - 42:20] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o1" [42:21 - 42:23] DeclRefExpr=o1:40:30
+// CHECK-LITERALS: Punctuation: "," [42:23 - 42:24] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "k2" [43:16 - 43:18] DeclRefExpr=k2:40:37
+// CHECK-LITERALS: Punctuation: ":" [43:19 - 43:20] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "o2" [43:21 - 43:23] DeclRefExpr=o2:40:44
+// CHECK-LITERALS: Punctuation: "," [43:23 - 43:24] UnexposedExpr=
+// CHECK-LITERALS: Identifier: "k3" [44:16 - 44:18] DeclRefExpr=k3:40:51
+// CHECK-LITERALS: Punctuation: ":" [44:19 - 44:20] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: "@" [44:21 - 44:22] UnexposedExpr=
+// CHECK-LITERALS: Literal: "17" [44:22 - 44:24] IntegerLiteral=
+// CHECK-LITERALS: Punctuation: "}" [44:25 - 44:26] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: ";" [44:26 - 44:27] DeclStmt=
+// CHECK-LITERALS: Identifier: "id" [45:3 - 45:5] TypeRef=id:0:0
+// CHECK-LITERALS: Identifier: "val" [45:6 - 45:9] VarDecl=val:45:6 (Definition)
+// CHECK-LITERALS: Punctuation: "=" [45:10 - 45:11] VarDecl=val:45:6 (Definition)
+// CHECK-LITERALS: Punctuation: "@" [45:12 - 45:13] UnexposedExpr=
+// CHECK-LITERALS: Punctuation: "(" [45:13 - 45:14] ParenExpr=
+// CHECK-LITERALS: Identifier: "s" [45:14 - 45:15] DeclRefExpr=s:40:64
+// CHECK-LITERALS: Punctuation: ")" [45:15 - 45:16] ParenExpr=
+// CHECK-LITERALS: Punctuation: ";" [45:16 - 45:17] DeclStmt=
+// CHECK-LITERALS: Punctuation: "}" [46:1 - 46:2] CompoundStmt=
 
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/PCH/subscripting-literals.m test/PCH/subscripting-literals.m
index 1675373..0975423 100644
--- test/PCH/subscripting-literals.m
+++ test/PCH/subscripting-literals.m
@@ -30,6 +30,14 @@
 
 @class NSString;
 
+@interface NSValue
++ (NSValue *)valueWithBytes:(const void *)bytes objCType:(const char *)type;
+@end
+
+typedef struct _some_struct {
+  int dummy;
+} some_struct __attribute__((objc_boxable));
+
 id testArray(int idx, id p) {
   NSMutableArray *array;
   array[idx] = p;
@@ -44,4 +52,9 @@ void testDict(NSString *key, id newObject, id oldObject) {
   NSDictionary *dict = @{ key: newObject, key: oldObject };
 }
 
+void testBoxableValue() {
+  some_struct ss;
+  id value = @(ss);
+}
+
 #endif
diff --git test/SemaObjC/objc-boxed-expressions-nsvalue.m test/SemaObjC/objc-boxed-expressions-nsvalue.m
new file mode 100644
index 0000000..5c3622d
--- /dev/null
+++ test/SemaObjC/objc-boxed-expressions-nsvalue.m
@@ -0,0 +1,94 @@
+// 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}}
+}
+
+CGRect getRect() {
+  CGRect r;
+  return r;
+}
+
+SomeStruct getSomeStruct() {
+  SomeStruct s;
+  return s;
+}
+
+void rvalue() {
+  id rv_rect = @(getRect());
+  id rv_some_struct = @(getSomeStruct()); // expected-error {{illegal type 'SomeStruct' (aka 'struct _SomeStruct') used in a boxed expression}}
+}
