diff options
author | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2009-06-02 17:58:47 +0000 |
commit | f27e5a09a0d815b8a4814152954ff87dadfdefc0 (patch) | |
tree | ce7d964cbb5e39695b71481698f10cb099c23d4a /lib/Sema/SemaAttr.cpp | |
download | FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.zip FreeBSD-src-f27e5a09a0d815b8a4814152954ff87dadfdefc0.tar.gz |
Import Clang, at r72732.
Diffstat (limited to 'lib/Sema/SemaAttr.cpp')
-rw-r--r-- | lib/Sema/SemaAttr.cpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp new file mode 100644 index 0000000..1bf8444 --- /dev/null +++ b/lib/Sema/SemaAttr.cpp @@ -0,0 +1,211 @@ +//===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for non-trivial attributes and +// pragmas. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "clang/AST/Expr.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Pragma Packed +//===----------------------------------------------------------------------===// + +namespace { + /// PragmaPackStack - Simple class to wrap the stack used by #pragma + /// pack. + class PragmaPackStack { + typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty; + + /// Alignment - The current user specified alignment. + unsigned Alignment; + + /// Stack - Entries in the #pragma pack stack, consisting of saved + /// alignments and optional names. + stack_ty Stack; + + public: + PragmaPackStack() : Alignment(0) {} + + 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, Name)); + } + + /// 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); + }; +} // end anonymous namespace. + +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 (Stack[i].second == Name) { + // Found it, pop up to and including this record. + Alignment = Stack[i].first; + Stack.erase(Stack.begin() + i, Stack.end()); + return true; + } + } + + return false; +} + + +/// FreePackedContext - Deallocate and null out PackContext. +void Sema::FreePackedContext() { + delete static_cast<PragmaPackStack*>(PackContext); + PackContext = 0; +} + +/// getPragmaPackAlignment() - Return the current alignment as specified by +/// the current #pragma pack directive, or 0 if none is currently active. +unsigned Sema::getPragmaPackAlignment() const { + if (PackContext) + return static_cast<PragmaPackStack*>(PackContext)->getAlignment(); + return 0; +} + +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; + + // pack(0) is like pack(), which just works out since that is what + // we use 0 for in PackAttr. + if (!Alignment->isIntegerConstantExpr(Val, Context) || + !(Val == 0 || Val.isPowerOf2()) || + Val.getZExtValue() > 16) { + Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment); + Alignment->Destroy(Context); + return; // Ignore + } + + AlignmentVal = (unsigned) Val.getZExtValue(); + } + + if (PackContext == 0) + PackContext = new PragmaPackStack(); + + PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); + + switch (Kind) { + case Action::PPK_Default: // pack([n]) + Context->setAlignment(AlignmentVal); + break; + + case Action::PPK_Show: // pack(show) + // Show the current alignment, making sure to show the right value + // for the default. + AlignmentVal = Context->getAlignment(); + // FIXME: This should come from the target. + if (AlignmentVal == 0) + AlignmentVal = 8; + Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; + break; + + case Action::PPK_Push: // pack(push [, id] [, [n]) + Context->push(Name); + // Set the new alignment if specified. + if (Alignment) + Context->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 (!Context->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) + Context->setAlignment(AlignmentVal); + } + break; + + default: + assert(0 && "Invalid #pragma pack kind."); + } +} + +void Sema::ActOnPragmaUnused(ExprTy **Exprs, unsigned NumExprs, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + + // Verify that all of the expressions are valid before + // modifying the attributes of any referenced decl. + Expr *ErrorExpr = 0; + + for (unsigned i = 0; i < NumExprs; ++i) { + Expr *Ex = (Expr*) Exprs[i]; + if (!isa<DeclRefExpr>(Ex)) { + ErrorExpr = Ex; + break; + } + + Decl *d = cast<DeclRefExpr>(Ex)->getDecl();; + + if (!isa<VarDecl>(d) || !cast<VarDecl>(d)->hasLocalStorage()) { + ErrorExpr = Ex; + break; + } + } + + // Delete the expressions if we encountered any error. + if (ErrorExpr) { + Diag(ErrorExpr->getLocStart(), diag::warn_pragma_unused_expected_localvar); + for (unsigned i = 0; i < NumExprs; ++i) + ((Expr*) Exprs[i])->Destroy(Context); + return; + } + + // Otherwise, add the 'unused' attribute to each referenced declaration. + for (unsigned i = 0; i < NumExprs; ++i) { + DeclRefExpr *DR = (DeclRefExpr*) Exprs[i]; + DR->getDecl()->addAttr(::new (Context) UnusedAttr()); + DR->Destroy(Context); + } +} |