blob: 42c1c5f5a2489bc7345b9b2dea84df3aba62455c [file] [log] [blame]
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +00001//===--- 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"
Chris Lattner500d3292009-01-29 05:15:15 +000015#include "clang/Parse/ParseDiagnostic.h"
Ted Kremenek4726d032009-03-23 22:28:25 +000016#include "clang/Parse/Parser.h"
John McCall19510852010-08-20 18:27:03 +000017#include "clang/Lex/Preprocessor.h"
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000018using namespace clang;
19
Eli Friedmanaa8b0d12010-08-05 06:57:20 +000020
21// #pragma GCC visibility comes in two variants:
22// 'push' '(' [visibility] ')'
23// 'pop'
Douglas Gregor80c60f72010-09-09 22:45:38 +000024void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
25 PragmaIntroducerKind Introducer,
26 Token &VisTok) {
Eli Friedmanaa8b0d12010-08-05 06:57:20 +000027 SourceLocation VisLoc = VisTok.getLocation();
28
29 Token Tok;
30 PP.Lex(Tok);
31
32 const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
33
34 bool IsPush;
35 const IdentifierInfo *VisType;
36 if (PushPop && PushPop->isStr("pop")) {
37 IsPush = false;
38 VisType = 0;
39 } else if (PushPop && PushPop->isStr("push")) {
40 IsPush = true;
41 PP.Lex(Tok);
42 if (Tok.isNot(tok::l_paren)) {
43 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
44 << "visibility";
45 return;
46 }
47 PP.Lex(Tok);
48 VisType = Tok.getIdentifierInfo();
49 if (!VisType) {
50 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
51 << "visibility";
52 return;
53 }
54 PP.Lex(Tok);
55 if (Tok.isNot(tok::r_paren)) {
56 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
57 << "visibility";
58 return;
59 }
60 } else {
61 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
62 << "visibility";
63 return;
64 }
65 PP.Lex(Tok);
66 if (Tok.isNot(tok::eom)) {
67 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
68 << "visibility";
69 return;
70 }
71
72 Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc);
73}
74
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000075// #pragma pack(...) comes in the following delicious flavors:
76// pack '(' [integer] ')'
77// pack '(' 'show' ')'
78// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
Douglas Gregor80c60f72010-09-09 22:45:38 +000079void PragmaPackHandler::HandlePragma(Preprocessor &PP,
80 PragmaIntroducerKind Introducer,
81 Token &PackTok) {
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000082 SourceLocation PackLoc = PackTok.getLocation();
83
84 Token Tok;
85 PP.Lex(Tok);
86 if (Tok.isNot(tok::l_paren)) {
Ted Kremenek4726d032009-03-23 22:28:25 +000087 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000088 return;
89 }
90
John McCallf312b1e2010-08-26 23:41:50 +000091 Sema::PragmaPackKind Kind = Sema::PPK_Default;
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000092 IdentifierInfo *Name = 0;
John McCall60d7b3a2010-08-24 06:29:42 +000093 ExprResult Alignment;
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000094 SourceLocation LParenLoc = Tok.getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +000095 PP.Lex(Tok);
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000096 if (Tok.is(tok::numeric_constant)) {
97 Alignment = Actions.ActOnNumericConstant(Tok);
Sebastian Redl0e9eabc2008-12-09 13:15:23 +000098 if (Alignment.isInvalid())
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +000099 return;
100
101 PP.Lex(Tok);
102 } else if (Tok.is(tok::identifier)) {
103 const IdentifierInfo *II = Tok.getIdentifierInfo();
Chris Lattner08631c52008-11-23 21:45:46 +0000104 if (II->isStr("show")) {
John McCallf312b1e2010-08-26 23:41:50 +0000105 Kind = Sema::PPK_Show;
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000106 PP.Lex(Tok);
107 } else {
Chris Lattner08631c52008-11-23 21:45:46 +0000108 if (II->isStr("push")) {
John McCallf312b1e2010-08-26 23:41:50 +0000109 Kind = Sema::PPK_Push;
Chris Lattner08631c52008-11-23 21:45:46 +0000110 } else if (II->isStr("pop")) {
John McCallf312b1e2010-08-26 23:41:50 +0000111 Kind = Sema::PPK_Pop;
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000112 } else {
113 PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
114 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000115 }
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000116 PP.Lex(Tok);
Mike Stump1eb44332009-09-09 15:08:12 +0000117
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000118 if (Tok.is(tok::comma)) {
119 PP.Lex(Tok);
Mike Stump1eb44332009-09-09 15:08:12 +0000120
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000121 if (Tok.is(tok::numeric_constant)) {
122 Alignment = Actions.ActOnNumericConstant(Tok);
Sebastian Redl0e9eabc2008-12-09 13:15:23 +0000123 if (Alignment.isInvalid())
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000124 return;
125
126 PP.Lex(Tok);
127 } else if (Tok.is(tok::identifier)) {
128 Name = Tok.getIdentifierInfo();
129 PP.Lex(Tok);
Mike Stump1eb44332009-09-09 15:08:12 +0000130
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000131 if (Tok.is(tok::comma)) {
132 PP.Lex(Tok);
Mike Stump1eb44332009-09-09 15:08:12 +0000133
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000134 if (Tok.isNot(tok::numeric_constant)) {
Chris Lattner08631c52008-11-23 21:45:46 +0000135 PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000136 return;
137 }
Mike Stump1eb44332009-09-09 15:08:12 +0000138
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000139 Alignment = Actions.ActOnNumericConstant(Tok);
Sebastian Redl0e9eabc2008-12-09 13:15:23 +0000140 if (Alignment.isInvalid())
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000141 return;
142
143 PP.Lex(Tok);
144 }
145 } else {
Chris Lattner08631c52008-11-23 21:45:46 +0000146 PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000147 return;
148 }
149 }
150 }
Sebastian Redl0e9eabc2008-12-09 13:15:23 +0000151 }
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000152
153 if (Tok.isNot(tok::r_paren)) {
Ted Kremenek4726d032009-03-23 22:28:25 +0000154 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000155 return;
156 }
157
Daniel Dunbar861800c2010-05-26 23:29:06 +0000158 SourceLocation RParenLoc = Tok.getLocation();
Eli Friedman99914792009-06-05 00:49:58 +0000159 PP.Lex(Tok);
160 if (Tok.isNot(tok::eom)) {
161 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
162 return;
163 }
164
Sebastian Redleffa8d12008-12-10 00:02:53 +0000165 Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
Daniel Dunbarfcdd8fe2008-10-04 19:21:03 +0000166 LParenLoc, RParenLoc);
167}
168
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000169// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
170// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
John McCallf312b1e2010-08-26 23:41:50 +0000171static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok,
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000172 bool IsOptions) {
Daniel Dunbar861800c2010-05-26 23:29:06 +0000173 Token Tok;
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000174
175 if (IsOptions) {
176 PP.Lex(Tok);
177 if (Tok.isNot(tok::identifier) ||
178 !Tok.getIdentifierInfo()->isStr("align")) {
179 PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
180 return;
181 }
Daniel Dunbar861800c2010-05-26 23:29:06 +0000182 }
Daniel Dunbar638e7cf2010-05-27 18:42:09 +0000183
Daniel Dunbar861800c2010-05-26 23:29:06 +0000184 PP.Lex(Tok);
185 if (Tok.isNot(tok::equal)) {
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000186 PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal)
187 << IsOptions;
Daniel Dunbar861800c2010-05-26 23:29:06 +0000188 return;
189 }
190
191 PP.Lex(Tok);
192 if (Tok.isNot(tok::identifier)) {
193 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000194 << (IsOptions ? "options" : "align");
Daniel Dunbar861800c2010-05-26 23:29:06 +0000195 return;
196 }
197
John McCallf312b1e2010-08-26 23:41:50 +0000198 Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural;
Daniel Dunbar861800c2010-05-26 23:29:06 +0000199 const IdentifierInfo *II = Tok.getIdentifierInfo();
Daniel Dunbar638e7cf2010-05-27 18:42:09 +0000200 if (II->isStr("native"))
John McCallf312b1e2010-08-26 23:41:50 +0000201 Kind = Sema::POAK_Native;
Daniel Dunbar638e7cf2010-05-27 18:42:09 +0000202 else if (II->isStr("natural"))
John McCallf312b1e2010-08-26 23:41:50 +0000203 Kind = Sema::POAK_Natural;
Daniel Dunbar6f739142010-05-27 18:42:17 +0000204 else if (II->isStr("packed"))
John McCallf312b1e2010-08-26 23:41:50 +0000205 Kind = Sema::POAK_Packed;
Daniel Dunbar861800c2010-05-26 23:29:06 +0000206 else if (II->isStr("power"))
John McCallf312b1e2010-08-26 23:41:50 +0000207 Kind = Sema::POAK_Power;
Daniel Dunbar861800c2010-05-26 23:29:06 +0000208 else if (II->isStr("mac68k"))
John McCallf312b1e2010-08-26 23:41:50 +0000209 Kind = Sema::POAK_Mac68k;
Daniel Dunbar861800c2010-05-26 23:29:06 +0000210 else if (II->isStr("reset"))
John McCallf312b1e2010-08-26 23:41:50 +0000211 Kind = Sema::POAK_Reset;
Daniel Dunbar861800c2010-05-26 23:29:06 +0000212 else {
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000213 PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option)
214 << IsOptions;
Daniel Dunbar861800c2010-05-26 23:29:06 +0000215 return;
216 }
217
218 SourceLocation KindLoc = Tok.getLocation();
219 PP.Lex(Tok);
220 if (Tok.isNot(tok::eom)) {
221 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000222 << (IsOptions ? "options" : "align");
Daniel Dunbar861800c2010-05-26 23:29:06 +0000223 return;
224 }
225
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000226 Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc);
227}
228
Douglas Gregor80c60f72010-09-09 22:45:38 +0000229void PragmaAlignHandler::HandlePragma(Preprocessor &PP,
230 PragmaIntroducerKind Introducer,
231 Token &AlignTok) {
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000232 ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false);
233}
234
Douglas Gregor80c60f72010-09-09 22:45:38 +0000235void PragmaOptionsHandler::HandlePragma(Preprocessor &PP,
236 PragmaIntroducerKind Introducer,
237 Token &OptionsTok) {
Daniel Dunbarcbb98ed2010-07-31 19:17:07 +0000238 ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true);
Daniel Dunbar861800c2010-05-26 23:29:06 +0000239}
240
Ted Kremenek4726d032009-03-23 22:28:25 +0000241// #pragma unused(identifier)
Douglas Gregor80c60f72010-09-09 22:45:38 +0000242void PragmaUnusedHandler::HandlePragma(Preprocessor &PP,
243 PragmaIntroducerKind Introducer,
244 Token &UnusedTok) {
Ted Kremenek4726d032009-03-23 22:28:25 +0000245 // FIXME: Should we be expanding macros here? My guess is no.
246 SourceLocation UnusedLoc = UnusedTok.getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000247
Ted Kremenek4726d032009-03-23 22:28:25 +0000248 // Lex the left '('.
249 Token Tok;
250 PP.Lex(Tok);
251 if (Tok.isNot(tok::l_paren)) {
252 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
253 return;
254 }
255 SourceLocation LParenLoc = Tok.getLocation();
Mike Stump1eb44332009-09-09 15:08:12 +0000256
Ted Kremenek4726d032009-03-23 22:28:25 +0000257 // Lex the declaration reference(s).
Ted Kremenek7a02a372009-08-03 23:24:57 +0000258 llvm::SmallVector<Token, 5> Identifiers;
Ted Kremenek4726d032009-03-23 22:28:25 +0000259 SourceLocation RParenLoc;
260 bool LexID = true;
Mike Stump1eb44332009-09-09 15:08:12 +0000261
Ted Kremenek4726d032009-03-23 22:28:25 +0000262 while (true) {
263 PP.Lex(Tok);
Mike Stump1eb44332009-09-09 15:08:12 +0000264
Ted Kremenek4726d032009-03-23 22:28:25 +0000265 if (LexID) {
Mike Stump1eb44332009-09-09 15:08:12 +0000266 if (Tok.is(tok::identifier)) {
Ted Kremenek7a02a372009-08-03 23:24:57 +0000267 Identifiers.push_back(Tok);
Ted Kremenek4726d032009-03-23 22:28:25 +0000268 LexID = false;
269 continue;
270 }
271
Ted Kremenek7a02a372009-08-03 23:24:57 +0000272 // Illegal token!
Ted Kremenek4726d032009-03-23 22:28:25 +0000273 PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
274 return;
275 }
Mike Stump1eb44332009-09-09 15:08:12 +0000276
Ted Kremenek4726d032009-03-23 22:28:25 +0000277 // We are execting a ')' or a ','.
278 if (Tok.is(tok::comma)) {
279 LexID = true;
280 continue;
281 }
Mike Stump1eb44332009-09-09 15:08:12 +0000282
Ted Kremenek4726d032009-03-23 22:28:25 +0000283 if (Tok.is(tok::r_paren)) {
284 RParenLoc = Tok.getLocation();
285 break;
286 }
Mike Stump1eb44332009-09-09 15:08:12 +0000287
Ted Kremenek7a02a372009-08-03 23:24:57 +0000288 // Illegal token!
Ted Kremenek4726d032009-03-23 22:28:25 +0000289 PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
290 return;
291 }
Eli Friedman99914792009-06-05 00:49:58 +0000292
293 PP.Lex(Tok);
294 if (Tok.isNot(tok::eom)) {
295 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
296 "unused";
297 return;
298 }
299
Ted Kremenek4726d032009-03-23 22:28:25 +0000300 // Verify that we have a location for the right parenthesis.
301 assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
Ted Kremenek7a02a372009-08-03 23:24:57 +0000302 assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
Ted Kremenek4726d032009-03-23 22:28:25 +0000303
Mike Stump1eb44332009-09-09 15:08:12 +0000304 // Perform the action to handle the pragma.
Ted Kremenek7a02a372009-08-03 23:24:57 +0000305 Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(),
Douglas Gregor23c94db2010-07-02 17:43:08 +0000306 parser.getCurScope(), UnusedLoc, LParenLoc, RParenLoc);
Ted Kremenek4726d032009-03-23 22:28:25 +0000307}
Eli Friedman99914792009-06-05 00:49:58 +0000308
309// #pragma weak identifier
310// #pragma weak identifier '=' identifier
Douglas Gregor80c60f72010-09-09 22:45:38 +0000311void PragmaWeakHandler::HandlePragma(Preprocessor &PP,
312 PragmaIntroducerKind Introducer,
313 Token &WeakTok) {
Eli Friedman99914792009-06-05 00:49:58 +0000314 // FIXME: Should we be expanding macros here? My guess is no.
315 SourceLocation WeakLoc = WeakTok.getLocation();
316
317 Token Tok;
318 PP.Lex(Tok);
319 if (Tok.isNot(tok::identifier)) {
320 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak";
321 return;
322 }
323
324 IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0;
325 SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc;
326
327 PP.Lex(Tok);
328 if (Tok.is(tok::equal)) {
329 PP.Lex(Tok);
330 if (Tok.isNot(tok::identifier)) {
Mike Stump1eb44332009-09-09 15:08:12 +0000331 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
Eli Friedman99914792009-06-05 00:49:58 +0000332 << "weak";
333 return;
334 }
335 AliasName = Tok.getIdentifierInfo();
336 AliasNameLoc = Tok.getLocation();
337 PP.Lex(Tok);
338 }
339
340 if (Tok.isNot(tok::eom)) {
341 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak";
342 return;
343 }
344
345 if (AliasName) {
346 Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc,
347 AliasNameLoc);
348 } else {
349 Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc);
350 }
351}