]> granicus.if.org Git - clang/commitdiff
Implements boxed expressions for Objective-C. <rdar://problem/10194391>
authorPatrick Beard <pcbeard@mac.com>
Thu, 19 Apr 2012 00:25:12 +0000 (00:25 +0000)
committerPatrick Beard <pcbeard@mac.com>
Thu, 19 Apr 2012 00:25:12 +0000 (00:25 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@155082 91177308-0d34-0410-b5e6-96231b3b80d8

35 files changed:
docs/LanguageExtensions.html
docs/ObjectiveCLiterals.html
include/clang/AST/ExprObjC.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/StmtNodes.td
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CodeGenFunction.h
lib/Lex/PPMacroExpansion.cpp
lib/Parse/ParseObjc.cpp
lib/Rewrite/RewriteModernObjC.cpp
lib/Sema/SemaExceptionSpec.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaExprObjC.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/CodeGenObjC/objc-literal-debugger-test.m
test/Parser/objc-boxing.m [new file with mode: 0644]
test/Rewriter/objc-modern-boxing.mm [new file with mode: 0644]
test/SemaObjC/boxing-illegal-types.m [new file with mode: 0644]
test/SemaTemplate/instantiate-objc-1.mm
tools/libclang/CXCursor.cpp
tools/libclang/IndexBody.cpp

index 68f0afc1ffa516d6256248749a741d9d8b7c92a8..9bae334f19b05d65b276f95475da937ffafa9e60 100644 (file)
@@ -91,7 +91,7 @@
     <li><a href="#objc_arc">Automatic reference counting</a></li>
     <li><a href="#objc_fixed_enum">Enumerations with a fixed underlying type</a></li>
     <li><a href="#objc_lambdas">Interoperability with C++11 lambdas</a></li>
-    <li><a href="#object-literals-subscripting">Object Literals and Subscripting</a></li>
+    <li><a href="#objc_object_literals_subscripting">Object Literals and Subscripting</a></li>
   </ul>
 </li>
 <li><a href="#overloading-in-c">Function Overloading in C</a></li>
@@ -1183,10 +1183,18 @@ in Objective-C++, and not in C++ with blocks, due to its use of
 Objective-C memory management (autorelease).</p>
 
 <!-- ======================================================================= -->
-<h2 id="object-literals-subscripting">Object Literals and Subscripting</h2>
+<h2 id="objc_object_literals_subscripting">Object Literals and Subscripting</h2>
 <!-- ======================================================================= -->
 
-<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals and Subscripting</a> in Objective-C, which simplifies common Objective-C programming patterns, makes programs more concise, and improves the safety of container creation. There are several feature macros associated with object literals and subscripting: <code>__has_feature(objc_array_literals)</code> tests the availability of array literals; <code>__has_feature(objc_dictionary_literals)</code> tests the availability of dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the availability of object subscripting.</p>
+<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals 
+and Subscripting</a> in Objective-C, which simplifies common Objective-C
+programming patterns, makes programs more concise, and improves the safety of
+container creation. There are several feature macros associated with object
+literals and subscripting: <code>__has_feature(objc_array_literals)</code>
+tests the availability of array literals;
+<code>__has_feature(objc_dictionary_literals)</code> tests the availability of
+dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the
+availability of object subscripting.</p>
 
 <!-- ======================================================================= -->
 <h2 id="overloading-in-c">Function Overloading in C</h2>
index 63b523c6dfcdecf38ed585aa551aa3f42e9c3f6b..dc2f2fff09ac3f6c8a4a2cc54d5c39eea6444bcc 100644 (file)
@@ -68,14 +68,15 @@ void main(int argc, const char *argv[]) {
 
 <h3>Discussion</h3>
 
-NSNumber literals only support literal scalar values after the '@'. Consequently, @INT_MAX works, but @INT_MIN does not, because they are defined like this:<p>
+NSNumber literals only support literal scalar values after the <code>'@'</code>. Consequently, <code>@INT_MAX</code> works, but <code>@INT_MIN</code> does not, because they are defined like this:<p>
 
 <pre>
 #define INT_MAX   2147483647  /* max value for an int */
 #define INT_MIN   (-2147483647-1) /* min value for an int */
 </pre>
 
-The definition of INT_MIN is not a simple literal, but a parenthesized expression. This is by design, but may be improved in subsequent compiler releases.<p>
+The definition of <code>INT_MIN</code> is not a simple literal, but a parenthesized expression. Parenthesized
+expressions are supported using the <a href="#objc_boxed_expressions">boxed expression</a> syntax, which is described in the next section.<p>
 
 Because <code>NSNumber</code> does not currently support wrapping <code>long double</code> values, the use of a <code>long double NSNumber</code> literal (e.g. <code>@123.23L</code>) will be rejected by the compiler.<p>
 
@@ -95,6 +96,94 @@ The compiler implicitly converts <code>__objc_yes</code> and <code>__objc_no</co
 
 Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.
 
+<!-- ======================================================================= -->
+<h2 id="objc_boxed_expressions">Boxed Expressions</h2>
+<!-- ======================================================================= -->
+
+<p>Objective-C provides a new syntax for boxing C expressions:</p>
+
+<pre>
+<code>@( <em>expression</em> )</code>
+</pre>
+
+<p>Expressions of scalar (numeric, enumerated, BOOL) and C string pointer types
+are supported:</p>
+
+<pre>
+// numbers.
+NSNumber *smallestInt = @(-INT_MAX - 1);
+NSNumber *piOverTwo = @(M_PI / 2);
+
+// enumerated types.
+typedef enum { Red, Green, Blue } Color;
+NSNumber *favoriteColor = @(Green);
+
+// strings.
+NSString *path = @(getenv("PATH"));
+NSArray *pathComponents = [path componentsSeparatedByString:@":"];
+</pre>
+
+<h3>Boxed Enums</h3>
+
+<p>
+Cocoa frameworks frequently define constant values using <em>enums.</em> Although enum values are integral, they may not be used directly as boxed literals (this avoids conflicts with future <code>'@'</code>-prefixed Objective-C keywords). Instead, an enum value must be placed inside a boxed expression. The following example demonstrates configuring an <code>AVAudioRecorder</code> using a dictionary that contains a boxed enumeration value:
+</p>
+
+<pre>
+enum {
+  AVAudioQualityMin = 0,
+  AVAudioQualityLow = 0x20,
+  AVAudioQualityMedium = 0x40,
+  AVAudioQualityHigh = 0x60,
+  AVAudioQualityMax = 0x7F
+};
+
+- (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {
+  NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };
+  return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];
+}
+</pre>
+
+<p>
+The expression <code>@(AVAudioQualityMax)</code> converts <code>AVAudioQualityMax</code> to an integer type, and boxes the value accordingly. If the enum has a <a href="http://clang.llvm.org/docs/LanguageExtensions.html#objc_fixed_enum">fixed underlying type</a> as in:
+</p>
+
+<pre>
+typedef enum : unsigned char { Red, Green, Blue } Color;
+NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]
+</pre>
+
+<p>
+then the fixed underlying type will be used to select the correct <code>NSNumber</code> creation method.
+</p>
+
+<h3>Boxed C Strings</h3>
+
+<p>
+A C string literal prefixed by the <code>'@'</code> token denotes an <code>NSString</code> literal in the same way a numeric literal prefixed by the <code>'@'</code> token denotes an <code>NSNumber</code> literal. When the type of the parenthesized expression is <code>(char *)</code> or <code>(const char *)</code>, the result of the boxed expression is a pointer to an <code>NSString</code> object containing equivalent character data. The following example converts C-style command line arguments into <code>NSString</code> objects.
+</p>
+
+<pre>
+// Partition command line arguments into positional and option arguments.
+NSMutableArray *args = [NSMutableArray new];
+NSMutableDictionary *options = [NSMutableArray new];
+while (--argc) {
+    const char *arg = *++argv;
+    if (strncmp(arg, "--", 2) == 0) {
+        options[@(arg + 2)] = @(*++argv);   // --key value
+    } else {
+        [args addObject:@(arg)];            // positional argument
+    }
+}
+</pre>
+
+<p>
+As with all C pointers, character pointer expressions can involve arbitrary pointer arithmetic, therefore programmers must ensure that the character data is valid. Passing <code>NULL</code> as the character pointer will raise an exception at runtime. When possible, the compiler will reject <code>NULL</code> character pointers used in boxed expressions.
+</p>
+
+<h3>Availability</h3>
+
+<p>This feature will be available in clang 3.2. It is not currently available in any Apple compiler.</p>
 
 <h2>Container Literals</h2>
 
