|  | //===--- 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); | 
|  | } | 
|  | } |