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