1 //===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements initializer parsing as specified by C99 6.7.8.
12 //===----------------------------------------------------------------------===//
14 #include "clang/Parse/Designator.h"
15 #include "clang/Parse/Parser.h"
16 #include "clang/Parse/ParseDiagnostic.h"
17 #include "llvm/ADT/SmallString.h"
18 using namespace clang
;
21 /// MayBeDesignationStart - Return true if this token might be the start of a
22 /// designator. If we can tell it is impossible that it is a designator, return
24 static bool MayBeDesignationStart(tok::TokenKind K
, Preprocessor
&PP
) {
26 default: return false;
27 case tok::period
: // designator: '.' identifier
28 case tok::l_square
: // designator: array-designator
30 case tok::identifier
: // designation: identifier ':'
31 return PP
.LookAhead(0).is(tok::colon
);
35 /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
36 /// checking to see if the token stream starts with a designator.
39 /// designator-list '='
40 /// [GNU] array-designator
41 /// [GNU] identifier ':'
45 /// designator-list designator
52 /// '[' constant-expression ']'
53 /// [GNU] '[' constant-expression '...' constant-expression ']'
55 /// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
56 /// initializer (because it is an expression). We need to consider this case
57 /// when parsing array designators.
59 Parser::OwningExprResult
Parser::ParseInitializerWithPotentialDesignator() {
61 // If this is the old-style GNU extension:
62 // designation ::= identifier ':'
63 // Handle it as a field designator. Otherwise, this must be the start of a
65 if (Tok
.is(tok::identifier
)) {
66 const IdentifierInfo
*FieldName
= Tok
.getIdentifierInfo();
68 std::string
NewSyntax(".");
69 NewSyntax
+= FieldName
->getName();
72 SourceLocation NameLoc
= ConsumeToken(); // Eat the identifier.
74 assert(Tok
.is(tok::colon
) && "MayBeDesignationStart not working properly!");
75 SourceLocation ColonLoc
= ConsumeToken();
77 Diag(Tok
, diag::ext_gnu_old_style_field_designator
)
78 << CodeModificationHint::CreateReplacement(SourceRange(NameLoc
,
83 D
.AddDesignator(Designator::getField(FieldName
, SourceLocation(), NameLoc
));
84 return Actions
.ActOnDesignatedInitializer(D
, ColonLoc
, true,
88 // Desig - This is initialized when we see our first designator. We may have
89 // an objc message send with no designator, so we don't want to create this
93 // Parse each designator in the designator list until we find an initializer.
94 while (Tok
.is(tok::period
) || Tok
.is(tok::l_square
)) {
95 if (Tok
.is(tok::period
)) {
96 // designator: '.' identifier
97 SourceLocation DotLoc
= ConsumeToken();
99 if (Tok
.isNot(tok::identifier
)) {
100 Diag(Tok
.getLocation(), diag::err_expected_field_designator
);
104 Desig
.AddDesignator(Designator::getField(Tok
.getIdentifierInfo(), DotLoc
,
106 ConsumeToken(); // Eat the identifier.
110 // We must have either an array designator now or an objc message send.
111 assert(Tok
.is(tok::l_square
) && "Unexpected token!");
113 // Handle the two forms of array designator:
114 // array-designator: '[' constant-expression ']'
115 // array-designator: '[' constant-expression '...' constant-expression ']'
117 // Also, we have to handle the case where the expression after the
118 // designator an an objc message send: '[' objc-message-expr ']'.
119 // Interesting cases are:
120 // [foo bar] -> objc message send
121 // [foo] -> array designator
122 // [foo ... bar] -> array designator
123 // [4][foo bar] -> obsolete GNU designation with objc message send.
125 SourceLocation StartLoc
= ConsumeBracket();
127 // If Objective-C is enabled and this is a typename or other identifier
128 // receiver, parse this as a message send expression.
129 if (getLang().ObjC1
&& isTokObjCMessageIdentifierReceiver()) {
130 // If we have exactly one array designator, this used the GNU
131 // 'designation: array-designator' extension, otherwise there should be no
132 // designators at all!
133 if (Desig
.getNumDesignators() == 1 &&
134 (Desig
.getDesignator(0).isArrayDesignator() ||
135 Desig
.getDesignator(0).isArrayRangeDesignator()))
136 Diag(StartLoc
, diag::ext_gnu_missing_equal_designator
);
137 else if (Desig
.getNumDesignators() > 0)
138 Diag(Tok
, diag::err_expected_equal_designator
);
140 IdentifierInfo
*Name
= Tok
.getIdentifierInfo();
141 SourceLocation NameLoc
= ConsumeToken();
142 return ParseAssignmentExprWithObjCMessageExprStart(
143 StartLoc
, NameLoc
, Name
, ExprArg(Actions
));
146 // Note that we parse this as an assignment expression, not a constant
147 // expression (allowing *=, =, etc) to handle the objc case. Sema needs
148 // to validate that the expression is a constant.
149 OwningExprResult
Idx(ParseAssignmentExpression());
150 if (Idx
.isInvalid()) {
151 SkipUntil(tok::r_square
);
155 // Given an expression, we could either have a designator (if the next
156 // tokens are '...' or ']' or an objc message send. If this is an objc
157 // message send, handle it now. An objc-message send is the start of
158 // an assignment-expression production.
159 if (getLang().ObjC1
&& Tok
.isNot(tok::ellipsis
) &&
160 Tok
.isNot(tok::r_square
)) {
162 // If we have exactly one array designator, this used the GNU
163 // 'designation: array-designator' extension, otherwise there should be no
164 // designators at all!
165 if (Desig
.getNumDesignators() == 1 &&
166 (Desig
.getDesignator(0).isArrayDesignator() ||
167 Desig
.getDesignator(0).isArrayRangeDesignator()))
168 Diag(StartLoc
, diag::ext_gnu_missing_equal_designator
);
169 else if (Desig
.getNumDesignators() > 0)
170 Diag(Tok
, diag::err_expected_equal_designator
);
172 return ParseAssignmentExprWithObjCMessageExprStart(StartLoc
,
177 // If this is a normal array designator, remember it.
178 if (Tok
.isNot(tok::ellipsis
)) {
179 Desig
.AddDesignator(Designator::getArray(Idx
.release(), StartLoc
));
181 // Handle the gnu array range extension.
182 Diag(Tok
, diag::ext_gnu_array_range
);
183 SourceLocation EllipsisLoc
= ConsumeToken();
185 OwningExprResult
RHS(ParseConstantExpression());
186 if (RHS
.isInvalid()) {
187 SkipUntil(tok::r_square
);
190 Desig
.AddDesignator(Designator::getArrayRange(Idx
.release(),
192 StartLoc
, EllipsisLoc
));
195 SourceLocation EndLoc
= MatchRHSPunctuation(tok::r_square
, StartLoc
);
196 Desig
.getDesignator(Desig
.getNumDesignators() - 1).setRBracketLoc(EndLoc
);
199 // Okay, we're done with the designator sequence. We know that there must be
200 // at least one designator, because the only case we can get into this method
201 // without a designator is when we have an objc message send. That case is
202 // handled and returned from above.
203 assert(!Desig
.empty() && "Designator is empty?");
205 // Handle a normal designator sequence end, which is an equal.
206 if (Tok
.is(tok::equal
)) {
207 SourceLocation EqualLoc
= ConsumeToken();
208 return Actions
.ActOnDesignatedInitializer(Desig
, EqualLoc
, false,
212 // We read some number of designators and found something that isn't an = or
213 // an initializer. If we have exactly one array designator, this
214 // is the GNU 'designation: array-designator' extension. Otherwise, it is a
216 if (Desig
.getNumDesignators() == 1 &&
217 (Desig
.getDesignator(0).isArrayDesignator() ||
218 Desig
.getDesignator(0).isArrayRangeDesignator())) {
219 Diag(Tok
, diag::ext_gnu_missing_equal_designator
)
220 << CodeModificationHint::CreateInsertion(Tok
.getLocation(), "= ");
221 return Actions
.ActOnDesignatedInitializer(Desig
, Tok
.getLocation(),
222 true, ParseInitializer());
225 Diag(Tok
, diag::err_expected_equal_designator
);
230 /// ParseBraceInitializer - Called when parsing an initializer that has a
231 /// leading open brace.
233 /// initializer: [C99 6.7.8]
234 /// '{' initializer-list '}'
235 /// '{' initializer-list ',' '}'
238 /// initializer-list:
239 /// designation[opt] initializer
240 /// initializer-list ',' designation[opt] initializer
242 Parser::OwningExprResult
Parser::ParseBraceInitializer() {
243 SourceLocation LBraceLoc
= ConsumeBrace();
245 /// InitExprs - This is the actual list of expressions contained in the
247 ExprVector
InitExprs(Actions
);
249 if (Tok
.is(tok::r_brace
)) {
250 // Empty initializers are a C++ feature and a GNU extension to C.
251 if (!getLang().CPlusPlus
)
252 Diag(LBraceLoc
, diag::ext_gnu_empty_initializer
);
254 return Actions
.ActOnInitList(LBraceLoc
, Action::MultiExprArg(Actions
),
258 bool InitExprsOk
= true;
261 // Parse: designation[opt] initializer
263 // If we know that this cannot be a designation, just parse the nested
264 // initializer directly.
265 OwningExprResult
SubElt(Actions
);
266 if (MayBeDesignationStart(Tok
.getKind(), PP
))
267 SubElt
= ParseInitializerWithPotentialDesignator();
269 SubElt
= ParseInitializer();
271 // If we couldn't parse the subelement, bail out.
272 if (!SubElt
.isInvalid()) {
273 InitExprs
.push_back(SubElt
.release());
277 // We have two ways to try to recover from this error: if the code looks
278 // gramatically ok (i.e. we have a comma coming up) try to continue
279 // parsing the rest of the initializer. This allows us to emit
280 // diagnostics for later elements that we find. If we don't see a comma,
281 // assume there is a parse error, and just skip to recover.
282 // FIXME: This comment doesn't sound right. If there is a r_brace
283 // immediately, it can't be an error, since there is no other way of
284 // leaving this loop except through this if.
285 if (Tok
.isNot(tok::comma
)) {
286 SkipUntil(tok::r_brace
, false, true);
291 // If we don't have a comma continued list, we're done.
292 if (Tok
.isNot(tok::comma
)) break;
294 // TODO: save comma locations if some client cares.
297 // Handle trailing comma.
298 if (Tok
.is(tok::r_brace
)) break;
300 if (InitExprsOk
&& Tok
.is(tok::r_brace
))
301 return Actions
.ActOnInitList(LBraceLoc
, move_arg(InitExprs
),
305 MatchRHSPunctuation(tok::r_brace
, LBraceLoc
);
306 return ExprError(); // an error occurred.