ParsePragma.cpp revision f315fa81eef1977b3457fd7a7d4639e060fe7278
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.Lex(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.Lex(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.Lex(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.Lex(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.Lex(Tok); 77 if (Tok.isNot(tok::eom)) { 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 } 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::eom)) { 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 'align' '=' {'native','natural','mac68k','power','reset'} 181// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} 182static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, 183 bool IsOptions) { 184 Token Tok; 185 186 if (IsOptions) { 187 PP.Lex(Tok); 188 if (Tok.isNot(tok::identifier) || 189 !Tok.getIdentifierInfo()->isStr("align")) { 190 PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); 191 return; 192 } 193 } 194 195 PP.Lex(Tok); 196 if (Tok.isNot(tok::equal)) { 197 PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal) 198 << IsOptions; 199 return; 200 } 201 202 PP.Lex(Tok); 203 if (Tok.isNot(tok::identifier)) { 204 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) 205 << (IsOptions ? "options" : "align"); 206 return; 207 } 208 209 Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural; 210 const IdentifierInfo *II = Tok.getIdentifierInfo(); 211 if (II->isStr("native")) 212 Kind = Sema::POAK_Native; 213 else if (II->isStr("natural")) 214 Kind = Sema::POAK_Natural; 215 else if (II->isStr("packed")) 216 Kind = Sema::POAK_Packed; 217 else if (II->isStr("power")) 218 Kind = Sema::POAK_Power; 219 else if (II->isStr("mac68k")) 220 Kind = Sema::POAK_Mac68k; 221 else if (II->isStr("reset")) 222 Kind = Sema::POAK_Reset; 223 else { 224 PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option) 225 << IsOptions; 226 return; 227 } 228 229 SourceLocation KindLoc = Tok.getLocation(); 230 PP.Lex(Tok); 231 if (Tok.isNot(tok::eom)) { 232 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) 233 << (IsOptions ? "options" : "align"); 234 return; 235 } 236 237 Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc); 238} 239 240void PragmaAlignHandler::HandlePragma(Preprocessor &PP, 241 PragmaIntroducerKind Introducer, 242 Token &AlignTok) { 243 ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false); 244} 245 246void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, 247 PragmaIntroducerKind Introducer, 248 Token &OptionsTok) { 249 ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true); 250} 251 252// #pragma unused(identifier) 253void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, 254 PragmaIntroducerKind Introducer, 255 Token &UnusedTok) { 256 // FIXME: Should we be expanding macros here? My guess is no. 257 SourceLocation UnusedLoc = UnusedTok.getLocation(); 258 259 // Lex the left '('. 260 Token Tok; 261 PP.Lex(Tok); 262 if (Tok.isNot(tok::l_paren)) { 263 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused"; 264 return; 265 } 266 SourceLocation LParenLoc = Tok.getLocation(); 267 268 // Lex the declaration reference(s). 269 llvm::SmallVector<Token, 5> Identifiers; 270 SourceLocation RParenLoc; 271 bool LexID = true; 272 273 while (true) { 274 PP.Lex(Tok); 275 276 if (LexID) { 277 if (Tok.is(tok::identifier)) { 278 Identifiers.push_back(Tok); 279 LexID = false; 280 continue; 281 } 282 283 // Illegal token! 284 PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var); 285 return; 286 } 287 288 // We are execting a ')' or a ','. 289 if (Tok.is(tok::comma)) { 290 LexID = true; 291 continue; 292 } 293 294 if (Tok.is(tok::r_paren)) { 295 RParenLoc = Tok.getLocation(); 296 break; 297 } 298 299 // Illegal token! 300 PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc); 301 return; 302 } 303 304 PP.Lex(Tok); 305 if (Tok.isNot(tok::eom)) { 306 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << 307 "unused"; 308 return; 309 } 310 311 // Verify that we have a location for the right parenthesis. 312 assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'"); 313 assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments"); 314 315 // For each identifier token, insert into the token stream a 316 // annot_pragma_unused token followed by the identifier token. 317 // This allows us to cache a "#pragma unused" that occurs inside an inline 318 // C++ member function. 319 320 Token *Toks = new Token[2*Identifiers.size()]; 321 for (unsigned i=0; i != Identifiers.size(); i++) { 322 Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1]; 323 pragmaUnusedTok.startToken(); 324 pragmaUnusedTok.setKind(tok::annot_pragma_unused); 325 pragmaUnusedTok.setLocation(UnusedLoc); 326 idTok = Identifiers[i]; 327 } 328 PP.EnterTokenStream(Toks, 2*Identifiers.size(), /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); 329} 330 331// #pragma weak identifier 332// #pragma weak identifier '=' identifier 333void PragmaWeakHandler::HandlePragma(Preprocessor &PP, 334 PragmaIntroducerKind Introducer, 335 Token &WeakTok) { 336 // FIXME: Should we be expanding macros here? My guess is no. 337 SourceLocation WeakLoc = WeakTok.getLocation(); 338 339 Token Tok; 340 PP.Lex(Tok); 341 if (Tok.isNot(tok::identifier)) { 342 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; 343 return; 344 } 345 346 IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0; 347 SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc; 348 349 PP.Lex(Tok); 350 if (Tok.is(tok::equal)) { 351 PP.Lex(Tok); 352 if (Tok.isNot(tok::identifier)) { 353 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) 354 << "weak"; 355 return; 356 } 357 AliasName = Tok.getIdentifierInfo(); 358 AliasNameLoc = Tok.getLocation(); 359 PP.Lex(Tok); 360 } 361 362 if (Tok.isNot(tok::eom)) { 363 PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; 364 return; 365 } 366 367 if (AliasName) { 368 Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc, 369 AliasNameLoc); 370 } else { 371 Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc); 372 } 373} 374 375void 376PragmaFPContractHandler::HandlePragma(Preprocessor &PP, 377 PragmaIntroducerKind Introducer, 378 Token &Tok) { 379 tok::OnOffSwitch OOS; 380 if (PP.LexOnOffSwitch(OOS)) 381 return; 382 383 Actions.ActOnPragmaFPContract(OOS); 384} 385 386void 387PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, 388 PragmaIntroducerKind Introducer, 389 Token &Tok) { 390 PP.Lex(Tok); 391 if (Tok.isNot(tok::identifier)) { 392 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << 393 "OPENCL"; 394 return; 395 } 396 IdentifierInfo *ename = Tok.getIdentifierInfo(); 397 SourceLocation NameLoc = Tok.getLocation(); 398 399 PP.Lex(Tok); 400 if (Tok.isNot(tok::colon)) { 401 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << ename; 402 return; 403 } 404 405 PP.Lex(Tok); 406 if (Tok.isNot(tok::identifier)) { 407 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); 408 return; 409 } 410 IdentifierInfo *op = Tok.getIdentifierInfo(); 411 412 unsigned state; 413 if (op->isStr("enable")) { 414 state = 1; 415 } else if (op->isStr("disable")) { 416 state = 0; 417 } else { 418 PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); 419 return; 420 } 421 422 OpenCLOptions &f = Actions.getOpenCLOptions(); 423 if (ename->isStr("all")) { 424#define OPENCLEXT(nm) f.nm = state; 425#include "clang/Basic/OpenCLExtensions.def" 426 } 427#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } 428#include "clang/Basic/OpenCLExtensions.def" 429 else { 430 PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; 431 return; 432 } 433} 434 435