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