• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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