diff --git a/docs/ObjectiveCLiterals.rst b/docs/ObjectiveCLiterals.rst
index 8907c1e..5fa582a 100644
--- a/docs/ObjectiveCLiterals.rst
+++ b/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 NSValue constructible types are supported:
 
 .. code-block:: objc
 
@@ -136,6 +136,18 @@ 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]
+
+    // Pointers
+    NSValue *memObject = @( malloc(42) );     // [NSValue valueWithPointer:malloc(42)]
+
+    // Objective-C objects
+    id obj = [NSObject new];
+    NSValue *nonretainedObject = @(obj);      // [NSValue valueWithNonretainedObject:obj]
+    NSValue *nonretainedString = @(@"Hello"); // [NSValue valueWithNonretainedObject:@"Hello"]
+
 Boxed Enums
 -----------
 
@@ -218,6 +230,28 @@ 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 Strucutres, pointers and NSObjects
+------------------
+
+Boxed expressions support construction of NSValue objects.
+It said that some C structures, pointers and NSObjects can be used:
+
+.. code-block:: objc
+
+    NSPoint p;
+    NSValue *point = @(p);          // valueWithPoint:
+    NSSize s;
+    NSValue *size = @(s);           // valueWithSize:
+    const void *p = malloc(42);
+    NSValue *memory = @(p);         // valueWithPointer:
+    id obj = [NSObject new];
+    NSValue *nonretained = @(obj);  // valueWithNonretainedObject:
+
+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 +573,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 a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
index 33fcce2..5a24392 100644
--- a/include/clang/AST/NSAPI.h
+++ b/include/clang/AST/NSAPI.h
@@ -33,9 +33,10 @@ public:
     ClassId_NSMutableArray,
     ClassId_NSDictionary,
     ClassId_NSMutableDictionary,
-    ClassId_NSNumber
+    ClassId_NSNumber,
+    ClassId_NSValue
   };
-  static const unsigned NumClassIds = 7;
+  static const unsigned NumClassIds = 8;
 
   enum NSStringMethodKind {
     NSStr_stringWithString,
@@ -158,12 +159,30 @@ public:
   };
   static const unsigned NumNSNumberLiteralMethods = 15;
 
+  /// \brief Enumerates the NSValue methods used to generate literals.
+  enum NSValueLiteralMethodKind {
+    NSValueWithPoint,
+    NSValueWithSize,
+    NSValueWithRect,
+    NSValueWithCGPoint,
+    NSValueWithCGSize,
+    NSValueWithCGRect,
+    NSValueWithRange,
+    NSValueWithEdgeInsets,
+    NSValueWithPointer,
+    NSValueWithNonretainedObject
+  };
+  static const unsigned NumNSValueLiteralMethods = 10;
+
   /// \brief The Objective-C NSNumber selectors used to create NSNumber literals.
   /// \param Instance if true it will return the selector for the init* method
   /// otherwise it will return the selector for the number* method.
   Selector getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
                                       bool Instance) const;
 
+  /// \brief The Objective-C NSValue selectors used to create NSValue literals.
+  Selector getNSValueLiteralSelector(NSValueLiteralMethodKind MK) const;
+
   bool isNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
                                  Selector Sel) const {
     return Sel == getNSNumberLiteralSelector(MK, false) ||
@@ -179,12 +198,33 @@ public:
   Optional<NSNumberLiteralMethodKind>
       getNSNumberFactoryMethodKind(QualType T) const;
 
+  /// \brief Determine the appropriate NSValue factory method kind for a
+  /// literal of the given type.
+  Optional<NSValueLiteralMethodKind>
+      getNSValueFactoryMethodKind(QualType T) const;
+
   /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
   bool isObjCBOOLType(QualType T) const;
   /// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
   bool isObjCNSIntegerType(QualType T) const;
   /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
   bool isObjCNSUIntegerType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "NSPoint" in objective-c.
+  bool isObjCNSPointType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "NSSize" in objective-c.
+  bool isObjCNSSizeType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "NSRect" in objective-c.
+  bool isObjCNSRectType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "CGPoint" in objective-c.
+  bool isObjCCGPointType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "CGSize" in objective-c.
+  bool isObjCCGSizeType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "CGRect" in objective-c.
+  bool isObjCCGRectType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "NSRange" in objective-c.
+  bool isObjCNSRangeType(QualType T) const;
+  /// \brief Returns true if \param T is a typedef of "NSEdgeInsets" in objective-c.
+  bool isObjCNSEdgeInsetsType(QualType T) const;
   /// \brief Returns one of NSIntegral typedef names if \param T is a typedef
   /// of that name in objective-c.
   StringRef GetNSIntegralKind(QualType T) const;
@@ -211,12 +251,18 @@ private:
   mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods];
   mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods];
 
+  /// \brief The Objective-C NSValue selectors used to create NSValue literals.
+  mutable Selector NSValueClassSelectors[NumNSValueLiteralMethods];
+
   mutable Selector objectForKeyedSubscriptSel, objectAtIndexedSubscriptSel,
                    setObjectForKeyedSubscriptSel,setObjectAtIndexedSubscriptSel,
                    isEqualSel;
 
   mutable IdentifierInfo *BOOLId, *NSIntegerId, *NSUIntegerId;
   mutable IdentifierInfo *NSASCIIStringEncodingId, *NSUTF8StringEncodingId;
+  mutable IdentifierInfo *NSPointId, *NSSizeId, *NSRectId;
+  mutable IdentifierInfo *CGPointId, *CGSizeId, *CGRectId;
+  mutable IdentifierInfo *NSRangeId, *NSEdgeInsetsId;
 };
 
 }  // end namespace clang
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 69f86b9..152b51a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2043,6 +2043,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 a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 95fc68f..cbece17 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -660,12 +660,21 @@ 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];
 
