SemaAttr.cpp revision ff214ccaf21d9165c10c89ba0a63659969a8cdbb
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"
18#include "clang/Basic/TargetInfo.h"
19#include "clang/Lex/Preprocessor.h"
20using namespace clang;
21
22//===----------------------------------------------------------------------===//
23// Pragma 'pack' and 'options align'
24//===----------------------------------------------------------------------===//
25
26namespace {
27  struct PackStackEntry {
28    unsigned Alignment;
29    IdentifierInfo *Name;
30  };
31
32  /// PragmaPackStack - Simple class to wrap the stack used by #pragma
33  /// pack.
34  class PragmaPackStack {
35    typedef std::vector<PackStackEntry> stack_ty;
36
37    /// Alignment - The current user specified alignment.
38    unsigned Alignment;
39
40    /// Stack - Entries in the #pragma pack stack, consisting of saved
41    /// alignments and optional names.
42    stack_ty Stack;
43
44  public:
45    PragmaPackStack() : Alignment(0) {}
46
47    void setAlignment(unsigned A) { Alignment = A; }
48    unsigned getAlignment() { return Alignment; }
49
50    /// push - Push the current alignment onto the stack, optionally
51    /// using the given \arg Name for the record, if non-zero.
52    void push(IdentifierInfo *Name) {
53      PackStackEntry PSE = { Alignment, Name };
54      Stack.push_back(PSE);
55    }
56
57    /// pop - Pop a record from the stack and restore the current
58    /// alignment to the previous value. If \arg Name is non-zero then
59    /// the first such named record is popped, otherwise the top record
60    /// is popped. Returns true if the pop succeeded.
61    bool pop(IdentifierInfo *Name);
62  };
63}  // end anonymous namespace.
64
65bool PragmaPackStack::pop(IdentifierInfo *Name) {
66  if (Stack.empty())
67    return false;
68
69  // If name is empty just pop top.
70  if (!Name) {
71    Alignment = Stack.back().Alignment;
72    Stack.pop_back();
73    return true;
74  }
75
76  // Otherwise, find the named record.
77  for (unsigned i = Stack.size(); i != 0; ) {
78    --i;
79    if (Stack[i].Name == Name) {
80      // Found it, pop up to and including this record.
81      Alignment = Stack[i].Alignment;
82      Stack.erase(Stack.begin() + i, Stack.end());
83      return true;
84    }
85  }
86
87  return false;
88}
89
90
91/// FreePackedContext - Deallocate and null out PackContext.
92void Sema::FreePackedContext() {
93  delete static_cast<PragmaPackStack*>(PackContext);
94  PackContext = 0;
95}
96
97void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
98  // If there is no pack context, we don't need any attributes.
99  if (!PackContext)
100    return;
101
102  PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext);
103
104  // Otherwise, check to see if we need a max field alignment attribute.
105  if (unsigned Alignment = Stack->getAlignment())
106    RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8));
107}
108
109void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
110                                   SourceLocation PragmaLoc,
111                                   SourceLocation KindLoc) {
112  if (PackContext == 0)
113    PackContext = new PragmaPackStack();
114
115  PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
116
117  // Reset just pops the top of the stack.
118  if (Kind == Action::POAK_Reset) {
119    // Do the pop.
120    if (!Context->pop(0)) {
121      // If a name was specified then failure indicates the name
122      // wasn't found. Otherwise failure indicates the stack was
123      // empty.
124      Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
125        << "stack empty";
126    }
127    return;
128  }
129
130  // We don't support #pragma options align=power.
131  switch (Kind) {
132  case POAK_Natural:
133    Context->push(0);
134    Context->setAlignment(0);
135    break;
136
137  case POAK_Mac68k:
138    // Check if the target supports this.
139    if (!PP.getTargetInfo().hasAlignMac68kSupport()) {
140      Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
141      return;
142    } else {
143      // Otherwise, just warn about it for now.
144      Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
145        << KindLoc;
146    }
147    break;
148
149  default:
150    Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
151      << KindLoc;
152    break;
153  }
154}
155
156void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
157                           ExprTy *alignment, SourceLocation PragmaLoc,
158                           SourceLocation LParenLoc, SourceLocation RParenLoc) {
159  Expr *Alignment = static_cast<Expr *>(alignment);
160
161  // If specified then alignment must be a "small" power of two.
162  unsigned AlignmentVal = 0;
163  if (Alignment) {
164    llvm::APSInt Val;
165
166    // pack(0) is like pack(), which just works out since that is what
167    // we use 0 for in PackAttr.
168    if (Alignment->isTypeDependent() ||
169        Alignment->isValueDependent() ||
170        !Alignment->isIntegerConstantExpr(Val, Context) ||
171        !(Val == 0 || Val.isPowerOf2()) ||
172        Val.getZExtValue() > 16) {
173      Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment);
174      Alignment->Destroy(Context);
175      return; // Ignore
176    }
177
178    AlignmentVal = (unsigned) Val.getZExtValue();
179  }
180
181  if (PackContext == 0)
182    PackContext = new PragmaPackStack();
183
184  PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
185
186  switch (Kind) {
187  case Action::PPK_Default: // pack([n])
188    Context->setAlignment(AlignmentVal);
189    break;
190
191  case Action::PPK_Show: // pack(show)
192    // Show the current alignment, making sure to show the right value
193    // for the default.
194    AlignmentVal = Context->getAlignment();
195    // FIXME: This should come from the target.
196    if (AlignmentVal == 0)
197      AlignmentVal = 8;
198    Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
199    break;
200
201  case Action::PPK_Push: // pack(push [, id] [, [n])
202    Context->push(Name);
203    // Set the new alignment if specified.
204    if (Alignment)
205      Context->setAlignment(AlignmentVal);
206    break;
207
208  case Action::PPK_Pop: // pack(pop [, id] [,  n])
209    // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
210    // "#pragma pack(pop, identifier, n) is undefined"
211    if (Alignment && Name)
212      Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
213
214    // Do the pop.
215    if (!Context->pop(Name)) {
216      // If a name was specified then failure indicates the name
217      // wasn't found. Otherwise failure indicates the stack was
218      // empty.
219      Diag(PragmaLoc, diag::warn_pragma_pack_pop_failed)
220        << (Name ? "no record matching name" : "stack empty");
221
222      // FIXME: Warn about popping named records as MSVC does.
223    } else {
224      // Pop succeeded, set the new alignment if specified.
225      if (Alignment)
226        Context->setAlignment(AlignmentVal);
227    }
228    break;
229
230  default:
231    assert(0 && "Invalid #pragma pack kind.");
232  }
233}
234
235void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers,
236                             Scope *curScope,
237                             SourceLocation PragmaLoc,
238                             SourceLocation LParenLoc,
239                             SourceLocation RParenLoc) {
240
241  for (unsigned i = 0; i < NumIdentifiers; ++i) {
242    const Token &Tok = Identifiers[i];
243    IdentifierInfo *Name = Tok.getIdentifierInfo();
244    LookupResult Lookup(*this, Name, Tok.getLocation(), LookupOrdinaryName);
245    LookupParsedName(Lookup, curScope, NULL, true);
246
247    if (Lookup.empty()) {
248      Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var)
249        << Name << SourceRange(Tok.getLocation());
250      continue;
251    }
252
253    VarDecl *VD = Lookup.getAsSingle<VarDecl>();
254    if (!VD || !VD->hasLocalStorage()) {
255      Diag(PragmaLoc, diag::warn_pragma_unused_expected_localvar)
256        << Name << SourceRange(Tok.getLocation());
257      continue;
258    }
259
260    VD->addAttr(::new (Context) UnusedAttr());
261  }
262}
263