Home | History | Annotate | Download | only in Parse
      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