1 //===--- Attributes.cpp ---------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the AttributeCommonInfo interface. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/Basic/Attributes.h" 14 #include "clang/Basic/AttrSubjectMatchRules.h" 15 #include "clang/Basic/IdentifierTable.h" 16 #include "clang/Basic/LangOptions.h" 17 #include "clang/Basic/ParsedAttrInfo.h" 18 #include "clang/Basic/TargetInfo.h" 19 20 #include "llvm/ADT/StringMap.h" 21 22 using namespace clang; 23 24 static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name, 25 StringRef ScopeName, const TargetInfo &Target, 26 const LangOptions &LangOpts) { 27 28 #include "clang/Basic/AttrHasAttributeImpl.inc" 29 30 return 0; 31 } 32 33 int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, 34 const IdentifierInfo *Scope, const IdentifierInfo *Attr, 35 const TargetInfo &Target, const LangOptions &LangOpts) { 36 StringRef Name = Attr->getName(); 37 // Normalize the attribute name, __foo__ becomes foo. 38 if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__")) 39 Name = Name.substr(2, Name.size() - 4); 40 41 // Normalize the scope name, but only for gnu and clang attributes. 42 StringRef ScopeName = Scope ? Scope->getName() : ""; 43 if (ScopeName == "__gnu__") 44 ScopeName = "gnu"; 45 else if (ScopeName == "_Clang") 46 ScopeName = "clang"; 47 48 // As a special case, look for the omp::sequence and omp::directive 49 // attributes. We support those, but not through the typical attribute 50 // machinery that goes through TableGen. We support this in all OpenMP modes 51 // so long as double square brackets are enabled. 52 // 53 // Other OpenMP attributes (e.g. [[omp::assume]]) are handled via the 54 // regular attribute parsing machinery. 55 if (LangOpts.OpenMP && ScopeName == "omp" && 56 (Name == "directive" || Name == "sequence")) 57 return 1; 58 59 int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts); 60 if (res) 61 return res; 62 63 // Check if any plugin provides this attribute. 64 for (auto &Ptr : getAttributePluginInstances()) 65 if (Ptr->hasSpelling(Syntax, Name)) 66 return 1; 67 68 return 0; 69 } 70 71 const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) { 72 switch (Rule) { 73 #define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \ 74 case attr::NAME: \ 75 return SPELLING; 76 #include "clang/Basic/AttrSubMatchRulesList.inc" 77 } 78 llvm_unreachable("Invalid subject match rule"); 79 } 80 81 static StringRef 82 normalizeAttrScopeName(const IdentifierInfo *Scope, 83 AttributeCommonInfo::Syntax SyntaxUsed) { 84 if (!Scope) 85 return ""; 86 87 // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name 88 // to be "clang". 89 StringRef ScopeName = Scope->getName(); 90 if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 91 SyntaxUsed == AttributeCommonInfo::AS_C23) { 92 if (ScopeName == "__gnu__") 93 ScopeName = "gnu"; 94 else if (ScopeName == "_Clang") 95 ScopeName = "clang"; 96 } 97 return ScopeName; 98 } 99 100 static StringRef normalizeAttrName(const IdentifierInfo *Name, 101 StringRef NormalizedScopeName, 102 AttributeCommonInfo::Syntax SyntaxUsed) { 103 // Normalize the attribute name, __foo__ becomes foo. This is only allowable 104 // for GNU attributes, and attributes using the double square bracket syntax. 105 bool ShouldNormalize = 106 SyntaxUsed == AttributeCommonInfo::AS_GNU || 107 ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 108 SyntaxUsed == AttributeCommonInfo::AS_C23) && 109 (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" || 110 NormalizedScopeName == "clang")); 111 StringRef AttrName = Name->getName(); 112 if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") && 113 AttrName.ends_with("__")) 114 AttrName = AttrName.slice(2, AttrName.size() - 2); 115 116 return AttrName; 117 } 118 119 bool AttributeCommonInfo::isGNUScope() const { 120 return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); 121 } 122 123 bool AttributeCommonInfo::isClangScope() const { 124 return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")); 125 } 126 127 #include "clang/Sema/AttrParsedAttrKinds.inc" 128 129 static SmallString<64> normalizeName(const IdentifierInfo *Name, 130 const IdentifierInfo *Scope, 131 AttributeCommonInfo::Syntax SyntaxUsed) { 132 StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed); 133 StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed); 134 135 SmallString<64> FullName = ScopeName; 136 if (!ScopeName.empty()) { 137 assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 138 SyntaxUsed == AttributeCommonInfo::AS_C23); 139 FullName += "::"; 140 } 141 FullName += AttrName; 142 143 return FullName; 144 } 145 146 AttributeCommonInfo::Kind 147 AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name, 148 const IdentifierInfo *ScopeName, 149 Syntax SyntaxUsed) { 150 return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed); 151 } 152 153 std::string AttributeCommonInfo::getNormalizedFullName() const { 154 return static_cast<std::string>( 155 normalizeName(getAttrName(), getScopeName(), getSyntax())); 156 } 157 158 // Sorted list of attribute scope names 159 static constexpr std::pair<StringRef, AttributeCommonInfo::Scope> ScopeList[] = 160 {{"", AttributeCommonInfo::Scope::NONE}, 161 {"clang", AttributeCommonInfo::Scope::CLANG}, 162 {"gnu", AttributeCommonInfo::Scope::GNU}, 163 {"gsl", AttributeCommonInfo::Scope::GSL}, 164 {"hlsl", AttributeCommonInfo::Scope::HLSL}, 165 {"msvc", AttributeCommonInfo::Scope::MSVC}, 166 {"omp", AttributeCommonInfo::Scope::OMP}, 167 {"riscv", AttributeCommonInfo::Scope::RISCV}}; 168 169 AttributeCommonInfo::Scope 170 getScopeFromNormalizedScopeName(StringRef ScopeName) { 171 auto It = std::lower_bound( 172 std::begin(ScopeList), std::end(ScopeList), ScopeName, 173 [](const std::pair<StringRef, AttributeCommonInfo::Scope> &Element, 174 StringRef Value) { return Element.first < Value; }); 175 assert(It != std::end(ScopeList) && It->first == ScopeName); 176 177 return It->second; 178 } 179 180 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const { 181 // Both variables will be used in tablegen generated 182 // attribute spell list index matching code. 183 auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax()); 184 StringRef ScopeName = normalizeAttrScopeName(getScopeName(), Syntax); 185 StringRef Name = normalizeAttrName(getAttrName(), ScopeName, Syntax); 186 187 AttributeCommonInfo::Scope ComputedScope = 188 getScopeFromNormalizedScopeName(ScopeName); 189 190 #include "clang/Sema/AttrSpellingListIndex.inc" 191 } 192