diff options
author | Daniel Dunbar <daniel@zuster.org> | 2008-10-14 05:35:18 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2008-10-14 05:35:18 +0000 |
commit | 4cde927072a70f3156d72c6431e7a5d95bf62366 (patch) | |
tree | 56004bdf53fc90d1c8466195c664220948d94454 /lib/Sema/SemaDecl.cpp | |
parent | e15fa2736413224dfdaf457e0fd7204d7c056b3d (diff) |
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
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 95 |
1 files changed, 95 insertions, 0 deletions
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<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; +} |