@@ -104,9 +193,11 @@ Objective-C now supports a new expression syntax for creating immutable array an
 
 Immutable array expression:<p>
  
- <pre>
+<blockquote>
+<pre>
 NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
 </pre>
+</blockquote>
 
 This creates an <code>NSArray</code> with 3 elements. The comma-separated sub-expressions of an array literal can be any Objective-C object pointer typed expression.<p>
 
@@ -309,6 +400,9 @@ Programs test for the new features by using clang's __has_feature checks. Here a
 
 Code can use also <code>__has_feature(objc_bool)</code> to check for the availability of numeric literals support. This checks for the new <code>__objc_yes / __objc_no</code> keywords, which enable the use of <code>@YES / @NO</code> literals.<p>
 
+<p>To check whether boxed expressions are supported, use
+<code>__has_feature(objc_boxed_expressions)</code> feature macro.</p>
+
 </div>
 </body>
 </html>
index 4bfd12c06930cb92933f184e391b26b87e44a74a..d59662fd9304aaaae71e5fefc09e742ed912e30b 100644 (file)
@@ -87,43 +87,45 @@ public:
   child_range children() { return child_range(); }
 };
 
-/// ObjCNumericLiteral - used for objective-c numeric literals;
-/// as in: @42 or @true (c++/objc++) or @__yes (c/objc)
-class ObjCNumericLiteral : public Expr {
-  /// Number - expression AST node for the numeric literal
-  Stmt *Number;
-  ObjCMethodDecl *ObjCNumericLiteralMethod;
-  SourceLocation AtLoc;
+/// ObjCBoxedExpr - used for generalized expression boxing.
+/// as in: @(strdup("hello world")) or @(random())
+/// 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;
+  ObjCMethodDecl *BoxingMethod;
+  SourceRange Range;
 public:
-  ObjCNumericLiteral(Stmt *NL, QualType T, ObjCMethodDecl *method,
-                     SourceLocation L)
-  : Expr(ObjCNumericLiteralClass, T, VK_RValue, OK_Ordinary, 
-         false, false, false, false), Number(NL), 
-    ObjCNumericLiteralMethod(method), AtLoc(L) {}
-  explicit ObjCNumericLiteral(EmptyShell Empty)
-  : Expr(ObjCNumericLiteralClass, Empty) {}
+  ObjCBoxedExpr(Expr *E, 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) {}
+  explicit ObjCBoxedExpr(EmptyShell Empty)
+  : Expr(ObjCBoxedExprClass, Empty) {}
   
-  Expr *getNumber() { return cast<Expr>(Number); }
-  const Expr *getNumber() const { return cast<Expr>(Number); }
+  Expr *getSubExpr() { return cast<Expr>(SubExpr); }
+  const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
   
-  ObjCMethodDecl *getObjCNumericLiteralMethod() const {
-    return ObjCNumericLiteralMethod; 
+  ObjCMethodDecl *getBoxingMethod() const {
+    return BoxingMethod; 
   }
-    
-  SourceLocation getAtLoc() const { return AtLoc; }
+  
+  SourceLocation getAtLoc() const { return Range.getBegin(); }
   
   SourceRange getSourceRange() const LLVM_READONLY {
-    return SourceRange(AtLoc, Number->getSourceRange().getEnd());
+    return Range;
   }
-
+  
   static bool classof(const Stmt *T) {
-      return T->getStmtClass() == ObjCNumericLiteralClass;
+    return T->getStmtClass() == ObjCBoxedExprClass;
   }
-  static bool classof(const ObjCNumericLiteral *) { return true; }
+  static bool classof(const ObjCBoxedExpr *) { return true; }
   
   // Iterators
-  child_range children() { return child_range(&Number, &Number+1); }
-    
+  child_range children() { return child_range(&SubExpr, &SubExpr+1); }
+  
   friend class ASTStmtReader;
 };
 
index f1b51710213712e2bd7a87efec9ceeb5318ab489..a2f192ba83b20e56c95718e7b71c48b430f68d64 100644 (file)
@@ -2209,7 +2209,7 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { })
 DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
 DEF_TRAVERSE_STMT(StringLiteral, { })
 DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
-DEF_TRAVERSE_STMT(ObjCNumericLiteral, { })
+DEF_TRAVERSE_STMT(ObjCBoxedExpr, { })
 DEF_TRAVERSE_STMT(ObjCArrayLiteral, { })
 DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
   
index a7c6ca3bbefccb381d9ffb56849b1ec7fcc77861..86d42bb72ce17d71eb80e811d1800bc6d6baea5d 100644 (file)
@@ -1518,6 +1518,10 @@ def err_undeclared_nsnumber : Error<
   "NSNumber must be available to use Objective-C literals">;
 def err_invalid_nsnumber_type : Error<
   "%0 is not a valid literal type for NSNumber">;
+def err_undeclared_nsstring : Error<
+  "cannot box a string value because NSString has not been declared">;
+def err_objc_illegal_boxed_expression_type : Error<
+  "Illegal type %0 used in a boxed expression">;
 def err_undeclared_nsarray : Error<
   "NSArray must be available to use Objective-C array literals">;
 def err_undeclared_nsdictionary : Error<
index e7718cd80cb3b3b9345cf3fa823b90064975ebd0..5abc50683c9c50a363a3ca326594704785c2e880 100644 (file)
@@ -134,7 +134,7 @@ def LambdaExpr : DStmt<Expr>;
 
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
-def ObjCNumericLiteral : DStmt<Expr>;
+def ObjCBoxedExpr : DStmt<Expr>;
 def ObjCArrayLiteral : DStmt<Expr>;
 def ObjCDictionaryLiteral : DStmt<Expr>;
 def ObjCEncodeExpr : DStmt<Expr>;
index de62ed2def53dbfcd8b49768b197bf2331e1a0a4..9d9a666c9c95e0354efcf9659d38e343c2c87d72 100644 (file)
@@ -1503,6 +1503,7 @@ private:
   ExprResult ParseObjCBooleanLiteral(SourceLocation AtLoc, bool ArgValue);
   ExprResult ParseObjCArrayLiteral(SourceLocation AtLoc);
   ExprResult ParseObjCDictionaryLiteral(SourceLocation AtLoc);
+  ExprResult ParseObjCBoxedExpr(SourceLocation AtLoc);
   ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
   ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc);
   ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc);
index 8ac7c3ee01a33413cae81bd495212b585d3e008b..e84a554505d137ba11f1efad42e931c5a9582d53 100644 (file)
@@ -523,9 +523,21 @@ public:
   /// \brief The declaration of the Objective-C NSNumber class.
   ObjCInterfaceDecl *NSNumberDecl;
   
