Skip to content

Commit 8d4de67

Browse files
committed
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. llvm-svn: 102031
1 parent 8e7ebea commit 8d4de67

File tree

7 files changed

+299
-65
lines changed

7 files changed

+299
-65
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,29 @@ class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
4141
virtual void print(llvm::raw_ostream &OS) const;
4242
};
4343

44+
/// PrecedenceLevels - These are precedences for the binary/ternary
45+
/// operators in the C99 grammar. These have been named to relate
46+
/// with the C99 grammar productions. Low precedences numbers bind
47+
/// more weakly than high numbers.
48+
namespace prec {
49+
enum Level {
50+
Unknown = 0, // Not binary operator.
51+
Comma = 1, // ,
52+
Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
53+
Conditional = 3, // ?
54+
LogicalOr = 4, // ||
55+
LogicalAnd = 5, // &&
56+
InclusiveOr = 6, // |
57+
ExclusiveOr = 7, // ^
58+
And = 8, // &
59+
Equality = 9, // ==, !=
60+
Relational = 10, // >=, <=, >, <
61+
Shift = 11, // <<, >>
62+
Additive = 12, // -, +
63+
Multiplicative = 13, // *, /, %
64+
PointerToMember = 14 // .*, ->*
65+
};
66+
}
4467

4568
/// Parser - This implements a parser for the C family of languages. After
4669
/// parsing units of the grammar, productions are invoked to handle whatever has
@@ -460,9 +483,11 @@ class Parser {
460483
//===--------------------------------------------------------------------===//
461484
// Diagnostic Emission and Error recovery.
462485

486+
public:
463487
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
464488
DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID);
465489

490+
private:
466491
void SuggestParentheses(SourceLocation Loc, unsigned DK,
467492
SourceRange ParenRange);
468493

@@ -846,7 +871,7 @@ class Parser {
846871

847872
//===--------------------------------------------------------------------===//
848873
// C99 6.5: Expressions.
849-
874+
850875
OwningExprResult ParseExpression();
851876
OwningExprResult ParseConstantExpression();
852877
// Expr that doesn't include commas.
@@ -857,7 +882,7 @@ class Parser {
857882
OwningExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc);
858883

859884
OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
860-
unsigned MinPrec);
885+
prec::Level MinPrec);
861886
OwningExprResult ParseCastExpression(bool isUnaryExpression,
862887
bool isAddressOfOperand,
863888
bool &NotCastExpr,
@@ -954,6 +979,8 @@ class Parser {
954979
// C++ 5.2.3: Explicit type conversion (functional notation)
955980
OwningExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS);
956981

982+
bool isCXXSimpleTypeSpecifier() const;
983+
957984
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
958985
/// This should only be called when the current token is known to be part of
959986
/// simple-type-specifier.
@@ -1011,6 +1038,7 @@ class Parser {
10111038
OwningExprResult ParseAssignmentExprWithObjCMessageExprStart(
10121039
SourceLocation LBracloc, SourceLocation SuperLoc,
10131040
TypeTy *ReceiverType, ExprArg ReceiverExpr);
1041+
bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr);
10141042

10151043
//===--------------------------------------------------------------------===//
10161044
// C99 6.8: Statements and Blocks.

clang/lib/Parse/ParseExpr.cpp

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,6 @@
2929
#include "llvm/ADT/SmallString.h"
3030
using namespace clang;
3131

32-
/// PrecedenceLevels - These are precedences for the binary/ternary operators in
33-
/// the C99 grammar. These have been named to relate with the C99 grammar
34-
/// productions. Low precedences numbers bind more weakly than high numbers.
35-
namespace prec {
36-
enum Level {
37-
Unknown = 0, // Not binary operator.
38-
Comma = 1, // ,
39-
Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
40-
Conditional = 3, // ?
41-
LogicalOr = 4, // ||
42-
LogicalAnd = 5, // &&
43-
InclusiveOr = 6, // |
44-
ExclusiveOr = 7, // ^
45-
And = 8, // &
46-
Equality = 9, // ==, !=
47-
Relational = 10, // >=, <=, >, <
48-
Shift = 11, // <<, >>
49-
Additive = 12, // -, +
50-
Multiplicative = 13, // *, /, %
51-
PointerToMember = 14 // .*, ->*
52-
};
53-
}
54-
55-
5632
/// getBinOpPrecedence - Return the precedence of the specified binary operator
5733
/// token. This returns:
5834
///
@@ -297,10 +273,10 @@ Parser::OwningExprResult Parser::ParseConstantExpression() {
297273
/// ParseRHSOfBinaryExpression - Parse a binary expression that starts with
298274
/// LHS and has a precedence of at least MinPrec.
299275
Parser::OwningExprResult
300-
Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
301-
unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(),
302-
GreaterThanIsOperator,
303-
getLang().CPlusPlus0x);
276+
Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) {
277+
prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
278+
GreaterThanIsOperator,
279+
getLang().CPlusPlus0x);
304280
SourceLocation ColonLoc;
305281

