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