+  /// \brief Pointer to NSNumber type (NSNumber *).
+  QualType NSNumberPointer;
+  
   /// \brief The Objective-C NSNumber methods used to create NSNumber literals.
   ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods];
   
+  /// \brief The declaration of the Objective-C NSString class.
+  ObjCInterfaceDecl *NSStringDecl;
+
+  /// \brief Pointer to NSString type (NSString *).
+  QualType NSStringPointer;
+  
+  /// \brief The declaration of the stringWithUTF8String: method.
+  ObjCMethodDecl *StringWithUTF8StringMethod;
+
   /// \brief The declaration of the Objective-C NSArray class.
   ObjCInterfaceDecl *NSArrayDecl;
 
@@ -3848,7 +3860,7 @@ public:
     
   ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S);
   
-  /// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the
+  /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the
   /// numeric literal expression. Type of the expression will be "NSNumber *"
   /// or "id" if NSNumber is unavailable.
   ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number);
@@ -3856,6 +3868,13 @@ public:
                                   bool Value);
   ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements);
   
+  // 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 *".
+  ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr);
+  
   ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
                                           Expr *IndexExpr,
                                           ObjCMethodDecl *getterMethod,
index f9bb8928a3628a796fb95bd7145ab2caee5754cb..f177b2fd5995b5d8eeb772d2d5688b8c47cc2348 100644 (file)
@@ -1066,7 +1066,7 @@ namespace clang {
       /// \brief An ObjCStringLiteral record.
       EXPR_OBJC_STRING_LITERAL,
 
-      EXPR_OBJC_NUMERIC_LITERAL,
+      EXPR_OBJC_BOXED_EXPRESSION,
       EXPR_OBJC_ARRAY_LITERAL,
       EXPR_OBJC_DICTIONARY_LITERAL,
 
index b091e19a8a95aa821902d87af90cdc6f69196c19..f958aded8d3b0e43ff66b3a6303484c1e962bc57 100644 (file)
@@ -158,7 +158,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
   case Expr::ObjCSelectorExprClass:
   case Expr::ObjCProtocolExprClass:
   case Expr::ObjCStringLiteralClass:
-  case Expr::ObjCNumericLiteralClass:
+  case Expr::ObjCBoxedExprClass:
   case Expr::ObjCArrayLiteralClass:
   case Expr::ObjCDictionaryLiteralClass:
   case Expr::ObjCBoolLiteralExprClass:
index 66a88b065ce1b96974eac4ce6e0c3c20e1b0e1bb..818548127cfbb8e7a7dfd39b4b75c1ce5714eb40 100644 (file)
@@ -3073,7 +3073,7 @@ public:
   bool VisitUnaryAddrOf(const UnaryOperator *E);
   bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
       { return Success(E); }
-  bool VisitObjCNumericLiteral(const ObjCNumericLiteral *E)
+  bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E)
       { return Success(E); }    
   bool VisitAddrLabelExpr(const AddrLabelExpr *E)
       { return Success(E); }
@@ -6501,7 +6501,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
   case Expr::CXXDependentScopeMemberExprClass:
   case Expr::UnresolvedMemberExprClass:
   case Expr::ObjCStringLiteralClass:
-  case Expr::ObjCNumericLiteralClass:
+  case Expr::ObjCBoxedExprClass:
   case Expr::ObjCArrayLiteralClass:
   case Expr::ObjCDictionaryLiteralClass:
   case Expr::ObjCEncodeExprClass:
index 0d405f1f57f21eca4b47bf9d205ab7d18b9d5bb2..cf624f6d8060f8e4348e85758c1d16c53d5188f9 100644 (file)
@@ -2390,7 +2390,7 @@ recurse:
   case Expr::ObjCProtocolExprClass:
   case Expr::ObjCSelectorExprClass:
   case Expr::ObjCStringLiteralClass:
-  case Expr::ObjCNumericLiteralClass:
+  case Expr::ObjCBoxedExprClass:
   case Expr::ObjCArrayLiteralClass:
   case Expr::ObjCDictionaryLiteralClass:
   case Expr::ObjCSubscriptRefExprClass:
index 0d1066b7e3225bf64c7ab17d4705d8a503fd73fa..af8e5c792a450b8590e1de33995961e065fb3f7d 100644 (file)
@@ -1727,9 +1727,9 @@ void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
   VisitStringLiteral(Node->getString());
 }
 
-void StmtPrinter::VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+void StmtPrinter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   OS << "@";
-  Visit(E->getNumber());
+  Visit(E->getSubExpr());
 }
 
 void StmtPrinter::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
index e50523ae860bec4020ea38729c255ca131bb4b92..e6b378e16f0360e1e5a73480ed1d22ba875405dc 100644 (file)
@@ -981,7 +981,7 @@ void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) {
   VisitExpr(S);
 }
 
-void StmtProfiler::VisitObjCNumericLiteral(const ObjCNumericLiteral *E) {
+void StmtProfiler::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
   VisitExpr(E);
 }
 
index 18891f7492a28ea588064c9a2b8436cee42f4d03..734531f724beb913cf7f1b4ad01649de6c288158 100644 (file)
@@ -498,8 +498,8 @@ public:
   Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
     return CGF.EmitObjCStringLiteral(E);
   }
-  Value *VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
-    return CGF.EmitObjCNumericLiteral(E);
+  Value *VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
+    return CGF.EmitObjCBoxedExpr(E);
   }
   Value *VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
     return CGF.EmitObjCArrayLiteral(E);
index d0aa0f5567a59a8e7492e5262bd520089ad66e88..fc274a93a8a7701a5bc6b4958fa3a21b3a4f479b 100644 (file)
@@ -51,36 +51,36 @@ llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
   return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
 }
 
-/// EmitObjCNumericLiteral - This routine generates code for
-/// the appropriate +[NSNumber numberWith<Type>:] method.
+/// EmitObjCBoxedExpr - This routine generates code to call
+/// the appropriate expression boxing method. This will either be
+/// one of +[NSNumber numberWith<Type>:], or +[NSString stringWithUTF8String:].
 ///
 llvm::Value *
-CodeGenFunction::EmitObjCNumericLiteral(const ObjCNumericLiteral *E) {
+CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
   // Generate the correct selector for this literal's concrete type.
-  const Expr *NL = E->getNumber();
+  const Expr *SubExpr = E->getSubExpr();
   // Get the method.
-  const ObjCMethodDecl *Method = E->getObjCNumericLiteralMethod();
-  assert(Method && "NSNumber method is null");
-  Selector Sel = Method->getSelector();
+  const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod();
+  assert(BoxingMethod && "BoxingMethod is null");
+  assert(BoxingMethod->isClassMethod() && "BoxingMethod must be a class method");
+  Selector Sel = BoxingMethod->getSelector();
   
   // Generate a reference to the class pointer, which will be the receiver.
-  QualType ResultType = E->getType(); // should be NSNumber *
-  const ObjCObjectPointerType *InterfacePointerType = 
-    ResultType->getAsObjCInterfacePointerType();
-  ObjCInterfaceDecl *NSNumberDecl = 
-    InterfacePointerType->getObjectType()->getInterface();
+  // Assumes that the method was introduced in the class that should be
+  // messaged (avoids pulling it out of the result type).
   CGObjCRuntime &Runtime = CGM.getObjCRuntime();
-  llvm::Value *Receiver = Runtime.GetClass(Builder, NSNumberDecl);
-
-  const ParmVarDecl *argDecl = *Method->param_begin();
+  const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
+  llvm::Value *Receiver = Runtime.GetClass(Builder, ClassDecl);
+  
+  const ParmVarDecl *argDecl = *BoxingMethod->param_begin();
   QualType ArgQT = argDecl->getType().getUnqualifiedType();
-  RValue RV = EmitAnyExpr(NL);
+  RValue RV = EmitAnyExpr(SubExpr);
   CallArgList Args;
   Args.add(RV, ArgQT);
-
+  
   RValue result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(), 
-                                              ResultType, Sel, Receiver, Args, 
-                                              NSNumberDecl, Method);
+                                              BoxingMethod->getResultType(), Sel, Receiver, Args, 
+                                              ClassDecl, BoxingMethod);
   return Builder.CreateBitCast(result.getScalarVal(), 
                                ConvertType(E->getType()));
 }
