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