+  /// \brief The Objective-C NSValue methods used to create NSValue literals.
+  ObjCMethodDecl *NSValueLiteralMethods[NSAPI::NumNSValueLiteralMethods];
+
   /// \brief The declaration of the Objective-C NSString class.
   ObjCInterfaceDecl *NSStringDecl;
 
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 3dc750a..5ba6725 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -17,7 +17,10 @@ using namespace clang;
 NSAPI::NSAPI(ASTContext &ctx)
   : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),
     NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),
-    NSUTF8StringEncodingId(nullptr) {}
+    NSUTF8StringEncodingId(nullptr), NSPointId(nullptr),
+    NSSizeId(nullptr), NSRectId(nullptr), CGPointId(nullptr),
+    CGSizeId(nullptr), CGRectId(nullptr), NSRangeId(nullptr),
+    NSEdgeInsetsId(nullptr) {}
 
 IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
   static const char *ClassName[NumClassIds] = {
@@ -27,7 +30,8 @@ IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
     "NSMutableArray",
     "NSDictionary",
     "NSMutableDictionary",
-    "NSNumber"
+    "NSNumber",
+    "NSValue"
   };
 
   if (!ClassIds[K])
@@ -279,6 +283,26 @@ Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
   return Sels[MK];
 }
 
+Selector NSAPI::getNSValueLiteralSelector(NSValueLiteralMethodKind MK) const {
+  static const char *ClassSelectorName[NumNSValueLiteralMethods] = {
+    "valueWithPoint",
+    "valueWithSize",
+    "valueWithRect",
+    "valueWithCGPoint",
+    "valueWithCGSize",
+    "valueWithCGRect",
+    "valueWithRange",
+    "valueWithEdgeInsets",
+    "valueWithPointer",
+    "valueWithNonretainedObject"
+  };
+
+  if (NSValueClassSelectors[MK].isNull())
+    NSValueClassSelectors[MK] =
+      Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(ClassSelectorName[MK]));
+  return NSValueClassSelectors[MK];
+}
+
 Optional<NSAPI::NSNumberLiteralMethodKind>
 NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
   for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
@@ -371,6 +395,39 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
   return None;
 }
 
+Optional<NSAPI::NSValueLiteralMethodKind>
+NSAPI::getNSValueFactoryMethodKind(QualType T) const {
+  const RecordType *RT = T->getAsStructureType();
+  if (RT) {
+    if (isObjCNSPointType(T))
+      return NSAPI::NSValueWithPoint;
+    if (isObjCNSSizeType(T))
+      return NSAPI::NSValueWithSize;
+    if (isObjCNSRectType(T))
+      return NSAPI::NSValueWithRect;
+    if (isObjCCGPointType(T))
+      return NSAPI::NSValueWithCGPoint;
+    if (isObjCCGSizeType(T))
+      return NSAPI::NSValueWithCGSize;
+    if (isObjCCGRectType(T))
+      return NSAPI::NSValueWithCGRect;
+    if (isObjCNSRangeType(T))
+      return NSAPI::NSValueWithRange;
+    if (isObjCNSEdgeInsetsType(T))
+      return NSAPI::NSValueWithEdgeInsets;
+
+    return None;
+  }
+
+  if (T->isVoidPointerType())
+    return NSAPI::NSValueWithPointer;
+  // isObjCObjectPointerType covers 'id' and ObjCObject * (NSObject *, NSString *, etc.)
+  if (T->isObjCObjectPointerType())
+    return NSAPI::NSValueWithNonretainedObject;
+
+  return None;
+}
+
 /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
 bool NSAPI::isObjCBOOLType(QualType T) const {
   return isObjCTypedef(T, "BOOL", BOOLId);
@@ -384,6 +441,46 @@ bool NSAPI::isObjCNSUIntegerType(QualType T) const {
   return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
 }
 
+/// \brief Returns true if \param T is a typedef of "NSPoint" in objective-c.
+bool NSAPI::isObjCNSPointType(QualType T) const {
+  return isObjCTypedef(T, "NSPoint", NSPointId);
+}
+
+/// \brief Returns true if \param T is a typedef of "NSSize" in objective-c.
+bool NSAPI::isObjCNSSizeType(QualType T) const {
+  return isObjCTypedef(T, "NSSize", NSSizeId);
+}
+
+/// \brief Returns true if \param T is a typedef of "NSRect" in objective-c.
+bool NSAPI::isObjCNSRectType(QualType T) const {
+  return isObjCTypedef(T, "NSRect", NSRectId);
+}
+
+/// \brief Returns true if \param T is a typedef of "CGPoint" in objective-c.
+bool NSAPI::isObjCCGPointType(QualType T) const {
+  return isObjCTypedef(T, "CGPoint", CGPointId);
+}
+
+/// \brief Returns true if \param T is a typedef of "CGSize" in objective-c.
+bool NSAPI::isObjCCGSizeType(QualType T) const {
+  return isObjCTypedef(T, "CGSize", CGSizeId);
+}
+
+/// \brief Returns true if \param T is a typedef of "CGRect" in objective-c.
+bool NSAPI::isObjCCGRectType(QualType T) const {
+  return isObjCTypedef(T, "CGRect", CGRectId);
+}
+
+/// \brief Returns true if \param T is a typedef of "NSRange" in objective-c.
+bool NSAPI::isObjCNSRangeType(QualType T) const {
+  return isObjCTypedef(T, "NSRange", NSRangeId);
+}
+
+/// \brief Returns true if \param T is a typedef of "NSEdgeInsets" in objective-c.
+bool NSAPI::isObjCNSEdgeInsetsType(QualType T) const {
+  return isObjCTypedef(T, "NSEdgeInsets", NSEdgeInsetsId);
+}
+
 StringRef NSAPI::GetNSIntegralKind(QualType T) const {
   if (!Ctx.getLangOpts().ObjC1 || T.isNull())
     return StringRef();
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 81bd108..98f99f7 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/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 valueWith<Type>:].
 ///
 llvm::Value *
 CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index cd05d06..dc45498 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -911,6 +911,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", LangOpts.ObjC2)
       // C11 features
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 9c3b51c..3e73a49 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -255,6 +255,86 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
   return Method;
 }
 
