From: Daniel Dunbar Date: Tue, 14 Oct 2008 05:35:18 +0000 (+0000) Subject: Add Sema implementation of #pragma pack stack. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4cde927072a70f3156d72c6431e7a5d95bf62366;p=clang Add Sema implementation of #pragma pack stack. - 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 --- diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 691f83e1b9..9cae8efaf2 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -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 diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 80ce2ccd0e..2113417753 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6ad65e5ba3..313b9aa701 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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 > 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. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6ee4ae17ec..fee732f2f5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(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 index 0000000000..2906e2b422 --- /dev/null +++ b/test/Sema/pragma-pack.c @@ -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)