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