index 83f1e2df9f45e0a11cede11463c0e0eba078b899..001a37100201d41fee22ea8a91ee76f4f60acad5 100644 (file)
@@ -2264,7 +2264,7 @@ public:
 
   llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E);
   llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E);
-  llvm::Value *EmitObjCNumericLiteral(const ObjCNumericLiteral *E);
+  llvm::Value *EmitObjCBoxedExpr(const ObjCBoxedExpr *E);
   llvm::Value *EmitObjCArrayLiteral(const ObjCArrayLiteral *E);
   llvm::Value *EmitObjCDictionaryLiteral(const ObjCDictionaryLiteral *E);
   llvm::Value *EmitObjCCollectionLiteral(const Expr *E,
index fe7058570efae8197c805c29488b6a922948d61a..50388687dcccf94843b8c1f38cd51d0c3144662d 100644 (file)
@@ -634,6 +634,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
            .Case("objc_subscripting", LangOpts.ObjCNonFragileABI)
            .Case("objc_array_literals", LangOpts.ObjC2)
            .Case("objc_dictionary_literals", LangOpts.ObjC2)
+           .Case("objc_boxed_expressions", LangOpts.ObjC2)
            .Case("arc_cf_code_audited", true)
            // C11 features
            .Case("c_alignas", LangOpts.C11)
index 789a8ae7a93a6ce2339ea69acd5f9da442bf8a01..dd8259964c698bd36381f67a8c55d79614b6677f 100644 (file)
@@ -2066,6 +2066,10 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
     // Objective-C dictionary literal
     return ParsePostfixExpressionSuffix(ParseObjCDictionaryLiteral(AtLoc));
           
+  case tok::l_paren:
+    // Objective-C boxed expression
+    return ParsePostfixExpressionSuffix(ParseObjCBoxedExpr(AtLoc));
+          
   default:
     if (Tok.getIdentifierInfo() == 0)
       return ExprError(Diag(AtLoc, diag::err_unexpected_at));
@@ -2580,6 +2584,28 @@ ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
   return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
 }
 
+/// ParseObjCBoxedExpr -
+/// objc-box-expression:
+///       @( assignment-expression )
+ExprResult
+Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
+  if (Tok.isNot(tok::l_paren))
+    return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@");
+
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+  T.consumeOpen();
+  ExprResult ValueExpr(ParseAssignmentExpression());
+  if (T.consumeClose())
+    return ExprError();
+  
+  // Wrap the sub-expression in a parenthesized expression, to distinguish
+  // a boxed expression from a literal.
+  SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
+  ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.take());
+  return Owned(Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
+                                          ValueExpr.take()));
+}
+
 ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
   ExprVector ElementExprs(Actions);                   // array elements.
   ConsumeBracket(); // consume the l_square.
index 94fba64e17a79a9c343470c7407645f542bce51d..b4da50583a18242a7a9b924fc292aedc98a221c4 100644 (file)
@@ -317,7 +317,7 @@ namespace {
     Stmt *RewriteMessageExpr(ObjCMessageExpr *Exp);
     Stmt *RewriteObjCStringLiteral(ObjCStringLiteral *Exp);
     Stmt *RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp);
-    Stmt *RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp);
+    Stmt *RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp);
     Stmt *RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp);
     Stmt *RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral *Exp);
     Stmt *RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp);
@@ -2471,7 +2471,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Exp) {
   return PE;
 }
 
-Stmt *RewriteModernObjC::RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp) {
+Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
   // synthesize declaration of helper functions needed in this routine.
   if (!SelGetUidFunctionDecl)
     SynthSelGetUidFunctionDecl();
@@ -2489,13 +2489,12 @@ Stmt *RewriteModernObjC::RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp)
   SmallVector<Expr*, 4> MsgExprs;
   SmallVector<Expr*, 4> ClsExprs;
   QualType argType = Context->getPointerType(Context->CharTy);
-  QualType expType = Exp->getType();
   
-  // Create a call to objc_getClass("NSNumber"). It will be th 1st argument.
-  ObjCInterfaceDecl *Class = 
-    expType->getPointeeType()->getAs<ObjCObjectType>()->getInterface();
+  // Create a call to objc_getClass("<BoxingClass>"). It will be the 1st argument.
+  ObjCMethodDecl *BoxingMethod = Exp->getBoxingMethod();
+  ObjCInterfaceDecl *BoxingClass = BoxingMethod->getClassInterface();
   
-  IdentifierInfo *clsName = Class->getIdentifier();
+  IdentifierInfo *clsName = BoxingClass->getIdentifier();
   ClsExprs.push_back(StringLiteral::Create(*Context,
                                            clsName->getName(),
                                            StringLiteral::Ascii, false,
@@ -2506,12 +2505,11 @@ Stmt *RewriteModernObjC::RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp)
                                                StartLoc, EndLoc);
   MsgExprs.push_back(Cls);
   
-  // Create a call to sel_registerName("numberWithBool:"), etc.
+  // Create a call to sel_registerName("<BoxingMethod>:"), etc.
   // it will be the 2nd argument.
   SmallVector<Expr*, 4> SelExprs;
-  ObjCMethodDecl *NumericMethod = Exp->getObjCNumericLiteralMethod();
   SelExprs.push_back(StringLiteral::Create(*Context,
-                                           NumericMethod->getSelector().getAsString(),
+                                           BoxingMethod->getSelector().getAsString(),
                                            StringLiteral::Ascii, false,
                                            argType, SourceLocation()));
   CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl,
@@ -2519,25 +2517,25 @@ Stmt *RewriteModernObjC::RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp)
                                                   StartLoc, EndLoc);
   MsgExprs.push_back(SelExp);
   
-  // User provided numeric literal is the 3rd, and last, argument.
-  Expr *userExpr  = Exp->getNumber();
-  if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(userExpr)) {
+  // User provided sub-expression is the 3rd, and last, argument.
+  Expr *subExpr  = Exp->getSubExpr();
+  if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(subExpr)) {
     QualType type = ICE->getType();
     const Expr *SubExpr = ICE->IgnoreParenImpCasts();
     CastKind CK = CK_BitCast;
     if (SubExpr->getType()->isIntegralType(*Context) && type->isBooleanType())
       CK = CK_IntegralToBoolean;
-    userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, userExpr);
+    subExpr = NoTypeInfoCStyleCastExpr(Context, type, CK, subExpr);
   }
-  MsgExprs.push_back(userExpr);
+  MsgExprs.push_back(subExpr);
   
   SmallVector<QualType, 4> ArgTypes;
   ArgTypes.push_back(Context->getObjCIdType());
   ArgTypes.push_back(Context->getObjCSelType());
-  for (ObjCMethodDecl::param_iterator PI = NumericMethod->param_begin(),
-       E = NumericMethod->param_end(); PI != E; ++PI)
+  for (ObjCMethodDecl::param_iterator PI = BoxingMethod->param_begin(),
+       E = BoxingMethod->param_end(); PI != E; ++PI)
     ArgTypes.push_back((*PI)->getType());
