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