"invalid constant for '#pragma pack', expected %0 - ignored")
DIAG(warn_pragma_pack_malformed, WARNING,
"malformed '#pragma pack', expected '#pragma pack(%0 [, id] [, n])' - ignored")
+// Follow the MSVC implementation.
+DIAG(warn_pragma_pack_show, WARNING,
+ "value of #pragma pack(show) == %0")
+// FIXME: Dehardcode.
+DIAG(warn_pragma_pack_invalid_alignment, WARNING,
+ "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'")
+DIAG(warn_pragma_pack_pop_identifer_and_alignment, WARNING,
+ "specifying both a name and alignment to pragma pack(pop, ...) is undefined")
+DIAG(warn_pragma_pack_pop_failed, WARNING,
+ "#pragma pack(pop, ...) failed: %0")
//===----------------------------------------------------------------------===//
// Semantic Analysis
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
: PP(pp), Context(ctxt), Consumer(consumer), CurContext(0), CurBlock(0),
- IdResolver(pp.getLangOptions()) {
+ PackContext(0), IdResolver(pp.getLangOptions()) {
// Get IdentifierInfo objects for known functions for which we
// do extra checking.
class ObjCPropertyDecl;
struct BlockSemaInfo;
+/// PragmaPackStack - Simple class to wrap the stack used by #pragma
+/// pack.
+class PragmaPackStack {
+ typedef std::vector< std::pair<unsigned, std::string> > stack_ty;
+
+ /// Alignment - The current user specified alignment.
+ unsigned Alignment;
+
+ /// Stack - Entries in the #pragma pack stack.
+ stack_ty Stack;
+
+public:
+ PragmaPackStack(unsigned A) : Alignment(A) {}
+
+ void setAlignment(unsigned A) { Alignment = A; }
+ unsigned getAlignment() { return Alignment; }
+
+ /// push - Push the current alignment onto the stack, optionally
+ /// using the given \arg Name for the record, if non-zero,
+ void push(IdentifierInfo *Name) {
+ Stack.push_back(std::make_pair(Alignment,
+ std::string(Name ? Name->getName() : "")));
+ }
+
+ /// pop - Pop a record from the stack and restore the current
+ /// alignment to the previous value. If \arg Name is non-zero then
+ /// the first such named record is popped, otherwise the top record
+ /// is popped. Returns true if the pop succeeded.
+ bool pop(IdentifierInfo *Name);
+};
+
/// Sema - This implements semantic analysis and AST building for C.
class Sema : public Action {
public:
/// the active block object that represents it.
BlockSemaInfo *CurBlock;
+ /// PackContext - Manages the stack for #pragma pack. An alignment
+ /// of 0 indicates default alignment.
+ PragmaPackStack PackContext;
+
/// LabelMap - This is a mapping from label identifiers to the LabelStmt for
/// it (which acts like the label decl in some ways). Forward referenced
/// labels have a LabelStmt created for them with a null location & SubStmt.
ExprTy *receiver, Selector Sel,
SourceLocation lbrac, SourceLocation rbrac,
ExprTy **ArgExprs, unsigned NumArgs);
+
+ /// ActOnPragmaPack - Called on well formed #pragma pack(...).
+ virtual void ActOnPragmaPack(PragmaPackKind Kind,
+ IdentifierInfo *Name,
+ ExprTy *Alignment,
+ SourceLocation PragmaLoc,
+ SourceLocation LParenLoc,
+ SourceLocation RParenLoc);
+
private:
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
/// cast. If there is already an implicit cast, merge into the existing one.
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) {
// FIXME: Add all the various semantics of linkage specifications
return LinkageSpecDecl::Create(Context, Loc, Language, dcl);
}
+
+void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
+ ExprTy *alignment, SourceLocation PragmaLoc,
+ SourceLocation LParenLoc, SourceLocation RParenLoc) {
+ Expr *Alignment = static_cast<Expr *>(alignment);
+
+ // If specified then alignment must be a "small" power of two.
+ unsigned AlignmentVal = 0;
+ if (Alignment) {
+ llvm::APSInt Val;
+ if (!Alignment->isIntegerConstantExpr(Val, Context) ||
+ !Val.isPowerOf2() ||
+ Val.getZExtValue() > 16) {
+ Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
+ delete Alignment;
+ return; // Ignore
+ }
+
+ AlignmentVal = (unsigned) Val.getZExtValue();
+ }
+
+ switch (Kind) {
+ case Action::PPK_Default: // pack([n])
+ PackContext.setAlignment(AlignmentVal);
+ break;
+
+ case Action::PPK_Show: // pack(show)
+ // Show the current alignment, making sure to show the right value
+ // for the default.
+ AlignmentVal = PackContext.getAlignment();
+ // FIXME: This should come from the target.
+ if (AlignmentVal == 0)
+ AlignmentVal = 8;
+ Diag(PragmaLoc, diag::warn_pragma_pack_show, llvm::utostr(AlignmentVal));
+ break;
+
+ case Action::PPK_Push: // pack(push [, id] [, [n])
+ PackContext.push(Name);
+ // Set the new alignment if specified.
+ if (Alignment)
+ PackContext.setAlignment(AlignmentVal);
+ break;
+
+ case Action::PPK_Pop: // pack(pop [, id] [, n])
+ // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
+ // "#pragma pack(pop, identifier, n) is undefined"
+ if (Alignment && Name)
+ Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
+
+ // Do the pop.
+ if (!PackContext.pop(Name)) {
+ // If a name was specified then failure indicates the name
+ // wasn't found. Otherwise failure indicates the stack was
+ // empty.
+ Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed,
+ Name ? "no record matching name" : "stack empty");
+
+ // FIXME: Warn about popping named records as MSVC does.
+ } else {
+ // Pop succeeded, set the new alignment if specified.
+ if (Alignment)
+ PackContext.setAlignment(AlignmentVal);
+ }
+ break;
+
+ default:
+ assert(0 && "Invalid #pragma pack kind.");
+ }
+}
+
+bool PragmaPackStack::pop(IdentifierInfo *Name) {
+ if (Stack.empty())
+ return false;
+
+ // If name is empty just pop top.
+ if (!Name) {
+ Alignment = Stack.back().first;
+ Stack.pop_back();
+ return true;
+ }
+
+ // Otherwise, find the named record.
+ for (unsigned i = Stack.size(); i != 0; ) {
+ --i;
+ if (strcmp(Stack[i].second.c_str(), Name->getName()) == 0) {
+ // Found it, pop up to and including this record.
+ Alignment = Stack[i].first;
+ Stack.erase(Stack.begin() + i, Stack.end());
+ return true;
+ }
+ }
+
+ return false;
+}
--- /dev/null
+// RUN: clang -m -triple i686-apple-darwin9 -fsyntax-only -verify %s
+
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+/* expected-warning {{expected #pragma pack parameter to be}} */ #pragma pack(3)
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+#pragma pack(4)
+/* expected-warning {{value of #pragma pack(show) == 4}} */ #pragma pack(show)
+#pragma pack() // resets to default
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+#pragma pack(2)
+#pragma pack(push, eek, 16) // -> (eek, 2), 16
+/* expected-warning {{value of #pragma pack(show) == 16}} */ #pragma pack(show)
+#pragma pack(push) // -> (eek, 2), (, 2), 16
+/* expected-warning {{value of #pragma pack(show) == 16}} */ #pragma pack(show)
+#pragma pack(1)
+#pragma pack(push, 8) // -> (eek, 2), (, 2), (, 1), 8
+/* expected-warning {{value of #pragma pack(show) == 8}} */ #pragma pack(show)
+#pragma pack(pop) // -> (eek, 2), (,2), 1
+/* expected-warning {{value of #pragma pack(show) == 1}} */ #pragma pack(show)
+#pragma pack(pop, eek)
+/* expected-warning {{value of #pragma pack(show) == 2}} */ #pragma pack(show)
+/* expected-warning {{#pragma pack(pop, ...) failed: stack empty}} */ #pragma pack(pop)