-    
+  
   QualType returnType = Exp->getType();
   // Get the type, we will need to reference it in a couple spots.
   QualType msgSendType = MsgSendFlavor->getType();
@@ -2547,13 +2545,13 @@ Stmt *RewriteModernObjC::RewriteObjCNumericLiteralExpr(ObjCNumericLiteral *Exp)
                                                VK_LValue, SourceLocation());
   
   CastExpr *cast = NoTypeInfoCStyleCastExpr(Context,
-                                  Context->getPointerType(Context->VoidTy),
-                                  CK_BitCast, DRE);
+                                            Context->getPointerType(Context->VoidTy),
+                                            CK_BitCast, DRE);
   
   // Now do the "normal" pointer to function cast.
   QualType castType =
-    getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
-                          NumericMethod->isVariadic());
+  getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
+                        BoxingMethod->isVariadic());
   castType = Context->getPointerType(castType);
   cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
                                   cast);
@@ -5214,8 +5212,8 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
   if (ObjCBoolLiteralExpr *BoolLitExpr = dyn_cast<ObjCBoolLiteralExpr>(S))
     return RewriteObjCBoolLiteralExpr(BoolLitExpr);
   
-  if (ObjCNumericLiteral *NumericLitExpr = dyn_cast<ObjCNumericLiteral>(S))
-    return RewriteObjCNumericLiteralExpr(NumericLitExpr);
+  if (ObjCBoxedExpr *BoxedExpr = dyn_cast<ObjCBoxedExpr>(S))
+    return RewriteObjCBoxedExpr(BoxedExpr);
   
   if (ObjCArrayLiteral *ArrayLitExpr = dyn_cast<ObjCArrayLiteral>(S))
     return RewriteObjCArrayLiteralExpr(ArrayLitExpr);
index 14b24341d09482e40ac699203f6fd0827582aad5..ec33f0ac8e64b06e47ce598173edfa2352a733db 100644 (file)
@@ -964,7 +964,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
     // possibility.
   case Expr::ObjCArrayLiteralClass:
   case Expr::ObjCDictionaryLiteralClass:
-  case Expr::ObjCNumericLiteralClass:
+  case Expr::ObjCBoxedExprClass:
     return CT_Can;
 
     // Many other things have subexpressions, so we have to test those.
index af86cb2c43e1318becdd691ef621ef23342c60e0..af0f971c1ca3f50d882d49d5c9a9b00893a01298 100644 (file)
@@ -4522,8 +4522,8 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
       ObjCMethodDecl *D = 0;
       if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
         D = Send->getMethodDecl();
-      } else if (ObjCNumericLiteral *NumLit = dyn_cast<ObjCNumericLiteral>(E)) {
-        D = NumLit->getObjCNumericLiteralMethod();
+      } else if (ObjCBoxedExpr *BoxedExpr = dyn_cast<ObjCBoxedExpr>(E)) {
+        D = BoxedExpr->getBoxingMethod();
       } else if (ObjCArrayLiteral *ArrayLit = dyn_cast<ObjCArrayLiteral>(E)) {
         D = ArrayLit->getArrayWithObjectsMethod();
       } else if (ObjCDictionaryLiteral *DictLit
index b62d56efdab60ca78e3d24833e990aa94b67de2f..41fd112c71882b9c1703c10dec6849e2f55bf287 100644 (file)
@@ -111,7 +111,7 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
       Ty = Context.getObjCIdType();
     }
   } else {
-    IdentifierInfo *NSIdent = &Context.Idents.get("NSString");
+    IdentifierInfo *NSIdent = NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
     NamedDecl *IF = LookupSingleName(TUScope, NSIdent, AtLoc,
                                      LookupOrdinaryName);
     if (ObjCInterfaceDecl *StrIF = dyn_cast_or_null<ObjCInterfaceDecl>(IF)) {
@@ -143,17 +143,20 @@ ExprResult Sema::BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S){
 /// \brief Retrieve the NSNumber factory method that should be used to create
 /// an Objective-C literal for the given type.
 static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
-                                                QualType T, QualType ReturnType,
-                                                SourceRange Range) {
+                                                QualType NumberType,
+                                                bool isLiteral = false,
+                                                SourceRange R = SourceRange()) {
   llvm::Optional<NSAPI::NSNumberLiteralMethodKind> Kind 
-    = S.NSAPIObj->getNSNumberFactoryMethodKind(T);
+    = S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
   
   if (!Kind) {
-    S.Diag(Loc, diag::err_invalid_nsnumber_type)
-      << T << Range;
+    if (isLiteral) {
+      S.Diag(Loc, diag::err_invalid_nsnumber_type)
+        << NumberType << R;
+    }
     return 0;
   }
-    
+  
   // If we already looked up this method, we're done.
   if (S.NSNumberLiteralMethods[*Kind])
     return S.NSNumberLiteralMethods[*Kind];
@@ -161,23 +164,52 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
   Selector Sel = S.NSAPIObj->getNSNumberLiteralSelector(*Kind,
                                                         /*Instance=*/false);
   
+  ASTContext &CX = S.Context;
+  
+  // Look up the NSNumber class, if we haven't done so already. It's cached
+  // in the Sema instance.
+  if (!S.NSNumberDecl) {
+    IdentifierInfo *NSNumberId = S.NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber);
+    NamedDecl *IF = S.LookupSingleName(S.TUScope, NSNumberId,
+                                       Loc, Sema::LookupOrdinaryName);
+    S.NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+    if (!S.NSNumberDecl) {
+      if (S.getLangOpts().DebuggerObjCLiteral) {
+        // Create a stub definition of NSNumber.
+        S.NSNumberDecl =  ObjCInterfaceDecl::Create (CX,
+                                                     CX.getTranslationUnitDecl(),
+                                                     SourceLocation(),  NSNumberId,
+                                                     0, SourceLocation());
+      } else {
+        // Otherwise, require a declaration of NSNumber.
+        S.Diag(Loc, diag::err_undeclared_nsnumber);
+        return 0;
+      }
+    } else if (!S.NSNumberDecl->hasDefinition()) {
+      S.Diag(Loc, diag::err_undeclared_nsnumber);
+      return 0;
+    }
+    
+    // generate the pointer to NSNumber type.
+    S.NSNumberPointer = CX.getObjCObjectPointerType(CX.getObjCInterfaceType(S.NSNumberDecl));
+  }
+  
   // Look for the appropriate method within NSNumber.
   ObjCMethodDecl *Method = S.NSNumberDecl->lookupClassMethod(Sel);;
   if (!Method && S.getLangOpts().DebuggerObjCLiteral) {
+    // create a stub definition this NSNumber factory method.
     TypeSourceInfo *ResultTInfo = 0;
-    Method = ObjCMethodDecl::Create(S.Context, SourceLocation(), SourceLocation(), Sel,
-                           ReturnType,
-                           ResultTInfo,
-                           S.Context.getTranslationUnitDecl(),
-                           false /*Instance*/, false/*isVariadic*/,
-                           /*isSynthesized=*/false,
-                           /*isImplicitlyDeclared=*/true, /*isDefined=*/false,
-                           ObjCMethodDecl::Required,
-                           false);
+    Method = ObjCMethodDecl::Create(CX, SourceLocation(), SourceLocation(), Sel,
+                                    S.NSNumberPointer, ResultTInfo, S.NSNumberDecl,
+                                    /*isInstance=*/false, /*isVariadic=*/false,
+                                    /*isSynthesized=*/false,
+                                    /*isImplicitlyDeclared=*/true,
+                                    /*isDefined=*/false, ObjCMethodDecl::Required,
+                                    /*HasRelatedResultType=*/false);
     ParmVarDecl *value = ParmVarDecl::Create(S.Context, Method,
                                              SourceLocation(), SourceLocation(),
-                                             &S.Context.Idents.get("value"),
-                                             T, /*TInfo=*/0, SC_None, SC_None, 0);
+                                             &CX.Idents.get("value"),
+                                             NumberType, /*TInfo=*/0, SC_None, SC_None, 0);
     Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>());
   }
 
