clang API Documentation

TargetAttributesSema.cpp
Go to the documentation of this file.
00001 //===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file contains semantic analysis implementation for target-specific
00011 // attributes.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "TargetAttributesSema.h"
00016 #include "clang/Sema/SemaInternal.h"
00017 #include "clang/Basic/TargetInfo.h"
00018 #include "clang/AST/DeclCXX.h"
00019 #include "llvm/ADT/Triple.h"
00020 
00021 using namespace clang;
00022 
00023 TargetAttributesSema::~TargetAttributesSema() {}
00024 bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D,
00025                                     const AttributeList &Attr, Sema &S) const {
00026   return false;
00027 }
00028 
00029 static void HandleMSP430InterruptAttr(Decl *d,
00030                                       const AttributeList &Attr, Sema &S) {
00031     // Check the attribute arguments.
00032     if (Attr.getNumArgs() != 1) {
00033       S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
00034       return;
00035     }
00036 
00037     // FIXME: Check for decl - it should be void ()(void).
00038 
00039     Expr *NumParamsExpr = static_cast<Expr *>(Attr.getArg(0));
00040     llvm::APSInt NumParams(32);
00041     if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
00042       S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
00043         << "interrupt" << NumParamsExpr->getSourceRange();
00044       return;
00045     }
00046 
00047     unsigned Num = NumParams.getLimitedValue(255);
00048     if ((Num & 1) || Num > 30) {
00049       S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
00050         << "interrupt" << (int)NumParams.getSExtValue()
00051         << NumParamsExpr->getSourceRange();
00052       return;
00053     }
00054 
00055     d->addAttr(::new (S.Context) MSP430InterruptAttr(Attr.getLoc(), S.Context, Num));
00056     d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
00057   }
00058 
00059 namespace {
00060   class MSP430AttributesSema : public TargetAttributesSema {
00061   public:
00062     MSP430AttributesSema() { }
00063     bool ProcessDeclAttribute(Scope *scope, Decl *D,
00064                               const AttributeList &Attr, Sema &S) const {
00065       if (Attr.getName()->getName() == "interrupt") {
00066         HandleMSP430InterruptAttr(D, Attr, S);
00067         return true;
00068       }
00069       return false;
00070     }
00071   };
00072 }
00073 
00074 static void HandleMBlazeInterruptHandlerAttr(Decl *d, const AttributeList &Attr,
00075                                              Sema &S) {
00076   // Check the attribute arguments.
00077   if (Attr.getNumArgs() != 0) {
00078     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
00079     return;
00080   }
00081 
00082   // FIXME: Check for decl - it should be void ()(void).
00083 
00084   d->addAttr(::new (S.Context) MBlazeInterruptHandlerAttr(Attr.getLoc(),
00085                                                           S.Context));
00086   d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
00087 }
00088 
00089 static void HandleMBlazeSaveVolatilesAttr(Decl *d, const AttributeList &Attr,
00090                                           Sema &S) {
00091   // Check the attribute arguments.
00092   if (Attr.getNumArgs() != 0) {
00093     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
00094     return;
00095   }
00096 
00097   // FIXME: Check for decl - it should be void ()(void).
00098 
00099   d->addAttr(::new (S.Context) MBlazeSaveVolatilesAttr(Attr.getLoc(),
00100                                                        S.Context));
00101   d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context));
00102 }
00103 
00104 
00105 namespace {
00106   class MBlazeAttributesSema : public TargetAttributesSema {
00107   public:
00108     MBlazeAttributesSema() { }
00109     bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
00110                               Sema &S) const {
00111       if (Attr.getName()->getName() == "interrupt_handler") {
00112         HandleMBlazeInterruptHandlerAttr(D, Attr, S);
00113         return true;
00114       } else if (Attr.getName()->getName() == "save_volatiles") {
00115         HandleMBlazeSaveVolatilesAttr(D, Attr, S);
00116         return true;
00117       }
00118       return false;
00119     }
00120   };
00121 }
00122 
00123 static void HandleX86ForceAlignArgPointerAttr(Decl *D,
00124                                               const AttributeList& Attr,
00125                                               Sema &S) {
00126   // Check the attribute arguments.
00127   if (Attr.getNumArgs() != 0) {
00128     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
00129     return;
00130   }
00131 
00132   // If we try to apply it to a function pointer, don't warn, but don't
00133   // do anything, either. It doesn't matter anyway, because there's nothing
00134   // special about calling a force_align_arg_pointer function.
00135   ValueDecl *VD = dyn_cast<ValueDecl>(D);
00136   if (VD && VD->getType()->isFunctionPointerType())
00137     return;
00138   // Also don't warn on function pointer typedefs.
00139   TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
00140   if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
00141              TD->getUnderlyingType()->isFunctionType()))
00142     return;
00143   // Attribute can only be applied to function types.
00144   if (!isa<FunctionDecl>(D)) {
00145     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
00146       << Attr.getName() << /* function */0;
00147     return;
00148   }
00149 
00150   D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(Attr.getRange(),
00151                                                            S.Context));
00152 }
00153 
00154 DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range) {
00155   if (D->hasAttr<DLLExportAttr>()) {
00156     Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
00157     return NULL;
00158   }
00159 
00160   if (D->hasAttr<DLLImportAttr>())
00161     return NULL;
00162 
00163   return ::new (Context) DLLImportAttr(Range, Context);
00164 }
00165 
00166 static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
00167   // check the attribute arguments.
00168   if (Attr.getNumArgs() != 0) {
00169     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
00170     return;
00171   }
00172 
00173   // Attribute can be applied only to functions or variables.
00174   FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
00175   if (!FD && !isa<VarDecl>(D)) {
00176     // Apparently Visual C++ thinks it is okay to not emit a warning
00177     // in this case, so only emit a warning when -fms-extensions is not
00178     // specified.
00179     if (!S.getLangOpts().MicrosoftExt)
00180       S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
00181         << Attr.getName() << 2 /*variable and function*/;
00182     return;
00183   }
00184 
00185   // Currently, the dllimport attribute is ignored for inlined functions.
00186   // Warning is emitted.
00187   if (FD && FD->isInlineSpecified()) {
00188     S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
00189     return;
00190   }
00191 
00192   DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange());
00193   if (NewAttr)
00194     D->addAttr(NewAttr);
00195 }
00196 
00197 DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range) {
00198   if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
00199     Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
00200     D->dropAttr<DLLImportAttr>();
00201   }
00202 
00203   if (D->hasAttr<DLLExportAttr>())
00204     return NULL;
00205 
00206   return ::new (Context) DLLExportAttr(Range, Context);
00207 }
00208 
00209 static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
00210   // check the attribute arguments.
00211   if (Attr.getNumArgs() != 0) {
00212     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
00213     return;
00214   }
00215 
00216   // Attribute can be applied only to functions or variables.
00217   FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
00218   if (!FD && !isa<VarDecl>(D)) {
00219     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
00220       << Attr.getName() << 2 /*variable and function*/;
00221     return;
00222   }
00223 
00224   // Currently, the dllexport attribute is ignored for inlined functions, unless
00225   // the -fkeep-inline-functions flag has been used. Warning is emitted;
00226   if (FD && FD->isInlineSpecified()) {
00227     // FIXME: ... unless the -fkeep-inline-functions flag has been used.
00228     S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllexport";
00229     return;
00230   }
00231 
00232   DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange());
00233   if (NewAttr)
00234     D->addAttr(NewAttr);
00235 }
00236 
00237 namespace {
00238   class X86AttributesSema : public TargetAttributesSema {
00239   public:
00240     X86AttributesSema() { }
00241     bool ProcessDeclAttribute(Scope *scope, Decl *D,
00242                               const AttributeList &Attr, Sema &S) const {
00243       const llvm::Triple &Triple(S.Context.getTargetInfo().getTriple());
00244       if (Triple.getOS() == llvm::Triple::Win32 ||
00245           Triple.getOS() == llvm::Triple::MinGW32) {
00246         switch (Attr.getKind()) {
00247         case AttributeList::AT_dllimport: HandleDLLImportAttr(D, Attr, S);
00248                                           return true;
00249         case AttributeList::AT_dllexport: HandleDLLExportAttr(D, Attr, S);
00250                                           return true;
00251         default:                          break;
00252         }
00253       }
00254       if (Triple.getArch() != llvm::Triple::x86_64 &&
00255           (Attr.getName()->getName() == "force_align_arg_pointer" ||
00256            Attr.getName()->getName() == "__force_align_arg_pointer__")) {
00257         HandleX86ForceAlignArgPointerAttr(D, Attr, S);
00258         return true;
00259       }
00260       return false;
00261     }
00262   };
00263 }
00264 
00265 const TargetAttributesSema &Sema::getTargetAttributesSema() const {
00266   if (TheTargetAttributesSema)
00267     return *TheTargetAttributesSema;
00268 
00269   const llvm::Triple &Triple(Context.getTargetInfo().getTriple());
00270   switch (Triple.getArch()) {
00271   case llvm::Triple::msp430:
00272     return *(TheTargetAttributesSema = new MSP430AttributesSema);
00273   case llvm::Triple::mblaze:
00274     return *(TheTargetAttributesSema = new MBlazeAttributesSema);
00275   case llvm::Triple::x86:
00276   case llvm::Triple::x86_64:
00277     return *(TheTargetAttributesSema = new X86AttributesSema);
00278   default:
00279     return *(TheTargetAttributesSema = new TargetAttributesSema);
00280   }
00281 }