Skip to content

Commit 0caa394

Browse files
committed
Implements boxed expressions for Objective-C. <rdar://problem/10194391>
llvm-svn: 155082
1 parent 201ba5f commit 0caa394

35 files changed

+624
-162
lines changed

clang/docs/LanguageExtensions.html

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ <h1>Clang Language Extensions</h1>
9191
<li><a href="#objc_arc">Automatic reference counting</a></li>
9292
<li><a href="#objc_fixed_enum">Enumerations with a fixed underlying type</a></li>
9393
<li><a href="#objc_lambdas">Interoperability with C++11 lambdas</a></li>
94-
<li><a href="#object-literals-subscripting">Object Literals and Subscripting</a></li>
94+
<li><a href="#objc_object_literals_subscripting">Object Literals and Subscripting</a></li>
9595
</ul>
9696
</li>
9797
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
@@ -1183,10 +1183,18 @@ <h2 id="objc_lambdas">Interoperability with C++11 lambdas</h2>
11831183
Objective-C memory management (autorelease).</p>
11841184

11851185
<!-- ======================================================================= -->
1186-
<h2 id="object-literals-subscripting">Object Literals and Subscripting</h2>
1186+
<h2 id="objc_object_literals_subscripting">Object Literals and Subscripting</h2>
11871187
<!-- ======================================================================= -->
11881188

1189-
<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>
1189+
<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals
1190+
and Subscripting</a> in Objective-C, which simplifies common Objective-C
1191+
programming patterns, makes programs more concise, and improves the safety of
1192+
container creation. There are several feature macros associated with object
1193+
literals and subscripting: <code>__has_feature(objc_array_literals)</code>
1194+
tests the availability of array literals;
1195+
<code>__has_feature(objc_dictionary_literals)</code> tests the availability of
1196+
dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the
1197+
availability of object subscripting.</p>
11901198

11911199
<!-- ======================================================================= -->
11921200
<h2 id="overloading-in-c">Function Overloading in C</h2>

clang/docs/ObjectiveCLiterals.html

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,15 @@ <h3>Examples</h3>
6868

6969
<h3>Discussion</h3>
7070

71-
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>
71+
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>
7272

7373
<pre>
7474
#define INT_MAX 2147483647 /* max value for an int */
7575
#define INT_MIN (-2147483647-1) /* min value for an int */
7676
</pre>
7777

78-
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>
78+
The definition of <code>INT_MIN</code> is not a simple literal, but a parenthesized expression. Parenthesized
79+
expressions are supported using the <a href="#objc_boxed_expressions">boxed expression</a> syntax, which is described in the next section.<p>
7980

8081
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>
8182

@@ -95,6 +96,94 @@ <h3>Discussion</h3>
9596

9697
Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.
9798

99+
<!-- ======================================================================= -->
100+
<h2 id="objc_boxed_expressions">Boxed Expressions</h2>
101+
<!-- ======================================================================= -->
102+
103+
<p>Objective-C provides a new syntax for boxing C expressions:</p>
104+
105+
<pre>
106+
<code>@( <em>expression</em> )</code>
107+
</pre>
108+
109+
<p>Expressions of scalar (numeric, enumerated, BOOL) and C string pointer types
110+
are supported:</p>
111+
112+
<pre>
113+
// numbers.
114+
NSNumber *smallestInt = @(-INT_MAX - 1);
115+
NSNumber *piOverTwo = @(M_PI / 2);
116+
117+
// enumerated types.
118+
typedef enum { Red, Green, Blue } Color;
119+
NSNumber *favoriteColor = @(Green);
120+
121+
// strings.
122+
NSString *path = @(getenv("PATH"));
123+
NSArray *pathComponents = [path componentsSeparatedByString:@":"];
124+
</pre>
125+
126+
<h3>Boxed Enums</h3>
127+
128+
<p>
129+
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:
130+
</p>
131+
132+
<pre>
133+
enum {
134+
AVAudioQualityMin = 0,
135+
AVAudioQualityLow = 0x20,
136+
AVAudioQualityMedium = 0x40,
137+
AVAudioQualityHigh = 0x60,
138+
AVAudioQualityMax = 0x7F
139+
};
140+
141+
- (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {
142+
NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };
143+
return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];
144+
}
145+
</pre>
146+
147+
<p>
148+
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:
149+
</p>
150+
151+
<pre>
152+
typedef enum : unsigned char { Red, Green, Blue } Color;
153+
NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]
154+
</pre>
155+
156+
<p>
157+
then the fixed underlying type will be used to select the correct <code>NSNumber</code> creation method.
158+
</p>
159+
160+
<h3>Boxed C Strings</h3>
161+
162+
<p>
163+
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.
164+
</p>
165+
166+
<pre>
167+
// Partition command line arguments into positional and option arguments.
168+
NSMutableArray *args = [NSMutableArray new];
169+
NSMutableDictionary *options = [NSMutableArray new];
170+
while (--argc) {
171+
const char *arg = *++argv;
172+
if (strncmp(arg, "--", 2) == 0) {
173+
options[@(arg + 2)] = @(*++argv); // --key value
174+
} else {
175+
[args addObject:@(arg)]; // positional argument
176+
}
177+
}
178+
</pre>
179+
180+
<p>
181+
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.
182+
</p>
183+
184+
<h3>Availability</h3>
185+
186+
<p>This feature will be available in clang 3.2. It is not currently available in any Apple compiler.</p>
98187