@@ -202,29 +234,12 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
   return Method;
 }
 
-/// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the
-/// numeric literal expression. Type of the expression will be "NSNumber *"
-/// or "id" if NSNumber is unavailable.
+/// 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) {
-  // Look up the NSNumber class, if we haven't done so already.
-  if (!NSNumberDecl) {
-    NamedDecl *IF = LookupSingleName(TUScope,
-                                NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber),
-                                AtLoc, LookupOrdinaryName);
-    NSNumberDecl = dyn_cast_or_null<ObjCInterfaceDecl>(IF);
+  // compute the effective range of the literal, including the leading '@'.
+  SourceRange SR(AtLoc, Number->getSourceRange().getEnd());
     
-    if (!NSNumberDecl && getLangOpts().DebuggerObjCLiteral)
-      NSNumberDecl =  ObjCInterfaceDecl::Create (Context,
-                        Context.getTranslationUnitDecl(),
-                        SourceLocation(), 
-                        NSAPIObj->getNSClassId(NSAPI::ClassId_NSNumber),
-                        0, SourceLocation());
-    if (!NSNumberDecl) {
-      Diag(AtLoc, diag::err_undeclared_nsnumber);
-      return ExprError();
-    }
-  }
-  
   // Determine the type of the literal.
   QualType NumberType = Number->getType();
   if (CharacterLiteral *Char = dyn_cast<CharacterLiteral>(Number)) {
@@ -249,29 +264,23 @@ ExprResult Sema::BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number) {
     }
   }
   
-  ObjCMethodDecl *Method = 0;
   // Look for the appropriate method within NSNumber.
   // Construct the literal.
-  QualType Ty
-    = Context.getObjCObjectPointerType(
-                                    Context.getObjCInterfaceType(NSNumberDecl));
-  Method  = getNSNumberFactoryMethod(*this, AtLoc, 
-                                     NumberType, Ty, 
-                                     Number->getSourceRange());
-
+  ObjCMethodDecl *Method = getNSNumberFactoryMethod(*this, AtLoc, NumberType,
+                                                    true, Number->getSourceRange());
   if (!Method)
     return ExprError();
 
   // Convert the number to the type that the parameter expects.
-  QualType ElementT = Method->param_begin()[0]->getType();
-  ExprResult ConvertedNumber = PerformImplicitConversion(Number, ElementT,
+  QualType ArgType = Method->param_begin()[0]->getType();
+  ExprResult ConvertedNumber = PerformImplicitConversion(Number, ArgType,
                                                          AA_Sending);
   if (ConvertedNumber.isInvalid())
     return ExprError();
   Number = ConvertedNumber.get();
   
   return MaybeBindToTemporary(
-           new (Context) ObjCNumericLiteral(Number, Ty, Method, AtLoc));
+           new (Context) ObjCBoxedExpr(Number, NSNumberPointer, Method, SR));
 }
 
 ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation AtLoc, 
@@ -385,6 +394,144 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element,
            Element->getLocStart(), Element);
 }
 
+ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
+  if (ValueExpr->isTypeDependent()) {
+    ObjCBoxedExpr *BoxedExpr = 
+      new (Context) ObjCBoxedExpr(ValueExpr, Context.DependentTy, NULL, SR);
+    return Owned(BoxedExpr);
+  }
+  ObjCMethodDecl *BoxingMethod = NULL;
+  QualType BoxedType;
+  // Convert the expression to an RValue, so we can check for pointer types...
+  ExprResult RValue = DefaultFunctionArrayLvalueConversion(ValueExpr);
+  if (RValue.isInvalid()) {
+    return ExprError();
+  }
+  ValueExpr = RValue.get();
+  QualType ValueType(ValueExpr->getType().getCanonicalType());
+  if (const PointerType *PT = ValueType->getAs<PointerType>()) {
+    QualType PointeeType = PT->getPointeeType();
+    if (Context.hasSameUnqualifiedType(PointeeType, Context.CharTy)) {
+
+      if (!NSStringDecl) {
+        IdentifierInfo *NSStringId =
+          NSAPIObj->getNSClassId(NSAPI::ClassId_NSString);
+        NamedDecl *Decl = LookupSingleName(TUScope, NSStringId,
+                                           SR.getBegin(), LookupOrdinaryName);
+        NSStringDecl = dyn_cast_or_null<ObjCInterfaceDecl>(Decl);
+        if (!NSStringDecl) {
+          if (getLangOpts().DebuggerObjCLiteral) {
+            // Support boxed expressions in the debugger w/o NSString declaration.
+            NSStringDecl = ObjCInterfaceDecl::Create(Context,
+                                                     Context.getTranslationUnitDecl(),
+                                                     SourceLocation(), NSStringId,
+                                                     0, SourceLocation());
+          } else {
+            Diag(SR.getBegin(), diag::err_undeclared_nsstring);
+            return ExprError();
+          }
+        } else if (!NSStringDecl->hasDefinition()) {
+          Diag(SR.getBegin(), diag::err_undeclared_nsstring);
+          return ExprError();
+        }
+        assert(NSStringDecl && "NSStringDecl should not be NULL");
+        NSStringPointer =
+          Context.getObjCObjectPointerType(Context.getObjCInterfaceType(NSStringDecl));
+      }
+      
+      if (!StringWithUTF8StringMethod) {
+        IdentifierInfo *II = &Context.Idents.get("stringWithUTF8String");
+        Selector stringWithUTF8String = Context.Selectors.getUnarySelector(II);
+
+        // Look for the appropriate method within NSString.
+        StringWithUTF8StringMethod = NSStringDecl->lookupClassMethod(stringWithUTF8String);
+        if (!StringWithUTF8StringMethod && getLangOpts().DebuggerObjCLiteral) {
+          // Debugger needs to work even if NSString hasn't been defined.
+          TypeSourceInfo *ResultTInfo = 0;
+          ObjCMethodDecl *M =
+            ObjCMethodDecl::Create(Context, SourceLocation(), SourceLocation(),
+                                   stringWithUTF8String, NSStringPointer,
+                                   ResultTInfo, NSStringDecl,
+                                   /*isInstance=*/false, /*isVariadic=*/false,
+                                   /*isSynthesized=*/false,
+                                   /*isImplicitlyDeclared=*/true,
+                                   /*isDefined=*/false,
+                                   ObjCMethodDecl::Required,
+                                   /*HasRelatedResultType=*/false);
+          ParmVarDecl *value =
+            ParmVarDecl::Create(Context, M,
+                                SourceLocation(), SourceLocation(),
+                                &Context.Idents.get("value"),
+                                Context.getPointerType(Context.CharTy.withConst()),
+                                /*TInfo=*/0,
+                                SC_None, SC_None, 0);
+          M->setMethodParams(Context, value, ArrayRef<SourceLocation>());
+          StringWithUTF8StringMethod = M;
+        }
+        assert(StringWithUTF8StringMethod &&
+               "StringWithUTF8StringMethod should not be NULL");
+      }
+      
+      BoxingMethod = StringWithUTF8StringMethod;
+      BoxedType = NSStringPointer;
+    }
+  } else if (isa<BuiltinType>(ValueType)) {
+    // 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.getWCharType();
+        break;
+        
+      case CharacterLiteral::UTF16:
+        ValueType = Context.Char16Ty;
+        break;
+        
+      case CharacterLiteral::UTF32:
+        ValueType = Context.Char32Ty;
+        break;
+      }
+    }
+    
+    // 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;
+  }
+
+  if (!BoxingMethod) {
+    Diag(SR.getBegin(), diag::err_objc_illegal_boxed_expression_type)
+      << ValueType << ValueExpr->getSourceRange();
+    return ExprError();
+  }
+  
+  // Convert the expression to the type that the parameter requires.
+  QualType ArgType = BoxingMethod->param_begin()[0]->getType();
+  ExprResult ConvertedValueExpr = PerformImplicitConversion(ValueExpr, ArgType,
+                                                            AA_Sending);
+  if (ConvertedValueExpr.isInvalid())
+    return ExprError();
+  ValueExpr = ConvertedValueExpr.get();
+  
+  ObjCBoxedExpr *BoxedExpr = 
+    new (Context) ObjCBoxedExpr(ValueExpr, BoxedType,
+                                      BoxingMethod, SR);
+  return MaybeBindToTemporary(BoxedExpr);
+}
+
 ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
                                         Expr *IndexExpr,
                                         ObjCMethodDecl *getterMethod,
