]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / clang / lib / Sema / TargetAttributesSema.cpp
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
21 using namespace clang;
22
23 TargetAttributesSema::~TargetAttributesSema() {}
24 bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
25                                     const AttributeList &Attr, Sema &S) const {
26   return false;
27 }
28
29 static 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
58 namespace {
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
73 static 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
105 namespace {
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
120 static 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
152 DLLImportAttr *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
175 static 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
208 DLLExportAttr *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
222 static 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
252 namespace {
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
280 static 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
297 static 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
315 namespace {
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
333 const 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 }