99188
<h2>Container Literals</h2>
100189

@@ -104,9 +193,11 @@ <h3>Examples</h3>
104193

105194
Immutable array expression:<p>
106195

107-
<pre>
196+
<blockquote>
197+
<pre>
108198
NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
109199
</pre>
200+
</blockquote>
110201

111202
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>
112203

@@ -309,6 +400,9 @@ <h2>Availability Checks</h2>
309400

310401
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>
311402

403+
<p>To check whether boxed expressions are supported, use
404+
<code>__has_feature(objc_boxed_expressions)</code> feature macro.</p>
405+
312406
</div>
313407
</body>
314408
</html>

clang/include/clang/AST/ExprObjC.h

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -87,43 +87,45 @@ class ObjCBoolLiteralExpr : public Expr {
8787
child_range children() { return child_range(); }
8888
};
8989

90-
/// ObjCNumericLiteral - used for objective-c numeric literals;
91-
/// as in: @42 or @true (c++/objc++) or @__yes (c/objc)
92-
class ObjCNumericLiteral : public Expr {
93-
/// Number - expression AST node for the numeric literal
94-
Stmt *Number;
95-
ObjCMethodDecl *ObjCNumericLiteralMethod;
96-
SourceLocation AtLoc;
90+
/// ObjCBoxedExpr - used for generalized expression boxing.
91+
/// as in: @(strdup("hello world")) or @(random())
92+
/// Also used for boxing non-parenthesized numeric literals;
93+
/// as in: @42 or @true (c++/objc++) or @__yes (c/objc).
94+
class ObjCBoxedExpr : public Expr {
95+
Stmt *SubExpr;
96+
ObjCMethodDecl *BoxingMethod;
97+
SourceRange Range;
9798
public:
98-
ObjCNumericLiteral(Stmt *NL, QualType T, ObjCMethodDecl *method,
99-
SourceLocation L)
100-
: Expr(ObjCNumericLiteralClass, T, VK_RValue, OK_Ordinary,
101-
false, false, false, false), Number(NL),
102-
ObjCNumericLiteralMethod(method), AtLoc(L) {}
103-
explicit ObjCNumericLiteral(EmptyShell Empty)
104-
: Expr(ObjCNumericLiteralClass, Empty) {}
99+
ObjCBoxedExpr(Expr *E, QualType T, ObjCMethodDecl *method,
100+
SourceRange R)
101+
: Expr(ObjCBoxedExprClass, T, VK_RValue, OK_Ordinary,
102+
E->isTypeDependent(), E->isValueDependent(),
103+
E->isInstantiationDependent(), E->containsUnexpandedParameterPack()),
104+
SubExpr(E), BoxingMethod(method), Range(R) {}
105+
explicit ObjCBoxedExpr(EmptyShell Empty)
106+
: Expr(ObjCBoxedExprClass, Empty) {}
105107

106-
Expr *getNumber() { return cast<Expr>(Number); }
107-
const Expr *getNumber() const { return cast<Expr>(Number); }
108+
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
109+
const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
108110

109-
ObjCMethodDecl *getObjCNumericLiteralMethod() const {
110-
return ObjCNumericLiteralMethod;
111+
ObjCMethodDecl *getBoxingMethod() const {
112+
return BoxingMethod;
111113
}
112-
113-
SourceLocation getAtLoc() const { return AtLoc; }
114+
115+
SourceLocation getAtLoc() const { return Range.getBegin(); }
114116

115117
SourceRange getSourceRange() const LLVM_READONLY {
116-
return SourceRange(AtLoc, Number->getSourceRange().getEnd());
118+
return Range;
117119
}
118-
120+
119121
static bool classof(const Stmt *T) {
120-
return T->getStmtClass() == ObjCNumericLiteralClass;
122+
return T->getStmtClass() == ObjCBoxedExprClass;
121123
}
122-
static bool classof(const ObjCNumericLiteral *) { return true; }
124+
static bool classof(const ObjCBoxedExpr *) { return true; }
123125

124126
// Iterators
125-
child_range children() { return child_range(&Number, &Number+1); }
126-
127+
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
128+
127129
friend class ASTStmtReader;
128130
};
129131

clang/include/clang/AST/RecursiveASTVisitor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2209,7 +2209,7 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { })
22092209
DEF_TRAVERSE_STMT(ImaginaryLiteral, { })
22102210
DEF_TRAVERSE_STMT(StringLiteral, { })
22112211
DEF_TRAVERSE_STMT(ObjCStringLiteral, { })
2212-
DEF_TRAVERSE_STMT(ObjCNumericLiteral, { })
2212+
DEF_TRAVERSE_STMT(ObjCBoxedExpr, { })
22132213
DEF_TRAVERSE_STMT(ObjCArrayLiteral, { })
22142214
DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { })
22152215

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1518,6 +1518,10 @@ def err_undeclared_nsnumber : Error<
15181518
"NSNumber must be available to use Objective-C literals">;
15191519
def err_invalid_nsnumber_type : Error<
15201520
"%0 is not a valid literal type for NSNumber">;
1521+
def err_undeclared_nsstring : Error<
1522+
"cannot box a string value because NSString has not been declared">;
1523+
def err_objc_illegal_boxed_expression_type : Error<
1524+
"Illegal type %0 used in a boxed expression">;
15211525
def err_undeclared_nsarray : Error<
15221526
"NSArray must be available to use Objective-C array literals">;
15231527
def err_undeclared_nsdictionary : Error<

