1 //===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains semantic analysis implementation for target-specific
13 //===----------------------------------------------------------------------===//
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"
21 using namespace clang;
23 TargetAttributesSema::~TargetAttributesSema() {}
24 bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
25 const AttributeList &Attr, Sema &S) const {
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)
39 SourceLocation ArgLoc;
41 if (Attr.getNumArgs() == 0)
43 else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
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;
53 unsigned Index = Attr.getAttributeSpellingListIndex();
54 d->addAttr(::new (S.Context)
55 ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index));
59 class ARMAttributesSema : public TargetAttributesSema {
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);
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;
82 // FIXME: Check for decl - it should be void ()(void).
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();
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();
101 d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
102 d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
106 class MSP430AttributesSema : public TargetAttributesSema {
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);
120 static void HandleX86ForceAlignArgPointerAttr(Decl *D,
121 const AttributeList& Attr,
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;
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())
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()))
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;
148 D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
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";
159 if (D->hasAttr<DLLImportAttr>())
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)
171 return ::new (Context) DLLImportAttr(Range, Context,
172 AttrSpellingListIndex);
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;
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
189 if (!S.getLangOpts().MicrosoftExt)
190 S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
191 << Attr.getName() << 2 /*variable and function*/;
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";
202 unsigned Index = Attr.getAttributeSpellingListIndex();
203 DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
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>();
215 if (D->hasAttr<DLLExportAttr>())
218 return ::new (Context) DLLExportAttr(Range, Context,
219 AttrSpellingListIndex);
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;
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*/;
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";
246 unsigned Index = Attr.getAttributeSpellingListIndex();
247 DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
253 class X86AttributesSema : public TargetAttributesSema {
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);
264 case AttributeList::AT_DLLExport: HandleDLLExportAttr(D, Attr, S);
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);
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;
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;
293 D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context,
294 Attr.getAttributeSpellingListIndex()));
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;
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;
310 D->addAttr(::new (S.Context)
311 NoMips16Attr(Attr.getRange(), S.Context,
312 Attr.getAttributeSpellingListIndex()));
316 class MipsAttributesSema : public TargetAttributesSema {
318 MipsAttributesSema() { }
319 bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
321 if (Attr.getName()->getName() == "mips16") {
322 HandleMips16Attr(D, Attr, S);
324 } else if (Attr.getName()->getName() == "nomips16") {
325 HandleNoMips16Attr(D, Attr, S);
333 const TargetAttributesSema &Sema::getTargetAttributesSema() const {
334 if (TheTargetAttributesSema)
335 return *TheTargetAttributesSema;
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);
351 return *(TheTargetAttributesSema = new TargetAttributesSema);