TargetAttributesSema.cpp revision 768d6cae40ad4ff3aed5483269d068ff7a45e229
1//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
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 contains semantic analysis implementation for target-specific
11// attributes.
12//
13//===----------------------------------------------------------------------===//
14
15#include "TargetAttributesSema.h"
16#include "clang/Sema/SemaInternal.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/AST/DeclCXX.h"
19#include "llvm/ADT/Triple.h"
20
21using namespace clang;
22
23TargetAttributesSema::~TargetAttributesSema() {}
24bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
25                                    const AttributeList &Attr, Sema &S) const {
26  return false;
27}
28
29static void HandleMSP430InterruptAttr(Decl *d,
30                                      const AttributeList &Attr, Sema &S) {
31    // Check the attribute arguments.
32    if (Attr.getNumArgs() != 1) {
33      S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
34      return;
35    }
36
37    // FIXME: Check for decl - it should be void ()(void).
38
39    Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
40    llvm::APSInt NumParams(32);
41    if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
42      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
43        << "interrupt" << NumParamsExpr->getSourceRange();
44      return;
45    }
46
47    unsigned Num = NumParams.getLimitedValue(255);
48    if ((Num & 1) || Num > 30) {
49      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
50        << "interrupt" << (int)NumParams.getSExtValue()
51        << NumParamsExpr->getSourceRange();
52      return;
53    }
54
55    d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
56    d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
57  }
58
59namespace {
60  class MSP430AttributesSema : public TargetAttributesSema {
61  public:
62    MSP430AttributesSema() { }
63    bool ProcessDeclAttribute(Scope *scope, Decl *D,
64                              const AttributeList &Attr, Sema &S) const {
65      if (Attr.getName()->getName() == "interrupt") {
66        HandleMSP430InterruptAttr(D, Attr, S);
67        return true;
68      }
69      return false;
70    }
71  };
72}
73
74static void HandleMBlazeInterruptHandlerAttr(Decl *d, const AttributeList &Attr,
75                                             Sema &S) {
76  // Check the attribute arguments.
77  if (Attr.getNumArgs() != 0) {
78    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
79    return;
80  }
81
82  // FIXME: Check for decl - it should be void ()(void).
83
84  d->addAttr(::new (S.Context) MBlazeInterruptHandlerAttr(Attr.getLoc(),
85                                                          S.Context));
86  d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
87}
88
89static void HandleMBlazeSaveVolatilesAttr(Decl *d, const AttributeList &Attr,
90                                          Sema &S) {
91  // Check the attribute arguments.
92  if (Attr.getNumArgs() != 0) {
93    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
94    return;
95  }
96
97  // FIXME: Check for decl - it should be void ()(void).
98
99  d->addAttr(::new (S.Context) MBlazeSaveVolatilesAttr(Attr.getLoc(),
100                                                       S.Context));
101  d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
102}
103
104
105namespace {
106  class MBlazeAttributesSema : public TargetAttributesSema {
107  public:
108    MBlazeAttributesSema() { }
109    bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
110                              Sema &S) const {
111      if (Attr.getName()->getName() == "interrupt_handler") {
112        HandleMBlazeInterruptHandlerAttr(D, Attr, S);
113        return true;
114      } else if (Attr.getName()->getName() == "save_volatiles") {
115        HandleMBlazeSaveVolatilesAttr(D, Attr, S);
116        return true;
117      }
118      return false;
119    }
120  };
121}
122
123static void HandleX86ForceAlignArgPointerAttr(Decl *D,
124                                              const AttributeList& Attr,
125                                              Sema &S) {
126  // Check the attribute arguments.
127  if (Attr.getNumArgs() != 0) {
128    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
129    return;
130  }
131
132  // If we try to apply it to a function pointer, don't warn, but don't
133  // do anything, either. It doesn't matter anyway, because there's nothing
134  // special about calling a force_align_arg_pointer function.
135  ValueDecl *VD = dyn_cast<ValueDecl>(D);
136  if (VD && VD->getType()->isFunctionPointerType())
137    return;
138  // Also don't warn on function pointer typedefs.
139  TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
140  if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
141             TD->getUnderlyingType()->isFunctionType()))
142    return;
143  // Attribute can only be applied to function types.
144  if (!isa<FunctionDecl>(D)) {
145    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
146      << Attr.getName() << /* function */0;
147    return;
148  }
149
150  D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
151                                                           S.Context));
152}
153
154static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
155  // check the attribute arguments.
156  if (Attr.getNumArgs() != 0) {
157    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
158    return;
159  }
160
161  // Attribute can be applied only to functions or variables.
162  if (isa<VarDecl>(D)) {
163    D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context));
164    return;
165  }
166
167  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
168  if (!FD) {
169    // Apparently Visual C++ thinks it is okay to not emit a warning
170    // in this case, so only emit a warning when -fms-extensions is not
171    // specified.
172    if (!S.getLangOptions().Microsoft)
173      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
174        << Attr.getName() << 2 /*variable and function*/;
175    return;
176  }
177
178  // Currently, the dllimport attribute is ignored for inlined functions.
179  // Warning is emitted.
180  if (FD->isInlineSpecified()) {
181    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
182    return;
183  }
184
185  // The attribute is also overridden by a subsequent declaration as dllexport.
186  // Warning is emitted.
187  for (AttributeList *nextAttr = Attr.getNext(); nextAttr;
188       nextAttr = nextAttr->getNext()) {
189    if (nextAttr->getKind() == AttributeList::AT_dllexport) {
190      S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
191      return;
192    }
193  }
194
195  if (D->getAttr<DLLExportAttr>()) {
196    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
197    return;
198  }
199
200  D->addAttr(::new (S.Context) DLLImportAttr(Attr.getLoc(), S.Context));
201}
202
203static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
204  // check the attribute arguments.
205  if (Attr.getNumArgs() != 0) {
206    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
207    return;
208  }
209
210  // Attribute can be applied only to functions or variables.
211  if (isa<VarDecl>(D)) {
212    D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context));
213    return;
214  }
215
216  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
217  if (!FD) {
218    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
219      << Attr.getName() << 2 /*variable and function*/;
220    return;
221  }
222
223  // Currently, the dllexport attribute is ignored for inlined functions, unless
224  // the -fkeep-inline-functions flag has been used. Warning is emitted;
225  if (FD->isInlineSpecified()) {
226    // FIXME: ... unless the -fkeep-inline-functions flag has been used.
227    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
228    return;
229  }
230
231  D->addAttr(::new (S.Context) DLLExportAttr(Attr.getLoc(), S.Context));
232}
233
234namespace {
235  class X86AttributesSema : public TargetAttributesSema {
236  public:
237    X86AttributesSema() { }
238    bool ProcessDeclAttribute(Scope *scope, Decl *D,
239                              const AttributeList &Attr, Sema &S) const {
240      const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple());
241      if (Triple.getOS() == llvm::Triple::Win32 ||
242          Triple.getOS() == llvm::Triple::MinGW32) {
243        switch (Attr.getKind()) {
244        case AttributeList::AT_dllimport: HandleDLLImportAttr(D, Attr, S);
245                                          return true;
246        case AttributeList::AT_dllexport: HandleDLLExportAttr(D, Attr, S);
247                                          return true;
248        default:                          break;
249        }
250      }
251      if (Attr.getName()->getName() == "force_align_arg_pointer" ||
252          Attr.getName()->getName() == "__force_align_arg_pointer__") {
253        HandleX86ForceAlignArgPointerAttr(D, Attr, S);
254        return true;
255      }
256      return false;
257    }
258  };
259}
260
261const TargetAttributesSema &Sema::getTargetAttributesSema() const {
262  if (TheTargetAttributesSema)
263    return *TheTargetAttributesSema;
264
265  const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
266  switch (Triple.getArch()) {
267  default:
268    return *(TheTargetAttributesSema = new TargetAttributesSema);
269
270  case llvm::Triple::msp430:
271    return *(TheTargetAttributesSema = new MSP430AttributesSema);
272  case llvm::Triple::mblaze:
273    return *(TheTargetAttributesSema = new MBlazeAttributesSema);
274  case llvm::Triple::x86:
275    return *(TheTargetAttributesSema = new X86AttributesSema);
276  }
277}
278