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