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