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 using namespace clang; 21 22 static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name, 23 StringRef ScopeName, const TargetInfo &Target, 24 const LangOptions &LangOpts) { 25 26 #include "clang/Basic/AttrHasAttributeImpl.inc" 27 28 return 0; 29 } 30 31 int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, 32 const IdentifierInfo *Scope, const IdentifierInfo *Attr, 33 const TargetInfo &Target, const LangOptions &LangOpts) { 34 StringRef Name = Attr->getName(); 35 // Normalize the attribute name, __foo__ becomes foo. 36 if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__")) 37 Name = Name.substr(2, Name.size() - 4); 38 39 // Normalize the scope name, but only for gnu and clang attributes. 40 StringRef ScopeName = Scope ? Scope->getName() : ""; 41 if (ScopeName == "__gnu__") 42 ScopeName = "gnu"; 43 else if (ScopeName == "_Clang") 44 ScopeName = "clang"; 45 46 // As a special case, look for the omp::sequence and omp::directive 47 // attributes. We support those, but not through the typical attribute 48 // machinery that goes through TableGen. We support this in all OpenMP modes 49 // so long as double square brackets are enabled. 50 // 51 // Other OpenMP attributes (e.g. [[omp::assume]]) are handled via the 52 // regular attribute parsing machinery. 53 if (LangOpts.OpenMP && ScopeName == "omp" && 54 (Name == "directive" || Name == "sequence")) 55 return 1; 56 57 int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts); 58 if (res) 59 return res; 60 61 // Check if any plugin provides this attribute. 62 for (auto &Ptr : getAttributePluginInstances()) 63 if (Ptr->hasSpelling(Syntax, Name)) 64 return 1; 65 66 return 0; 67 } 68 69 const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) { 70 switch (Rule) { 71 #define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract) \ 72 case attr::NAME: \ 73 return SPELLING; 74 #include "clang/Basic/AttrSubMatchRulesList.inc" 75 } 76 llvm_unreachable("Invalid subject match rule"); 77 } 78 79 static StringRef 80 normalizeAttrScopeName(const IdentifierInfo *Scope, 81 AttributeCommonInfo::Syntax SyntaxUsed) { 82 if (!Scope) 83 return ""; 84 85 // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name 86 // to be "clang". 87 StringRef ScopeName = Scope->getName(); 88 if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 89 SyntaxUsed == AttributeCommonInfo::AS_C23) { 90 if (ScopeName == "__gnu__") 91 ScopeName = "gnu"; 92 else if (ScopeName == "_Clang") 93 ScopeName = "clang"; 94 } 95 return ScopeName; 96 } 97 98 static StringRef normalizeAttrName(const IdentifierInfo *Name, 99 StringRef NormalizedScopeName, 100 AttributeCommonInfo::Syntax SyntaxUsed) { 101 // Normalize the attribute name, __foo__ becomes foo. This is only allowable 102 // for GNU attributes, and attributes using the double square bracket syntax. 103 bool ShouldNormalize = 104 SyntaxUsed == AttributeCommonInfo::AS_GNU || 105 ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 106 SyntaxUsed == AttributeCommonInfo::AS_C23) && 107 (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" || 108 NormalizedScopeName == "clang")); 109 StringRef AttrName = Name->getName(); 110 if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") && 111 AttrName.ends_with("__")) 112 AttrName = AttrName.slice(2, AttrName.size() - 2); 113 114 return AttrName; 115 } 116 117 bool AttributeCommonInfo::isGNUScope() const { 118 return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); 119 } 120 121 bool AttributeCommonInfo::isClangScope() const { 122 return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")); 123 } 124 125 #include "clang/Sema/AttrParsedAttrKinds.inc" 126 127 static SmallString<64> normalizeName(const IdentifierInfo *Name, 128 const IdentifierInfo *Scope, 129 AttributeCommonInfo::Syntax SyntaxUsed) { 130 StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed); 131 StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed); 132 133 SmallString<64> FullName = ScopeName; 134 if (!ScopeName.empty()) { 135 assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 || 136 SyntaxUsed == AttributeCommonInfo::AS_C23); 137 FullName += "::"; 138 } 139 FullName += AttrName; 140 141 return FullName; 142 } 143 144 AttributeCommonInfo::Kind 145 AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name, 146 const IdentifierInfo *ScopeName, 147 Syntax SyntaxUsed) { 148 return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed); 149 } 150 151 std::string AttributeCommonInfo::getNormalizedFullName() const { 152 return static_cast<std::string>( 153 normalizeName(getAttrName(), getScopeName(), getSyntax())); 154 } 155 156 unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const { 157 // Both variables will be used in tablegen generated 158 // attribute spell list index matching code. 159 auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax()); 160 StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax); 161 StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax); 162 163 #include "clang/Sema/AttrSpellingListIndex.inc" 164 } 165