index a66378e51783d2104a590483c25e075501db14a5..7387eac667ba25db736dbbd4e1c781e5c15f630d 100644 (file)
@@ -2225,6 +2225,14 @@ public:
                                                 RParenLoc);
   }
 
+  /// \brief Build a new Objective-C boxed expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  ExprResult RebuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
+    return getSema().BuildObjCBoxedExpr(SR, ValueExpr);
+  }
+  
   /// \brief Build a new Objective-C array literal.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -8352,8 +8360,16 @@ TreeTransform<Derived>::TransformObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) {
 
 template<typename Derived>
 ExprResult
-TreeTransform<Derived>::TransformObjCNumericLiteral(ObjCNumericLiteral *E) {
-  return SemaRef.MaybeBindToTemporary(E);
+TreeTransform<Derived>::TransformObjCBoxedExpr(ObjCBoxedExpr *E) {
+  ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+  if (SubExpr.isInvalid())
+    return ExprError();
+
+  if (!getDerived().AlwaysRebuild() &&
+      SubExpr.get() == E->getSubExpr())
+    return SemaRef.Owned(E);
+
+  return getDerived().RebuildObjCBoxedExpr(E->getSourceRange(), SubExpr.get());
 }
 
 template<typename Derived>
index 007ecee9f53fa73eb4eeb11eaaf3dc5c43b59918..73b5ab7ec6d1cbb342618a1c63ad48b588c1a3f8 100644 (file)
@@ -816,12 +816,12 @@ void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) {
   E->setAtLoc(ReadSourceLocation(Record, Idx));
 }
 
-void ASTStmtReader::VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+void ASTStmtReader::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   VisitExpr(E);
   // could be one of several IntegerLiteral, FloatLiteral, etc.
-  E->Number = Reader.ReadSubStmt();
-  E->ObjCNumericLiteralMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
-  E->AtLoc = ReadSourceLocation(Record, Idx);
+  E->SubExpr = Reader.ReadSubStmt();
+  E->BoxingMethod = ReadDeclAs<ObjCMethodDecl>(Record, Idx);
+  E->Range = ReadSourceRange(Record, Idx);
 }
 
 void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
@@ -1888,8 +1888,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
     case EXPR_OBJC_STRING_LITERAL:
       S = new (Context) ObjCStringLiteral(Empty);
       break;
-    case EXPR_OBJC_NUMERIC_LITERAL:
-      S = new (Context) ObjCNumericLiteral(Empty);
+    case EXPR_OBJC_BOXED_EXPRESSION:
+      S = new (Context) ObjCBoxedExpr(Empty);
       break;
     case EXPR_OBJC_ARRAY_LITERAL:
       S = ObjCArrayLiteral::CreateEmpty(Context,
index 81c0a9dd48acd1c2192478e263c1f097f92d0ef2..e9c0596becb8789460f54bf41b9f3a0cc92a73a8 100644 (file)
@@ -696,7 +696,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
   RECORD(EXPR_BLOCK);
   RECORD(EXPR_GENERIC_SELECTION);
   RECORD(EXPR_OBJC_STRING_LITERAL);
-  RECORD(EXPR_OBJC_NUMERIC_LITERAL);
+  RECORD(EXPR_OBJC_BOXED_EXPRESSION);
   RECORD(EXPR_OBJC_ARRAY_LITERAL);
   RECORD(EXPR_OBJC_DICTIONARY_LITERAL);
   RECORD(EXPR_OBJC_ENCODE);
index 1e312114631944b619a277e10a5b9dc408552aa8..89436157df98be7c6e77330c9da282ee50bca615 100644 (file)
@@ -777,12 +777,12 @@ void ASTStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) {
   Code = serialization::EXPR_OBJC_STRING_LITERAL;
 }
 
-void ASTStmtWriter::VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+void ASTStmtWriter::VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
   VisitExpr(E);
-  Writer.AddStmt(E->getNumber());
-  Writer.AddDeclRef(E->getObjCNumericLiteralMethod(), Record);
-  Writer.AddSourceLocation(E->getAtLoc(), Record);
-  Code = serialization::EXPR_OBJC_NUMERIC_LITERAL;
+  Writer.AddStmt(E->getSubExpr());
+  Writer.AddDeclRef(E->getBoxingMethod(), Record);
+  Writer.AddSourceRange(E->getSourceRange(), Record);
+  Code = serialization::EXPR_OBJC_BOXED_EXPRESSION;
 }
 
 void ASTStmtWriter::VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
index 1fd90685186e16fd55c6eb73961e7092efae1097..abc63165384dba31a6f39a61ba2a694699367a30 100644 (file)
@@ -592,7 +592,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::ObjCIsaExprClass:
     case Stmt::ObjCProtocolExprClass:
     case Stmt::ObjCSelectorExprClass:
-    case Expr::ObjCNumericLiteralClass:
+    case Expr::ObjCBoxedExprClass:
     case Stmt::ParenListExprClass:
     case Stmt::PredefinedExprClass:
     case Stmt::ShuffleVectorExprClass:
