TargetAttributesSema.cpp revision beba3e80378f38f3d1e1ef030dacdd438373d3d5
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/AST/DeclCXX.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Sema/SemaInternal.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
154DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
155                                        unsigned AttrSpellingListIndex) {
156  if (D->hasAttr<DLLExportAttr>()) {
157    Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
158    return NULL;
159  }
160
161  if (D->hasAttr<DLLImportAttr>())
162    return NULL;
163
164  if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
165    if (VD->hasDefinition()) {
166      // dllimport cannot be applied to definitions.
167      Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition)
168        << "dllimport";
169      return NULL;
170    }
171  }
172
173  return ::new (Context) DLLImportAttr(Range, Context,
174                                       AttrSpellingListIndex);
175}
176
177static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
178  // check the attribute arguments.
179  if (Attr.getNumArgs() != 0) {
180    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
181    return;
182  }
183
184  // Attribute can be applied only to functions or variables.
185  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
186  if (!FD && !isa<VarDecl>(D)) {
187    // Apparently Visual C++ thinks it is okay to not emit a warning
188    // in this case, so only emit a warning when -fms-extensions is not
189    // specified.
190    if (!S.getLangOpts().MicrosoftExt)
191      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
192        << Attr.getName() << 2 /*variable and function*/;
193    return;
194  }
195
196  // Currently, the dllimport attribute is ignored for inlined functions.
197  // Warning is emitted.
198  if (FD && FD->isInlineSpecified()) {
199    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
200    return;
201  }
202
203  unsigned Index = Attr.getAttributeSpellingListIndex();
204  DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
205  if (NewAttr)
206    D->addAttr(NewAttr);
207}
208
209DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
210                                        unsigned AttrSpellingListIndex) {
211  if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
212    Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
213    D->dropAttr<DLLImportAttr>();
214  }
215
216  if (D->hasAttr<DLLExportAttr>())
217    return NULL;
218
219  return ::new (Context) DLLExportAttr(Range, Context,
220                                       AttrSpellingListIndex);
221}
222
223static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
224  // check the attribute arguments.
225  if (Attr.getNumArgs() != 0) {
226    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
227    return;
228  }
229
230  // Attribute can be applied only to functions or variables.
231  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
232  if (!FD && !isa<VarDecl>(D)) {
233    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
234      << Attr.getName() << 2 /*variable and function*/;
235    return;
236  }
237
238  // Currently, the dllexport attribute is ignored for inlined functions, unless
239  // the -fkeep-inline-functions flag has been used. Warning is emitted;
240  if (FD && FD->isInlineSpecified()) {
241    // FIXME: ... unless the -fkeep-inline-functions flag has been used.
242    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
243    return;
244  }
245
246  unsigned Index = Attr.getAttributeSpellingListIndex();
247  DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
248  if (NewAttr)
249    D->addAttr(NewAttr);
250}
251
252namespace {
253  class X86AttributesSema : public TargetAttributesSema {
254  public:
255    X86AttributesSema() { }
256    bool ProcessDeclAttribute(Scope *scope, Decl *D,
257                              const AttributeList &Attr, Sema &S) const {
258      const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple());
259      if (Triple.getOS() == llvm::Triple::Win32 ||
260          Triple.getOS() == llvm::Triple::MinGW32) {
261        switch (Attr.getKind()) {
262        case AttributeList::AT_DLLImport: HandleDLLImportAttr(D, Attr, S);
263                                          return true;
264        case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S);
265                                          return true;
266        default:                          break;
267        }
268      }
269      if (Triple.getArch() != llvm::Triple::x86_64 &&
270          (Attr.getName()->getName() == "force_align_arg_pointer" ||
271           Attr.getName()->getName() == "__force_align_arg_pointer__")) {
272        HandleX86ForceAlignArgPointerAttr(D, Attr, S);
273        return true;
274      }
275      return false;
276    }
277  };
278}
279
280static void HandleMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
281  // check the attribute arguments.
282  if (Attr.hasParameterOrArguments()) {
283    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
284    return;
285  }
286  // Attribute can only be applied to function types.
287  if (!isa<FunctionDecl>(D)) {
288    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
289      << Attr.getName() << /* function */0;
290    return;
291  }
292  D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context,
293                                          Attr.getAttributeSpellingListIndex()));
294}
295
296static void HandleNoMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
297  // check the attribute arguments.
298  if (Attr.hasParameterOrArguments()) {
299    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
300    return;
301  }
302  // Attribute can only be applied to function types.
303  if (!isa<FunctionDecl>(D)) {
304    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
305      << Attr.getName() << /* function */0;
306    return;
307  }
308  D->addAttr(::new (S.Context)
309             NoMips16Attr(Attr.getRange(), S.Context,
310                          Attr.getAttributeSpellingListIndex()));
311}
312
313namespace {
314  class MipsAttributesSema : public TargetAttributesSema {
315  public:
316    MipsAttributesSema() { }
317    bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
318                              Sema &S) const {
319      if (Attr.getName()->getName() == "mips16") {
320        HandleMips16Attr(D, Attr, S);
321        return true;
322      } else if (Attr.getName()->getName() == "nomips16") {
323        HandleNoMips16Attr(D, Attr, S);
324        return true;
325      }
326      return false;
327    }
328  };
329}
330
331const TargetAttributesSema &Sema::getTargetAttributesSema() const {
332  if (TheTargetAttributesSema)
333    return *TheTargetAttributesSema;
334
335  const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
336  switch (Triple.getArch()) {
337  case llvm::Triple::msp430:
338    return *(TheTargetAttributesSema = new MSP430AttributesSema);
339  case llvm::Triple::mblaze:
340    return *(TheTargetAttributesSema = new MBlazeAttributesSema);
341  case llvm::Triple::x86:
342  case llvm::Triple::x86_64:
343    return *(TheTargetAttributesSema = new X86AttributesSema);
344  case llvm::Triple::mips:
345  case llvm::Triple::mipsel:
346    return *(TheTargetAttributesSema = new MipsAttributesSema);
347  default:
348    return *(TheTargetAttributesSema = new TargetAttributesSema);
349  }
350}
351