+/// \brief Retrieve the NSValue factory method that should be used to create
+/// an Objective-C literal for the given type.
+static ObjCMethodDecl *getNSValueFactoryMethod(Sema &S, SourceLocation Loc,
+                                               QualType ValueType) {
+  Optional<NSAPI::NSValueLiteralMethodKind> Kind =
+  S.NSAPIObj->getNSValueFactoryMethodKind(ValueType);
+
+  if (!Kind) {
+    return nullptr;
+  }
+
+  // If we already looked up this method, we're done.
+  if (S.NSValueLiteralMethods[*Kind])
+    return S.NSValueLiteralMethods[*Kind];
+
+  Selector Sel = S.NSAPIObj->getNSValueLiteralSelector(*Kind);
+
+  ASTContext &CX = S.Context;
+
+  // Look up the NSValue class, if we haven't done so already. It's cached
+  // in the Sema instance.
+  if (!S.NSValueDecl) {
+    IdentifierInfo *NSValueId =
+    S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSValue);
+    NamedDecl *IF = S.LookupSingleName(S.TUScope, NSValueId,
+                                       Loc, Sema::LookupOrdinaryName);
+    S.NSValueDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+    if (!S.NSValueDecl) {
+      if (S.getLangOpts().DebuggerObjCLiteral) {
+        // Create a stub definition of NSValue.
+        S.NSValueDecl = ObjCInterfaceDecl::Create(CX,
+                                                  CX.getTranslationUnitDecl(),
+                                                  SourceLocation(), NSValueId,
+                                                  nullptr, SourceLocation());
+      } else {
+        // Otherwise, require a declaration of NSValue.
+        S.Diag(Loc, diag::err_undeclared_nsvalue);
+        return nullptr;
+      }
+    } else if (!S.NSValueDecl->hasDefinition()) {
+      S.Diag(Loc, diag::err_undeclared_nsvalue);
+      return nullptr;
+    }
+
+    // generate the pointer to NSValue type.
+    QualType NSValueObject = CX.getObjCInterfaceType(S.NSValueDecl);
+    S.NSValuePointer = CX.getObjCObjectPointerType(NSValueObject);
+  }
+
+  // Look for the appropriate method within NSValue.
+  ObjCMethodDecl *Method = S.NSValueDecl->lookupClassMethod(Sel);
+  if (!Method && S.getLangOpts().DebuggerObjCLiteral) {
+    // create a stub definition this NSValue factory method.
+    TypeSourceInfo *ReturnTInfo = nullptr;
+    Method =
+    ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel,
+                           S.NSValuePointer, ReturnTInfo, S.NSValueDecl,
+                           /*isInstance=*/false, /*isVariadic=*/false,
+                           /*isPropertyAccessor=*/false,
+                           /*isImplicitlyDeclared=*/true,
+                           /*isDefined=*/false, ObjCMethodDecl::Required,
+                           /*HasRelatedResultType=*/false);
+    ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method,
+                                             SourceLocation(), SourceLocation(),
+                                             &CX.Idents.get("value"),
+                                             ValueType, /*TInfo=*/nullptr,
+                                             SC_None, nullptr);
+    Method->setMethodParams(S.Context, value, None);
+  }
+
+  if (!validateBoxingMethod(S, Loc, S.NSValueDecl, Sel, Method))
+    return nullptr;
+
+  // Note: if the parameter type is out-of-line, we'll catch it later in the
+  // implicit conversion.
+
+  S.NSValueLiteralMethods[*Kind] = Method;
+  return Method;
+}
+
 /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the
 /// numeric literal expression. Type of the expression will be "NSNumber *".
 ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
@@ -456,10 +536,56 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
   }
   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;
+
+  } else if (ValueType->isStructureType() || ValueType->isPointerType() || ValueType->isObjCObjectPointerType()) {
+    // Support of NSValue and NSString construction
+
+    // Check if we can construct NSString from chars
+    const PointerType *PT = ValueType->getAs<PointerType>();
+    if (PT && Context.hasSameUnqualifiedType(PT->getPointeeType(), Context.CharTy)) {
       if (!NSStringDecl) {
         IdentifierInfo *NSStringId =
           NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
@@ -525,53 +651,15 @@ 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;
-      }
-    }
-    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 {
+      // Support for +valueWithNonretaintedObject and +valueWithPointer.
+      // Limited support for structure types, such as NSRange,
+      // NS/CG Rect, Size, Point and NSEdgeInsets.
 
-  } 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();
+      // Look for the appropriate method within NSValue.
+      BoxingMethod = getNSValueFactoryMethod(*this, SR.getBegin(), ValueType);
+      BoxedType = NSValuePointer;
     }
-
-    BoxingMethod = getNSNumberFactoryMethod(*this, SR.getBegin(),
-                                            ET->getDecl()->getIntegerType());
-    BoxedType = NSNumberPointer;
   }
 
   if (!BoxingMethod) {
@@ -580,6 +668,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
     return ExprError();
   }
   
