diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 1e9580c3ce11..584682f4fbde 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -556,6 +556,20 @@ DIAG(err_expected_lparen_after_type, ERROR, DIAG(err_expected_equal_after_declarator, ERROR, "expected '=' after declarator") +// Language specific pragmas + +// #pragma pack +DIAG(warn_pragma_pack_expected_lparen, WARNING, + "missing '(' after '#pragma pack' - ignoring") +DIAG(warn_pragma_pack_expected_rparen, WARNING, + "missing ')' after '#pragma pack' - ignoring") +DIAG(warn_pragma_pack_invalid_action, WARNING, + "unknown action for '#pragma pack' - ignored") +DIAG(warn_pragma_pack_invalid_constant, WARNING, + "invalid constant for '#pragma pack', expected %0 - ignored") +DIAG(warn_pragma_pack_malformed, WARNING, + "malformed '#pragma pack', expected '#pragma pack(%0 [, id] [, n])' - ignored") + //===----------------------------------------------------------------------===// // Semantic Analysis //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 99f8b46622bd..dc15ec2f7608 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -857,6 +857,25 @@ public: SourceLocation RParenLoc) { return 0; } + + //===---------------------------- Pragmas -------------------------------===// + + enum PragmaPackKind { + PPK_Default, // #pragma pack([n]) + PPK_Show, // #pragma pack(show), only supported by MSVC. + PPK_Push, // #pragma pack(push, [identifier], [n]) + PPK_Pop // #pragma pack(pop, [identifier], [n]) + }; + + /// ActOnPragmaPack - Called on well formed #pragma pack(...). + virtual void ActOnPragmaPack(PragmaPackKind Kind, + IdentifierInfo *Name, + ExprTy *Alignment, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return; + } }; /// MinimalAction - Minimal actions are used by light-weight clients of the diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index eb508d723441..561359b2c085 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -19,11 +19,12 @@ #include namespace clang { + class AttributeList; class DeclSpec; - class ObjCDeclSpec; class Declarator; class FieldDeclarator; - class AttributeList; + class ObjCDeclSpec; + class PragmaHandler; class Scope; /// Parser - This implements a parser for the C family of languages. After @@ -56,6 +57,8 @@ class Parser { /// comparison. IdentifierInfo *Ident_super; + PragmaHandler *PackHandler; + public: Parser(Preprocessor &PP, Action &Actions); ~Parser(); diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp new file mode 100644 index 000000000000..fbdb123bdabe --- /dev/null +++ b/clang/lib/Parse/ParsePragma.cpp @@ -0,0 +1,108 @@ +//===--- 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/Basic/Diagnostic.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/Action.h" +using namespace clang; + +// #pragma pack(...) comes in the following delicious flavors: +// pack '(' [integer] ')' +// pack '(' 'show' ')' +// pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' +void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { + // FIXME: Should we be expanding macros here? My guess is no. + SourceLocation PackLoc = PackTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_expected_lparen); + return; + } + + Action::PragmaPackKind Kind = Action::PPK_Default; + IdentifierInfo *Name = 0; + Action::ExprResult Alignment; + 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 == &PP.getIdentifierTable().get("show")) { + Kind = Action::PPK_Show; + PP.Lex(Tok); + } else { + if (II == &PP.getIdentifierTable().get("push")) { + Kind = Action::PPK_Push; + } else if (II == &PP.getIdentifierTable().get("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, + II->getName()); + return; + } + + Alignment = Actions.ActOnNumericConstant(Tok); + if (Alignment.isInvalid) + return; + + PP.Lex(Tok); + } + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed, + II->getName()); + return; + } + } + } + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_expected_rparen); + return; + } + + SourceLocation RParenLoc = Tok.getLocation(); + Actions.ActOnPragmaPack(Kind, Name, Alignment.Val, PackLoc, + LParenLoc, RParenLoc); +} + diff --git a/clang/lib/Parse/ParsePragma.h b/clang/lib/Parse/ParsePragma.h new file mode 100644 index 000000000000..8a9ae5765ba6 --- /dev/null +++ b/clang/lib/Parse/ParsePragma.h @@ -0,0 +1,33 @@ +//===---- ParserPragmas.h - Language specific pragmas -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines #pragma handlers for language specific pragmas. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_PARSEPRAGMA_H +#define LLVM_CLANG_PARSE_PARSEPRAGMA_H + +#include "clang/Lex/Pragma.h" + +namespace clang { + class Action; + +class PragmaPackHandler : public PragmaHandler { + Action &Actions; +public: + PragmaPackHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); +}; + +} // end namespace clang + +#endif diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 797de9284ecc..800be8dd0139 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" +#include "ParsePragma.h" using namespace clang; Parser::Parser(Preprocessor &pp, Action &actions) @@ -24,6 +25,13 @@ Parser::Parser(Preprocessor &pp, Action &actions) NumCachedScopes = 0; ParenCount = BracketCount = BraceCount = 0; ObjCImpDecl = 0; + + // Add #pragma handlers. These are removed and destroyed in the + // destructor. + PackHandler = + new PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions); + PP.AddPragmaHandler(0, PackHandler); + // Instantiate a LexedMethodsForTopClass for all the non-nested classes. PushTopClassStack(); } @@ -233,6 +241,10 @@ Parser::~Parser() { // Free the scope cache. for (unsigned i = 0, e = NumCachedScopes; i != e; ++i) delete ScopeCache[i]; + + // Remove the pragma handlers we installed. + PP.RemovePragmaHandler(0, PackHandler); + delete PackHandler; } /// Initialize - Warm up the parser. diff --git a/clang/test/Parser/pragma-pack.c b/clang/test/Parser/pragma-pack.c new file mode 100644 index 000000000000..79474f001bc3 --- /dev/null +++ b/clang/test/Parser/pragma-pack.c @@ -0,0 +1,30 @@ +// RUN: clang -fsyntax-only -verify %s +// XFAIL + +#pragma pack 10 // expected-warning {{missing '(' after '#pragma pack'}} +#pragma pack() +#pragma pack(8) + +#pragma pack(hello) // expected-warning {{unknown action for '#pragma pack'}} +#pragma pack(push) +#pragma pack(pop) + +#pragma pack(push,) // expected-warning {{malformed '#pragma pack', expected '#pragma pack(push}} +#pragma pack(push,) // expected-warning {{malformed '#pragma pack', expected '#pragma pack(push}} +#pragma pack(pop,) // expected-warning {{malformed '#pragma pack', expected '#pragma pack(pop}} + +#pragma pack(push,i) +#pragma pack(push,i, // expected-warning {{malformed '#pragma pack', expected}} +#pragma pack(push,i,) // expected-warning {{malformed '#pragma pack', expected}} + +#pragma pack(push,8) +#pragma pack(push,8, // expected-warning {{malformed '#pragma pack', expected}} +#pragma pack(push,8,help) // expected-warning {{malformed '#pragma pack', expected}} +#pragma pack(push,8,) // expected-warning {{missing ')' after '#pragma pack'}} +#pragma pack(push,i,8 // expected-warning {{missing ')' after '#pragma pack'}} +#pragma pack(push,i,8) + +#pragma pack(push // expected-warning {{missing ')' after '#pragma pack'}} + +_Pragma("pack(push)") +_Pragma("pack(push,)") // expected-warning {{malformed '#pragma pack', expected '#pragma pack(push}}