diff options
Diffstat (limited to 'clang')
35 files changed, 624 insertions, 162 deletions
diff --git a/clang/docs/LanguageExtensions.html b/clang/docs/LanguageExtensions.html index 68f0afc1ffa..9bae334f19b 100644 --- a/clang/docs/LanguageExtensions.html +++ b/clang/docs/LanguageExtensions.html @@ -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> diff --git a/clang/docs/ObjectiveCLiterals.html b/clang/docs/ObjectiveCLiterals.html index 63b523c6dfc..dc2f2fff09a 100644 --- a/clang/docs/ObjectiveCLiterals.html +++ b/clang/docs/ObjectiveCLiterals.html @@ -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> diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h index 4bfd12c0693..d59662fd930 100644 --- a/clang/include/clang/AST/ExprObjC.h +++ b/clang/include/clang/AST/ExprObjC.h @@ -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;  }; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f1b51710213..a2f192ba83b 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -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, { }) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index a7c6ca3bbef..86d42bb72ce 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index e7718cd80cb..5abc50683c9 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -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>; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index de62ed2def5..9d9a666c9c9 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8ac7c3ee01a..e84a554505d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -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, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index f9bb8928a36..f177b2fd599 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -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, diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index b091e19a8a9..f958aded8d3 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -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: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 66a88b065ce..818548127cf 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 0d405f1f57f..cf624f6d806 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -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: diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 0d1066b7e32..af8e5c792a4 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -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) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index e50523ae860..e6b378e16f0 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -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);  } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 18891f7492a..734531f724b 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -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); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index d0aa0f5567a..fc274a93a8a 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -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()));  } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 83f1e2df9f4..001a3710020 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -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, diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index fe7058570ef..50388687dcc 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -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) diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 789a8ae7a93..dd8259964c6 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -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. diff --git a/clang/lib/Rewrite/RewriteModernObjC.cpp b/clang/lib/Rewrite/RewriteModernObjC.cpp index 94fba64e17a..b4da50583a1 100644 --- a/clang/lib/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Rewrite/RewriteModernObjC.cpp @@ -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); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 14b24341d09..ec33f0ac8e6 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -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. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index af86cb2c43e..af0f971c1ca 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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 diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index b62d56efdab..41fd112c718 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -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, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index a66378e5178..7387eac667b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -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> diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 007ecee9f53..73b5ab7ec6d 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -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, diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 81c0a9dd48a..e9c0596becb 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -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); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 1e312114631..89436157df9 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -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) { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 1fd90685186..abc63165384 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -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: diff --git a/clang/test/CodeGenObjC/objc-literal-debugger-test.m b/clang/test/CodeGenObjC/objc-literal-debugger-test.m index 389ef2248a4..f6a6dfa853c 100644 --- a/clang/test/CodeGenObjC/objc-literal-debugger-test.m +++ b/clang/test/CodeGenObjC/objc-literal-debugger-test.m @@ -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/clang/test/Parser/objc-boxing.m b/clang/test/Parser/objc-boxing.m new file mode 100644 index 00000000000..a16a137b8f6 --- /dev/null +++ b/clang/test/Parser/objc-boxing.m @@ -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/clang/test/Rewriter/objc-modern-boxing.mm b/clang/test/Rewriter/objc-modern-boxing.mm new file mode 100644 index 00000000000..9a2ce681d57 --- /dev/null +++ b/clang/test/Rewriter/objc-modern-boxing.mm @@ -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/clang/test/SemaObjC/boxing-illegal-types.m b/clang/test/SemaObjC/boxing-illegal-types.m new file mode 100644 index 00000000000..dcfcee81606 --- /dev/null +++ b/clang/test/SemaObjC/boxing-illegal-types.m @@ -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}} +} diff --git a/clang/test/SemaTemplate/instantiate-objc-1.mm b/clang/test/SemaTemplate/instantiate-objc-1.mm index 2780f8e5797..1a1a86885d6 100644 --- a/clang/test/SemaTemplate/instantiate-objc-1.mm +++ b/clang/test/SemaTemplate/instantiate-objc-1.mm @@ -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}} diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index a2987595624..678798f9aa8 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -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; diff --git a/clang/tools/libclang/IndexBody.cpp b/clang/tools/libclang/IndexBody.cpp index 74a8d37d42f..239dde21bd4 100644 --- a/clang/tools/libclang/IndexBody.cpp +++ b/clang/tools/libclang/IndexBody.cpp @@ -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(),  | 

