ParsePragma.cpp revision 193326
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  // FIXME: Should we be expanding macros here? My guess is no.
27  SourceLocation PackLoc = PackTok.getLocation();
28
29  Token Tok;
30  PP.Lex(Tok);
31  if (Tok.isNot(tok::l_paren)) {
32    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
33    return;
34  }
35
36  Action::PragmaPackKind Kind = Action::PPK_Default;
37  IdentifierInfo *Name = 0;
38  Action::OwningExprResult Alignment(Actions);
39  SourceLocation LParenLoc = Tok.getLocation();
40  PP.Lex(Tok);
41  if (Tok.is(tok::numeric_constant)) {
42    Alignment = Actions.ActOnNumericConstant(Tok);
43    if (Alignment.isInvalid())
44      return;
45
46    PP.Lex(Tok);
47  } else if (Tok.is(tok::identifier)) {
48    const IdentifierInfo *II = Tok.getIdentifierInfo();
49    if (II->isStr("show")) {
50      Kind = Action::PPK_Show;
51      PP.Lex(Tok);
52    } else {
53      if (II->isStr("push")) {
54        Kind = Action::PPK_Push;
55      } else if (II->isStr("pop")) {
56        Kind = Action::PPK_Pop;
57      } else {
58        PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
59        return;
60      }
61      PP.Lex(Tok);
62
63      if (Tok.is(tok::comma)) {
64        PP.Lex(Tok);
65
66        if (Tok.is(tok::numeric_constant)) {
67          Alignment = Actions.ActOnNumericConstant(Tok);
68          if (Alignment.isInvalid())
69            return;
70
71          PP.Lex(Tok);
72        } else if (Tok.is(tok::identifier)) {
73          Name = Tok.getIdentifierInfo();
74          PP.Lex(Tok);
75
76          if (Tok.is(tok::comma)) {
77            PP.Lex(Tok);
78
79            if (Tok.isNot(tok::numeric_constant)) {
80              PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
81              return;
82            }
83
84            Alignment = Actions.ActOnNumericConstant(Tok);
85            if (Alignment.isInvalid())
86              return;
87
88            PP.Lex(Tok);
89          }
90        } else {
91          PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
92          return;
93        }
94      }
95    }
96  }
97
98  if (Tok.isNot(tok::r_paren)) {
99    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
100    return;
101  }
102
103  SourceLocation RParenLoc = Tok.getLocation();
104  Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
105                          LParenLoc, RParenLoc);
106}
107
108// #pragma unused(identifier)
109void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
110  // FIXME: Should we be expanding macros here? My guess is no.
111  SourceLocation UnusedLoc = UnusedTok.getLocation();
112
113  // Lex the left '('.
114  Token Tok;
115  PP.Lex(Tok);
116  if (Tok.isNot(tok::l_paren)) {
117    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
118    return;
119  }
120  SourceLocation LParenLoc = Tok.getLocation();
121
122  // Lex the declaration reference(s).
123  llvm::SmallVector<Action::ExprTy*, 5> Ex;
124  SourceLocation RParenLoc;
125  bool LexID = true;
126
127  while (true) {
128    PP.Lex(Tok);
129
130    if (LexID) {
131      if (Tok.is(tok::identifier)) {
132        Action::OwningExprResult Name =
133          Actions.ActOnIdentifierExpr(parser.CurScope, Tok.getLocation(),
134                                      *Tok.getIdentifierInfo(), false);
135
136        if (Name.isInvalid()) {
137          if (!Ex.empty())
138            Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
139          return;
140        }
141
142        Ex.push_back(Name.release());
143        LexID = false;
144        continue;
145      }
146
147      // Illegal token! Release the parsed expressions (if any) and emit
148      // a warning.
149      if (!Ex.empty())
150        Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
151
152      PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
153      return;
154    }
155
156    // We are execting a ')' or a ','.
157    if (Tok.is(tok::comma)) {
158      LexID = true;
159      continue;
160    }
161
162    if (Tok.is(tok::r_paren)) {
163      RParenLoc = Tok.getLocation();
164      break;
165    }
166
167    // Illegal token! Release the parsed expressions (if any) and emit
168    // a warning.
169    if (!Ex.empty())
170      Action::MultiExprArg Release(Actions, &Ex[0], Ex.size());
171
172    PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
173    return;
174  }
175
176  // Verify that we have a location for the right parenthesis.
177  assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
178  assert(!Ex.empty() && "Valid '#pragma unused' must have arguments");
179
180  // Perform the action to handle the pragma.
181  Actions.ActOnPragmaUnused(&Ex[0], Ex.size(), UnusedLoc, LParenLoc, RParenLoc);
182}
183