xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Attributes.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric #include "clang/Basic/Attributes.h"
20b57cec5SDimitry Andric #include "clang/Basic/AttrSubjectMatchRules.h"
3a7dea167SDimitry Andric #include "clang/Basic/AttributeCommonInfo.h"
40b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
5*06c3fb27SDimitry Andric #include "clang/Basic/ParsedAttrInfo.h"
60b57cec5SDimitry Andric using namespace clang;
70b57cec5SDimitry Andric 
8*06c3fb27SDimitry Andric static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
9*06c3fb27SDimitry Andric                             StringRef ScopeName, const TargetInfo &Target,
10*06c3fb27SDimitry Andric                             const LangOptions &LangOpts) {
11*06c3fb27SDimitry Andric 
12*06c3fb27SDimitry Andric #include "clang/Basic/AttrHasAttributeImpl.inc"
13*06c3fb27SDimitry Andric 
14*06c3fb27SDimitry Andric   return 0;
15*06c3fb27SDimitry Andric }
16*06c3fb27SDimitry Andric 
1781ad6265SDimitry Andric int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
1881ad6265SDimitry Andric                         const IdentifierInfo *Scope, const IdentifierInfo *Attr,
1981ad6265SDimitry Andric                         const TargetInfo &Target, const LangOptions &LangOpts) {
200b57cec5SDimitry Andric   StringRef Name = Attr->getName();
210b57cec5SDimitry Andric   // Normalize the attribute name, __foo__ becomes foo.
220b57cec5SDimitry Andric   if (Name.size() >= 4 && Name.startswith("__") && Name.endswith("__"))
230b57cec5SDimitry Andric     Name = Name.substr(2, Name.size() - 4);
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric   // Normalize the scope name, but only for gnu and clang attributes.
260b57cec5SDimitry Andric   StringRef ScopeName = Scope ? Scope->getName() : "";
270b57cec5SDimitry Andric   if (ScopeName == "__gnu__")
280b57cec5SDimitry Andric     ScopeName = "gnu";
290b57cec5SDimitry Andric   else if (ScopeName == "_Clang")
300b57cec5SDimitry Andric     ScopeName = "clang";
310b57cec5SDimitry Andric 
32fe6060f1SDimitry Andric   // As a special case, look for the omp::sequence and omp::directive
33fe6060f1SDimitry Andric   // attributes. We support those, but not through the typical attribute
34fe6060f1SDimitry Andric   // machinery that goes through TableGen. We support this in all OpenMP modes
35fe6060f1SDimitry Andric   // so long as double square brackets are enabled.
36*06c3fb27SDimitry Andric   if (LangOpts.OpenMP && ScopeName == "omp")
37fe6060f1SDimitry Andric     return (Name == "directive" || Name == "sequence") ? 1 : 0;
38fe6060f1SDimitry Andric 
39*06c3fb27SDimitry Andric   int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts);
40*06c3fb27SDimitry Andric   if (res)
41*06c3fb27SDimitry Andric     return res;
42*06c3fb27SDimitry Andric 
43*06c3fb27SDimitry Andric   // Check if any plugin provides this attribute.
44*06c3fb27SDimitry Andric   for (auto &Ptr : getAttributePluginInstances())
45*06c3fb27SDimitry Andric     if (Ptr->hasSpelling(Syntax, Name))
46*06c3fb27SDimitry Andric       return 1;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   return 0;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
520b57cec5SDimitry Andric   switch (Rule) {
530b57cec5SDimitry Andric #define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract)                            \
540b57cec5SDimitry Andric   case attr::NAME:                                                             \
550b57cec5SDimitry Andric     return SPELLING;
560b57cec5SDimitry Andric #include "clang/Basic/AttrSubMatchRulesList.inc"
570b57cec5SDimitry Andric   }
580b57cec5SDimitry Andric   llvm_unreachable("Invalid subject match rule");
590b57cec5SDimitry Andric }
60a7dea167SDimitry Andric 
61a7dea167SDimitry Andric static StringRef
625ffd83dbSDimitry Andric normalizeAttrScopeName(const IdentifierInfo *Scope,
63a7dea167SDimitry Andric                        AttributeCommonInfo::Syntax SyntaxUsed) {
645ffd83dbSDimitry Andric   if (!Scope)
655ffd83dbSDimitry Andric     return "";
665ffd83dbSDimitry Andric 
67a7dea167SDimitry Andric   // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
68a7dea167SDimitry Andric   // to be "clang".
695ffd83dbSDimitry Andric   StringRef ScopeName = Scope->getName();
70a7dea167SDimitry Andric   if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
71a7dea167SDimitry Andric       SyntaxUsed == AttributeCommonInfo::AS_C2x) {
72a7dea167SDimitry Andric     if (ScopeName == "__gnu__")
73a7dea167SDimitry Andric       ScopeName = "gnu";
74a7dea167SDimitry Andric     else if (ScopeName == "_Clang")
75a7dea167SDimitry Andric       ScopeName = "clang";
76a7dea167SDimitry Andric   }
77a7dea167SDimitry Andric   return ScopeName;
78a7dea167SDimitry Andric }
79a7dea167SDimitry Andric 
805ffd83dbSDimitry Andric static StringRef normalizeAttrName(const IdentifierInfo *Name,
81a7dea167SDimitry Andric                                    StringRef NormalizedScopeName,
82a7dea167SDimitry Andric                                    AttributeCommonInfo::Syntax SyntaxUsed) {
83a7dea167SDimitry Andric   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
84a7dea167SDimitry Andric   // for GNU attributes, and attributes using the double square bracket syntax.
85a7dea167SDimitry Andric   bool ShouldNormalize =
86a7dea167SDimitry Andric       SyntaxUsed == AttributeCommonInfo::AS_GNU ||
87a7dea167SDimitry Andric       ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
88a7dea167SDimitry Andric         SyntaxUsed == AttributeCommonInfo::AS_C2x) &&
89a7dea167SDimitry Andric        (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
90a7dea167SDimitry Andric         NormalizedScopeName == "clang"));
915ffd83dbSDimitry Andric   StringRef AttrName = Name->getName();
92a7dea167SDimitry Andric   if (ShouldNormalize && AttrName.size() >= 4 && AttrName.startswith("__") &&
93a7dea167SDimitry Andric       AttrName.endswith("__"))
94a7dea167SDimitry Andric     AttrName = AttrName.slice(2, AttrName.size() - 2);
95a7dea167SDimitry Andric 
96a7dea167SDimitry Andric   return AttrName;
97a7dea167SDimitry Andric }
98a7dea167SDimitry Andric 
99a7dea167SDimitry Andric bool AttributeCommonInfo::isGNUScope() const {
100a7dea167SDimitry Andric   return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
101a7dea167SDimitry Andric }
102a7dea167SDimitry Andric 
10381ad6265SDimitry Andric bool AttributeCommonInfo::isClangScope() const {
10481ad6265SDimitry Andric   return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang"));
10581ad6265SDimitry Andric }
10681ad6265SDimitry Andric 
107a7dea167SDimitry Andric #include "clang/Sema/AttrParsedAttrKinds.inc"
108a7dea167SDimitry Andric 
1095ffd83dbSDimitry Andric static SmallString<64> normalizeName(const IdentifierInfo *Name,
1105ffd83dbSDimitry Andric                                      const IdentifierInfo *Scope,
1115ffd83dbSDimitry Andric                                      AttributeCommonInfo::Syntax SyntaxUsed) {
1125ffd83dbSDimitry Andric   StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
1135ffd83dbSDimitry Andric   StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed);
1145ffd83dbSDimitry Andric 
1155ffd83dbSDimitry Andric   SmallString<64> FullName = ScopeName;
1165ffd83dbSDimitry Andric   if (!ScopeName.empty()) {
1175ffd83dbSDimitry Andric     assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
1185ffd83dbSDimitry Andric            SyntaxUsed == AttributeCommonInfo::AS_C2x);
1195ffd83dbSDimitry Andric     FullName += "::";
1205ffd83dbSDimitry Andric   }
1215ffd83dbSDimitry Andric   FullName += AttrName;
1225ffd83dbSDimitry Andric 
1235ffd83dbSDimitry Andric   return FullName;
1245ffd83dbSDimitry Andric }
1255ffd83dbSDimitry Andric 
126a7dea167SDimitry Andric AttributeCommonInfo::Kind
127a7dea167SDimitry Andric AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
128a7dea167SDimitry Andric                                    const IdentifierInfo *ScopeName,
129a7dea167SDimitry Andric                                    Syntax SyntaxUsed) {
1305ffd83dbSDimitry Andric   return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
1315ffd83dbSDimitry Andric }
132a7dea167SDimitry Andric 
1335ffd83dbSDimitry Andric std::string AttributeCommonInfo::getNormalizedFullName() const {
1345ffd83dbSDimitry Andric   return static_cast<std::string>(
1355ffd83dbSDimitry Andric       normalizeName(getAttrName(), getScopeName(), getSyntax()));
136a7dea167SDimitry Andric }
137a7dea167SDimitry Andric 
138a7dea167SDimitry Andric unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
139a7dea167SDimitry Andric   // Both variables will be used in tablegen generated
140a7dea167SDimitry Andric   // attribute spell list index matching code.
141a7dea167SDimitry Andric   auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
1425ffd83dbSDimitry Andric   StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax);
1435ffd83dbSDimitry Andric   StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax);
144a7dea167SDimitry Andric 
145a7dea167SDimitry Andric #include "clang/Sema/AttrSpellingListIndex.inc"
146a7dea167SDimitry Andric }
147