TargetAttributesSema.cpp revision 263508
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 HandleARMInterruptAttr(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_too_many_arguments)
34        << 1;
35    return;
36  }
37
38  StringRef Str;
39  SourceLocation ArgLoc;
40
41  if (Attr.getNumArgs() == 0)
42    Str = "";
43  else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
44    return;
45
46  ARMInterruptAttr::InterruptType Kind;
47  if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
48    S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
49        << Attr.getName() << Str << ArgLoc;
50    return;
51  }
52
53  unsigned Index = Attr.getAttributeSpellingListIndex();
54  d->addAttr(::new (S.Context)
55             ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index));
56}
57
58namespace {
59  class ARMAttributesSema : public TargetAttributesSema {
60  public:
61    ARMAttributesSema() { }
62    bool ProcessDeclAttribute(Scope *scope, Decl *D,
63                              const AttributeList &Attr, Sema &S) const {
64      if (Attr.getName()->getName() == "interrupt") {
65        HandleARMInterruptAttr(D, Attr, S);
66        return true;
67      }
68      return false;
69    }
70  };
71}
72
73static void HandleMSP430InterruptAttr(Decl *d,
74                                      const AttributeList &Attr, Sema &S) {
75    // Check the attribute arguments.
76    if (Attr.getNumArgs() != 1) {
77      S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
78        << Attr.getName() << 1;
79      return;
80    }
81
82    // FIXME: Check for decl - it should be void ()(void).
83
84    Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
85    llvm::APSInt NumParams(32);
86    if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
87      S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
88        << Attr.getName() << AANT_ArgumentIntegerConstant
89        << NumParamsExpr->getSourceRange();
90      return;
91    }
92
93    unsigned Num = NumParams.getLimitedValue(255);
94    if ((Num & 1) || Num > 30) {
95      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
96        << "interrupt" << (int)NumParams.getSExtValue()
97        << NumParamsExpr->getSourceRange();
98      return;
99    }
100
101    d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
102    d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
103  }
104
105namespace {
106  class MSP430AttributesSema : public TargetAttributesSema {
107  public:
108    MSP430AttributesSema() { }
109    bool ProcessDeclAttribute(Scope *scope, Decl *D,
110                              const AttributeList &Attr, Sema &S) const {
111      if (Attr.getName()->getName() == "interrupt") {
112        HandleMSP430InterruptAttr(D, Attr, S);
113        return true;
114      }
115      return false;
116    }
117  };
118}
119
120static void HandleX86ForceAlignArgPointerAttr(Decl *D,
121                                              const AttributeList& Attr,
122                                              Sema &S) {
123  // Check the attribute arguments.
124  if (Attr.getNumArgs() != 0) {
125    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
126      << Attr.getName() << 0;
127    return;
128  }
129
130  // If we try to apply it to a function pointer, don't warn, but don't
131  // do anything, either. It doesn't matter anyway, because there's nothing
132  // special about calling a force_align_arg_pointer function.
133  ValueDecl *VD = dyn_cast<ValueDecl>(D);
134  if (VD && VD->getType()->isFunctionPointerType())
135    return;
136  // Also don't warn on function pointer typedefs.
137  TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
138  if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
139             TD->getUnderlyingType()->isFunctionType()))
140    return;
141  // Attribute can only be applied to function types.
142  if (!isa<FunctionDecl>(D)) {
143    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
144      << Attr.getName() << /* function */0;
145    return;
146  }
147
148  D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
149                                                           S.Context));
150}
151
152DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
153                                        unsigned AttrSpellingListIndex) {
154  if (D->hasAttr<DLLExportAttr>()) {
155    Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
156    return NULL;
157  }
158
159  if (D->hasAttr<DLLImportAttr>())
160    return NULL;
161
162  if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
163    if (VD->hasDefinition()) {
164      // dllimport cannot be applied to definitions.
165      Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition)
166        << "dllimport";
167      return NULL;
168    }
169  }
170
171  return ::new (Context) DLLImportAttr(Range, Context,
172                                       AttrSpellingListIndex);
173}
174
175static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
176  // check the attribute arguments.
177  if (Attr.getNumArgs() != 0) {
178    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
179      << Attr.getName() << 0;
180    return;
181  }
182
183  // Attribute can be applied only to functions or variables.
184  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
185  if (!FD && !isa<VarDecl>(D)) {
186    // Apparently Visual C++ thinks it is okay to not emit a warning
187    // in this case, so only emit a warning when -fms-extensions is not
188    // specified.
189    if (!S.getLangOpts().MicrosoftExt)
190      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
191        << Attr.getName() << 2 /*variable and function*/;
192    return;
193  }
194
195  // Currently, the dllimport attribute is ignored for inlined functions.
196  // Warning is emitted.
197  if (FD && FD->isInlineSpecified()) {
198    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
199    return;
200  }
201
202  unsigned Index = Attr.getAttributeSpellingListIndex();
203  DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
204  if (NewAttr)
205    D->addAttr(NewAttr);
206}
207
208DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
209                                        unsigned AttrSpellingListIndex) {
210  if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
211    Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
212    D->dropAttr<DLLImportAttr>();
213  }
214
215  if (D->hasAttr<DLLExportAttr>())
216    return NULL;
217
218  return ::new (Context) DLLExportAttr(Range, Context,
219                                       AttrSpellingListIndex);
220}
221
222static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
223  // check the attribute arguments.
224  if (Attr.getNumArgs() != 0) {
225    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
226      << Attr.getName() << 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.getNumArgs()) {
283    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
284      << Attr.getName() << 0;
285    return;
286  }
287  // Attribute can only be applied to function types.
288  if (!isa<FunctionDecl>(D)) {
289    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
290      << Attr.getName() << /* function */0;
291    return;
292  }
293  D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context,
294                                          Attr.getAttributeSpellingListIndex()));
295}
296
297static void HandleNoMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
298  // check the attribute arguments.
299  if (Attr.getNumArgs()) {
300    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
301      << Attr.getName() << 0;
302    return;
303  }
304  // Attribute can only be applied to function types.
305  if (!isa<FunctionDecl>(D)) {
306    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
307      << Attr.getName() << /* function */0;
308    return;
309  }
310  D->addAttr(::new (S.Context)
311             NoMips16Attr(Attr.getRange(), S.Context,
312                          Attr.getAttributeSpellingListIndex()));
313}
314
315namespace {
316  class MipsAttributesSema : public TargetAttributesSema {
317  public:
318    MipsAttributesSema() { }
319    bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
320                              Sema &S) const {
321      if (Attr.getName()->getName() == "mips16") {
322        HandleMips16Attr(D, Attr, S);
323        return true;
324      } else if (Attr.getName()->getName() == "nomips16") {
325        HandleNoMips16Attr(D, Attr, S);
326        return true;
327      }
328      return false;
329    }
330  };
331}
332
333const TargetAttributesSema &Sema::getTargetAttributesSema() const {
334  if (TheTargetAttributesSema)
335    return *TheTargetAttributesSema;
336
337  const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
338  switch (Triple.getArch()) {
339  case llvm::Triple::arm:
340  case llvm::Triple::thumb:
341    return *(TheTargetAttributesSema = new ARMAttributesSema);
342  case llvm::Triple::msp430:
343    return *(TheTargetAttributesSema = new MSP430AttributesSema);
344  case llvm::Triple::x86:
345  case llvm::Triple::x86_64:
346    return *(TheTargetAttributesSema = new X86AttributesSema);
347  case llvm::Triple::mips:
348  case llvm::Triple::mipsel:
349    return *(TheTargetAttributesSema = new MipsAttributesSema);
350  default:
351    return *(TheTargetAttributesSema = new TargetAttributesSema);
352  }
353}
354