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