index 389ef2248a48113ad2137975c507af6fdd400885..f6a6dfa853c04218d49f7510ae274ebcacb0d672 100644 (file)
@@ -1,7 +1,8 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdebugger-objc-literal -emit-llvm -o - %s | FileCheck %s
 
 int main() {
-  id l = @'a';
+  // object literals.
+  id l;
   l = @'a';
   l = @42;
   l = @-42;
@@ -11,6 +12,19 @@ int main() {
   l = @__objc_no;
   l = @{ @"name":@666 };
   l = @[ @"foo", @"bar" ];
+
+#if __has_feature(objc_boxed_expressions)
+  // boxed expressions.
+  id b;
+  b = @('a');
+  b = @(42);
+  b = @(-42);
+  b = @(42u);
+  b = @(3.141592654f);
+  b = @(__objc_yes);
+  b = @(__objc_no);
+  b = @("hello");
+#endif
 }
 
 // CHECK: declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind
diff --git a/test/Parser/objc-boxing.m b/test/Parser/objc-boxing.m
new file mode 100644 (file)
index 0000000..a16a137
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface NSString @end
+
+@interface NSString (NSStringExtensionMethods)
++ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
+@end
+
+extern char *strdup(const char *str);
+
+id constant_string() {
+    return @("boxed constant string.");
+}
+
+id dynamic_string() {
+    return @(strdup("boxed dynamic string"));
+}
+
+id const_char_pointer() {
+    return @((const char *)"constant character pointer");
+}
+
+id missing_parentheses() {
+    return @(5;             // expected-error {{expected ')'}} \
+                            // expected-note {{to match this '('}}
+}
diff --git a/test/Rewriter/objc-modern-boxing.mm b/test/Rewriter/objc-modern-boxing.mm
new file mode 100644 (file)
index 0000000..9a2ce68
--- /dev/null
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -E %s -o %t.mm
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o %t-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-rw.cpp -Wno-attributes -Werror
+
+extern char *strdup(const char *str);
+extern "C" void *sel_registerName(const char *);
+
+typedef signed char BOOL;
+typedef long NSInteger;
+typedef unsigned long NSUInteger;
+
+#if __has_feature(objc_bool)
+#define YES             __objc_yes
+#define NO              __objc_no
+#else
+#define YES             ((BOOL)1)
+#define NO              ((BOOL)0)
+#endif
+
+@interface NSNumber
++ (NSNumber *)numberWithChar:(char)value;
++ (NSNumber *)numberWithUnsignedChar:(unsigned char)value;
++ (NSNumber *)numberWithShort:(short)value;
++ (NSNumber *)numberWithUnsignedShort:(unsigned short)value;
++ (NSNumber *)numberWithInt:(int)value;
++ (NSNumber *)numberWithUnsignedInt:(unsigned int)value;
++ (NSNumber *)numberWithLong:(long)value;
++ (NSNumber *)numberWithUnsignedLong:(unsigned long)value;
++ (NSNumber *)numberWithLongLong:(long long)value;
++ (NSNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
++ (NSNumber *)numberWithFloat:(float)value;
++ (NSNumber *)numberWithDouble:(double)value;
++ (NSNumber *)numberWithBool:(BOOL)value;
++ (NSNumber *)numberWithInteger:(NSInteger)value ;
++ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value ;
+@end
+
+@interface NSString
++ (id)stringWithUTF8String:(const char *)str;
+@end
+
+int main(int argc, const char *argv[]) {
+  // character.
+  NSNumber *theLetterZ = @('Z');          // equivalent to [NSNumber numberWithChar:('Z')]
+
+  // integral.
+  NSNumber *fortyTwo = @(42);             // equivalent to [NSNumber numberWithInt:(42)]
+  NSNumber *fortyTwoUnsigned = @(42U);    // equivalent to [NSNumber numberWithUnsignedInt:(42U)]
+  NSNumber *fortyTwoLong = @(42L);        // equivalent to [NSNumber numberWithLong:(42L)]
+  NSNumber *fortyTwoLongLong = @(42LL);   // equivalent to [NSNumber numberWithLongLong:(42LL)]
+
+  // floating point.
+  NSNumber *piFloat = @(3.141592654F);    // equivalent to [NSNumber numberWithFloat:(3.141592654F)]
+  NSNumber *piDouble = @(3.1415926535);   // equivalent to [NSNumber numberWithDouble:(3.1415926535)]
+
+  // Strings.
+  NSString *duplicateString = @(strdup("Hello"));
+}
+
+// CHECK:  NSNumber *theLetterZ = ((NSNumber *(*)(id, SEL, char))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithChar:"), ('Z'));
+// CHECK:  NSNumber *fortyTwo = ((NSNumber *(*)(id, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), (42));
+// CHECK:  NSNumber *fortyTwoUnsigned = ((NSNumber *(*)(id, SEL, unsigned int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithUnsignedInt:"), (42U));
+// CHECK:  NSNumber *fortyTwoLong = ((NSNumber *(*)(id, SEL, long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLong:"), (42L));
+// CHECK:  NSNumber *fortyTwoLongLong = ((NSNumber *(*)(id, SEL, long long))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithLongLong:"), (42LL));
+// CHECK:  NSNumber *piFloat = ((NSNumber *(*)(id, SEL, float))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithFloat:"), (3.1415927));
+// CHECK:  NSNumber *piDouble = ((NSNumber *(*)(id, SEL, double))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithDouble:"), (3.1415926535));
+// CHECK:  NSString *duplicateString = ((NSString *(*)(id, SEL, const char *))(void *)objc_msgSend)(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), (const char *)(strdup("Hello")));
diff --git a/test/SemaObjC/boxing-illegal-types.m b/test/SemaObjC/boxing-illegal-types.m
new file mode 100644 (file)
index 0000000..dcfcee8
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wattributes %s
+
+typedef struct {
+    int x, y, z;
+} point;
+
+void testStruct() {
+    point p = { 0, 0, 0 };
+    id boxed = @(p);    // expected-error {{Illegal type 'point' used in a boxed expression}}
+}
+
+void testPointers() {
+    void *null = 0;
+    id boxed_null = @(null);        // expected-error {{Illegal type 'void *' used in a boxed expression}}
+    int numbers[] = { 0, 1, 2 };
+    id boxed_numbers = @(numbers);  // expected-error {{Illegal type 'int *' used in a boxed expression}}
+}
index 2780f8e5797835382df767f0d52b32a9265ff969..1a1a86885d68e9d58c2a67c1857938caa2906d1c 100644 (file)
@@ -46,3 +46,24 @@ template <typename T> struct EncodeTest {
 template struct EncodeTest<int>;
 template struct EncodeTest<double>;
 template struct EncodeTest<wchar_t>;
+
+// @() boxing expressions.
+template <typename T> struct BoxingTest {
+  static id box(T value) {
+    return @(value);                     // expected-error {{Illegal type 'int *' used in a boxed expression}} \
+                                         // expected-error {{Illegal type 'long double' used in a boxed expression}}
+  }
+};
+
+@interface NSNumber
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+@interface NSString
++ (id)stringWithUTF8String:(const char *)str;
+@end
+
+template struct BoxingTest<int>;
+template struct BoxingTest<const char *>;
+template struct BoxingTest<int *>;        // expected-note {{in instantiation of member function 'BoxingTest<int *>::box' requested here}}
+template struct BoxingTest<long double>;  // expected-note {{in instantiation of member function 'BoxingTest<long double>::box' requested here}}
index a2987595624359bdcc379cfbd035a2f21c420382..678798f9aa8ee725b4d7b688c49f7c8277886234 100644 (file)
@@ -229,7 +229,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
   case Stmt::VAArgExprClass:
   case Stmt::ObjCArrayLiteralClass:
   case Stmt::ObjCDictionaryLiteralClass:
-  case Stmt::ObjCNumericLiteralClass:
+  case Stmt::ObjCBoxedExprClass:
   case Stmt::ObjCSubscriptRefExprClass:
     K = CXCursor_UnexposedExpr;
     break;
index 74a8d37d42fc1fdc315bdc80d44f78653a78d79b..239dde21bd4e2f07caa970a92c2001d2c245d07e 100644 (file)
@@ -90,13 +90,13 @@ public:
     return true;
   }
 
-  bool VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
-    if (ObjCMethodDecl *MD = E->getObjCNumericLiteralMethod())
+  bool VisitObjCBoxedExpr(ObjCBoxedExpr *E) {
+    if (ObjCMethodDecl *MD = E->getBoxingMethod())
       IndexCtx.handleReference(MD, E->getLocStart(),
                                Parent, ParentDC, E, CXIdxEntityRef_Implicit);
     return true;
   }
-
+  
   bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
     if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod())
       IndexCtx.handleReference(MD, E->getLocStart(),