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