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