TargetAttributesSema.cpp revision 9f939f75c64770c746d78579f75a49f9c657e426
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)
34        << Attr.getName() << 1;
35      return;
36    }
37
38    // FIXME: Check for decl - it should be void ()(void).
39
40    Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
41    llvm::APSInt NumParams(32);
42    if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
43      S.Diag(Attr.getLoc(), diag::err_attribute_argument_type)
44        << Attr.getName() << AANT_ArgumentIntegerConstant
45        << NumParamsExpr->getSourceRange();
46      return;
47    }
48
49    unsigned Num = NumParams.getLimitedValue(255);
50    if ((Num & 1) || Num > 30) {
51      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
52        << "interrupt" << (int)NumParams.getSExtValue()
53        << NumParamsExpr->getSourceRange();
54      return;
55    }
56
57    d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
58    d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
59  }
60
61namespace {
62  class MSP430AttributesSema : public TargetAttributesSema {
63  public:
64    MSP430AttributesSema() { }
65    bool ProcessDeclAttribute(Scope *scope, Decl *D,
66                              const AttributeList &Attr, Sema &S) const {
67      if (Attr.getName()->getName() == "interrupt") {
68        HandleMSP430InterruptAttr(D, Attr, S);
69        return true;
70      }
71      return false;
72    }
73  };
74}
75
76static void HandleX86ForceAlignArgPointerAttr(Decl *D,
77                                              const AttributeList& Attr,
78                                              Sema &S) {
79  // Check the attribute arguments.
80  if (Attr.getNumArgs() != 0) {
81    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
82      << Attr.getName() << 0;
83    return;
84  }
85
86  // If we try to apply it to a function pointer, don't warn, but don't
87  // do anything, either. It doesn't matter anyway, because there's nothing
88  // special about calling a force_align_arg_pointer function.
89  ValueDecl *VD = dyn_cast<ValueDecl>(D);
90  if (VD && VD->getType()->isFunctionPointerType())
91    return;
92  // Also don't warn on function pointer typedefs.
93  TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
94  if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
95             TD->getUnderlyingType()->isFunctionType()))
96    return;
97  // Attribute can only be applied to function types.
98  if (!isa<FunctionDecl>(D)) {
99    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
100      << Attr.getName() << /* function */0;
101    return;
102  }
103
104  D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
105                                                           S.Context));
106}
107
108DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
109                                        unsigned AttrSpellingListIndex) {
110  if (D->hasAttr<DLLExportAttr>()) {
111    Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
112    return NULL;
113  }
114
115  if (D->hasAttr<DLLImportAttr>())
116    return NULL;
117
118  if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
119    if (VD->hasDefinition()) {
120      // dllimport cannot be applied to definitions.
121      Diag(D->getLocation(), diag::warn_attribute_invalid_on_definition)
122        << "dllimport";
123      return NULL;
124    }
125  }
126
127  return ::new (Context) DLLImportAttr(Range, Context,
128                                       AttrSpellingListIndex);
129}
130
131static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
132  // check the attribute arguments.
133  if (Attr.getNumArgs() != 0) {
134    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
135      << Attr.getName() << 0;
136    return;
137  }
138
139  // Attribute can be applied only to functions or variables.
140  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
141  if (!FD && !isa<VarDecl>(D)) {
142    // Apparently Visual C++ thinks it is okay to not emit a warning
143    // in this case, so only emit a warning when -fms-extensions is not
144    // specified.
145    if (!S.getLangOpts().MicrosoftExt)
146      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
147        << Attr.getName() << 2 /*variable and function*/;
148    return;
149  }
150
151  // Currently, the dllimport attribute is ignored for inlined functions.
152  // Warning is emitted.
153  if (FD && FD->isInlineSpecified()) {
154    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
155    return;
156  }
157
158  unsigned Index = Attr.getAttributeSpellingListIndex();
159  DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
160  if (NewAttr)
161    D->addAttr(NewAttr);
162}
163
164DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
165                                        unsigned AttrSpellingListIndex) {
166  if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
167    Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
168    D->dropAttr<DLLImportAttr>();
169  }
170
171  if (D->hasAttr<DLLExportAttr>())
172    return NULL;
173
174  return ::new (Context) DLLExportAttr(Range, Context,
175                                       AttrSpellingListIndex);
176}
177
178static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
179  // check the attribute arguments.
180  if (Attr.getNumArgs() != 0) {
181    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
182      << Attr.getName() << 0;
183    return;
184  }
185
186  // Attribute can be applied only to functions or variables.
187  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
188  if (!FD && !isa<VarDecl>(D)) {
189    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
190      << Attr.getName() << 2 /*variable and function*/;
191    return;
192  }
193
194  // Currently, the dllexport attribute is ignored for inlined functions, unless
195  // the -fkeep-inline-functions flag has been used. Warning is emitted;
196  if (FD && FD->isInlineSpecified()) {
197    // FIXME: ... unless the -fkeep-inline-functions flag has been used.
198    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
199    return;
200  }
201
202  unsigned Index = Attr.getAttributeSpellingListIndex();
203  DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
204  if (NewAttr)
205    D->addAttr(NewAttr);
206}
207
208namespace {
209  class X86AttributesSema : public TargetAttributesSema {
210  public:
211    X86AttributesSema() { }
212    bool ProcessDeclAttribute(Scope *scope, Decl *D,
213                              const AttributeList &Attr, Sema &S) const {
214      const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple());
215      if (Triple.getOS() == llvm::Triple::Win32 ||
216          Triple.getOS() == llvm::Triple::MinGW32) {
217        switch (Attr.getKind()) {
218        case AttributeList::AT_DLLImport: HandleDLLImportAttr(D, Attr, S);
219                                          return true;
220        case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S);
221                                          return true;
222        default:                          break;
223        }
224      }
225      if (Triple.getArch() != llvm::Triple::x86_64 &&
226          (Attr.getName()->getName() == "force_align_arg_pointer" ||
227           Attr.getName()->getName() == "__force_align_arg_pointer__")) {
228        HandleX86ForceAlignArgPointerAttr(D, Attr, S);
229        return true;
230      }
231      return false;
232    }
233  };
234}
235
236static void HandleMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
237  // check the attribute arguments.
238  if (Attr.hasParameterOrArguments()) {
239    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
240      << Attr.getName() << 0;
241    return;
242  }
243  // Attribute can only be applied to function types.
244  if (!isa<FunctionDecl>(D)) {
245    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
246      << Attr.getName() << /* function */0;
247    return;
248  }
249  D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context,
250                                          Attr.getAttributeSpellingListIndex()));
251}
252
253static void HandleNoMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
254  // check the attribute arguments.
255  if (Attr.hasParameterOrArguments()) {
256    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments)
257      << Attr.getName() << 0;
258    return;
259  }
260  // Attribute can only be applied to function types.
261  if (!isa<FunctionDecl>(D)) {
262    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
263      << Attr.getName() << /* function */0;
264    return;
265  }
266  D->addAttr(::new (S.Context)
267             NoMips16Attr(Attr.getRange(), S.Context,
268                          Attr.getAttributeSpellingListIndex()));
269}
270
271namespace {
272  class MipsAttributesSema : public TargetAttributesSema {
273  public:
274    MipsAttributesSema() { }
275    bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
276                              Sema &S) const {
277      if (Attr.getName()->getName() == "mips16") {
278        HandleMips16Attr(D, Attr, S);
279        return true;
280      } else if (Attr.getName()->getName() == "nomips16") {
281        HandleNoMips16Attr(D, Attr, S);
282        return true;
283      }
284      return false;
285    }
286  };
287}
288
289const TargetAttributesSema &Sema::getTargetAttributesSema() const {
290  if (TheTargetAttributesSema)
291    return *TheTargetAttributesSema;
292
293  const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
294  switch (Triple.getArch()) {
295  case llvm::Triple::msp430:
296    return *(TheTargetAttributesSema = new MSP430AttributesSema);
297  case llvm::Triple::x86:
298  case llvm::Triple::x86_64:
299    return *(TheTargetAttributesSema = new X86AttributesSema);
300  case llvm::Triple::mips:
301  case llvm::Triple::mipsel:
302    return *(TheTargetAttributesSema = new MipsAttributesSema);
303  default:
304    return *(TheTargetAttributesSema = new TargetAttributesSema);
305  }
306}
307