]> granicus.if.org Git - clang/commitdiff
Add Sema implementation of #pragma pack stack.
authorDaniel Dunbar <daniel@zuster.org>
Tue, 14 Oct 2008 05:35:18 +0000 (05:35 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Tue, 14 Oct 2008 05:35:18 +0000 (05:35 +0000)
 - Follows the MSVC (original) implementation, including support of
   pack(show) (useful for testing).
 - Implements support for named pack records which gcc seems to
   ignore (or implements incorrectly).
 - Not currently wired to anything, only functionality change is the
   type checking of the pragma.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57476 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticKinds.def
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
test/Sema/pragma-pack.c [new file with mode: 0644]

index 691f83e1b97bdd4251bdebc19fd9297ba9ceb271..9cae8efaf2837b7237a27e6e689bd1e78bcd5291 100644 (file)
@@ -571,6 +571,16 @@ 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")
+// 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
index 80ce2ccd0ef440c553594fe7e215b53cfef97ce8..2113417753782767ad56712d72672ef0a9d14fb2 100644 (file)
@@ -82,7 +82,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
 
 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.  
index 6ad65e5ba3ab1ba6850abfa4eecf6d7aebc8506d..313b9aa7016af18c4edfde4c307935c7239d741f 100644 (file)
@@ -66,6 +66,37 @@ namespace clang {
   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:
@@ -80,6 +111,10 @@ 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.
@@ -809,6 +844,15 @@ public:
     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.
index 6ee4ae17ec5720c780d46b0d7a56be3440c409d0..fee732f2f56ca10e8fe14fc202d738a1a8d94c7e 100644 (file)
@@ -25,6 +25,7 @@
 #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) {
@@ -2559,3 +2560,97 @@ Sema::DeclTy* Sema::ActOnLinkageSpec(SourceLocation Loc,
   // 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;
+}
diff --git a/test/Sema/pragma-pack.c b/test/Sema/pragma-pack.c
new file mode 100644 (file)
index 0000000..2906e2b
--- /dev/null
@@ -0,0 +1,22 @@
+// 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)