306282
while (1) {
@@ -363,7 +339,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
363339

364340
// Remember the precedence of this operator and get the precedence of the
365341
// operator immediately to the right of the RHS.
366-
unsigned ThisPrec = NextTokPrec;
342+
prec::Level ThisPrec = NextTokPrec;
367343
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
368344
getLang().CPlusPlus0x);
369345

@@ -380,7 +356,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
380356
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
381357
// A=(B=(C=D)), where each paren is a level of recursion here.
382358
// The function takes ownership of the RHS.
383-
RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc);
359+
RHS = ParseRHSOfBinaryExpression(move(RHS),
360+
static_cast<prec::Level>(ThisPrec + !isRightAssoc));
384361
if (RHS.isInvalid())
385362
return move(RHS);
386363

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,36 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult,
749749
return false;
750750
}
751751

752+
/// \brief Determine whether the current token starts a C++
753+
/// simple-type-specifier.
754+
bool Parser::isCXXSimpleTypeSpecifier() const {
755+
switch (Tok.getKind()) {
756+
case tok::annot_typename:
757+
case tok::kw_short:
758+
case tok::kw_long:
759+
case tok::kw_signed:
760+
case tok::kw_unsigned:
761+
case tok::kw_void:
762+
case tok::kw_char:
763+
case tok::kw_int:
764+
case tok::kw_float:
765+
case tok::kw_double:
766+
case tok::kw_wchar_t:
767+
case tok::kw_char16_t:
768+
case tok::kw_char32_t:
769+
case tok::kw_bool:
770+
// FIXME: C++0x decltype support.
771+
// GNU typeof support.
772+
case tok::kw_typeof:
773+
return true;
774+
775+
default:
776+
break;
777+
}
778+
779+
return false;
780+
}
781+
752782
/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
753783
/// This should only be called when the current token is known to be part of
754784
/// simple-type-specifier.
@@ -837,6 +867,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
837867
DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID);
838868
break;
839869

870+
// FIXME: C++0x decltype support.
840871
// GNU typeof support.
841872
case tok::kw_typeof:
842873
ParseTypeofSpecifier(DS);

clang/lib/Parse/ParseInit.cpp

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
3434
}
3535
}
3636

37+
static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
38+
Designation &Desig) {
39+
// If we have exactly one array designator, this used the GNU
40+
// 'designation: array-designator' extension, otherwise there should be no
41+
// designators at all!
42+
if (Desig.getNumDesignators() == 1 &&
43+
(Desig.getDesignator(0).isArrayDesignator() ||
44+
Desig.getDesignator(0).isArrayRangeDesignator()))
45+
P.Diag(Loc, diag::ext_gnu_missing_equal_designator);
46+
else if (Desig.getNumDesignators() > 0)
47+
P.Diag(Loc, diag::err_expected_equal_designator);
48+
}
49+
3750
/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
3851
/// checking to see if the token stream starts with a designator.
3952
///
@@ -124,10 +137,46 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
124137
// [4][foo bar] -> obsolete GNU designation with objc message send.
125138
//
126139
SourceLocation StartLoc = ConsumeBracket();
140+
OwningExprResult Idx(Actions);
141+
142+
// If Objective-C is enabled and this is a typename (class message
143+
// send) or send to 'super', parse this as a message send
144+
// expression. We handle C++ and C separately, since C++ requires
145+
// much more complicated parsing.
146+
if (getLang().ObjC1 && getLang().CPlusPlus) {
147+
// Send to 'super'.
148+
if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super &&
149+
NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) {
150+
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
151+
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
152+
ConsumeToken(), 0,
153+
ExprArg(Actions));
154+
}
127155

