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