ParsePragma.cpp revision 226633
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  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] ')'
90void 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
182void 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'}
214static 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
272void PragmaAlignHandler::HandlePragma(Preprocessor &PP,
273                                      PragmaIntroducerKind Introducer,
274                                      Token &AlignTok) {
275  ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false);
276}
277
278void PragmaOptionsHandler::HandlePragma(Preprocessor &PP,
279                                        PragmaIntroducerKind Introducer,
280                                        Token &OptionsTok) {
281  ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true);
282}
283
284// #pragma unused(identifier)
285void 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  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
364void 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
406void
407PragmaFPContractHandler::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
417void
418PragmaOpenCLExtensionHandler::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  // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions,
455  // overriding all previously issued extension directives, but only if the
456  // behavior is set to disable."
457  if (state == 0 && ename->isStr("all")) {
458#define OPENCLEXT(nm)   f.nm = 0;
459#include "clang/Basic/OpenCLExtensions.def"
460  }
461#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; }
462#include "clang/Basic/OpenCLExtensions.def"
463  else {
464    PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename;
465    return;
466  }
467}
468
469