clang/include/clang/Basic/StmtNodes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def LambdaExpr : DStmt<Expr>;
134134

135135
// Obj-C Expressions.
136136
def ObjCStringLiteral : DStmt<Expr>;
137-
def ObjCNumericLiteral : DStmt<Expr>;
137+
def ObjCBoxedExpr : DStmt<Expr>;
138138
def ObjCArrayLiteral : DStmt<Expr>;
139139
def ObjCDictionaryLiteral : DStmt<Expr>;
140140
def ObjCEncodeExpr : DStmt<Expr>;

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,7 @@ class Parser : public CodeCompletionHandler {
15031503
ExprResult ParseObjCBooleanLiteral(SourceLocation AtLoc, bool ArgValue);
15041504
ExprResult ParseObjCArrayLiteral(SourceLocation AtLoc);
15051505
ExprResult ParseObjCDictionaryLiteral(SourceLocation AtLoc);
1506+
ExprResult ParseObjCBoxedExpr(SourceLocation AtLoc);
15061507
ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc);
15071508
ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc);
15081509
ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc);

clang/include/clang/Sema/Sema.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,9 +523,21 @@ class Sema {
523523
/// \brief The declaration of the Objective-C NSNumber class.
524524
ObjCInterfaceDecl *NSNumberDecl;
525525

526+
/// \brief Pointer to NSNumber type (NSNumber *).
527+
QualType NSNumberPointer;
528+
526529
/// \brief The Objective-C NSNumber methods used to create NSNumber literals.
527530
ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods];
528531

532+
/// \brief The declaration of the Objective-C NSString class.
533+
ObjCInterfaceDecl *NSStringDecl;
534+
535+
/// \brief Pointer to NSString type (NSString *).
536+
QualType NSStringPointer;
537+
538+
/// \brief The declaration of the stringWithUTF8String: method.
539+
ObjCMethodDecl *StringWithUTF8StringMethod;
540+
529541
/// \brief The declaration of the Objective-C NSArray class.
530542
ObjCInterfaceDecl *NSArrayDecl;
531543

@@ -3848,14 +3860,21 @@ class Sema {
38483860

38493861
ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S);
38503862

3851-
/// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the
3863+
/// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the
38523864
/// numeric literal expression. Type of the expression will be "NSNumber *"
38533865
/// or "id" if NSNumber is unavailable.
38543866
ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number);
38553867
ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc,
38563868
bool Value);
38573869
ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements);
38583870

3871+
// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the
3872+
// '@' prefixed parenthesized expression. The type of the expression will
3873+
// either be "NSNumber *" or "NSString *" depending on the type of
3874+
// ValueType, which is allowed to be a built-in numeric type or
3875+
// "char *" or "const char *".
3876+
ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr);
3877+
38593878
ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
38603879
Expr *IndexExpr,
38613880
ObjCMethodDecl *getterMethod,

clang/include/clang/Serialization/ASTBitCodes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1066,7 +1066,7 @@ namespace clang {
10661066
/// \brief An ObjCStringLiteral record.
10671067
EXPR_OBJC_STRING_LITERAL,
10681068

1069-
EXPR_OBJC_NUMERIC_LITERAL,
1069+
EXPR_OBJC_BOXED_EXPRESSION,
10701070
EXPR_OBJC_ARRAY_LITERAL,
10711071
EXPR_OBJC_DICTIONARY_LITERAL,
10721072

clang/lib/AST/ExprClassification.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
158158
case Expr::ObjCSelectorExprClass:
159159
case Expr::ObjCProtocolExprClass:
160160
case Expr::ObjCStringLiteralClass:
161-
case Expr::ObjCNumericLiteralClass:
161+
case Expr::ObjCBoxedExprClass:
162162
case Expr::ObjCArrayLiteralClass:
163163
case Expr::ObjCDictionaryLiteralClass:
164164
case Expr::ObjCBoolLiteralExprClass:

0 commit comments

Comments
 (0)