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