+  DiagnoseUseOfDecl(BoxingMethod, SR.getBegin());
+
   // Convert the expression to the type that the parameter requires.
   ParmVarDecl *ParamDecl = BoxingMethod->parameters()[0];
   InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
diff --git a/test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h b/test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h
new file mode 100644
index 0000000..d5b1bae
--- /dev/null
+++ b/test/CodeGenObjC/Inputs/nsvalue-boxed-expressions-support.h
@@ -0,0 +1,72 @@
+#ifndef NSVALUE_BOXED_EXPRESSIONS_SUPPORT_H
+#define NSVALUE_BOXED_EXPRESSIONS_SUPPORT_H
+
+typedef unsigned long NSUInteger;
+typedef double CGFloat;
+
+typedef struct _NSRange {
+    NSUInteger location;
+    NSUInteger length;
+} NSRange;
+
+typedef struct _NSPoint {
+    CGFloat x;
+    CGFloat y;
+} NSPoint __attribute__((availability(macosx,introduced=10.0)));
+
+typedef struct _NSSize {
+    CGFloat width;
+    CGFloat height;
+} NSSize __attribute__((availability(macosx,introduced=10.0)));
+
+typedef struct _NSRect {
+    NSPoint origin;
+    NSSize size;
+} NSRect __attribute__((availability(macosx,introduced=10.0)));
+
+struct CGPoint {
+  CGFloat x;
+  CGFloat y;
+} __attribute__((availability(ios,introduced=2.0)));
+typedef struct CGPoint CGPoint;
+
+struct CGSize {
+  CGFloat width;
+  CGFloat height;
+} __attribute__((availability(ios,introduced=2.0)));
+typedef struct CGSize CGSize;
+
+struct CGRect {
+  CGPoint origin;
+  CGSize size;
+} __attribute__((availability(ios,introduced=2.0)));
+typedef struct CGRect CGRect;
+
+struct NSEdgeInsets {
+  CGFloat top;
+  CGFloat left;
+  CGFloat bottom;
+  CGFloat right;
+};
+typedef struct NSEdgeInsets NSEdgeInsets;
+
+@interface NSValue
++ (NSValue *)valueWithRange:(NSRange)range;
+
++ (NSValue *)valueWithPoint:(NSPoint)point __attribute__((availability(macosx, introduced=10.0)));
++ (NSValue *)valueWithSize:(NSSize)size __attribute__((availability(macosx, introduced=10.0)));
++ (NSValue *)valueWithRect:(NSRect)rect __attribute__((availability(macosx, introduced=10.0)));
+
++ (NSValue *)valueWithCGPoint:(CGPoint)point __attribute__((availability(ios, introduced=2.0)));
++ (NSValue *)valueWithCGSize:(CGSize)size __attribute__((availability(ios, introduced=2.0)));
++ (NSValue *)valueWithCGRect:(CGRect)rect __attribute__((availability(ios, introduced=2.0)));
+
++ (NSValue *)valueWithEdgeInsets:(NSEdgeInsets)edgeInsets 
+  __attribute__((availability(macosx, introduced=10.10))) 
+  __attribute__((availability(ios, introduced=8.0)));
+
++ (NSValue *)valueWithPointer:(const void *)pointer;
++ (NSValue *)valueWithNonretainedObject:(id)object;
+@end
+
+#endif // NSVALUE_BOXED_EXPRESSIONS_SUPPORT_H
diff --git a/test/CodeGenObjC/nsvalue-boxed-expressions-ios-arc.m b/test/CodeGenObjC/nsvalue-boxed-expressions-ios-arc.m
new file mode 100644
index 0000000..c417d60
--- /dev/null
+++ b/test/CodeGenObjC/nsvalue-boxed-expressions-ios-arc.m
@@ -0,0 +1,136 @@
+// 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:      [[METH:@.*]]            = private global{{.*}}valueWithRange:{{.*}}
+// CHECK-NEXT: [[RANGE_SEL:@.*]]       = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithCGPoint:{{.*}}
+// CHECK-NEXT: [[CGPOINT_SEL:@.*]]     = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithCGSize:{{.*}}
+// CHECK-NEXT: [[CGSIZE_SEL:@.*]]      = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithCGRect:{{.*}}
+// CHECK-NEXT: [[CGRECT_SEL:@.*]]      = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithEdgeInsets:{{.*}}
+// CHECK-NEXT: [[EDGE_INSETS_SEL:@.*]] = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithPointer:{{.*}}
+// CHECK-NEXT: [[POINTER_SEL:@.*]]  = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithNonretainedObject:{{.*}}
+// CHECK-NEXT: [[NONRET_SEL:@.*]]   = {{.*}}[[METH]]{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]     = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[RANGE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[RANGE_PTR:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[PARAM:%.*]]     = load [2 x i32]* [[RANGE_PTR]]{{.*}}
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [2 x i32] [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *range = @(ns_range);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT:      ret void
+}
+
+// CHECK-LABEL: define void @doCGPoint()
+void doCGPoint() {
+  // CHECK:      [[POINT:%.*]]     = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[CGPOINT_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[POINT_PTR:%.*]] = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      [[PARAM:%.*]]     = load [4 x i32]* [[POINT_PTR]]{{.*}}
+  CGPoint cg_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [4 x i32] [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *point = @(cg_point);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doCGSize()
+void doCGSize() {
+  // CHECK:      [[SIZE:%.*]]     = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[CGSIZE_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[SIZE_PTR:%.*]] = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      [[PARAM:%.*]]    = load [4 x i32]* [[SIZE_PTR]]{{.*}}
+  CGSize cg_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [4 x i32] [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *size = @(cg_size);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doCGRect()
+void doCGRect() {
+  // CHECK:      [[RECT:%.*]]     = alloca %struct.CGRect{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[CGRECT_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[RECT_PTR:%.*]] = bitcast %struct.CGRect* {{.*}}
+  // CHECK:      [[PARAM:%.*]]    = load [8 x i32]* [[RECT_PTR]]{{.*}}
+  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]], [8 x i32] [[PARAM]])
+  // 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_INSETS:%.*]]     = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]        = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]             = load i8** [[EDGE_INSETS_SEL]]
+  // CHECK:      [[RECV:%.*]]            = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[EDGE_INSETS_PTR:%.*]] = bitcast %struct.NSEdgeInsets* {{.*}}
+  // CHECK:      [[PARAM:%.*]]           = load [8 x i32]* [[EDGE_INSETS_PTR]]{{.*}}
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [8 x i32] [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doVoidPointer()
+void doVoidPointer() {
+  // CHECK:      [[POINTER:%.*]]  = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[POINTER]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[POINTER_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  const void *pointer = 0;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *value = @(pointer);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doNonretainedObject()
+void doNonretainedObject() {
+  // CHECK:      [[OBJ:%.*]]      = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[OBJ]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[NONRET_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  id obj;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *object = @(obj);
+  // CHECK:      call void @objc_release
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjC/nsvalue-boxed-expressions-ios.m b/test/CodeGenObjC/nsvalue-boxed-expressions-ios.m
new file mode 100644
index 0000000..aa5c602
--- /dev/null
+++ b/test/CodeGenObjC/nsvalue-boxed-expressions-ios.m
@@ -0,0 +1,122 @@
+// 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:      [[METH:@.*]]            = private global{{.*}}valueWithRange:{{.*}}
+// CHECK-NEXT: [[RANGE_SEL:@.*]]       = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithCGPoint:{{.*}}
+// CHECK-NEXT: [[CGPOINT_SEL:@.*]]     = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithCGSize:{{.*}}
+// CHECK-NEXT: [[CGSIZE_SEL:@.*]]      = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithCGRect:{{.*}}
+// CHECK-NEXT: [[CGRECT_SEL:@.*]]      = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithEdgeInsets:{{.*}}
+// CHECK-NEXT: [[EDGE_INSETS_SEL:@.*]] = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithPointer:{{.*}}
+// CHECK-NEXT: [[POINTER_SEL:@.*]]  = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithNonretainedObject:{{.*}}
+// CHECK-NEXT: [[NONRET_SEL:@.*]]   = {{.*}}[[METH]]{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]     = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[RANGE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[RANGE_PTR:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[PARAM:%.*]]     = load [2 x i32]* [[RANGE_PTR]]{{.*}}
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [2 x i32] [[PARAM]])
+  NSValue *range = @(ns_range);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doCGPoint()
+void doCGPoint() {
+  // CHECK:      [[POINT:%.*]]     = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[CGPOINT_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[POINT_PTR:%.*]] = bitcast %struct.CGPoint* {{.*}}
+  // CHECK:      [[PARAM:%.*]]     = load [4 x i32]* [[POINT_PTR]]{{.*}}
+  CGPoint cg_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [4 x i32] [[PARAM]])
+  NSValue *point = @(cg_point);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doCGSize()
+void doCGSize() {
+  // CHECK:      [[SIZE:%.*]]     = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[CGSIZE_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[SIZE_PTR:%.*]] = bitcast %struct.CGSize* {{.*}}
+  // CHECK:      [[PARAM:%.*]]    = load [4 x i32]* [[SIZE_PTR]]{{.*}}
+  CGSize cg_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [4 x i32] [[PARAM]])
+  NSValue *size = @(cg_size);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doCGRect()
+void doCGRect() {
+  // CHECK:      [[RECT:%.*]]     = alloca %struct.CGRect{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[CGRECT_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[RECT_PTR:%.*]] = bitcast %struct.CGRect* {{.*}}
+  // CHECK:      [[PARAM:%.*]]    = load [8 x i32]* [[RECT_PTR]]{{.*}}
+  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]], [8 x i32] [[PARAM]])
+  NSValue *rect = @(cg_rect);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doNSEdgeInsets()
+void doNSEdgeInsets() {
+  // CHECK:      [[EDGE_INSETS:%.*]]     = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]        = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]             = load i8** [[EDGE_INSETS_SEL]]
+  // CHECK:      [[RECV:%.*]]            = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[EDGE_INSETS_PTR:%.*]] = bitcast %struct.NSEdgeInsets* {{.*}}
+  // CHECK:      [[PARAM:%.*]]           = load [8 x i32]* [[EDGE_INSETS_PTR]]{{.*}}
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], [8 x i32] [[PARAM]])
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doVoidPointer()
+void doVoidPointer() {
+  // CHECK:      [[POINTER:%.*]]  = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[POINTER]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[POINTER_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  const void *pointer = 0;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  NSValue *value = @(pointer);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doNonretainedObject()
+void doNonretainedObject() {
+  // CHECK:      [[OBJ:%.*]]      = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[OBJ]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[NONRET_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  id obj;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  NSValue *object = @(obj);
+  // CHECK:      ret void
+}
+
diff --git a/test/CodeGenObjC/nsvalue-boxed-expressions-mac-arc.m b/test/CodeGenObjC/nsvalue-boxed-expressions-mac-arc.m
new file mode 100644
index 0000000..7854d42
--- /dev/null
+++ b/test/CodeGenObjC/nsvalue-boxed-expressions-mac-arc.m
@@ -0,0 +1,142 @@
+// 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:      [[METH:@.*]]            = private global{{.*}}valueWithRange:{{.*}}
+// CHECK-NEXT: [[RANGE_SEL:@.*]]       = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithPoint:{{.*}}
+// CHECK-NEXT: [[POINT_SEL:@.*]]       = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithSize:{{.*}}
+// CHECK-NEXT: [[SIZE_SEL:@.*]]        = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithRect:{{.*}}
+// CHECK-NEXT: [[RECT_SEL:@.*]]        = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithEdgeInsets:{{.*}}
+// CHECK-NEXT: [[EDGE_INSETS_SEL:@.*]] = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithPointer:{{.*}}
+// CHECK-NEXT: [[POINTER_SEL:@.*]]  = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithNonretainedObject:{{.*}}
+// CHECK-NEXT: [[NONRET_SEL:@.*]]   = {{.*}}[[METH]]{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]     = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[RANGE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[RANGE_PTR:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK-NEXT: [[P1_PTR:%.*]]    = getelementptr {{.*}} [[RANGE_PTR]], i32 0, i32 0
+  // CHECK-NEXT: [[P1:%.*]]        = load i64* [[P1_PTR]], align 1
+  // CHECK-NEXT: [[P2_PTR:%.*]]    = getelementptr {{.*}} [[RANGE_PTR]], i32 0, i32 1
+  // CHECK-NEXT: [[P2:%.*]]        = load i64* [[P2_PTR]], align 1
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i64 [[P1]], i64 [[P2]])
+  // 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:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[POINT_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[POINT_PTR:%.*]] = bitcast %struct._NSPoint* {{.*}}
+  // CHECK-NEXT: [[P1_PTR:%.*]]    = getelementptr {{.*}} [[POINT_PTR]], i32 0, i32 0
+  // CHECK-NEXT: [[P1:%.*]]        = load double* [[P1_PTR]], align 1
+  // CHECK-NEXT: [[P2_PTR:%.*]]    = getelementptr {{.*}} [[POINT_PTR]], i32 0, i32 1
+  // CHECK-NEXT: [[P2:%.*]]        = load double* [[P2_PTR]], align 1
+  NSPoint ns_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], double [[P1]], double [[P2]])
+  // 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:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[SIZE_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[SIZE_PTR:%.*]] = bitcast %struct._NSSize* {{.*}}
+  // CHECK-NEXT: [[P1_PTR:%.*]]   = getelementptr {{.*}} [[SIZE_PTR]], i32 0, i32 0
+  // CHECK-NEXT: [[P1:%.*]]       = load double* [[P1_PTR]], align 1
+  // CHECK-NEXT: [[P2_PTR:%.*]]   = getelementptr {{.*}} [[SIZE_PTR]], i32 0, i32 1
+  // CHECK-NEXT: [[P2:%.*]]       = load double* [[P2_PTR]], align 1
+  NSSize ns_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], double [[P1]], double [[P2]])
+  // 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:      [[SEL:%.*]]      = load i8** [[RECT_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]], %struct._NSRect* byval align 8 [[RECT]])
+  // 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_INSETS:%.*]] = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]    = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]         = load i8** [[EDGE_INSETS_SEL]]
+  // CHECK:      [[RECV:%.*]]        = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], %struct.NSEdgeInsets* byval align 8 [[EDGE_INSETS]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doVoidPointer()
+void doVoidPointer() {
+  // CHECK:      [[POINTER:%.*]]  = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[POINTER]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[POINTER_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  const void *pointer = 0;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *value = @(pointer);
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
+// CHECK-LABEL: define void @doNonretainedObject()
+void doNonretainedObject() {
+  // CHECK:      [[OBJ:%.*]]      = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[OBJ]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[NONRET_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  id obj;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  // CHECK:      call i8* @objc_retainAutoreleasedReturnValue
+  NSValue *object = @(obj);
+  // CHECK:      call void @objc_release
+  // CHECK:      call void @objc_release
+  // CHECK-NEXT: ret void
+}
+
diff --git a/test/CodeGenObjC/nsvalue-boxed-expressions-mac.m b/test/CodeGenObjC/nsvalue-boxed-expressions-mac.m
new file mode 100644
index 0000000..2d17a70
--- /dev/null
+++ b/test/CodeGenObjC/nsvalue-boxed-expressions-mac.m
@@ -0,0 +1,127 @@
+// 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:      [[METH:@.*]]            = private global{{.*}}valueWithRange:{{.*}}
+// CHECK-NEXT: [[RANGE_SEL:@.*]]       = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithPoint:{{.*}}
+// CHECK-NEXT: [[POINT_SEL:@.*]]       = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithSize:{{.*}}
+// CHECK-NEXT: [[SIZE_SEL:@.*]]        = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithRect:{{.*}}
+// CHECK-NEXT: [[RECT_SEL:@.*]]        = {{.*}}[[METH]]{{.*}}
+// CHECK:      [[METH:@.*]]            = private global{{.*}}valueWithEdgeInsets:{{.*}}
+// CHECK-NEXT: [[EDGE_INSETS_SEL:@.*]] = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithPointer:{{.*}}
+// CHECK-NEXT: [[POINTER_SEL:@.*]]  = {{.*}}[[METH]]{{.*}}
+
+// CHECK:      [[METH:@.*]]         = private global{{.*}}valueWithNonretainedObject:{{.*}}
+// CHECK-NEXT: [[NONRET_SEL:@.*]]   = {{.*}}[[METH]]{{.*}}
+
+// CHECK-LABEL: define void @doRange()
+void doRange() {
+  // CHECK:      [[RANGE:%.*]]     = bitcast %struct._NSRange* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[RANGE_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[RANGE_PTR:%.*]] = bitcast %struct._NSRange* {{.*}}
+  // CHECK-NEXT: [[P1_PTR:%.*]]    = getelementptr {{.*}} [[RANGE_PTR]], i32 0, i32 0
+  // CHECK-NEXT: [[P1:%.*]]        = load i64* [[P1_PTR]], align 1
+  // CHECK-NEXT: [[P2_PTR:%.*]]    = getelementptr {{.*}} [[RANGE_PTR]], i32 0, i32 1
+  // CHECK-NEXT: [[P2:%.*]]        = load i64* [[P2_PTR]], align 1
+  NSRange ns_range = { .location = 0, .length = 42 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i64 [[P1]], i64 [[P2]])
+  NSValue *range = @(ns_range);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doPoint()
+void doPoint() {
+  // CHECK:      [[POINT:%.*]]     = bitcast %struct._NSPoint* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]  = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]       = load i8** [[POINT_SEL]]
+  // CHECK:      [[RECV:%.*]]      = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[POINT_PTR:%.*]] = bitcast %struct._NSPoint* {{.*}}
+  // CHECK-NEXT: [[P1_PTR:%.*]]    = getelementptr {{.*}} [[POINT_PTR]], i32 0, i32 0
+  // CHECK-NEXT: [[P1:%.*]]        = load double* [[P1_PTR]], align 1
+  // CHECK-NEXT: [[P2_PTR:%.*]]    = getelementptr {{.*}} [[POINT_PTR]], i32 0, i32 1
+  // CHECK-NEXT: [[P2:%.*]]        = load double* [[P2_PTR]], align 1
+  NSPoint ns_point = { .x = 42, .y = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], double [[P1]], double [[P2]])
+  NSValue *point = @(ns_point);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doSize()
+void doSize() {
+  // CHECK:      [[SIZE:%.*]]     = bitcast %struct._NSSize* {{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[SIZE_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  // CHECK:      [[SIZE_PTR:%.*]] = bitcast %struct._NSSize* {{.*}}
+  // CHECK-NEXT: [[P1_PTR:%.*]]   = getelementptr {{.*}} [[SIZE_PTR]], i32 0, i32 0
+  // CHECK-NEXT: [[P1:%.*]]       = load double* [[P1_PTR]], align 1
+  // CHECK-NEXT: [[P2_PTR:%.*]]   = getelementptr {{.*}} [[SIZE_PTR]], i32 0, i32 1
+  // CHECK-NEXT: [[P2:%.*]]       = load double* [[P2_PTR]], align 1
+  NSSize ns_size = { .width = 42, .height = 24 };
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], double [[P1]], double [[P2]])
+  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:      [[SEL:%.*]]      = load i8** [[RECT_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]], %struct._NSRect* byval align 8 [[RECT]])
+  NSValue *rect = @(ns_rect);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doNSEdgeInsets()
+void doNSEdgeInsets() {
+  // CHECK:      [[EDGE_INSETS:%.*]] = alloca %struct.NSEdgeInsets{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]]    = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[SEL:%.*]]         = load i8** [[EDGE_INSETS_SEL]]
+  // CHECK:      [[RECV:%.*]]        = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  NSEdgeInsets ns_edge_insets;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], %struct.NSEdgeInsets* byval align 8 [[EDGE_INSETS]])
+  NSValue *edge_insets = @(ns_edge_insets);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doVoidPointer()
+void doVoidPointer() {
+  // CHECK:      [[POINTER:%.*]]  = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[POINTER]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[POINTER_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  const void *pointer = 0;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  NSValue *value = @(pointer);
+  // CHECK:      ret void
+}
+
+// CHECK-LABEL: define void @doNonretainedObject()
+void doNonretainedObject() {
+  // CHECK:      [[OBJ:%.*]]      = alloca i8*{{.*}}
+  // CHECK:      [[RECV_PTR:%.*]] = load {{.*}} [[NSVALUE]]
+  // CHECK:      [[PARAM:%.*]]    = load i8** [[OBJ]]
+  // CHECK:      [[SEL:%.*]]      = load i8** [[NONRET_SEL]]
+  // CHECK:      [[RECV:%.*]]     = bitcast %struct._class_t* [[RECV_PTR]] to i8*
+  id obj;
+  // CHECK:      call {{.*objc_msgSend.*}}(i8* [[RECV]], i8* [[SEL]], i8* [[PARAM]])
+  NSValue *object = @(obj);
+  // CHECK:      ret void
+}
+
diff --git a/test/Lexer/has_feature_boxed_nsvalue_expressions.m b/test/Lexer/has_feature_boxed_nsvalue_expressions.m
new file mode 100644
index 0000000..8c66bcb
--- /dev/null
+++ b/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 a/test/SemaObjC/boxing-illegal.m b/test/SemaObjC/boxing-illegal.m
index 59b5c8b..a196370 100644
--- a/test/SemaObjC/boxing-illegal.m
+++ b/test/SemaObjC/boxing-illegal.m
@@ -4,6 +4,8 @@ typedef long NSInteger;
 typedef unsigned long NSUInteger;
 typedef signed char BOOL;
 
+@interface NSValue @end
+
 @interface NSNumber
 @end
 @interface NSNumber (NSNumberCreation)
@@ -34,8 +36,8 @@ void testStruct() {
 }
 
 void testPointers() {
-    void *null = 0;
-    id boxed_null = @(null);        // expected-error {{illegal type 'void *' used in a boxed expression}}
+    float *null = 0;
+    id boxed_null = @(null);        // expected-error {{illegal type 'float *' used in a boxed expression}}
     int numbers[] = { 0, 1, 2 };
     id boxed_numbers = @(numbers);  // expected-error {{illegal type 'int *' used in a boxed expression}}
 }
diff --git a/test/SemaObjC/objc-boxed-expressions-nsvalue-availability.m b/test/SemaObjC/objc-boxed-expressions-nsvalue-availability.m
new file mode 100644
index 0000000..2b2a023
--- /dev/null
+++ b/test/SemaObjC/objc-boxed-expressions-nsvalue-availability.m
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1  -fsyntax-only -triple x86_64-apple-macosx10.9 -verify %s
+
+typedef struct _NSPoint {
+  int dummy;
+} NSPoint;
+
+typedef struct _NSSize {
+  int dummy;
+} NSSize;
+
+typedef struct _NSRect {
+  int dummy;
+} NSRect;
+
+@interface NSValue
++ (NSValue *)valueWithPoint:(NSPoint)point __attribute__((availability(macosx, deprecated=10.8, message=""))); // expected-note {{'valueWithPoint:' has been explicitly marked deprecated here}}
++ (NSValue *)valueWithSize:(NSSize)size __attribute__((availability(macosx, unavailable))); // expected-note {{'valueWithSize:' has been explicitly marked unavailable here}}
++ (NSValue *)valueWithRect:(NSRect)rect __attribute__((availability(macosx, introduced=10.10)));
+@end
+
+int main() {
+  NSPoint ns_point;
+  id ns_point_value = @(ns_point); // expected-warning {{'valueWithPoint:' is deprecated: first deprecated in OS X 10.8}}
+
+  NSSize ns_size;
+  id ns_size_value = @(ns_size); // expected-error {{'valueWithSize:' is unavailable: not available on OS X}}
+
+  NSRect ns_rect;
+  id ns_rect_value = @(ns_rect);
+}
diff --git a/test/SemaObjC/objc-boxed-expressions-nsvalue.m b/test/SemaObjC/objc-boxed-expressions-nsvalue.m
new file mode 100644
index 0000000..af9b276
--- /dev/null
+++ b/test/SemaObjC/objc-boxed-expressions-nsvalue.m
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1  -fsyntax-only -triple x86_64-apple-darwin10.9 -verify %s
+
+typedef struct _NSPoint {
+  int dummy;
+} NSPoint;
+
+typedef struct _NSSize {
+  int dummy;
+} NSSize;
+
+typedef struct _NSRect {
+  int dummy;
+} NSRect;
+
+typedef struct _CGPoint {
+  int dummy;
+} CGPoint;
+
+typedef struct _CGSize {
+  int dummy;
+} CGSize;
+
+typedef struct _CGRect {
+  int dummy;
+} CGRect;
+
+typedef struct _NSRange {
+  int dummy;
+} NSRange;
+
+typedef struct _NSEdgeInsets {
+  int dummy;
+} NSEdgeInsets;
+
+typedef struct _SomeStruct {
+  double d;
+} SomeStruct;
+
+@interface NSObject @end
+
+@interface ObjCObject @end
+
+void checkNSValueDiagnostic() {
+  NSRect rect;
+  id value = @(rect); // expected-error{{NSValue must be available to use Objective-C boxed expressions}} \
+                      // expected-error{{illegal type 'NSRect' (aka 'struct _NSRect') used in a boxed expression}}
+}
+
+@interface NSValue
++ (NSValue *)valueWithPoint:(NSPoint)point;
++ (NSValue *)valueWithSize:(NSSize)size;
++ (NSValue *)valueWithRect:(NSRect)rect;
+
++ (NSValue *)valueWithCGPoint:(CGPoint)point;
++ (NSValue *)valueWithCGSize:(CGSize)size;
++ (NSValue *)valueWithCGRect:(CGRect)rect;
+
++ (NSValue *)valueWithRange:(NSRange)range;
+
++ (NSValue *)valueWithPointer:(const void *)pinter;
++ (NSValue *)valueWithNonretainedObject:(id)anObject;
++ (NSValue *)valueWithEdgeInsets:(NSEdgeInsets)insets __attribute__((availability(macosx, introduced=10.10)));
+@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);
+
+  const void *void_pointer;
+  id void_pointer_value = @(void_pointer);
+
+  id id_object;
+  id id_object_value = @(id_object);
+
+  NSObject *ns_object;
+  id ns_object_value = @(ns_object);
+
+  ObjCObject *objc_object;
+  id objc_object_value = @(objc_object);
+
+  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}}
+}
diff --git a/test/SemaObjCXX/boxing-illegal-types.mm b/test/SemaObjCXX/boxing-illegal-types.mm
index 7729753..70e30c5 100644
--- a/test/SemaObjCXX/boxing-illegal-types.mm
+++ b/test/SemaObjCXX/boxing-illegal-types.mm
@@ -4,6 +4,8 @@ typedef long NSInteger;
 typedef unsigned long NSUInteger;
 typedef signed char BOOL;
 
+@interface NSValue @end
+
 @interface NSNumber
 @end
 @interface NSNumber (NSNumberCreation)
@@ -34,8 +36,8 @@ void testStruct() {
 }
 
 void testPointers() {
-    void *null = 0;
-    id boxed_null = @(null);        // expected-error {{illegal type 'void *' used in a boxed expression}}
+    float *null = 0;
+    id boxed_null = @(null);        // expected-error {{illegal type 'float *' used in a boxed expression}}
     int numbers[] = { 0, 1, 2 };
     id boxed_numbers = @(numbers);  // expected-error {{illegal type 'int *' used in a boxed expression}}
 }