128-
// If Objective-C is enabled and this is a typename (class message send) or
129-
// send to 'super', parse this as a message send expression.
130-
if (getLang().ObjC1 && Tok.is(tok::identifier)) {
156+
// Parse the receiver, which is either a type or an expression.
157+
bool IsExpr;
158+
void *TypeOrExpr;
159+
if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) {
160+
SkipUntil(tok::r_square);
161+
return ExprError();
162+
}
163+
164+
// If the receiver was a type, we have a class message; parse
165+
// the rest of it.
166+
if (!IsExpr) {
167+
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
168+
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
169+
SourceLocation(),
170+
TypeOrExpr,
171+
ExprArg(Actions));
172+
}
173+
174+
// If the receiver was an expression, we still don't know
175+
// whether we have a message send or an array designator; just
176+
// adopt the expression for further analysis below.
177+
// FIXME: potentially-potentially evaluated expression above?
178+
Idx = OwningExprResult(Actions, TypeOrExpr);
179+
} else if (getLang().ObjC1 && Tok.is(tok::identifier)) {
131180
IdentifierInfo *II = Tok.getIdentifierInfo();
132181
SourceLocation IILoc = Tok.getLocation();
133182
TypeTy *ReceiverType;
@@ -141,16 +190,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
141190
ReceiverType)) {
142191
case Action::ObjCSuperMessage:
143192
case Action::ObjCClassMessage:
144-
// If we have exactly one array designator, this used the GNU
145-
// 'designation: array-designator' extension, otherwise there should be no
146-
// designators at all!
147-
if (Desig.getNumDesignators() == 1 &&
148-
(Desig.getDesignator(0).isArrayDesignator() ||
149-
Desig.getDesignator(0).isArrayRangeDesignator()))
150-
Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
151-
else if (Desig.getNumDesignators() > 0)
152-
Diag(Tok, diag::err_expected_equal_designator);
153-
193+
CheckArrayDesignatorSyntax(*this, StartLoc, Desig);
154194
if (Kind == Action::ObjCSuperMessage)
155195
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
156196
ConsumeToken(),
@@ -175,13 +215,19 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
175215
}
176216
}
177217

218+
// Parse the index expression, if we haven't already gotten one
219+
// above (which can only happen in Objective-C++).
178220
// Note that we parse this as an assignment expression, not a constant
179221
// expression (allowing *=, =, etc) to handle the objc case. Sema needs
180222
// to validate that the expression is a constant.
181-
OwningExprResult Idx(ParseAssignmentExpression());
182-
if (Idx.isInvalid()) {
183-
SkipUntil(tok::r_square);
184-
return move(Idx);
223+
// FIXME: We also need to tell Sema that we're in a
224+
// potentially-potentially evaluated context.
225+
if (!Idx.get()) {
226+
Idx = ParseAssignmentExpression();
227+
if (Idx.isInvalid()) {
228+
SkipUntil(tok::r_square);
229+
return move(Idx);
230+
}
185231
}
186232

187233
// Given an expression, we could either have a designator (if the next
@@ -190,17 +236,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() {
190236
// an assignment-expression production.
191237
if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) &&
192238
Tok.isNot(tok::r_square)) {
193-
194-
// If we have exactly one array designator, this used the GNU
195-
// 'designation: array-designator' extension, otherwise there should be no
196-
// designators at all!
197-
if (Desig.getNumDesignators() == 1 &&
198-
(Desig.getDesignator(0).isArrayDesignator() ||
199-
Desig.getDesignator(0).isArrayRangeDesignator()))
200-
Diag(StartLoc, diag::ext_gnu_missing_equal_designator);
201-
else if (Desig.getNumDesignators() > 0)
202-
Diag(Tok, diag::err_expected_equal_designator);
203-
239+
CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig);
204240
return ParseAssignmentExprWithObjCMessageExprStart(StartLoc,
205241
SourceLocation(),
206242
0, move(Idx));

0 commit comments

Comments
 (0)