1 //===--- ParsePragma.cpp - Language specific pragma parsing ---------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the language specific #pragma handlers.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "ParsePragma.h"
15 #include "clang/Parse/ParseDiagnostic.h"
16 #include "clang/Parse/Parser.h"
17 #include "clang/Lex/Preprocessor.h"
18 using namespace clang;
19
20 /// \brief Handle the annotation token produced for #pragma unused(...)
21 ///
22 /// Each annot_pragma_unused is followed by the argument token so e.g.
23 /// "#pragma unused(x,y)" becomes:
24 /// annot_pragma_unused 'x' annot_pragma_unused 'y'
HandlePragmaUnused()25 void Parser::HandlePragmaUnused() {
26 assert(Tok.is(tok::annot_pragma_unused));
27 SourceLocation UnusedLoc = ConsumeToken();
28 Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc);
29 ConsumeToken(); // The argument token.
30 }
31
32 // #pragma GCC visibility comes in two variants:
33 // 'push' '(' [visibility] ')'
34 // 'pop'
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & VisTok)35 void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
36 PragmaIntroducerKind Introducer,
37 Token &VisTok) {
38 SourceLocation VisLoc = VisTok.getLocation();
39
40 Token Tok;
41 PP.LexUnexpandedToken(Tok);
42
43 const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
44
45 bool IsPush;
46 const IdentifierInfo *VisType;
47 if (PushPop && PushPop->isStr("pop")) {
48 IsPush = false;
49 VisType = 0;
50 } else if (PushPop && PushPop->isStr("push")) {
51 IsPush = true;
52 PP.LexUnexpandedToken(Tok);
53 if (Tok.isNot(tok::l_paren)) {
54 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
55 << "visibility";
56 return;
57 }
58 PP.LexUnexpandedToken(Tok);
59 VisType = Tok.getIdentifierInfo();
60 if (!VisType) {
61 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
62 << "visibility";
63 return;
64 }
65 PP.LexUnexpandedToken(Tok);
66 if (Tok.isNot(tok::r_paren)) {
67 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
68 << "visibility";
69 return;
70 }
71 } else {
72 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
73 << "visibility";
74 return;
75 }
76 PP.LexUnexpandedToken(Tok);
77 if (Tok.isNot(tok::eod)) {
78 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
79 << "visibility";
80 return;
81 }
82
83 Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc);
84 }
85
86 // #pragma pack(...) comes in the following delicious flavors:
87 // pack '(' [integer] ')'
88 // pack '(' 'show' ')'
89 // pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & PackTok)90 void PragmaPackHandler::HandlePragma(Preprocessor &PP,
91 PragmaIntroducerKind Introducer,
92 Token &PackTok) {
93 SourceLocation PackLoc = PackTok.getLocation();
94
95 Token Tok;
96 PP.Lex(Tok);
97 if (Tok.isNot(tok::l_paren)) {
98 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
99 return;
100 }
101
102 Sema::PragmaPackKind Kind = Sema::PPK_Default;
103 IdentifierInfo *Name = 0;
104 ExprResult Alignment;
105 SourceLocation LParenLoc = Tok.getLocation();
106 PP.Lex(Tok);
107 if (Tok.is(tok::numeric_constant)) {
108 Alignment = Actions.ActOnNumericConstant(Tok);
109 if (Alignment.isInvalid())
110 return;
111
112 PP.Lex(Tok);
113 } else if (Tok.is(tok::identifier)) {
114 const IdentifierInfo *II = Tok.getIdentifierInfo();
115 if (II->isStr("show")) {
116 Kind = Sema::PPK_Show;
117 PP.Lex(Tok);
118 } else {
119 if (II->isStr("push")) {
120 Kind = Sema::PPK_Push;
121 } else if (II->isStr("pop")) {
122 Kind = Sema::PPK_Pop;
123 } else {
124 PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
125 return;
126 }
127 PP.Lex(Tok);
128
129 if (Tok.is(tok::comma)) {
130 PP.Lex(Tok);
131
132 if (Tok.is(tok::numeric_constant)) {
133 Alignment = Actions.ActOnNumericConstant(Tok);
134 if (Alignment.isInvalid())
135 return;
136
137 PP.Lex(Tok);
138 } else if (Tok.is(tok::identifier)) {
139 Name = Tok.getIdentifierInfo();
140 PP.Lex(Tok);
141
142 if (Tok.is(tok::comma)) {
143 PP.Lex(Tok);
144
145 if (Tok.isNot(tok::numeric_constant)) {
146 PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
147 return;
148 }
149
150 Alignment = Actions.ActOnNumericConstant(Tok);
151 if (Alignment.isInvalid())
152 return;
153
154 PP.Lex(Tok);
155 }
156 } else {
157 PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
158 return;
159 }
160 }
161 }
162 }
163
164 if (Tok.isNot(tok::r_paren)) {
165 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
166 return;
167 }
168
169 SourceLocation RParenLoc = Tok.getLocation();
170 PP.Lex(Tok);
171 if (Tok.isNot(tok::eod)) {
172 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
173 return;
174 }
175
176 Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
177 LParenLoc, RParenLoc);
178 }
179
180 // #pragma ms_struct on
181 // #pragma ms_struct off
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & MSStructTok)182 void PragmaMSStructHandler::HandlePragma(Preprocessor &PP,
183 PragmaIntroducerKind Introducer,
184 Token &MSStructTok) {
185 Sema::PragmaMSStructKind Kind = Sema::PMSST_OFF;
186
187 Token Tok;
188 PP.Lex(Tok);
189 if (Tok.isNot(tok::identifier)) {
190 PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct);
191 return;
192 }
193 const IdentifierInfo *II = Tok.getIdentifierInfo();
194 if (II->isStr("on")) {
195 Kind = Sema::PMSST_ON;
196 PP.Lex(Tok);
197 }
198 else if (II->isStr("off") || II->isStr("reset"))
199 PP.Lex(Tok);
200 else {
201 PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct);
202 return;
203 }
204
205 if (Tok.isNot(tok::eod)) {
206 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "ms_struct";
207 return;
208 }
209 Actions.ActOnPragmaMSStruct(Kind);
210 }
211
212 // #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
213 // #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
ParseAlignPragma(Sema & Actions,Preprocessor & PP,Token & FirstTok,bool IsOptions)214 static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
215 bool IsOptions) {
216 Token Tok;
217
218 if (IsOptions) {
219 PP.Lex(Tok);
220 if (Tok.isNot(tok::identifier) ||
221 !Tok.getIdentifierInfo()->isStr("align")) {
222 PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
223 return;
224 }
225 }
226
227 PP.Lex(Tok);
228 if (Tok.isNot(tok::equal)) {
229 PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal)
230 << IsOptions;
231 return;
232 }
233
234 PP.Lex(Tok);
235 if (Tok.isNot(tok::identifier)) {
236 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
237 << (IsOptions ? "options" : "align");
238 return;
239 }
240
241 Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural;
242 const IdentifierInfo *II = Tok.getIdentifierInfo();
243 if (II->isStr("native"))
244 Kind = Sema::POAK_Native;
245 else if (II->isStr("natural"))
246 Kind = Sema::POAK_Natural;
247 else if (II->isStr("packed"))
248 Kind = Sema::POAK_Packed;
249 else if (II->isStr("power"))
250 Kind = Sema::POAK_Power;
251 else if (II->isStr("mac68k"))
252 Kind = Sema::POAK_Mac68k;
253 else if (II->isStr("reset"))
254 Kind = Sema::POAK_Reset;
255 else {
256 PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option)
257 << IsOptions;
258 return;
259 }
260
261 SourceLocation KindLoc = Tok.getLocation();
262 PP.Lex(Tok);
263 if (Tok.isNot(tok::eod)) {
264 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
265 << (IsOptions ? "options" : "align");
266 return;
267 }
268
269 Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc);
270 }
271
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & AlignTok)272 void PragmaAlignHandler::HandlePragma(Preprocessor &PP,
273 PragmaIntroducerKind Introducer,
274 Token &AlignTok) {
275 ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false);
276 }
277
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & OptionsTok)278 void PragmaOptionsHandler::HandlePragma(Preprocessor &PP,
279 PragmaIntroducerKind Introducer,
280 Token &OptionsTok) {
281 ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true);
282 }
283
284 // #pragma unused(identifier)
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & UnusedTok)285 void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
286 PragmaIntroducerKind Introducer,
287 Token &UnusedTok) {
288 // FIXME: Should we be expanding macros here? My guess is no.
289 SourceLocation UnusedLoc = UnusedTok.getLocation();
290
291 // Lex the left '('.
292 Token Tok;
293 PP.Lex(Tok);
294 if (Tok.isNot(tok::l_paren)) {
295 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
296 return;
297 }
298
299 // Lex the declaration reference(s).
300 llvm::SmallVector<Token, 5> Identifiers;
301 SourceLocation RParenLoc;
302 bool LexID = true;
303
304 while (true) {
305 PP.Lex(Tok);
306
307 if (LexID) {
308 if (Tok.is(tok::identifier)) {
309 Identifiers.push_back(Tok);
310 LexID = false;
311 continue;
312 }
313
314 // Illegal token!
315 PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
316 return;
317 }
318
319 // We are execting a ')' or a ','.
320 if (Tok.is(tok::comma)) {
321 LexID = true;
322 continue;
323 }
324
325 if (Tok.is(tok::r_paren)) {
326 RParenLoc = Tok.getLocation();
327 break;
328 }
329
330 // Illegal token!
331 PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
332 return;
333 }
334
335 PP.Lex(Tok);
336 if (Tok.isNot(tok::eod)) {
337 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
338 "unused";
339 return;
340 }
341
342 // Verify that we have a location for the right parenthesis.
343 assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
344 assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
345
346 // For each identifier token, insert into the token stream a
347 // annot_pragma_unused token followed by the identifier token.
348 // This allows us to cache a "#pragma unused" that occurs inside an inline
349 // C++ member function.
350
351 Token *Toks = new Token[2*Identifiers.size()];
352 for (unsigned i=0; i != Identifiers.size(); i++) {
353 Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1];
354 pragmaUnusedTok.startToken();
355 pragmaUnusedTok.setKind(tok::annot_pragma_unused);
356 pragmaUnusedTok.setLocation(UnusedLoc);
357 idTok = Identifiers[i];
358 }
359 PP.EnterTokenStream(Toks, 2*Identifiers.size(), /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
360 }
361
362 // #pragma weak identifier
363 // #pragma weak identifier '=' identifier
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & WeakTok)364 void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
365 PragmaIntroducerKind Introducer,
366 Token &WeakTok) {
367 // FIXME: Should we be expanding macros here? My guess is no.
368 SourceLocation WeakLoc = WeakTok.getLocation();
369
370 Token Tok;
371 PP.Lex(Tok);
372 if (Tok.isNot(tok::identifier)) {
373 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak";
374 return;
375 }
376
377 IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0;
378 SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc;
379
380 PP.Lex(Tok);
381 if (Tok.is(tok::equal)) {
382 PP.Lex(Tok);
383 if (Tok.isNot(tok::identifier)) {
384 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
385 << "weak";
386 return;
387 }
388 AliasName = Tok.getIdentifierInfo();
389 AliasNameLoc = Tok.getLocation();
390 PP.Lex(Tok);
391 }
392
393 if (Tok.isNot(tok::eod)) {
394 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak";
395 return;
396 }
397
398 if (AliasName) {
399 Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc,
400 AliasNameLoc);
401 } else {
402 Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc);
403 }
404 }
405
406 void
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & Tok)407 PragmaFPContractHandler::HandlePragma(Preprocessor &PP,
408 PragmaIntroducerKind Introducer,
409 Token &Tok) {
410 tok::OnOffSwitch OOS;
411 if (PP.LexOnOffSwitch(OOS))
412 return;
413
414 Actions.ActOnPragmaFPContract(OOS);
415 }
416
417 void
HandlePragma(Preprocessor & PP,PragmaIntroducerKind Introducer,Token & Tok)418 PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
419 PragmaIntroducerKind Introducer,
420 Token &Tok) {
421 PP.LexUnexpandedToken(Tok);
422 if (Tok.isNot(tok::identifier)) {
423 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) <<
424 "OPENCL";
425 return;
426 }
427 IdentifierInfo *ename = Tok.getIdentifierInfo();
428 SourceLocation NameLoc = Tok.getLocation();
429
430 PP.Lex(Tok);
431 if (Tok.isNot(tok::colon)) {
432 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << ename;
433 return;
434 }
435
436 PP.Lex(Tok);
437 if (Tok.isNot(tok::identifier)) {
438 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable);
439 return;
440 }
441 IdentifierInfo *op = Tok.getIdentifierInfo();
442
443 unsigned state;
444 if (op->isStr("enable")) {
445 state = 1;
446 } else if (op->isStr("disable")) {
447 state = 0;
448 } else {
449 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable);
450 return;
451 }
452
453 OpenCLOptions &f = Actions.getOpenCLOptions();
454 if (ename->isStr("all")) {
455 #define OPENCLEXT(nm) f.nm = state;
456 #include "clang/Basic/OpenCLExtensions.def"
457 }
458 #define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
459 #include "clang/Basic/OpenCLExtensions.def"
460 else {
461 PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename;
462 return;
463 }
464 }
465
466