TargetAttributesSema.cpp revision 263508
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 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 58namespace { 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 73static 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 105namespace { 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 120static 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 152DLLImportAttr *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 175static 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 208DLLExportAttr *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 222static 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 252namespace { 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 280static 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 297static 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 315namespace { 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 333const 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} 354