[cfe-commits] r102031 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseInit.cpp lib/Parse/ParseObjc.cpp test/Parser/objc-init.m test/SemaObjCXX/message.mm
Douglas Gregor
dgregor at apple.com
Wed Apr 21 15:36:40 PDT 2010
Author: dgregor
Date: Wed Apr 21 17:36:40 2010
New Revision: 102031
URL: http://llvm.org/viewvc/llvm-project?rev=102031&view=rev
Log:
Implement parsing for message sends in Objective-C++. Message sends in
Objective-C++ have a more complex grammar than in Objective-C
(surprise!), because
(1) The receiver of an instance message can be a qualified name such
as ::I or identity<I>::type.
(2) Expressions in C++ can start with a type.
The receiver grammar isn't actually ambiguous; it just takes a bit of
work to parse past the type before deciding whether we have a type or
expression. We do this in two places within the grammar: once for
message sends and once when we're determining whether a []'d clause in
an initializer list is a message send or a C99 designated initializer.
This implementation of Objective-C++ message sends contains one known
extension beyond GCC's implementation, which is to permit a
typename-specifier as the receiver type for a class message, e.g.,
[typename compute_receiver_type<T>::type method];
Note that the same effect can be achieved in GCC by way of a typedef,
e.g.,
typedef typename computed_receiver_type<T>::type Computed;
[Computed method];
so this is merely a convenience.
Note also that message sends still cannot involve dependent types or
values.
Modified:
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseExpr.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseInit.cpp
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/test/Parser/objc-init.m
cfe/trunk/test/SemaObjCXX/message.mm
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Apr 21 17:36:40 2010
@@ -41,6 +41,29 @@
virtual void print(llvm::raw_ostream &OS) const;
};
+/// PrecedenceLevels - These are precedences for the binary/ternary
+/// operators in the C99 grammar. These have been named to relate
+/// with the C99 grammar productions. Low precedences numbers bind
+/// more weakly than high numbers.
+namespace prec {
+ enum Level {
+ Unknown = 0, // Not binary operator.
+ Comma = 1, // ,
+ Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+ Conditional = 3, // ?
+ LogicalOr = 4, // ||
+ LogicalAnd = 5, // &&
+ InclusiveOr = 6, // |
+ ExclusiveOr = 7, // ^
+ And = 8, // &
+ Equality = 9, // ==, !=
+ Relational = 10, // >=, <=, >, <
+ Shift = 11, // <<, >>
+ Additive = 12, // -, +
+ Multiplicative = 13, // *, /, %
+ PointerToMember = 14 // .*, ->*
+ };
+}
/// Parser - This implements a parser for the C family of languages. After
/// parsing units of the grammar, productions are invoked to handle whatever has
@@ -460,9 +483,11 @@
//===--------------------------------------------------------------------===//
// Diagnostic Emission and Error recovery.
+public:
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID);
+private:
void SuggestParentheses(SourceLocation Loc, unsigned DK,
SourceRange ParenRange);
@@ -846,7 +871,7 @@
//===--------------------------------------------------------------------===//
// C99 6.5: Expressions.
-
+
OwningExprResult ParseExpression();
OwningExprResult ParseConstantExpression();
// Expr that doesn't include commas.
@@ -857,7 +882,7 @@
OwningExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
- unsigned MinPrec);
+ prec::Level MinPrec);
OwningExprResult ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
@@ -954,6 +979,8 @@
// C++ 5.2.3: Explicit type conversion (functional notation)
OwningExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS);
+ bool isCXXSimpleTypeSpecifier() const;
+
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
/// This should only be called when the current token is known to be part of
/// simple-type-specifier.
@@ -1011,6 +1038,7 @@
OwningExprResult ParseAssignmentExprWithObjCMessageExprStart(
SourceLocation LBracloc, SourceLocation SuperLoc,
TypeTy *ReceiverType, ExprArg ReceiverExpr);
+ bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr);
//===--------------------------------------------------------------------===//
// C99 6.8: Statements and Blocks.
Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Apr 21 17:36:40 2010
@@ -29,30 +29,6 @@
#include "llvm/ADT/SmallString.h"
using namespace clang;
-/// PrecedenceLevels - These are precedences for the binary/ternary operators in
-/// the C99 grammar. These have been named to relate with the C99 grammar
-/// productions. Low precedences numbers bind more weakly than high numbers.
-namespace prec {
- enum Level {
- Unknown = 0, // Not binary operator.
- Comma = 1, // ,
- Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
- Conditional = 3, // ?
- LogicalOr = 4, // ||
- LogicalAnd = 5, // &&
- InclusiveOr = 6, // |
- ExclusiveOr = 7, // ^
- And = 8, // &
- Equality = 9, // ==, !=
- Relational = 10, // >=, <=, >, <
- Shift = 11, // <<, >>
- Additive = 12, // -, +
- Multiplicative = 13, // *, /, %
- PointerToMember = 14 // .*, ->*
- };
-}
-
-
/// getBinOpPrecedence - Return the precedence of the specified binary operator
/// token. This returns:
///
@@ -297,10 +273,10 @@
/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
/// LHS and has a precedence of at least MinPrec.
Parser::OwningExprResult
-Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
- unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
- GreaterThanIsOperator,
- getLang().CPlusPlus0x);
+Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) {
+ prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
+ GreaterThanIsOperator,
+ getLang().CPlusPlus0x);
SourceLocation ColonLoc;
while (1) {
@@ -363,7 +339,7 @@
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
- unsigned ThisPrec = NextTokPrec;
+ prec::Level ThisPrec = NextTokPrec;
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
getLang().CPlusPlus0x);
@@ -380,7 +356,8 @@
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
// A=(B=(C=D)), where each paren is a level of recursion here.
// The function takes ownership of the RHS.
- RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
+ RHS = ParseRHSOfBinaryExpression(move(RHS),
+ static_cast<prec::Level>(ThisPrec + !isRightAssoc));
if (RHS.isInvalid())
return move(RHS);
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Apr 21 17:36:40 2010
@@ -749,6 +749,36 @@
return false;
}
+/// \brief Determine whether the current token starts a C++
+/// simple-type-specifier.
+bool Parser::isCXXSimpleTypeSpecifier() const {
+ switch (Tok.getKind()) {
+ case tok::annot_typename:
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_bool:
+ // FIXME: C++0x decltype support.
+ // GNU typeof support.
+ case tok::kw_typeof:
+ return true;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
/// This should only be called when the current token is known to be part of
/// simple-type-specifier.
@@ -837,6 +867,7 @@
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
break;
+ // FIXME: C++0x decltype support.
// GNU typeof support.
case tok::kw_typeof:
ParseTypeofSpecifier(DS);
Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Wed Apr 21 17:36:40 2010
@@ -34,6 +34,19 @@
}
}
+static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
+ Designation &Desig) {
+ // If we have exactly one array designator, this used the GNU
+ // 'designation: array-designator' extension, otherwise there should be no
+ // designators at all!
+ if (Desig.getNumDesignators() == 1 &&
+ (Desig.getDesignator(0).isArrayDesignator() ||
+ Desig.getDesignator(0).isArrayRangeDesignator()))
+ P.Diag(Loc, diag::ext_gnu_missing_equal_designator);
+ else if (Desig.getNumDesignators() > 0)
+ P.Diag(Loc, diag::err_expected_equal_designator);
+}
+
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
/// checking to see if the token stream starts with a designator.
///
@@ -124,10 +137,46 @@
// [4][foo bar] -> obsolete GNU designation with objc message send.
//
SourceLocation StartLoc = ConsumeBracket();
+ OwningExprResult Idx(Actions);
+
+ // If Objective-C is enabled and this is a typename (class message
+ // send) or send to 'super', parse this as a message send
+ // expression. We handle C++ and C separately, since C++ requires
+ // much more complicated parsing.
+ if (getLang().ObjC1 && getLang().CPlusPlus) {
+ // Send to 'super'.
+ if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+ NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) {
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ ConsumeToken(), 0,
+ ExprArg(Actions));
+ }
+
+ // Parse the receiver, which is either a type or an expression.
+ bool IsExpr;
+ void *TypeOrExpr;
+ if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ // If the receiver was a type, we have a class message; parse
+ // the rest of it.
+ if (!IsExpr) {
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
+ return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
+ SourceLocation(),
+ TypeOrExpr,
+ ExprArg(Actions));
+ }
- // If Objective-C is enabled and this is a typename (class message send) or
- // send to 'super', parse this as a message send expression.
- if (getLang().ObjC1 && Tok.is(tok::identifier)) {
+ // If the receiver was an expression, we still don't know
+ // whether we have a message send or an array designator; just
+ // adopt the expression for further analysis below.
+ // FIXME: potentially-potentially evaluated expression above?
+ Idx = OwningExprResult(Actions, TypeOrExpr);
+ } else if (getLang().ObjC1 && Tok.is(tok::identifier)) {
IdentifierInfo *II = Tok.getIdentifierInfo();
SourceLocation IILoc = Tok.getLocation();
TypeTy *ReceiverType;
@@ -141,16 +190,7 @@
ReceiverType)) {
case Action::ObjCSuperMessage:
case Action::ObjCClassMessage:
- // If we have exactly one array designator, this used the GNU
- // 'designation: array-designator' extension, otherwise there should be no
- // designators at all!
- if (Desig.getNumDesignators() == 1 &&
- (Desig.getDesignator(0).isArrayDesignator() ||
- Desig.getDesignator(0).isArrayRangeDesignator()))
- Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
- else if (Desig.getNumDesignators() > 0)
- Diag(Tok, diag::err_expected_equal_designator);
-
+ CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
if (Kind == Action::ObjCSuperMessage)
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
ConsumeToken(),
@@ -175,13 +215,19 @@
}
}
+ // Parse the index expression, if we haven't already gotten one
+ // above (which can only happen in Objective-C++).
// Note that we parse this as an assignment expression, not a constant
// expression (allowing *=, =, etc) to handle the objc case. Sema needs
// to validate that the expression is a constant.
- OwningExprResult Idx(ParseAssignmentExpression());
- if (Idx.isInvalid()) {
- SkipUntil(tok::r_square);
- return move(Idx);
+ // FIXME: We also need to tell Sema that we're in a
+ // potentially-potentially evaluated context.
+ if (!Idx.get()) {
+ Idx = ParseAssignmentExpression();
+ if (Idx.isInvalid()) {
+ SkipUntil(tok::r_square);
+ return move(Idx);
+ }
}
// Given an expression, we could either have a designator (if the next
@@ -190,17 +236,7 @@
// an assignment-expression production.
if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
Tok.isNot(tok::r_square)) {
-
- // If we have exactly one array designator, this used the GNU
- // 'designation: array-designator' extension, otherwise there should be no
- // designators at all!
- if (Desig.getNumDesignators() == 1 &&
- (Desig.getDesignator(0).isArrayDesignator() ||
- Desig.getDesignator(0).isArrayRangeDesignator()))
- Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
- else if (Desig.getNumDesignators() > 0)
- Diag(Tok, diag::err_expected_equal_designator);
-
+ CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
SourceLocation(),
0, move(Idx));
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Wed Apr 21 17:36:40 2010
@@ -1711,6 +1711,92 @@
}
}
+/// \brirg Parse the receiver of an Objective-C++ message send.
+///
+/// This routine parses the receiver of a message send in
+/// Objective-C++ either as a type or as an expression. Note that this
+/// routine must not be called to parse a send to 'super', since it
+/// has no way to return such a result.
+///
+/// \param IsExpr Whether the receiver was parsed as an expression.
+///
+/// \param TypeOrExpr If the receiver was parsed as an expression (\c
+/// IsExpr is true), the parsed expression. If the receiver was parsed
+/// as a type (\c IsExpr is false), the parsed type.
+///
+/// \returns True if an error occurred during parsing or semantic
+/// analysis, in which case the arguments do not have valid
+/// values. Otherwise, returns false for a successful parse.
+///
+/// objc-receiver: [C++]
+/// 'super' [not parsed here]
+/// expression
+/// simple-type-specifier
+/// typename-specifier
+
+bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) {
+ if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope))
+ TryAnnotateTypeOrScopeToken();
+
+ if (!isCXXSimpleTypeSpecifier()) {
+ // objc-receiver:
+ // expression
+ OwningExprResult Receiver = ParseExpression();
+ if (Receiver.isInvalid())
+ return true;
+
+ IsExpr = true;
+ TypeOrExpr = Receiver.take();
+ return false;
+ }
+
+ // objc-receiver:
+ // typename-specifier
+ // simple-type-specifier
+ // expression (that starts with one of the above)
+ DeclSpec DS;
+ ParseCXXSimpleTypeSpecifier(DS);
+
+ if (Tok.is(tok::l_paren)) {
+ // If we see an opening parentheses at this point, we are
+ // actually parsing an expression that starts with a
+ // function-style cast, e.g.,
+ //
+ // postfix-expression:
+ // simple-type-specifier ( expression-list [opt] )
+ // typename-specifier ( expression-list [opt] )
+ //
+ // Parse the remainder of this case, then the (optional)
+ // postfix-expression suffix, followed by the (optional)
+ // right-hand side of the binary expression. We have an
+ // instance method.
+ OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS);
+ if (!Receiver.isInvalid())
+ Receiver = ParsePostfixExpressionSuffix(move(Receiver));
+ if (!Receiver.isInvalid())
+ Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma);
+ if (Receiver.isInvalid())
+ return true;
+
+ IsExpr = true;
+ TypeOrExpr = Receiver.take();
+ return false;
+ }
+
+ // We have a class message. Turn the simple-type-specifier or
+ // typename-specifier we parsed into a type and parse the
+ // remainder of the class message.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ TypeResult Type = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
+ if (Type.isInvalid())
+ return true;
+
+ IsExpr = false;
+ TypeOrExpr = Type.get();
+ return false;
+}
+
/// objc-message-expr:
/// '[' objc-receiver objc-message-args ']'
///
@@ -1719,11 +1805,38 @@
/// expression
/// class-name
/// type-name
+///
Parser::OwningExprResult Parser::ParseObjCMessageExpression() {
assert(Tok.is(tok::l_square) && "'[' expected");
SourceLocation LBracLoc = ConsumeBracket(); // consume '['
- if (Tok.is(tok::identifier)) {
+ if (getLang().CPlusPlus) {
+ // We completely separate the C and C++ cases because C++ requires
+ // more complicated (read: slower) parsing.
+
+ // Handle send to super.
+ // FIXME: This doesn't benefit from the same typo-correction we
+ // get in Objective-C.
+ if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
+ NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope())
+ return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0,
+ ExprArg(Actions));
+
+ // Parse the receiver, which is either a type or an expression.
+ bool IsExpr;
+ void *TypeOrExpr;
+ if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
+ SkipUntil(tok::r_square);
+ return ExprError();
+ }
+
+ if (IsExpr)
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0,
+ OwningExprResult(Actions, TypeOrExpr));
+
+ return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(),
+ TypeOrExpr, ExprArg(Actions));
+ } else if (Tok.is(tok::identifier)) {
IdentifierInfo *Name = Tok.getIdentifierInfo();
SourceLocation NameLoc = Tok.getLocation();
TypeTy *ReceiverType;
Modified: cfe/trunk/test/Parser/objc-init.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objc-init.m?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/test/Parser/objc-init.m (original)
+++ cfe/trunk/test/Parser/objc-init.m Wed Apr 21 17:36:40 2010
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -pedantic
+// RUN: %clang_cc1 -fsyntax-only -verify -x objective-c++ %s
// rdar://5707001
@interface NSNumber;
Modified: cfe/trunk/test/SemaObjCXX/message.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/message.mm?rev=102031&r1=102030&r2=102031&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/message.mm (original)
+++ cfe/trunk/test/SemaObjCXX/message.mm Wed Apr 21 17:36:40 2010
@@ -1,12 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
@interface I1
-- (void)method;
+- (int*)method;
@end
@implementation I1
-- (void)method {
+- (int*)method {
struct x { };
[x method]; // expected-error{{receiver type 'x' is not an Objective-C class}}
+ return 0;
}
@end
@@ -15,15 +16,62 @@
@interface I2 {
id ivar;
}
-- (void)method;
+- (int*)method;
+ (void)method;
@end
+struct I2_holder {
+ I2_holder();
+
+ I2 *get();
+};
+
+I2 *operator+(I2_holder, int);
+
@implementation I2
-- (void)method {
+- (int*)method {
[ivar method];
+
+ // Test instance messages that start with a simple-type-specifier.
+ [I2_holder().get() method];
+ [I2_holder().get() + 17 method];
+ return 0;
}
+ (void)method {
[ivar method]; // expected-error{{receiver type 'ivar' (aka 'ivar') is not an Objective-C class}}
}
@end
+
+// Class message sends
+ at interface I3
++ (int*)method;
+ at end
+
+ at interface I4 : I3
++ (int*)otherMethod;
+ at end
+
+template<typename T>
+struct identity {
+ typedef T type;
+};
+
+ at implementation I4
++ (int *)otherMethod {
+ // Test class messages that use non-trivial simple-type-specifiers
+ // or typename-specifiers.
+ if (false) {
+ if (true)
+ return [typename identity<I3>::type method];
+
+ return [::I3 method];
+ }
+
+ int* ip1 = {[super method]};
+ int* ip2 = {[::I3 method]};
+ int* ip3 = {[typename identity<I3>::type method]};
+ int* ip4 = {[typename identity<I2_holder>::type().get() method]};
+ int array[5] = {[3] = 2};
+ return [super method];
+}
+ at end
More information about the cfe-commits
mailing list