ParsePragma.cpp revision 212904
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
21// #pragma GCC visibility comes in two variants:
22//   'push' '(' [visibility] ')'
23//   'pop'
24void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Token &VisTok) {
25  SourceLocation VisLoc = VisTok.getLocation();
26
27  Token Tok;
28  PP.Lex(Tok);
29
30  const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
31
32  bool IsPush;
33  const IdentifierInfo *VisType;
34  if (PushPop && PushPop->isStr("pop")) {
35    IsPush = false;
36    VisType = 0;
37  } else if (PushPop && PushPop->isStr("push")) {
38    IsPush = true;
39    PP.Lex(Tok);
40    if (Tok.isNot(tok::l_paren)) {
41      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
42        << "visibility";
43      return;
44    }
45    PP.Lex(Tok);
46    VisType = Tok.getIdentifierInfo();
47    if (!VisType) {
48      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
49        << "visibility";
50      return;
51    }
52    PP.Lex(Tok);
53    if (Tok.isNot(tok::r_paren)) {
54      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
55        << "visibility";
56      return;
57    }
58  } else {
59    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
60      << "visibility";
61    return;
62  }
63  PP.Lex(Tok);
64  if (Tok.isNot(tok::eom)) {
65    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
66      << "visibility";
67    return;
68  }
69
70  Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc);
71}
72
73// #pragma pack(...) comes in the following delicious flavors:
74//   pack '(' [integer] ')'
75//   pack '(' 'show' ')'
76//   pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
77void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
78  SourceLocation PackLoc = PackTok.getLocation();
79
80  Token Tok;
81  PP.Lex(Tok);
82  if (Tok.isNot(tok::l_paren)) {
83    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
84    return;
85  }
86
87  Sema::PragmaPackKind Kind = Sema::PPK_Default;
88  IdentifierInfo *Name = 0;
89  ExprResult Alignment;
90  SourceLocation LParenLoc = Tok.getLocation();
91  PP.Lex(Tok);
92  if (Tok.is(tok::numeric_constant)) {
93    Alignment = Actions.ActOnNumericConstant(Tok);
94    if (Alignment.isInvalid())
95      return;
96
97    PP.Lex(Tok);
98  } else if (Tok.is(tok::identifier)) {
99    const IdentifierInfo *II = Tok.getIdentifierInfo();
100    if (II->isStr("show")) {
101      Kind = Sema::PPK_Show;
102      PP.Lex(Tok);
103    } else {
104      if (II->isStr("push")) {
105        Kind = Sema::PPK_Push;
106      } else if (II->isStr("pop")) {
107        Kind = Sema::PPK_Pop;
108      } else {
109        PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
110        return;
111      }
112      PP.Lex(Tok);
113
114      if (Tok.is(tok::comma)) {
115        PP.Lex(Tok);
116
117        if (Tok.is(tok::numeric_constant)) {
118          Alignment = Actions.ActOnNumericConstant(Tok);
119          if (Alignment.isInvalid())
120            return;
121
122          PP.Lex(Tok);
123        } else if (Tok.is(tok::identifier)) {
124          Name = Tok.getIdentifierInfo();
125          PP.Lex(Tok);
126
127          if (Tok.is(tok::comma)) {
128            PP.Lex(Tok);
129
130            if (Tok.isNot(tok::numeric_constant)) {
131              PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
132              return;
133            }
134
135            Alignment = Actions.ActOnNumericConstant(Tok);
136            if (Alignment.isInvalid())
137              return;
138
139            PP.Lex(Tok);
140          }
141        } else {
142          PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
143          return;
144        }
145      }
146    }
147  }
148
149  if (Tok.isNot(tok::r_paren)) {
150    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
151    return;
152  }
153
154  SourceLocation RParenLoc = Tok.getLocation();
155  PP.Lex(Tok);
156  if (Tok.isNot(tok::eom)) {
157    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
158    return;
159  }
160
161  Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
162                          LParenLoc, RParenLoc);
163}
164
165// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
166// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
167static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
168                             bool IsOptions) {
169  Token Tok;
170
171  if (IsOptions) {
172    PP.Lex(Tok);
173    if (Tok.isNot(tok::identifier) ||
174        !Tok.getIdentifierInfo()->isStr("align")) {
175      PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
176      return;
177    }
178  }
179
180  PP.Lex(Tok);
181  if (Tok.isNot(tok::equal)) {
182    PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal)
183      << IsOptions;
184    return;
185  }
186
187  PP.Lex(Tok);
188  if (Tok.isNot(tok::identifier)) {
189    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
190      << (IsOptions ? "options" : "align");
191    return;
192  }
193
194  Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural;
195  const IdentifierInfo *II = Tok.getIdentifierInfo();
196  if (II->isStr("native"))
197    Kind = Sema::POAK_Native;
198  else if (II->isStr("natural"))
199    Kind = Sema::POAK_Natural;
200  else if (II->isStr("packed"))
201    Kind = Sema::POAK_Packed;
202  else if (II->isStr("power"))
203    Kind = Sema::POAK_Power;
204  else if (II->isStr("mac68k"))
205    Kind = Sema::POAK_Mac68k;
206  else if (II->isStr("reset"))
207    Kind = Sema::POAK_Reset;
208  else {
209    PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option)
210      << IsOptions;
211    return;
212  }
213
214  SourceLocation KindLoc = Tok.getLocation();
215  PP.Lex(Tok);
216  if (Tok.isNot(tok::eom)) {
217    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
218      << (IsOptions ? "options" : "align");
219    return;
220  }
221
222  Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc);
223}
224
225void PragmaAlignHandler::HandlePragma(Preprocessor &PP, Token &AlignTok) {
226  ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false);
227}
228
229void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) {
230  ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true);
231}
232
233// #pragma unused(identifier)
234void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
235  // FIXME: Should we be expanding macros here? My guess is no.
236  SourceLocation UnusedLoc = UnusedTok.getLocation();
237
238  // Lex the left '('.
239  Token Tok;
240  PP.Lex(Tok);
241  if (Tok.isNot(tok::l_paren)) {
242    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
243    return;
244  }
245  SourceLocation LParenLoc = Tok.getLocation();
246
247  // Lex the declaration reference(s).
248  llvm::SmallVector<Token, 5> Identifiers;
249  SourceLocation RParenLoc;
250  bool LexID = true;
251
252  while (true) {
253    PP.Lex(Tok);
254
255    if (LexID) {
256      if (Tok.is(tok::identifier)) {
257        Identifiers.push_back(Tok);
258        LexID = false;
259        continue;
260      }
261
262      // Illegal token!
263      PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
264      return;
265    }
266
267    // We are execting a ')' or a ','.
268    if (Tok.is(tok::comma)) {
269      LexID = true;
270      continue;
271    }
272
273    if (Tok.is(tok::r_paren)) {
274      RParenLoc = Tok.getLocation();
275      break;
276    }
277
278    // Illegal token!
279    PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
280    return;
281  }
282
283  PP.Lex(Tok);
284  if (Tok.isNot(tok::eom)) {
285    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
286        "unused";
287    return;
288  }
289
290  // Verify that we have a location for the right parenthesis.
291  assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
292  assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
293
294  // Perform the action to handle the pragma.
295  Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(),
296                            parser.getCurScope(), UnusedLoc, LParenLoc, RParenLoc);
297}
298
299// #pragma weak identifier
300// #pragma weak identifier '=' identifier
301void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) {
302  // FIXME: Should we be expanding macros here? My guess is no.
303  SourceLocation WeakLoc = WeakTok.getLocation();
304
305  Token Tok;
306  PP.Lex(Tok);
307  if (Tok.isNot(tok::identifier)) {
308    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak";
309    return;
310  }
311
312  IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0;
313  SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc;
314
315  PP.Lex(Tok);
316  if (Tok.is(tok::equal)) {
317    PP.Lex(Tok);
318    if (Tok.isNot(tok::identifier)) {
319      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
320          << "weak";
321      return;
322    }
323    AliasName = Tok.getIdentifierInfo();
324    AliasNameLoc = Tok.getLocation();
325    PP.Lex(Tok);
326  }
327
328  if (Tok.isNot(tok::eom)) {
329    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak";
330    return;
331  }
332
333  if (AliasName) {
334    Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc,
335                                 AliasNameLoc);
336  } else {
337    Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc);
338  }
339}
340