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