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