xref: /freebsd/contrib/llvm-project/clang/lib/Basic/Attributes.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15f757f3fSDimitry Andric //===--- Attributes.cpp ---------------------------------------------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric //
95f757f3fSDimitry Andric // This file implements the AttributeCommonInfo interface.
105f757f3fSDimitry Andric //
115f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
125f757f3fSDimitry Andric 
130b57cec5SDimitry Andric #include "clang/Basic/Attributes.h"
140b57cec5SDimitry Andric #include "clang/Basic/AttrSubjectMatchRules.h"
150b57cec5SDimitry Andric #include "clang/Basic/IdentifierTable.h"
165f757f3fSDimitry Andric #include "clang/Basic/LangOptions.h"
1706c3fb27SDimitry Andric #include "clang/Basic/ParsedAttrInfo.h"
185f757f3fSDimitry Andric #include "clang/Basic/TargetInfo.h"
195f757f3fSDimitry Andric 
200b57cec5SDimitry Andric using namespace clang;
210b57cec5SDimitry Andric 
hasAttributeImpl(AttributeCommonInfo::Syntax Syntax,StringRef Name,StringRef ScopeName,const TargetInfo & Target,const LangOptions & LangOpts)2206c3fb27SDimitry Andric static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name,
2306c3fb27SDimitry Andric                             StringRef ScopeName, const TargetInfo &Target,
2406c3fb27SDimitry Andric                             const LangOptions &LangOpts) {
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric #include "clang/Basic/AttrHasAttributeImpl.inc"
2706c3fb27SDimitry Andric 
2806c3fb27SDimitry Andric   return 0;
2906c3fb27SDimitry Andric }
3006c3fb27SDimitry Andric 
hasAttribute(AttributeCommonInfo::Syntax Syntax,const IdentifierInfo * Scope,const IdentifierInfo * Attr,const TargetInfo & Target,const LangOptions & LangOpts)3181ad6265SDimitry Andric int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax,
3281ad6265SDimitry Andric                         const IdentifierInfo *Scope, const IdentifierInfo *Attr,
3381ad6265SDimitry Andric                         const TargetInfo &Target, const LangOptions &LangOpts) {
340b57cec5SDimitry Andric   StringRef Name = Attr->getName();
350b57cec5SDimitry Andric   // Normalize the attribute name, __foo__ becomes foo.
365f757f3fSDimitry Andric   if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__"))
370b57cec5SDimitry Andric     Name = Name.substr(2, Name.size() - 4);
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric   // Normalize the scope name, but only for gnu and clang attributes.
400b57cec5SDimitry Andric   StringRef ScopeName = Scope ? Scope->getName() : "";
410b57cec5SDimitry Andric   if (ScopeName == "__gnu__")
420b57cec5SDimitry Andric     ScopeName = "gnu";
430b57cec5SDimitry Andric   else if (ScopeName == "_Clang")
440b57cec5SDimitry Andric     ScopeName = "clang";
450b57cec5SDimitry Andric 
46fe6060f1SDimitry Andric   // As a special case, look for the omp::sequence and omp::directive
47fe6060f1SDimitry Andric   // attributes. We support those, but not through the typical attribute
48fe6060f1SDimitry Andric   // machinery that goes through TableGen. We support this in all OpenMP modes
49fe6060f1SDimitry Andric   // so long as double square brackets are enabled.
50*0fca6ea1SDimitry Andric   //
51*0fca6ea1SDimitry Andric   // Other OpenMP attributes (e.g. [[omp::assume]]) are handled via the
52*0fca6ea1SDimitry Andric   // regular attribute parsing machinery.
53*0fca6ea1SDimitry Andric   if (LangOpts.OpenMP && ScopeName == "omp" &&
54*0fca6ea1SDimitry Andric       (Name == "directive" || Name == "sequence"))
55*0fca6ea1SDimitry Andric     return 1;
56fe6060f1SDimitry Andric 
5706c3fb27SDimitry Andric   int res = hasAttributeImpl(Syntax, Name, ScopeName, Target, LangOpts);
5806c3fb27SDimitry Andric   if (res)
5906c3fb27SDimitry Andric     return res;
6006c3fb27SDimitry Andric 
6106c3fb27SDimitry Andric   // Check if any plugin provides this attribute.
6206c3fb27SDimitry Andric   for (auto &Ptr : getAttributePluginInstances())
6306c3fb27SDimitry Andric     if (Ptr->hasSpelling(Syntax, Name))
6406c3fb27SDimitry Andric       return 1;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   return 0;
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule)690b57cec5SDimitry Andric const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) {
700b57cec5SDimitry Andric   switch (Rule) {
710b57cec5SDimitry Andric #define ATTR_MATCH_RULE(NAME, SPELLING, IsAbstract)                            \
720b57cec5SDimitry Andric   case attr::NAME:                                                             \
730b57cec5SDimitry Andric     return SPELLING;
740b57cec5SDimitry Andric #include "clang/Basic/AttrSubMatchRulesList.inc"
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric   llvm_unreachable("Invalid subject match rule");
770b57cec5SDimitry Andric }
78a7dea167SDimitry Andric 
79a7dea167SDimitry Andric static StringRef
normalizeAttrScopeName(const IdentifierInfo * Scope,AttributeCommonInfo::Syntax SyntaxUsed)805ffd83dbSDimitry Andric normalizeAttrScopeName(const IdentifierInfo *Scope,
81a7dea167SDimitry Andric                        AttributeCommonInfo::Syntax SyntaxUsed) {
825ffd83dbSDimitry Andric   if (!Scope)
835ffd83dbSDimitry Andric     return "";
845ffd83dbSDimitry Andric 
85a7dea167SDimitry Andric   // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name
86a7dea167SDimitry Andric   // to be "clang".
875ffd83dbSDimitry Andric   StringRef ScopeName = Scope->getName();
88a7dea167SDimitry Andric   if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
895f757f3fSDimitry Andric       SyntaxUsed == AttributeCommonInfo::AS_C23) {
90a7dea167SDimitry Andric     if (ScopeName == "__gnu__")
91a7dea167SDimitry Andric       ScopeName = "gnu";
92a7dea167SDimitry Andric     else if (ScopeName == "_Clang")
93a7dea167SDimitry Andric       ScopeName = "clang";
94a7dea167SDimitry Andric   }
95a7dea167SDimitry Andric   return ScopeName;
96a7dea167SDimitry Andric }
97a7dea167SDimitry Andric 
normalizeAttrName(const IdentifierInfo * Name,StringRef NormalizedScopeName,AttributeCommonInfo::Syntax SyntaxUsed)985ffd83dbSDimitry Andric static StringRef normalizeAttrName(const IdentifierInfo *Name,
99a7dea167SDimitry Andric                                    StringRef NormalizedScopeName,
100a7dea167SDimitry Andric                                    AttributeCommonInfo::Syntax SyntaxUsed) {
101a7dea167SDimitry Andric   // Normalize the attribute name, __foo__ becomes foo. This is only allowable
102a7dea167SDimitry Andric   // for GNU attributes, and attributes using the double square bracket syntax.
103a7dea167SDimitry Andric   bool ShouldNormalize =
104a7dea167SDimitry Andric       SyntaxUsed == AttributeCommonInfo::AS_GNU ||
105a7dea167SDimitry Andric       ((SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
1065f757f3fSDimitry Andric         SyntaxUsed == AttributeCommonInfo::AS_C23) &&
107a7dea167SDimitry Andric        (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" ||
108a7dea167SDimitry Andric         NormalizedScopeName == "clang"));
1095ffd83dbSDimitry Andric   StringRef AttrName = Name->getName();
1105f757f3fSDimitry Andric   if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") &&
1115f757f3fSDimitry Andric       AttrName.ends_with("__"))
112a7dea167SDimitry Andric     AttrName = AttrName.slice(2, AttrName.size() - 2);
113a7dea167SDimitry Andric 
114a7dea167SDimitry Andric   return AttrName;
115a7dea167SDimitry Andric }
116a7dea167SDimitry Andric 
isGNUScope() const117a7dea167SDimitry Andric bool AttributeCommonInfo::isGNUScope() const {
118a7dea167SDimitry Andric   return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__"));
119a7dea167SDimitry Andric }
120a7dea167SDimitry Andric 
isClangScope() const12181ad6265SDimitry Andric bool AttributeCommonInfo::isClangScope() const {
12281ad6265SDimitry Andric   return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang"));
12381ad6265SDimitry Andric }
12481ad6265SDimitry Andric 
125a7dea167SDimitry Andric #include "clang/Sema/AttrParsedAttrKinds.inc"
126a7dea167SDimitry Andric 
normalizeName(const IdentifierInfo * Name,const IdentifierInfo * Scope,AttributeCommonInfo::Syntax SyntaxUsed)1275ffd83dbSDimitry Andric static SmallString<64> normalizeName(const IdentifierInfo *Name,
1285ffd83dbSDimitry Andric                                      const IdentifierInfo *Scope,
1295ffd83dbSDimitry Andric                                      AttributeCommonInfo::Syntax SyntaxUsed) {
1305ffd83dbSDimitry Andric   StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed);
1315ffd83dbSDimitry Andric   StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed);
1325ffd83dbSDimitry Andric 
1335ffd83dbSDimitry Andric   SmallString<64> FullName = ScopeName;
1345ffd83dbSDimitry Andric   if (!ScopeName.empty()) {
1355ffd83dbSDimitry Andric     assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 ||
1365f757f3fSDimitry Andric            SyntaxUsed == AttributeCommonInfo::AS_C23);
1375ffd83dbSDimitry Andric     FullName += "::";
1385ffd83dbSDimitry Andric   }
1395ffd83dbSDimitry Andric   FullName += AttrName;
1405ffd83dbSDimitry Andric 
1415ffd83dbSDimitry Andric   return FullName;
1425ffd83dbSDimitry Andric }
1435ffd83dbSDimitry Andric 
144a7dea167SDimitry Andric AttributeCommonInfo::Kind
getParsedKind(const IdentifierInfo * Name,const IdentifierInfo * ScopeName,Syntax SyntaxUsed)145a7dea167SDimitry Andric AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name,
146a7dea167SDimitry Andric                                    const IdentifierInfo *ScopeName,
147a7dea167SDimitry Andric                                    Syntax SyntaxUsed) {
1485ffd83dbSDimitry Andric   return ::getAttrKind(normalizeName(Name, ScopeName, SyntaxUsed), SyntaxUsed);
1495ffd83dbSDimitry Andric }
150a7dea167SDimitry Andric 
getNormalizedFullName() const1515ffd83dbSDimitry Andric std::string AttributeCommonInfo::getNormalizedFullName() const {
1525ffd83dbSDimitry Andric   return static_cast<std::string>(
1535ffd83dbSDimitry Andric       normalizeName(getAttrName(), getScopeName(), getSyntax()));
154a7dea167SDimitry Andric }
155a7dea167SDimitry Andric 
calculateAttributeSpellingListIndex() const156a7dea167SDimitry Andric unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const {
157a7dea167SDimitry Andric   // Both variables will be used in tablegen generated
158a7dea167SDimitry Andric   // attribute spell list index matching code.
159a7dea167SDimitry Andric   auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax());
1605ffd83dbSDimitry Andric   StringRef Scope = normalizeAttrScopeName(getScopeName(), Syntax);
1615ffd83dbSDimitry Andric   StringRef Name = normalizeAttrName(getAttrName(), Scope, Syntax);
162a7dea167SDimitry Andric 
163a7dea167SDimitry Andric #include "clang/Sema/AttrSpellingListIndex.inc"
164a7dea167SDimitry Andric }
165