SemaAttr.cpp revision 25cf760b54d3b88633827501013bc51a29b28aba
1//===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements semantic analysis for non-trivial attributes and
11// pragmas.
12//
13//===----------------------------------------------------------------------===//
14
15#include "Sema.h"
16#include "clang/AST/Expr.h"
17using namespace clang;
18
19//===----------------------------------------------------------------------===//
20// Pragma Packed
21//===----------------------------------------------------------------------===//
22
23namespace {
24  /// PragmaPackStack - Simple class to wrap the stack used by #pragma
25  /// pack.
26  class PragmaPackStack {
27    typedef std::vector< std::pair<unsigned, IdentifierInfo*> > stack_ty;
28
29    /// Alignment - The current user specified alignment.
30    unsigned Alignment;
31
32    /// Stack - Entries in the #pragma pack stack, consisting of saved
33    /// alignments and optional names.
34    stack_ty Stack;
35
36  public:
37    PragmaPackStack() : Alignment(0) {}
38
39    void setAlignment(unsigned A) { Alignment = A; }
40    unsigned getAlignment() { return Alignment; }
41
42    /// push - Push the current alignment onto the stack, optionally
43    /// using the given \arg Name for the record, if non-zero.
44    void push(IdentifierInfo *Name) {
45      Stack.push_back(std::make_pair(Alignment, Name));
46    }
47
48    /// pop - Pop a record from the stack and restore the current
49    /// alignment to the previous value. If \arg Name is non-zero then
50    /// the first such named record is popped, otherwise the top record
51    /// is popped. Returns true if the pop succeeded.
52    bool pop(IdentifierInfo *Name);
53  };
54}  // end anonymous namespace.
55
56bool PragmaPackStack::pop(IdentifierInfo *Name) {
57  if (Stack.empty())
58    return false;
59
60  // If name is empty just pop top.
61  if (!Name) {
62    Alignment = Stack.back().first;
63    Stack.pop_back();
64    return true;
65  }
66
67  // Otherwise, find the named record.
68  for (unsigned i = Stack.size(); i != 0; ) {
69    --i;
70    if (Stack[i].second == Name) {
71      // Found it, pop up to and including this record.
72      Alignment = Stack[i].first;
73      Stack.erase(Stack.begin() + i, Stack.end());
74      return true;
75    }
76  }
77
78  return false;
79}
80
81
82/// FreePackedContext - Deallocate and null out PackContext.
83void Sema::FreePackedContext() {
84  delete static_cast<PragmaPackStack*>(PackContext);
85  PackContext = 0;
86}
87
88/// getPragmaPackAlignment() - Return the current alignment as specified by
89/// the current #pragma pack directive, or 0 if none is currently active.
90unsigned Sema::getPragmaPackAlignment() const {
91  if (PackContext)
92    return static_cast<PragmaPackStack*>(PackContext)->getAlignment();
93  return 0;
94}
95
96void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
97                           ExprTy *alignment, SourceLocation PragmaLoc,
98                           SourceLocation LParenLoc, SourceLocation RParenLoc) {
99  Expr *Alignment = static_cast<Expr *>(alignment);
100
101  // If specified then alignment must be a "small" power of two.
102  unsigned AlignmentVal = 0;
103  if (Alignment) {
104    llvm::APSInt Val;
105
106    // pack(0) is like pack(), which just works out since that is what
107    // we use 0 for in PackAttr.
108    if (!Alignment->isIntegerConstantExpr(Val, Context) ||
109        !(Val == 0 || Val.isPowerOf2()) ||
110        Val.getZExtValue() > 16) {
111      Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
112      Alignment->Destroy(Context);
113      return; // Ignore
114    }
115
116    AlignmentVal = (unsigned) Val.getZExtValue();
117  }
118
119  if (PackContext == 0)
120    PackContext = new PragmaPackStack();
121
122  PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
123
124  switch (Kind) {
125  case Action::PPK_Default: // pack([n])
126    Context->setAlignment(AlignmentVal);
127    break;
128
129  case Action::PPK_Show: // pack(show)
130    // Show the current alignment, making sure to show the right value
131    // for the default.
132    AlignmentVal = Context->getAlignment();
133    // FIXME: This should come from the target.
134    if (AlignmentVal == 0)
135      AlignmentVal = 8;
136    Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
137    break;
138
139  case Action::PPK_Push: // pack(push [, id] [, [n])
140    Context->push(Name);
141    // Set the new alignment if specified.
142    if (Alignment)
143      Context->setAlignment(AlignmentVal);
144    break;
145
146  case Action::PPK_Pop: // pack(pop [, id] [,  n])
147    // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
148    // "#pragma pack(pop, identifier, n) is undefined"
149    if (Alignment && Name)
150      Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
151
152    // Do the pop.
153    if (!Context->pop(Name)) {
154      // If a name was specified then failure indicates the name
155      // wasn't found. Otherwise failure indicates the stack was
156      // empty.
157      Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed)
158        << (Name ? "no record matching name" : "stack empty");
159
160      // FIXME: Warn about popping named records as MSVC does.
161    } else {
162      // Pop succeeded, set the new alignment if specified.
163      if (Alignment)
164        Context->setAlignment(AlignmentVal);
165    }
166    break;
167
168  default:
169    assert(0 && "Invalid #pragma pack kind.");
170  }
171}
172
173void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
174                             Scope *curScope,
175                             SourceLocation PragmaLoc,
176                             SourceLocation LParenLoc,
177                             SourceLocation RParenLoc) {
178
179  for (unsigned i = 0; i < NumIdentifiers; ++i) {
180    const Token &Tok = Identifiers[i];
181    IdentifierInfo *Name = Tok.getIdentifierInfo();
182    const LookupResult &Lookup = LookupParsedName(curScope, NULL, Name,
183                                                  LookupOrdinaryName,
184                                                  false, true,
185                                                  Tok.getLocation());
186    // FIXME: Handle Lookup.isAmbiguous?
187
188    NamedDecl *ND = Lookup.getAsDecl();
189
190    if (!ND) {
191      Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
192        << Name << SourceRange(Tok.getLocation());
193      continue;
194    }
195
196    if (!isa<VarDecl>(ND) || !cast<VarDecl>(ND)->hasLocalStorage()) {
197      Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar)
198        << Name << SourceRange(Tok.getLocation());
199      continue;
200    }
201
202    ND->addAttr(::new (Context) UnusedAttr());
203  }
204}
205