Home | History | Annotate | Download | only in Sema
      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 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 
     61 namespace {
     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 
     76 static 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 
    108 DLLImportAttr *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 
    131 static 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 
    164 DLLExportAttr *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 
    178 static 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 
    208 namespace {
    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 
    236 static 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 
    253 static 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 
    271 namespace {
    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 
    289 const 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