зеркало из https://github.com/microsoft/clang.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102031 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
1569f95831
Коммит
6aa14d8327
|
@ -41,6 +41,29 @@ public:
|
|||
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 @@ private:
|
|||
//===--------------------------------------------------------------------===//
|
||||
// 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);
|
||||
|
||||
|
@ -857,7 +882,7 @@ private:
|
|||
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 @@ private:
|
|||
// 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 @@ private:
|
|||
OwningExprResult ParseAssignmentExprWithObjCMessageExprStart(
|
||||
SourceLocation LBracloc, SourceLocation SuperLoc,
|
||||
TypeTy *ReceiverType, ExprArg ReceiverExpr);
|
||||
bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C99 6.8: Statements and Blocks.
|
||||
|
|
|
@ -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,8 +273,8 @@ Parser::OwningExprResult Parser::ParseConstantExpression() {
|
|||
/// 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(),
|
||||
Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) {
|
||||
prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
|
||||
GreaterThanIsOperator,
|
||||
getLang().CPlusPlus0x);
|
||||
SourceLocation ColonLoc;
|
||||
|
@ -363,7 +339,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
|
|||
|
||||
// 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 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
|
|||
// 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);
|
||||
|
||||
|
|
|
@ -749,6 +749,36 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
|
|||
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 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
|
|||
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
|
||||
break;
|
||||
|
||||
// FIXME: C++0x decltype support.
|
||||
// GNU typeof support.
|
||||
case tok::kw_typeof:
|
||||
ParseTypeofSpecifier(DS);
|
||||
|
|
|
@ -34,6 +34,19 @@ static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
|
|||
// [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.
|
||||
if (getLang().ObjC1 && Tok.is(tok::identifier)) {
|
||||
// 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 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 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
|
|||
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,14 +215,20 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
|
|||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
// 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
|
||||
// tokens are '...' or ']' or an objc message send. If this is an objc
|
||||
|
@ -190,17 +236,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
|
|||
// 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));
|
||||
|
|
|
@ -1711,6 +1711,92 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
|||
}
|
||||
}
|
||||
|
||||
/// \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 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
|
|||
/// 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 @@ typedef struct { int x; } ivar;
|
|||
@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
|
||||
@interface I3
|
||||
+ (int*)method;
|
||||
@end
|
||||
|
||||
@interface I4 : I3
|
||||
+ (int*)otherMethod;
|
||||
@end
|
||||
|
||||
template<typename T>
|
||||
struct identity {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
@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];
|
||||
}
|
||||
@end
|
||||
|
|
Загрузка…
Ссылка в новой задаче