blob: c468869e5b48c2f2775e85a7004dbc82aea0cfce [file] [log] [blame]
//===--- ParsePragma.cpp - Language specific pragma parsing ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the language specific #pragma handlers.
//
//===----------------------------------------------------------------------===//
#include "ParsePragma.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Action.h"
using namespace clang;
// #pragma GCC visibility comes in two variants:
// 'push' '(' [visibility] ')'
// 'pop'
void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Token &VisTok) {
SourceLocation VisLoc = VisTok.getLocation();
Token Tok;
PP.Lex(Tok);
const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
bool IsPush;
const IdentifierInfo *VisType;
if (PushPop && PushPop->isStr("pop")) {
IsPush = false;
VisType = 0;
} else if (PushPop && PushPop->isStr("push")) {
IsPush = true;
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen)
<< "visibility";
return;
}
PP.Lex(Tok);
VisType = Tok.getIdentifierInfo();
if (!VisType) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "visibility";
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen)
<< "visibility";
return;
}
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "visibility";
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eom)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "visibility";
return;
}
Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc);
}
// #pragma pack(...) comes in the following delicious flavors:
// pack '(' [integer] ')'
// pack '(' 'show' ')'
// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
SourceLocation PackLoc = PackTok.getLocation();
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack";
return;
}
Action::PragmaPackKind Kind = Action::PPK_Default;
IdentifierInfo *Name = 0;
Action::OwningExprResult Alignment(Actions);
SourceLocation LParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Tok);
if (Alignment.isInvalid())
return;
PP.Lex(Tok);
} else if (Tok.is(tok::identifier)) {
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("show")) {
Kind = Action::PPK_Show;
PP.Lex(Tok);
} else {
if (II->isStr("push")) {
Kind = Action::PPK_Push;
} else if (II->isStr("pop")) {
Kind = Action::PPK_Pop;
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action);
return;
}
PP.Lex(Tok);
if (Tok.is(tok::comma)) {
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Tok);
if (Alignment.isInvalid())
return;
PP.Lex(Tok);
} else if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
PP.Lex(Tok);
if (Tok.is(tok::comma)) {
PP.Lex(Tok);
if (Tok.isNot(tok::numeric_constant)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
return;
}
Alignment = Actions.ActOnNumericConstant(Tok);
if (Alignment.isInvalid())
return;
PP.Lex(Tok);
}
} else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed);
return;
}
}
}
}
if (Tok.isNot(tok::r_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack";
return;
}
SourceLocation RParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eom)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
return;
}
Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
LParenLoc, RParenLoc);
}
// #pragma 'align' '=' {'native','natural','mac68k','power','reset'}
// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'}
static void ParseAlignPragma(Action &Actions, Preprocessor &PP, Token &FirstTok,
bool IsOptions) {
Token Tok;
if (IsOptions) {
PP.Lex(Tok);
if (Tok.isNot(tok::identifier) ||
!Tok.getIdentifierInfo()->isStr("align")) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
return;
}
}
PP.Lex(Tok);
if (Tok.isNot(tok::equal)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal)
<< IsOptions;
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< (IsOptions ? "options" : "align");
return;
}
Action::PragmaOptionsAlignKind Kind = Action::POAK_Natural;
const IdentifierInfo *II = Tok.getIdentifierInfo();
if (II->isStr("native"))
Kind = Action::POAK_Native;
else if (II->isStr("natural"))
Kind = Action::POAK_Natural;
else if (II->isStr("packed"))
Kind = Action::POAK_Packed;
else if (II->isStr("power"))
Kind = Action::POAK_Power;
else if (II->isStr("mac68k"))
Kind = Action::POAK_Mac68k;
else if (II->isStr("reset"))
Kind = Action::POAK_Reset;
else {
PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option)
<< IsOptions;
return;
}
SourceLocation KindLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.isNot(tok::eom)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< (IsOptions ? "options" : "align");
return;
}
Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc);
}
void PragmaAlignHandler::HandlePragma(Preprocessor &PP, Token &AlignTok) {
ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false);
}
void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) {
ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true);
}
// #pragma unused(identifier)
void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
// FIXME: Should we be expanding macros here? My guess is no.
SourceLocation UnusedLoc = UnusedTok.getLocation();
// Lex the left '('.
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::l_paren)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused";
return;
}
SourceLocation LParenLoc = Tok.getLocation();
// Lex the declaration reference(s).
llvm::SmallVector<Token, 5> Identifiers;
SourceLocation RParenLoc;
bool LexID = true;
while (true) {
PP.Lex(Tok);
if (LexID) {
if (Tok.is(tok::identifier)) {
Identifiers.push_back(Tok);
LexID = false;
continue;
}
// Illegal token!
PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var);
return;
}
// We are execting a ')' or a ','.
if (Tok.is(tok::comma)) {
LexID = true;
continue;
}
if (Tok.is(tok::r_paren)) {
RParenLoc = Tok.getLocation();
break;
}
// Illegal token!
PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc);
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eom)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) <<
"unused";
return;
}
// Verify that we have a location for the right parenthesis.
assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'");
assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments");
// Perform the action to handle the pragma.
Actions.ActOnPragmaUnused(Identifiers.data(), Identifiers.size(),
parser.getCurScope(), UnusedLoc, LParenLoc, RParenLoc);
}
// #pragma weak identifier
// #pragma weak identifier '=' identifier
void PragmaWeakHandler::HandlePragma(Preprocessor &PP, Token &WeakTok) {
// FIXME: Should we be expanding macros here? My guess is no.
SourceLocation WeakLoc = WeakTok.getLocation();
Token Tok;
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak";
return;
}
IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0;
SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc;
PP.Lex(Tok);
if (Tok.is(tok::equal)) {
PP.Lex(Tok);
if (Tok.isNot(tok::identifier)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
<< "weak";
return;
}
AliasName = Tok.getIdentifierInfo();
AliasNameLoc = Tok.getLocation();
PP.Lex(Tok);
}
if (Tok.isNot(tok::eom)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak";
return;
}
if (AliasName) {
Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc,
AliasNameLoc);
} else {
Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc);
}
}