OLD | NEW |
1 //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// | 1 //===--- ParseDecl.cpp - Declaration Parsing ------------------------------===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // This file implements the Declaration portions of the Parser interfaces. | 10 // This file implements the Declaration portions of the Parser interfaces. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 ParseDeclarator(DeclaratorInfo); | 48 ParseDeclarator(DeclaratorInfo); |
49 if (Range) | 49 if (Range) |
50 *Range = DeclaratorInfo.getSourceRange(); | 50 *Range = DeclaratorInfo.getSourceRange(); |
51 | 51 |
52 if (DeclaratorInfo.isInvalidType()) | 52 if (DeclaratorInfo.isInvalidType()) |
53 return true; | 53 return true; |
54 | 54 |
55 return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); | 55 return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); |
56 } | 56 } |
57 | 57 |
| 58 |
| 59 /// isAttributeLateParsed - Return true if the attribute has arguments that |
| 60 /// require late parsing. |
| 61 static bool isAttributeLateParsed(const IdentifierInfo &II) { |
| 62 return llvm::StringSwitch<bool>(II.getName()) |
| 63 #include "clang/Parse/AttrLateParsed.inc" |
| 64 .Default(false); |
| 65 } |
| 66 |
| 67 |
58 /// ParseGNUAttributes - Parse a non-empty attributes list. | 68 /// ParseGNUAttributes - Parse a non-empty attributes list. |
59 /// | 69 /// |
60 /// [GNU] attributes: | 70 /// [GNU] attributes: |
61 /// attribute | 71 /// attribute |
62 /// attributes attribute | 72 /// attributes attribute |
63 /// | 73 /// |
64 /// [GNU] attribute: | 74 /// [GNU] attribute: |
65 /// '__attribute__' '(' '(' attribute-list ')' ')' | 75 /// '__attribute__' '(' '(' attribute-list ')' ')' |
66 /// | 76 /// |
67 /// [GNU] attribute-list: | 77 /// [GNU] attribute-list: |
(...skipping 17 matching lines...) Expand all Loading... |
85 /// token lookahead. Comment from gcc: "If they start with an identifier | 95 /// token lookahead. Comment from gcc: "If they start with an identifier |
86 /// which is followed by a comma or close parenthesis, then the arguments | 96 /// which is followed by a comma or close parenthesis, then the arguments |
87 /// start with that identifier; otherwise they are an expression list." | 97 /// start with that identifier; otherwise they are an expression list." |
88 /// | 98 /// |
89 /// At the moment, I am not doing 2 token lookahead. I am also unaware of | 99 /// At the moment, I am not doing 2 token lookahead. I am also unaware of |
90 /// any attributes that don't work (based on my limited testing). Most | 100 /// any attributes that don't work (based on my limited testing). Most |
91 /// attributes are very simple in practice. Until we find a bug, I don't see | 101 /// attributes are very simple in practice. Until we find a bug, I don't see |
92 /// a pressing need to implement the 2 token lookahead. | 102 /// a pressing need to implement the 2 token lookahead. |
93 | 103 |
94 void Parser::ParseGNUAttributes(ParsedAttributes &attrs, | 104 void Parser::ParseGNUAttributes(ParsedAttributes &attrs, |
95 SourceLocation *endLoc) { | 105 SourceLocation *endLoc, |
| 106 LateParsedAttrList *LateAttrs) { |
96 assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); | 107 assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!"); |
97 | 108 |
98 while (Tok.is(tok::kw___attribute)) { | 109 while (Tok.is(tok::kw___attribute)) { |
99 ConsumeToken(); | 110 ConsumeToken(); |
100 if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, | 111 if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, |
101 "attribute")) { | 112 "attribute")) { |
102 SkipUntil(tok::r_paren, true); // skip until ) or ; | 113 SkipUntil(tok::r_paren, true); // skip until ) or ; |
103 return; | 114 return; |
104 } | 115 } |
105 if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { | 116 if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) { |
106 SkipUntil(tok::r_paren, true); // skip until ) or ; | 117 SkipUntil(tok::r_paren, true); // skip until ) or ; |
107 return; | 118 return; |
108 } | 119 } |
109 // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) | 120 // Parse the attribute-list. e.g. __attribute__(( weak, alias("__f") )) |
110 while (Tok.is(tok::identifier) || isDeclarationSpecifier() || | 121 while (Tok.is(tok::identifier) || isDeclarationSpecifier() || |
111 Tok.is(tok::comma)) { | 122 Tok.is(tok::comma)) { |
112 | |
113 if (Tok.is(tok::comma)) { | 123 if (Tok.is(tok::comma)) { |
114 // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) | 124 // allows for empty/non-empty attributes. ((__vector_size__(16),,,,)) |
115 ConsumeToken(); | 125 ConsumeToken(); |
116 continue; | 126 continue; |
117 } | 127 } |
118 // we have an identifier or declaration specifier (const, int, etc.) | 128 // we have an identifier or declaration specifier (const, int, etc.) |
119 IdentifierInfo *AttrName = Tok.getIdentifierInfo(); | 129 IdentifierInfo *AttrName = Tok.getIdentifierInfo(); |
120 SourceLocation AttrNameLoc = ConsumeToken(); | 130 SourceLocation AttrNameLoc = ConsumeToken(); |
121 | 131 |
122 // Availability attributes have their own grammar. | 132 if (Tok.is(tok::l_paren)) { |
123 if (AttrName->isStr("availability")) | 133 // handle "parameterized" attributes |
124 ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc); | 134 if (LateAttrs && !ClassStack.empty() && |
125 // Thread safety attributes fit into the FIXME case above, so we | 135 isAttributeLateParsed(*AttrName)) { |
126 // just parse the arguments as a list of expressions | 136 // Delayed parsing is only available for attributes that occur |
127 else if (IsThreadSafetyAttribute(AttrName->getName())) | 137 // in certain locations within a class scope. |
128 ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, attrs, endLoc); | 138 LateParsedAttribute *LA = |
129 // check if we have a "parameterized" attribute | 139 new LateParsedAttribute(this, *AttrName, AttrNameLoc); |
130 else if (Tok.is(tok::l_paren)) { | 140 LateAttrs->push_back(LA); |
131 ConsumeParen(); // ignore the left paren loc for now | 141 getCurrentClass().LateParsedDeclarations.push_back(LA); |
132 | 142 |
133 if (Tok.is(tok::identifier)) { | 143 // consume everything up to and including the matching right parens |
134 IdentifierInfo *ParmName = Tok.getIdentifierInfo(); | 144 ConsumeAndStoreUntil(tok::r_paren, LA->Toks, true, false); |
135 SourceLocation ParmLoc = ConsumeToken(); | |
136 | 145 |
137 if (Tok.is(tok::r_paren)) { | 146 Token Eof; |
138 // __attribute__(( mode(byte) )) | 147 Eof.startToken(); |
139 ConsumeParen(); // ignore the right paren loc for now | 148 Eof.setLocation(Tok.getLocation()); |
140 attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, | 149 LA->Toks.push_back(Eof); |
141 ParmName, ParmLoc, 0, 0); | 150 } else { |
142 } else if (Tok.is(tok::comma)) { | 151 ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc); |
143 ConsumeToken(); | |
144 // __attribute__(( format(printf, 1, 2) )) | |
145 ExprVector ArgExprs(Actions); | |
146 bool ArgExprsOk = true; | |
147 | |
148 // now parse the non-empty comma separated list of expressions | |
149 while (1) { | |
150 ExprResult ArgExpr(ParseAssignmentExpression()); | |
151 if (ArgExpr.isInvalid()) { | |
152 ArgExprsOk = false; | |
153 SkipUntil(tok::r_paren); | |
154 break; | |
155 } else { | |
156 ArgExprs.push_back(ArgExpr.release()); | |
157 } | |
158 if (Tok.isNot(tok::comma)) | |
159 break; | |
160 ConsumeToken(); // Eat the comma, move to the next argument | |
161 } | |
162 if (ArgExprsOk && Tok.is(tok::r_paren)) { | |
163 ConsumeParen(); // ignore the right paren loc for now | |
164 attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, | |
165 ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); | |
166 } | |
167 } | |
168 } else { // not an identifier | |
169 switch (Tok.getKind()) { | |
170 case tok::r_paren: | |
171 // parse a possibly empty comma separated list of expressions | |
172 // __attribute__(( nonnull() )) | |
173 ConsumeParen(); // ignore the right paren loc for now | |
174 attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, | |
175 0, SourceLocation(), 0, 0); | |
176 break; | |
177 case tok::kw_char: | |
178 case tok::kw_wchar_t: | |
179 case tok::kw_char16_t: | |
180 case tok::kw_char32_t: | |
181 case tok::kw_bool: | |
182 case tok::kw_short: | |
183 case tok::kw_int: | |
184 case tok::kw_long: | |
185 case tok::kw___int64: | |
186 case tok::kw_signed: | |
187 case tok::kw_unsigned: | |
188 case tok::kw_float: | |
189 case tok::kw_double: | |
190 case tok::kw_void: | |
191 case tok::kw_typeof: { | |
192 AttributeList *attr | |
193 = attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, | |
194 0, SourceLocation(), 0, 0); | |
195 if (attr->getKind() == AttributeList::AT_IBOutletCollection) | |
196 Diag(Tok, diag::err_iboutletcollection_builtintype); | |
197 // If it's a builtin type name, eat it and expect a rparen | |
198 // __attribute__(( vec_type_hint(char) )) | |
199 ConsumeToken(); | |
200 if (Tok.is(tok::r_paren)) | |
201 ConsumeParen(); | |
202 break; | |
203 } | |
204 default: | |
205 // __attribute__(( aligned(16) )) | |
206 ExprVector ArgExprs(Actions); | |
207 bool ArgExprsOk = true; | |
208 | |
209 // now parse the list of expressions | |
210 while (1) { | |
211 ExprResult ArgExpr(ParseAssignmentExpression()); | |
212 if (ArgExpr.isInvalid()) { | |
213 ArgExprsOk = false; | |
214 SkipUntil(tok::r_paren); | |
215 break; | |
216 } else { | |
217 ArgExprs.push_back(ArgExpr.release()); | |
218 } | |
219 if (Tok.isNot(tok::comma)) | |
220 break; | |
221 ConsumeToken(); // Eat the comma, move to the next argument | |
222 } | |
223 // Match the ')'. | |
224 if (ArgExprsOk && Tok.is(tok::r_paren)) { | |
225 ConsumeParen(); // ignore the right paren loc for now | |
226 attrs.addNew(AttrName, AttrNameLoc, 0, | |
227 AttrNameLoc, 0, SourceLocation(), | |
228 ArgExprs.take(), ArgExprs.size()); | |
229 } | |
230 break; | |
231 } | |
232 } | 152 } |
233 } else { | 153 } else { |
234 attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, | 154 attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, |
235 0, SourceLocation(), 0, 0); | 155 0, SourceLocation(), 0, 0); |
236 } | 156 } |
237 } | 157 } |
238 if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) | 158 if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) |
239 SkipUntil(tok::r_paren, false); | 159 SkipUntil(tok::r_paren, false); |
240 SourceLocation Loc = Tok.getLocation(); | 160 SourceLocation Loc = Tok.getLocation(); |
241 if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { | 161 if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { |
242 SkipUntil(tok::r_paren, false); | 162 SkipUntil(tok::r_paren, false); |
243 } | 163 } |
244 if (endLoc) | 164 if (endLoc) |
245 *endLoc = Loc; | 165 *endLoc = Loc; |
246 } | 166 } |
247 } | 167 } |
248 | 168 |
| 169 |
| 170 /// Parse the arguments to a parameterized GNU attribute |
| 171 void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, |
| 172 SourceLocation AttrNameLoc, |
| 173 ParsedAttributes &Attrs, |
| 174 SourceLocation *EndLoc) { |
| 175 |
| 176 assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); |
| 177 |
| 178 // Availability attributes have their own grammar. |
| 179 if (AttrName->isStr("availability")) { |
| 180 ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); |
| 181 return; |
| 182 } |
| 183 // Thread safety attributes fit into the FIXME case above, so we |
| 184 // just parse the arguments as a list of expressions |
| 185 if (IsThreadSafetyAttribute(AttrName->getName())) { |
| 186 ParseThreadSafetyAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc); |
| 187 return; |
| 188 } |
| 189 |
| 190 ConsumeParen(); // ignore the left paren loc for now |
| 191 |
| 192 if (Tok.is(tok::identifier)) { |
| 193 IdentifierInfo *ParmName = Tok.getIdentifierInfo(); |
| 194 SourceLocation ParmLoc = ConsumeToken(); |
| 195 |
| 196 if (Tok.is(tok::r_paren)) { |
| 197 // __attribute__(( mode(byte) )) |
| 198 ConsumeParen(); // ignore the right paren loc for now |
| 199 Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, |
| 200 ParmName, ParmLoc, 0, 0); |
| 201 } else if (Tok.is(tok::comma)) { |
| 202 ConsumeToken(); |
| 203 // __attribute__(( format(printf, 1, 2) )) |
| 204 ExprVector ArgExprs(Actions); |
| 205 bool ArgExprsOk = true; |
| 206 |
| 207 // now parse the non-empty comma separated list of expressions |
| 208 while (1) { |
| 209 ExprResult ArgExpr(ParseAssignmentExpression()); |
| 210 if (ArgExpr.isInvalid()) { |
| 211 ArgExprsOk = false; |
| 212 SkipUntil(tok::r_paren); |
| 213 break; |
| 214 } else { |
| 215 ArgExprs.push_back(ArgExpr.release()); |
| 216 } |
| 217 if (Tok.isNot(tok::comma)) |
| 218 break; |
| 219 ConsumeToken(); // Eat the comma, move to the next argument |
| 220 } |
| 221 if (ArgExprsOk && Tok.is(tok::r_paren)) { |
| 222 ConsumeParen(); // ignore the right paren loc for now |
| 223 Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, |
| 224 ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); |
| 225 } |
| 226 } |
| 227 } else { // not an identifier |
| 228 switch (Tok.getKind()) { |
| 229 case tok::r_paren: |
| 230 // parse a possibly empty comma separated list of expressions |
| 231 // __attribute__(( nonnull() )) |
| 232 ConsumeParen(); // ignore the right paren loc for now |
| 233 Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, |
| 234 0, SourceLocation(), 0, 0); |
| 235 break; |
| 236 case tok::kw_char: |
| 237 case tok::kw_wchar_t: |
| 238 case tok::kw_char16_t: |
| 239 case tok::kw_char32_t: |
| 240 case tok::kw_bool: |
| 241 case tok::kw_short: |
| 242 case tok::kw_int: |
| 243 case tok::kw_long: |
| 244 case tok::kw___int64: |
| 245 case tok::kw_signed: |
| 246 case tok::kw_unsigned: |
| 247 case tok::kw_float: |
| 248 case tok::kw_double: |
| 249 case tok::kw_void: |
| 250 case tok::kw_typeof: { |
| 251 AttributeList *attr |
| 252 = Attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, |
| 253 0, SourceLocation(), 0, 0); |
| 254 if (attr->getKind() == AttributeList::AT_IBOutletCollection) |
| 255 Diag(Tok, diag::err_iboutletcollection_builtintype); |
| 256 // If it's a builtin type name, eat it and expect a rparen |
| 257 // __attribute__(( vec_type_hint(char) )) |
| 258 ConsumeToken(); |
| 259 if (Tok.is(tok::r_paren)) |
| 260 ConsumeParen(); |
| 261 break; |
| 262 } |
| 263 default: |
| 264 // __attribute__(( aligned(16) )) |
| 265 ExprVector ArgExprs(Actions); |
| 266 bool ArgExprsOk = true; |
| 267 |
| 268 // now parse the list of expressions |
| 269 while (1) { |
| 270 ExprResult ArgExpr(ParseAssignmentExpression()); |
| 271 if (ArgExpr.isInvalid()) { |
| 272 ArgExprsOk = false; |
| 273 SkipUntil(tok::r_paren); |
| 274 break; |
| 275 } else { |
| 276 ArgExprs.push_back(ArgExpr.release()); |
| 277 } |
| 278 if (Tok.isNot(tok::comma)) |
| 279 break; |
| 280 ConsumeToken(); // Eat the comma, move to the next argument |
| 281 } |
| 282 // Match the ')'. |
| 283 if (ArgExprsOk && Tok.is(tok::r_paren)) { |
| 284 ConsumeParen(); // ignore the right paren loc for now |
| 285 Attrs.addNew(AttrName, AttrNameLoc, 0, |
| 286 AttrNameLoc, 0, SourceLocation(), |
| 287 ArgExprs.take(), ArgExprs.size()); |
| 288 } |
| 289 break; |
| 290 } |
| 291 } |
| 292 } |
| 293 |
| 294 |
249 /// ParseMicrosoftDeclSpec - Parse an __declspec construct | 295 /// ParseMicrosoftDeclSpec - Parse an __declspec construct |
250 /// | 296 /// |
251 /// [MS] decl-specifier: | 297 /// [MS] decl-specifier: |
252 /// __declspec ( extended-decl-modifier-seq ) | 298 /// __declspec ( extended-decl-modifier-seq ) |
253 /// | 299 /// |
254 /// [MS] extended-decl-modifier-seq: | 300 /// [MS] extended-decl-modifier-seq: |
255 /// extended-decl-modifier[opt] | 301 /// extended-decl-modifier[opt] |
256 /// extended-decl-modifier extended-decl-modifier-seq | 302 /// extended-decl-modifier extended-decl-modifier-seq |
257 | 303 |
258 void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { | 304 void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { |
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
651 // Record this attribute | 697 // Record this attribute |
652 attrs.addNew(&Availability, AvailabilityLoc,· | 698 attrs.addNew(&Availability, AvailabilityLoc,· |
653 0, SourceLocation(), | 699 0, SourceLocation(), |
654 Platform, PlatformLoc, | 700 Platform, PlatformLoc, |
655 Changes[Introduced], | 701 Changes[Introduced], |
656 Changes[Deprecated], | 702 Changes[Deprecated], |
657 Changes[Obsoleted],· | 703 Changes[Obsoleted],· |
658 UnavailableLoc, false, false); | 704 UnavailableLoc, false, false); |
659 } | 705 } |
660 | 706 |
| 707 |
| 708 // Late Parsed Attributes: |
| 709 // See other examples of late parsing in lib/Parse/ParseCXXInlineMethods |
| 710 |
| 711 void Parser::LateParsedDeclaration::ParseLexedAttributes() {} |
| 712 |
| 713 void Parser::LateParsedClass::ParseLexedAttributes() { |
| 714 Self->ParseLexedAttributes(*Class); |
| 715 } |
| 716 |
| 717 void Parser::LateParsedAttribute::ParseLexedAttributes() { |
| 718 Self->ParseLexedAttribute(*this); |
| 719 } |
| 720 |
| 721 /// Wrapper class which calls ParseLexedAttribute, after setting up the |
| 722 /// scope appropriately. |
| 723 void Parser::ParseLexedAttributes(ParsingClass &Class) { |
| 724 // Deal with templates |
| 725 // FIXME: Test cases to make sure this does the right thing for templates. |
| 726 bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; |
| 727 ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, |
| 728 HasTemplateScope); |
| 729 if (HasTemplateScope) |
| 730 Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); |
| 731 |
| 732 // Set or update the scope flags to include Scope::ThisScope. |
| 733 bool AlreadyHasClassScope = Class.TopLevelClass; |
| 734 unsigned ScopeFlags = Scope::ClassScope|Scope::DeclScope|Scope::ThisScope; |
| 735 ParseScope ClassScope(this, ScopeFlags, !AlreadyHasClassScope); |
| 736 ParseScopeFlags ClassScopeFlags(this, ScopeFlags, AlreadyHasClassScope); |
| 737 |
| 738 for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i) { |
| 739 Class.LateParsedDeclarations[i]->ParseLexedAttributes(); |
| 740 } |
| 741 } |
| 742 |
| 743 /// \brief Finish parsing an attribute for which parsing was delayed. |
| 744 /// This will be called at the end of parsing a class declaration |
| 745 /// for each LateParsedAttribute. We consume the saved tokens and |
| 746 /// create an attribute with the arguments filled in. We add this· |
| 747 /// to the Attribute list for the decl. |
| 748 void Parser::ParseLexedAttribute(LateParsedAttribute &LA) { |
| 749 // Save the current token position. |
| 750 SourceLocation OrigLoc = Tok.getLocation(); |
| 751 |
| 752 // Append the current token at the end of the new token stream so that it |
| 753 // doesn't get lost. |
| 754 LA.Toks.push_back(Tok); |
| 755 PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false); |
| 756 // Consume the previously pushed token. |
| 757 ConsumeAnyToken(); |
| 758 |
| 759 ParsedAttributes Attrs(AttrFactory); |
| 760 SourceLocation endLoc; |
| 761 |
| 762 ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); |
| 763 |
| 764 // Late parsed attributes must be attached to Decls by hand. If the |
| 765 // LA.D is not set, then this was not done properly. |
| 766 assert(LA.D && "No decl attached to late parsed attribute"); |
| 767 Actions.ActOnFinishDelayedAttribute(getCurScope(), LA.D, Attrs); |
| 768 |
| 769 if (Tok.getLocation() != OrigLoc) { |
| 770 // Due to a parsing error, we either went over the cached tokens or |
| 771 // there are still cached tokens left, so we skip the leftover tokens. |
| 772 // Since this is an uncommon situation that should be avoided, use the |
| 773 // expensive isBeforeInTranslationUnit call. |
| 774 if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(), |
| 775 OrigLoc)) |
| 776 while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) |
| 777 ConsumeAnyToken(); |
| 778 } |
| 779 } |
| 780 |
661 /// \brief Wrapper around a case statement checking if AttrName is | 781 /// \brief Wrapper around a case statement checking if AttrName is |
662 /// one of the thread safety attributes | 782 /// one of the thread safety attributes |
663 bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){ | 783 bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){ |
664 return llvm::StringSwitch<bool>(AttrName) | 784 return llvm::StringSwitch<bool>(AttrName) |
665 .Case("guarded_by", true) | 785 .Case("guarded_by", true) |
666 .Case("guarded_var", true) | 786 .Case("guarded_var", true) |
667 .Case("pt_guarded_by", true) | 787 .Case("pt_guarded_by", true) |
668 .Case("pt_guarded_var", true) | 788 .Case("pt_guarded_var", true) |
669 .Case("lockable", true) | 789 .Case("lockable", true) |
670 .Case("scoped_lockable", true) | 790 .Case("scoped_lockable", true) |
(...skipping 21 matching lines...) Expand all Loading... |
692 /// the arguments will be added to a list of "arguments". However, | 812 /// the arguments will be added to a list of "arguments". However, |
693 /// subsequent tokens in the first argument are lost. We instead parse each | 813 /// subsequent tokens in the first argument are lost. We instead parse each |
694 /// argument as an expression and add all arguments to the list of "arguments". | 814 /// argument as an expression and add all arguments to the list of "arguments". |
695 /// In future, we will take advantage of this special case to also | 815 /// In future, we will take advantage of this special case to also |
696 /// deal with some argument scoping issues here (for example, referring to a | 816 /// deal with some argument scoping issues here (for example, referring to a |
697 /// function parameter in the attribute on that function). | 817 /// function parameter in the attribute on that function). |
698 void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, | 818 void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, |
699 SourceLocation AttrNameLoc, | 819 SourceLocation AttrNameLoc, |
700 ParsedAttributes &Attrs, | 820 ParsedAttributes &Attrs, |
701 SourceLocation *EndLoc) { | 821 SourceLocation *EndLoc) { |
| 822 assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); |
702 | 823 |
703 if (Tok.is(tok::l_paren)) { | 824 SourceLocation LeftParenLoc = Tok.getLocation(); |
704 SourceLocation LeftParenLoc = Tok.getLocation(); | 825 ConsumeParen(); |
705 ConsumeParen(); // ignore the left paren loc for now | 826 |
706 | 827 ExprVector ArgExprs(Actions); |
707 ExprVector ArgExprs(Actions); | 828 bool ArgExprsOk = true; |
708 bool ArgExprsOk = true; | 829 |
709 | 830 // now parse the list of expressions |
710 // now parse the list of expressions | 831 while (1) { |
711 while (1) { | 832 ExprResult ArgExpr(ParseAssignmentExpression()); |
712 ExprResult ArgExpr(ParseAssignmentExpression()); | 833 if (ArgExpr.isInvalid()) { |
713 if (ArgExpr.isInvalid()) { | 834 ArgExprsOk = false; |
714 ArgExprsOk = false; | 835 MatchRHSPunctuation(tok::r_paren, LeftParenLoc); |
715 MatchRHSPunctuation(tok::r_paren, LeftParenLoc); | 836 break; |
716 break; | 837 } else { |
717 } else { | 838 ArgExprs.push_back(ArgExpr.release()); |
718 ArgExprs.push_back(ArgExpr.release()); | |
719 } | |
720 if (Tok.isNot(tok::comma)) | |
721 break; | |
722 ConsumeToken(); // Eat the comma, move to the next argument | |
723 } | 839 } |
724 // Match the ')'. | 840 if (Tok.isNot(tok::comma)) |
725 if (ArgExprsOk && Tok.is(tok::r_paren)) { | 841 break; |
726 ConsumeParen(); // ignore the right paren loc for now | 842 ConsumeToken(); // Eat the comma, move to the next argument |
727 Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), | 843 } |
728 ArgExprs.take(), ArgExprs.size()); | 844 // Match the ')'. |
729 } | 845 if (ArgExprsOk && Tok.is(tok::r_paren)) { |
730 } else { | 846 if (EndLoc) |
731 Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, | 847 *EndLoc = Tok.getLocation(); |
732 0, SourceLocation(), 0, 0); | 848 ConsumeParen(); |
| 849 Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), |
| 850 ArgExprs.take(), ArgExprs.size()); |
733 } | 851 } |
734 } | 852 } |
735 | 853 |
736 void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { | 854 void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { |
737 Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) | 855 Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) |
738 << attrs.Range; | 856 << attrs.Range; |
739 } | 857 } |
740 | 858 |
741 /// ParseDeclaration - Parse a full 'declaration', which consists of | 859 /// ParseDeclaration - Parse a full 'declaration', which consists of |
742 /// declaration-specifiers, some number of declarators, and a semicolon. | 860 /// declaration-specifiers, some number of declarators, and a semicolon. |
(...skipping 3605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4348 default: | 4466 default: |
4349 break; | 4467 break; |
4350 } | 4468 } |
4351 } else if ((Tok.getIdentifierInfo() == Ident_pixel) && | 4469 } else if ((Tok.getIdentifierInfo() == Ident_pixel) && |
4352 DS.isTypeAltiVecVector()) { | 4470 DS.isTypeAltiVecVector()) { |
4353 isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); | 4471 isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); |
4354 return true; | 4472 return true; |
4355 } | 4473 } |
4356 return false; | 4474 return false; |
4357 } | 4475 } |
OLD | NEW |