ParsePragma.cpp revision 208954
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/Lex/Preprocessor.h"
17#include "clang/Parse/Action.h"
18#include "clang/Parse/Parser.h"
19using namespace clang;
20
21// #pragma pack(...) comes in the following delicious flavors:
22//   pack '(' [integer] ')'
23//   pack '(' 'show' ')'
24//   pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
25void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
26  SourceLocation PackLoc = PackTok.getLocation();
27
28  Token Tok;
29  PP.Lex(Tok);
30  if (Tok.isNot(tok::l_paren)) {
31    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
32    return;
33  }
34
35  Action::PragmaPackKind Kind = Action::PPK_Default;
36  IdentifierInfo *Name = 0;
37  Action::OwningExprResult Alignment(Actions);
38  SourceLocation LParenLoc = Tok.getLocation();
39  PP.Lex(Tok);
40  if (Tok.is(tok::numeric_constant)) {
41    Alignment = Actions.ActOnNumericConstant(Tok);
42    if (Alignment.isInvalid())
43      return;
44
45    PP.Lex(Tok);
46  } else if (Tok.is(tok::identifier)) {
47    const IdentifierInfo *II = Tok.getIdentifierInfo();
48    if (II->isStr("show")) {
49      Kind = Action::PPK_Show;
50      PP.Lex(Tok);
51    } else {
52      if (II->isStr("push")) {
53        Kind = Action::PPK_Push;
54      } else if (II->isStr("pop")) {
55        Kind = Action::PPK_Pop;
56      } else {
57        PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
58        return;
59      }
60      PP.Lex(Tok);
61
62      if (Tok.is(tok::comma)) {
63        PP.Lex(Tok);
64
65        if (Tok.is(tok::numeric_constant)) {
66          Alignment = Actions.ActOnNumericConstant(Tok);
67          if (Alignment.isInvalid())
68            return;
69
70          PP.Lex(Tok);
71        } else if (Tok.is(tok::identifier)) {
72          Name = Tok.getIdentifierInfo();
73          PP.Lex(Tok);
74
75          if (Tok.is(tok::comma)) {
76            PP.Lex(Tok);
77
78            if (Tok.isNot(tok::numeric_constant)) {
79              PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
80              return;
81            }
82
83            Alignment = Actions.ActOnNumericConstant(Tok);
84            if (Alignment.isInvalid())
85              return;
86
87            PP.Lex(Tok);
88          }
89        } else {
90          PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
91          return;
92        }
93      }
94    }
95  }
96
97  if (Tok.isNot(tok::r_paren)) {
98    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
99    return;
100  }
101
102  SourceLocation RParenLoc = Tok.getLocation();
103  PP.Lex(Tok);
104  if (Tok.isNot(tok::eom)) {
105    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
106    return;
107  }
108
109  Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
110                          LParenLoc, RParenLoc);
111}
112
113// #pragma 'options' 'align' '=' {'natural', 'mac68k', 'power', 'reset'}
114void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) {
115  SourceLocation OptionsLoc = OptionsTok.getLocation();
116
117  Token Tok;
118  PP.Lex(Tok);
119  if (Tok.isNot(tok::identifier) || !Tok.getIdentifierInfo()->isStr("align")) {
120    PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
121    return;
122  }
123
124  PP.Lex(Tok);
125  if (Tok.isNot(tok::equal)) {
126    PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_equal);
127    return;
128  }
129
130  PP.Lex(Tok);
131  if (Tok.isNot(tok::identifier)) {
132    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
133      << "options";
134    return;
135  }
136
137  Action::PragmaOptionsAlignKind Kind = Action::POAK_Natural;
138  const IdentifierInfo *II = Tok.getIdentifierInfo();
139  if (II->isStr("natural"))
140    Kind = Action::POAK_Natural;
141  else if (II->isStr("power"))
142    Kind = Action::POAK_Power;
143  else if (II->isStr("mac68k"))
144    Kind = Action::POAK_Mac68k;
145  else if (II->isStr("reset"))
146    Kind = Action::POAK_Reset;
147  else {
148    PP.Diag(Tok.getLocation(), diag::warn_pragma_options_invalid_option);
149    return;
150  }
151
152  SourceLocation KindLoc = Tok.getLocation();
153  PP.Lex(Tok);
154  if (Tok.isNot(tok::eom)) {
155    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
156      << "options";
157    return;
158  }
159
160  Actions.ActOnPragmaOptionsAlign(Kind, OptionsLoc, KindLoc);
161}
162
163// #pragma unused(identifier)
164void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
165  // FIXME: Should we be expanding macros here? My guess is no.
166  SourceLocation UnusedLoc = UnusedTok.getLocation();
167
168  // Lex the left '('.
169  Token Tok;
170  PP.Lex(Tok);
171  if (Tok.isNot(tok::l_paren)) {
172    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
173    return;
174  }
175  SourceLocation LParenLoc = Tok.getLocation();
176
177  // Lex the declaration reference(s).
178  llvm::SmallVector<Token, 5> Identifiers;
179  SourceLocation RParenLoc;
180  bool LexID = true;
181
182  while (true) {
183    PP.Lex(Tok);
184
185    if (LexID) {
186      if (Tok.is(tok::identifier)) {
187        Identifiers.push_back(Tok);
188        LexID = false;
189        continue;
190      }
191
192      // Illegal token!
193      PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
194      return;
195    }
196
197    // We are execting a ')' or a ','.
198    if (Tok.is(tok::comma)) {
199      LexID = true;
200      continue;
201    }
202
203    if (Tok.is(tok::r_paren)) {
204      RParenLoc = Tok.getLocation();
205      break;
206    }
207
208    // Illegal token!
209    PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
210    return;
211  }
212
213  PP.Lex(Tok);
214  if (Tok.isNot(tok::eom)) {
215    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
216        "unused";
217    return;
218  }
219
220  // Verify that we have a location for the right parenthesis.
221  assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
222  assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
223
224  // Perform the action to handle the pragma.
225  Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(),
226                            parser.CurScope, UnusedLoc, LParenLoc, RParenLoc);
227}
228
229// #pragma weak identifier
230// #pragma weak identifier '=' identifier
231void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) {
232  // FIXME: Should we be expanding macros here? My guess is no.
233  SourceLocation WeakLoc = WeakTok.getLocation();
234
235  Token Tok;
236  PP.Lex(Tok);
237  if (Tok.isNot(tok::identifier)) {
238    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak";
239    return;
240  }
241
242  IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0;
243  SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc;
244
245  PP.Lex(Tok);
246  if (Tok.is(tok::equal)) {
247    PP.Lex(Tok);
248    if (Tok.isNot(tok::identifier)) {
249      PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
250          << "weak";
251      return;
252    }
253    AliasName = Tok.getIdentifierInfo();
254    AliasNameLoc = Tok.getLocation();
255    PP.Lex(Tok);
256  }
257
258  if (Tok.isNot(tok::eom)) {
259    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak";
260    return;
261  }
262
263  if (AliasName) {
264    Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc,
265                                 AliasNameLoc);
266  } else {
267    Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc);
268  }
269}
270